diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 88547359e..faf5a745d 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -275,6 +275,8 @@ public: int volume_id; // Instance ID, which is equal to the index of the respective ModelInstance in ModelObject.instances array. int instance_id; + bool operator==(const CompositeID &rhs) const { return object_id == rhs.object_id && volume_id == rhs.volume_id && instance_id == rhs.instance_id; } + bool operator!=(const CompositeID &rhs) const { return ! (*this == rhs); } }; CompositeID composite_id; // Fingerprint of the source geometry. For ModelVolumes, it is the ModelVolume::ID and ModelInstanceID, diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 8aa3205a7..6690e33e3 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1870,8 +1870,12 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (m_reload_delayed) return; + bool update_object_list = false; + if (m_regenerate_volumes) { + if (m_volumes.volumes != glvolumes_new) + update_object_list = true; m_volumes.volumes = std::move(glvolumes_new); for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++ obj_idx) { const ModelObject &model_object = *m_model->objects[obj_idx]; @@ -1886,12 +1890,16 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // New volume. m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_use_VBOs && m_initialized); m_volumes.volumes.back()->geometry_id = key.geometry_id; + update_object_list = true; } else { // Recycling an old GLVolume. GLVolume &existing_volume = *m_volumes.volumes[it->volume_idx]; assert(existing_volume.geometry_id == key.geometry_id); // Update the Object/Volume/Instance indices into the current Model. - existing_volume.composite_id = it->composite_id; + if (existing_volume.composite_id != it->composite_id) { + existing_volume.composite_id = it->composite_id; + update_object_list = true; + } } } } @@ -1999,7 +2007,8 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re m_gizmos.update_data(*this); // Update the toolbar - post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); + if (update_object_list) + post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT)); // checks for geometry outside the print volume to render it accordingly if (!m_volumes.empty()) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 663ff8ad9..3c569b591 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -16,6 +16,50 @@ namespace Slic3r namespace GUI { +static wxBitmapComboBox* create_word_local_combo(wxWindow *parent) +{ + wxSize size(15 * wxGetApp().em_unit(), -1); + + wxBitmapComboBox *temp = nullptr; +#ifdef __WXOSX__ + /* wxBitmapComboBox with wxCB_READONLY style return NULL for GetTextCtrl(), + * so ToolTip doesn't shown. + * Next workaround helps to solve this problem + */ + temp = new wxBitmapComboBox(); + temp->SetTextCtrlStyle(wxTE_READONLY); + temp->Create(parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr); +#else + temp = new wxBitmapComboBox(parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr, wxCB_READONLY); +#endif //__WXOSX__ + + temp->SetFont(Slic3r::GUI::wxGetApp().normal_font()); + temp->SetBackgroundStyle(wxBG_STYLE_PAINT); + + temp->Append(_(L("World"))); + temp->Append(_(L("Local"))); + temp->SetSelection(0); + temp->SetValue(temp->GetString(0)); + +#ifndef __WXGTK__ + /* Workaround for a correct rendering of the control without Bitmap (under MSW and OSX): + * + * 1. We should create small Bitmap to fill Bitmaps RefData, + * ! in this case wxBitmap.IsOK() return true. + * 2. But then set width to 0 value for no using of bitmap left and right spacing + * 3. Set this empty bitmap to the at list one item and BitmapCombobox will be recreated correct + * + * Note: Set bitmap height to the Font size because of OSX rendering. + */ + wxBitmap empty_bmp(1, temp->GetFont().GetPixelSize().y + 2); + empty_bmp.SetWidth(0); + temp->SetItemBitmap(0, empty_bmp); +#endif + + temp->SetToolTip(_(L("Select coordinate space, in which the transformation will be performed."))); + return temp; +} + ObjectManipulation::ObjectManipulation(wxWindow* parent) : OG_Settings(parent, true) #ifndef __APPLE__ @@ -63,6 +107,12 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : Option option = Option(def, axis + "_axis_legend"); line.append_option(option); } + line.near_label_widget = [this](wxWindow* parent) { + wxBitmapComboBox *combo = create_word_local_combo(parent); + combo->Bind(wxEVT_COMBOBOX, ([this](wxCommandEvent &evt) { this->set_world_coordinates(evt.GetSelection() != 1); }), combo->GetId()); + m_word_local_combo = combo; + return combo; + }; m_og->append_line(line); auto add_og_to_object_settings = [this, field_width](const std::string& option_name, const std::string& sidetext) @@ -145,9 +195,8 @@ bool ObjectManipulation::IsShown() void ObjectManipulation::UpdateAndShow(const bool show) { - if (show) { + if (show) update_settings_value(wxGetApp().plater()->canvas3D()->get_selection()); - } OG_Settings::UpdateAndShow(show); } @@ -164,8 +213,8 @@ void ObjectManipulation::update_settings_value(const Selection& selection) // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); m_new_position = volume->get_instance_offset(); - m_new_rotation = volume->get_instance_rotation(); - m_new_scale = volume->get_instance_scaling_factor(); + m_new_rotation = volume->get_instance_rotation() * (180. / M_PI); + m_new_scale = volume->get_instance_scaling_factor() * 100.; int obj_idx = volume->object_idx(); int instance_idx = volume->instance_idx(); if ((0 <= obj_idx) && (obj_idx < (int)wxGetApp().model_objects()->size())) @@ -178,7 +227,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) changed_box = true; } //FIXME matching an instance idx may not be enough. Check for ModelObject id an all ModelVolume ids. - if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(100.0 * m_new_scale)) + if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(m_new_scale)) m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(m_cache.instance.box_size); } else { @@ -197,7 +246,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) const BoundingBoxf3& box = selection.get_bounding_box(); m_new_position = box.center(); m_new_rotation = Vec3d::Zero(); - m_new_scale = Vec3d(1.0, 1.0, 1.0); + m_new_scale = Vec3d(100., 100., 100.); m_new_size = box.size(); m_new_rotate_label_string = L("Rotate"); m_new_scale_label_string = L("Scale"); @@ -210,8 +259,8 @@ void ObjectManipulation::update_settings_value(const Selection& selection) // the selection contains a single volume const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); m_new_position = volume->get_volume_offset(); - m_new_rotation = volume->get_volume_rotation(); - m_new_scale = volume->get_volume_scaling_factor(); + m_new_rotation = volume->get_volume_rotation() * (180. / M_PI); + m_new_scale = volume->get_volume_scaling_factor() * 100.; m_new_size = volume->get_volume_transformation().get_scaling_factor().cwiseProduct(volume->bounding_box.size()); m_new_enabled = true; } @@ -226,7 +275,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) } else { // No selection, reset the cache. - assert(selection.is_empty()); +// assert(selection.is_empty()); reset_settings_value(); } @@ -249,26 +298,24 @@ void ObjectManipulation::update_if_dirty() update_label(m_cache.rotate_label_string, m_new_rotate_label_string, m_rotate_Label); update_label(m_cache.scale_label_string, m_new_scale_label_string, m_scale_Label); - Vec3d scale = m_new_scale * 100.0; - Vec3d deg_rotation = (180.0 / M_PI) * m_new_rotation; - char axis[2] = "x"; for (int i = 0; i < 3; ++ i, ++ axis[0]) { - if (m_cache.position(i) != m_new_position(i)) - m_og->set_value(std::string("position_") + axis, double_to_string(m_new_position(i), 2)); - if (m_cache.scale(i) != scale(i)) - m_og->set_value(std::string("scale_") + axis, double_to_string(scale(i), 2)); - if (m_cache.size(i) != m_new_size(i)) - m_og->set_value(std::string("size_") + axis, double_to_string(m_new_size(i), 2)); - if (m_cache.rotation(i) != m_new_rotation(i) || m_new_rotation(i) == 0.0) - m_og->set_value(std::string("rotation_") + axis, double_to_string(deg_rotation(i), 2)); + auto update = [this, i, &axis](Vec3d &cached, Vec3d &cached_rounded, const char *key, const Vec3d &new_value) { + wxString new_text = double_to_string(new_value(i), 2); + double new_rounded; + new_text.ToDouble(&new_rounded); + if (std::abs(cached_rounded(i) - new_rounded) > EPSILON) { + cached_rounded(i) = new_rounded; + m_og->set_value(std::string(key) + axis, new_text); + } + cached(i) = new_value(i); + }; + update(m_cache.position, m_cache.position_rounded, "position_", m_new_position); + update(m_cache.scale, m_cache.scale_rounded, "scale_", m_new_scale); + update(m_cache.size, m_cache.size_rounded, "size_", m_new_size); + update(m_cache.rotation, m_cache.rotation_rounded, "rotation_", m_new_rotation); } - m_cache.position = m_new_position; - m_cache.scale = scale; - m_cache.size = m_new_size; - m_cache.rotation = deg_rotation; - if (wxGetApp().plater()->canvas3D()->get_selection().requires_uniform_scale()) { m_lock_bnt->SetLock(true); m_lock_bnt->Disable(); @@ -278,6 +325,12 @@ void ObjectManipulation::update_if_dirty() m_lock_bnt->Enable(); } + { + int new_selection = m_world_coordinates ? 0 : 1; + if (m_word_local_combo->GetSelection() != new_selection) + m_word_local_combo->SetSelection(new_selection); + } + if (m_new_enabled) m_og->enable(); else @@ -314,8 +367,14 @@ void ObjectManipulation::reset_settings_value() m_dirty = true; } -void ObjectManipulation::change_position_value(const Vec3d& position) +void ObjectManipulation::change_position_value(int axis, double value) { + if (std::abs(m_cache.position_rounded(axis) - value) < EPSILON) + return; + + Vec3d position = m_cache.position; + position(axis) = value; + auto canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); selection.start_dragging(); @@ -323,10 +382,18 @@ void ObjectManipulation::change_position_value(const Vec3d& position) canvas->do_move(); m_cache.position = position; + m_cache.position_rounded(axis) = DBL_MAX; + this->UpdateAndShow(true); } -void ObjectManipulation::change_rotation_value(const Vec3d& rotation) +void ObjectManipulation::change_rotation_value(int axis, double value) { + if (std::abs(m_cache.rotation_rounded(axis) - value) < EPSILON) + return; + + Vec3d rotation = m_cache.rotation; + rotation(axis) = value; + GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); @@ -346,20 +413,36 @@ void ObjectManipulation::change_rotation_value(const Vec3d& rotation) canvas->do_rotate(); m_cache.rotation = rotation; + m_cache.rotation_rounded(axis) = DBL_MAX; + this->UpdateAndShow(true); } -void ObjectManipulation::change_scale_value(const Vec3d& scale) +void ObjectManipulation::change_scale_value(int axis, double value) { + if (std::abs(m_cache.scale_rounded(axis) - value) < EPSILON) + return; + + Vec3d scale = m_cache.scale; + scale(axis) = value; + this->do_scale(scale); if (!m_cache.scale.isApprox(scale)) m_cache.instance.instance_idx = -1; m_cache.scale = scale; + m_cache.scale_rounded(axis) = DBL_MAX; + this->UpdateAndShow(true); } -void ObjectManipulation::change_size_value(const Vec3d& size) +void ObjectManipulation::change_size_value(int axis, double value) { + if (std::abs(m_cache.size_rounded(axis) - value) < EPSILON) + return; + + Vec3d size = m_cache.size; + size(axis) = value; + const Selection& selection = wxGetApp().plater()->canvas3D()->get_selection(); Vec3d ref_size = m_cache.size; @@ -371,9 +454,11 @@ void ObjectManipulation::change_size_value(const Vec3d& size) else if (selection.is_single_full_instance() && ! m_world_coordinates) ref_size = m_cache.instance.box_size; - this->do_scale(100.0 * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2))); + this->do_scale(100. * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2))); m_cache.size = size; + m_cache.size_rounded(axis) = DBL_MAX; + this->UpdateAndShow(true); } void ObjectManipulation::do_scale(const Vec3d &scale) const @@ -407,20 +492,17 @@ void ObjectManipulation::on_change(t_config_option_key opt_key, const boost::any if (!m_cache.is_valid()) return; - // Value of all three axes of the position / rotation / scale / size is extracted. - Vec3d new_value; - opt_key.back() = 'x'; - for (int i = 0; i < 3; ++ i, ++ opt_key.back()) - new_value(i) = boost::any_cast(m_og->get_value(opt_key)); + int axis = opt_key.back() - 'x'; + double new_value = boost::any_cast(m_og->get_value(opt_key)); if (boost::starts_with(opt_key, "position_")) - change_position_value(new_value); + change_position_value(axis, new_value); else if (boost::starts_with(opt_key, "rotation_")) - change_rotation_value(new_value); + change_rotation_value(axis, new_value); else if (boost::starts_with(opt_key, "scale_")) - change_scale_value(new_value); + change_scale_value(axis, new_value); else if (boost::starts_with(opt_key, "size_")) - change_size_value(new_value); + change_size_value(axis, new_value); } void ObjectManipulation::on_fill_empty_value(const std::string& opt_key) @@ -435,19 +517,28 @@ void ObjectManipulation::on_fill_empty_value(const std::string& opt_key) return; const Vec3d *vec = nullptr; - if (boost::starts_with(opt_key, "position_")) + Vec3d *rounded = nullptr; + if (boost::starts_with(opt_key, "position_")) { vec = &m_cache.position; - else if (boost::starts_with(opt_key, "rotation_")) + rounded = &m_cache.position_rounded; + } else if (boost::starts_with(opt_key, "rotation_")) { vec = &m_cache.rotation; - else if (boost::starts_with(opt_key, "scale_")) + rounded = &m_cache.rotation_rounded; + } else if (boost::starts_with(opt_key, "scale_")) { vec = &m_cache.scale; - else if (boost::starts_with(opt_key, "size_")) + rounded = &m_cache.scale_rounded; + } else if (boost::starts_with(opt_key, "size_")) { vec = &m_cache.size; - else + rounded = &m_cache.size_rounded; + } else assert(false); - if (vec != nullptr) - m_og->set_value(opt_key, double_to_string((*vec)(opt_key.back() - 'x'))); + if (vec != nullptr) { + int axis = opt_key.back() - 'x'; + wxString new_text = double_to_string((*vec)(axis)); + m_og->set_value(opt_key, new_text); + new_text.ToDouble(&(*rounded)(axis)); + } } } //namespace GUI diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index ecd306c0a..09b1b4fe6 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -19,9 +19,13 @@ class ObjectManipulation : public OG_Settings struct Cache { Vec3d position; + Vec3d position_rounded; Vec3d rotation; + Vec3d rotation_rounded; Vec3d scale; + Vec3d scale_rounded; Vec3d size; + Vec3d size_rounded; std::string move_label_string; std::string rotate_label_string; @@ -46,10 +50,10 @@ class ObjectManipulation : public OG_Settings Cache() { reset(); } void reset() { - position = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); - rotation = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); - scale = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); - size = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); + position = position_rounded = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); + rotation = rotation_rounded = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); + scale = scale_rounded = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); + size = size_rounded = Vec3d(DBL_MAX, DBL_MAX, DBL_MAX); move_label_string = ""; rotate_label_string = ""; scale_label_string = ""; @@ -79,6 +83,7 @@ class ObjectManipulation : public OG_Settings // Does the object manipulation panel work in World or Local coordinates? bool m_world_coordinates = true; PrusaLockButton* m_lock_bnt{ nullptr }; + wxBitmapComboBox* m_word_local_combo = nullptr; #ifndef __APPLE__ // Currently focused option name (empty if none) @@ -101,6 +106,7 @@ public: void set_uniform_scaling(const bool uniform_scale) { m_uniform_scale = uniform_scale;} bool get_uniform_scaling() const { return m_uniform_scale; } // Does the object manipulation panel work in World or Local coordinates? + void set_world_coordinates(const bool world_coordinates) { m_world_coordinates = world_coordinates; this->UpdateAndShow(true); } bool get_world_coordinates() const { return m_world_coordinates; } void reset_cache() { m_cache.reset(); } @@ -120,10 +126,10 @@ private: void update_rotation_value(const Vec3d& rotation); // change values - void change_position_value(const Vec3d& position); - void change_rotation_value(const Vec3d& rotation); - void change_scale_value(const Vec3d& scale); - void change_size_value(const Vec3d& size); + void change_position_value(int axis, double value); + void change_rotation_value(int axis, double value); + void change_scale_value(int axis, double value); + void change_size_value(int axis, double value); void do_scale(const Vec3d &scale) const; void on_change(t_config_option_key opt_key, const boost::any& value); diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 4abbbd45a..a4686d4d2 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -172,19 +172,21 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n // Build a label if we have it wxStaticText* label=nullptr; if (label_width != 0) { - long label_style = staticbox ? 0 : wxALIGN_RIGHT; -#ifdef __WXGTK__ - // workaround for correct text align of the StaticBox on Linux - // flags wxALIGN_RIGHT and wxALIGN_CENTRE don't work when Ellipsize flags are _not_ given. - // Text is properly aligned only when Ellipsize is checked. - label_style |= staticbox ? 0 : wxST_ELLIPSIZE_END; -#endif /* __WXGTK__ */ - label = new wxStaticText(this->ctrl_parent(), wxID_ANY, line.label + (line.label.IsEmpty() ? "" : ": "), - wxDefaultPosition, wxSize(label_width, -1), label_style); - label->SetBackgroundStyle(wxBG_STYLE_PAINT); - label->SetFont(label_font); - label->Wrap(label_width); // avoid a Linux/GTK bug - if (!line.near_label_widget) + if (! line.near_label_widget || ! line.label.IsEmpty()) { + long label_style = staticbox ? 0 : wxALIGN_RIGHT; + #ifdef __WXGTK__ + // workaround for correct text align of the StaticBox on Linux + // flags wxALIGN_RIGHT and wxALIGN_CENTRE don't work when Ellipsize flags are _not_ given. + // Text is properly aligned only when Ellipsize is checked. + label_style |= staticbox ? 0 : wxST_ELLIPSIZE_END; + #endif /* __WXGTK__ */ + label = new wxStaticText(this->ctrl_parent(), wxID_ANY, line.label + (line.label.IsEmpty() ? "" : ": "), + wxDefaultPosition, wxSize(label_width, -1), label_style); + label->SetBackgroundStyle(wxBG_STYLE_PAINT); + label->SetFont(label_font); + label->Wrap(label_width); // avoid a Linux/GTK bug + } + if (! line.near_label_widget) grid_sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, line.label.IsEmpty() ? 0 : 5); else if (line.near_label_widget && line.label.IsEmpty()) grid_sizer->Add(line.near_label_widget(this->ctrl_parent()), 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 7); @@ -196,7 +198,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n sizer->Add(line.near_label_widget(this->ctrl_parent()), 0, wxRIGHT, 7); sizer->Add(label, 0, (staticbox ? 0 : wxALIGN_RIGHT | wxRIGHT) | wxALIGN_CENTER_VERTICAL, 5); } - if (line.label_tooltip.compare("") != 0) + if (label != nullptr && line.label_tooltip != "") label->SetToolTip(line.label_tooltip); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8eb68fc39..b41b27af8 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1056,9 +1056,9 @@ void Sidebar::enable_buttons(bool enable) p->btn_send_gcode->Enable(enable); } -void Sidebar::show_reslice(bool show) const { p->btn_reslice->Show(show); } -void Sidebar::show_export(bool show) const { p->btn_export_gcode->Show(show); } -void Sidebar::show_send(bool show) const { p->btn_send_gcode->Show(show); } +bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Show(show); } +bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); } +bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); } bool Sidebar::is_multifilament() { @@ -3129,17 +3129,18 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const // when a background processing is ON, export_btn and/or send_btn are showing if (wxGetApp().app_config->get("background_processing") == "1") { - sidebar->show_reslice(false); - sidebar->show_export(true); - sidebar->show_send(send_gcode_shown); - } + if (sidebar->show_reslice(false) | + sidebar->show_export(true) | + sidebar->show_send(send_gcode_shown)) + sidebar->Layout(); + } else { - sidebar->show_reslice(is_ready_to_slice); - sidebar->show_export(!is_ready_to_slice); - sidebar->show_send(send_gcode_shown && !is_ready_to_slice); - } - sidebar->Layout(); + if (sidebar->show_reslice(is_ready_to_slice) | + sidebar->show_export(!is_ready_to_slice) | + sidebar->show_send(send_gcode_shown && !is_ready_to_slice)) + sidebar->Layout(); + } } void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& label) const diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 5319e3b43..f9c5a4d7f 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -96,9 +96,9 @@ public: void show_sliced_info_sizer(const bool show); void enable_buttons(bool enable); void set_btn_label(const ActionButtonType btn_type, const wxString& label) const; - void show_reslice(bool show) const; - void show_export(bool show) const; - void show_send(bool show) const; + bool show_reslice(bool show) const; + bool show_export(bool show) const; + bool show_send(bool show) const; bool is_multifilament(); void update_mode();