diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index e657796865..a899e14cc9 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1661,7 +1661,7 @@ unsigned int ModelObject::update_instances_print_volume_state(const BuildVolume if (inside_outside == INSIDE) ++num_printable; if (bed_idx != -1) - s_multiple_beds.set_instance_bed(model_instance->id(), bed_idx); + s_multiple_beds.set_instance_bed(model_instance->id(), model_instance->printable, bed_idx); } return num_printable; } diff --git a/src/libslic3r/MultipleBeds.cpp b/src/libslic3r/MultipleBeds.cpp index 6996646289..67e94ced42 100644 --- a/src/libslic3r/MultipleBeds.cpp +++ b/src/libslic3r/MultipleBeds.cpp @@ -115,12 +115,16 @@ Vec3d MultipleBeds::get_bed_translation(int id) const void MultipleBeds::clear_inst_map() { m_inst_to_bed.clear(); + m_occupied_beds_cache.fill(false); } -void MultipleBeds::set_instance_bed(ObjectID id, int bed_idx) +void MultipleBeds::set_instance_bed(ObjectID id, bool printable, int bed_idx) { assert(bed_idx < get_max_beds()); m_inst_to_bed[id] = bed_idx; + + if (printable) + m_occupied_beds_cache[bed_idx] = true; } void MultipleBeds::inst_map_updated() @@ -298,6 +302,11 @@ Vec2d MultipleBeds::bed_gap() const return Vec2d::Ones() * gap; } +bool MultipleBeds::is_bed_occupied(int i) const +{ + return m_occupied_beds_cache[i]; +} + Vec2crd MultipleBeds::get_bed_gap() const { return scaled(Vec2d{bed_gap() / 2.0}); diff --git a/src/libslic3r/MultipleBeds.hpp b/src/libslic3r/MultipleBeds.hpp index 6daa7ce99a..ac27a710ab 100644 --- a/src/libslic3r/MultipleBeds.hpp +++ b/src/libslic3r/MultipleBeds.hpp @@ -32,9 +32,10 @@ public: Vec3d get_bed_translation(int id) const; void clear_inst_map(); - void set_instance_bed(ObjectID id, int bed_idx); + void set_instance_bed(ObjectID id, bool printable, int bed_idx); void inst_map_updated(); const std::map &get_inst_map() const { return m_inst_to_bed; } + bool is_bed_occupied(int bed_idx) const; int get_number_of_beds() const { return m_number_of_beds; } bool should_show_next_bed() const { return m_show_next_bed; } @@ -78,6 +79,7 @@ private: bool m_show_next_bed = false; std::map m_inst_to_bed; std::map m_printbase_to_texture; + std::array m_occupied_beds_cache; int m_last_hovered_bed = -1; BoundingBoxf m_build_volume_bb; bool m_legacy_layout = false; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9cbf2c8d24..1e2d01fa0d 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -139,6 +139,7 @@ void GLCanvas3D::select_bed(int i, bool triggered_by_user) wxGetApp().plater()->get_camera().translate_world(s_multiple_beds.get_bed_translation(i) - s_multiple_beds.get_bed_translation(old_bed)); } wxGetApp().plater()->schedule_background_process(); + wxGetApp().plater()->object_list_changed(); // Updates Slice Now / Export buttons. if (s_multiple_beds.is_autoslicing() && triggered_by_user) s_multiple_beds.stop_autoslice(false); }); @@ -6314,7 +6315,7 @@ void GLCanvas3D::_render_overlays() void Slic3r::GUI::GLCanvas3D::_render_bed_selector() { static float btn_side = 80.f; - static float btn_border = 4.f; + static float btn_border = 2.f; static bool hide_title = true; ImVec2 btn_size = ImVec2(btn_side, btn_side); @@ -6325,27 +6326,38 @@ void Slic3r::GUI::GLCanvas3D::_render_bed_selector() //ImGui::Text("%d", i); //ImGui::SameLine(); + bool empty = ! s_multiple_beds.is_bed_occupied(i); bool inactive = i != s_multiple_beds.get_active_bed() || s_multiple_beds.is_autoslicing(); - if (inactive) - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0., 0., 0., .5)); - if (bool clicked = (i >= int(s_th_tex_id.size())) - ? ImGui::Button(std::to_string(i).c_str(), btn_size) - : ImGui::ImageButton((void*)(int64_t)s_th_tex_id[i], btn_size, ImVec2(0, 1), ImVec2(1, 0)); - clicked) + + ImGui::PushStyleColor(ImGuiCol_Button, ImGuiPureWrap::COL_GREY_DARK); + ImGui::PushStyleColor(ImGuiCol_Border, inactive ? ImGuiPureWrap::COL_GREY_DARK : ImGuiPureWrap::COL_BUTTON_ACTIVE); + + if (empty) + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + + bool clicked = false; + ImVec2 btn_padding = ImVec2(btn_border, btn_border); + if (i >= int(s_th_tex_id.size()) || empty) + clicked = ImGui::Button(empty ? "empty" : std::to_string(i + 1).c_str(), btn_size + btn_padding); + else + clicked = ImGui::ImageButton((void*)(int64_t)s_th_tex_id[i], btn_size - btn_padding, ImVec2(0, 1), ImVec2(1, 0), btn_border); + + if (clicked && ! empty) select_bed(i, true); - if (inactive) - ImGui::PopStyleColor(); + ImGui::PopStyleColor(2); + if (empty) + ImGui::PopItemFlag(); - std::string status_text; - if (wxGetApp().plater()->get_fff_prints()[i]->finished()) - status_text = "Finished"; - else if (m_process->fff_print() == wxGetApp().plater()->get_fff_prints()[i].get() && m_process->running()) - status_text = "Running"; - else - status_text = "Idle"; - if (ImGui::IsItemHovered()) - ImGui::SetTooltip(status_text.c_str()); + //std::string status_text; + //if (wxGetApp().plater()->get_fff_prints()[i]->finished()) + // status_text = "Finished"; + //else if (m_process->fff_print() == wxGetApp().plater()->get_fff_prints()[i].get() && m_process->running()) + // status_text = "Running"; + //else + // status_text = "Idle"; + //if (ImGui::IsItemHovered()) + // ImGui::SetTooltip(status_text.c_str()); }; ImGuiWrapper& imgui = *wxGetApp().imgui(); @@ -6365,9 +6377,8 @@ void Slic3r::GUI::GLCanvas3D::_render_bed_selector() #endif ImGui::Begin("Bed selector", 0, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.f); ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2()); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(btn_border, btn_border)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2()); // Disable for now. //if (imgui.image_button(ImGui::SliceAllBtnIcon, "Slice All")) { @@ -6386,7 +6397,7 @@ void Slic3r::GUI::GLCanvas3D::_render_bed_selector() ImGui::SameLine(); } - ImGui::PopStyleVar(4); + ImGui::PopStyleVar(3); #if use_scrolling bool extra_frame{ false }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index e62d11f55f..cb45ef0488 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1874,7 +1874,7 @@ void Plater::priv::object_list_changed() // XXX: is this right? const bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() == ModelInstancePVS_Inside; - sidebar->enable_buttons(!model.objects.empty() && !export_in_progress && model_fits); + sidebar->enable_buttons(s_multiple_beds.is_bed_occupied(s_multiple_beds.get_active_bed()) && !model.objects.empty() && !export_in_progress && model_fits); } void Plater::priv::select_all() @@ -2979,13 +2979,17 @@ void Plater::priv::set_current_panel(wxPanel* panel) // FIXME: it may be better to have a single function making this check and let it be called wherever needed bool export_in_progress = this->background_process.is_export_scheduled(); bool model_fits = view3D->get_canvas3d()->check_volumes_outside_state() != ModelInstancePVS_Partly_Outside; - if (!model.objects.empty() && !export_in_progress && model_fits) { + if (s_multiple_beds.is_bed_occupied(s_multiple_beds.get_active_bed()) && !model.objects.empty() && !export_in_progress && model_fits) { preview->get_canvas3d()->init_gcode_viewer(); preview->load_gcode_shells(); q->reslice(); } // keeps current gcode preview, if any preview->reload_print(); + + if (! s_multiple_beds.is_bed_occupied(s_multiple_beds.get_active_bed())) + preview->get_canvas3d()->reset_gcode_toolpaths(); + } preview->set_as_dirty(); @@ -4564,6 +4568,11 @@ void Plater::reload_print() p->preview->reload_print(); } +void Plater::object_list_changed() +{ + p->object_list_changed(); +} + std::vector Plater::load_files(const std::vector& input_files, bool load_model, bool load_config, bool imperial_units /*= false*/) { return p->load_files(input_files, load_model, load_config, imperial_units); } // To be called when providing a list of files to the GUI slic3r on command line. @@ -5535,8 +5544,9 @@ void Plater::apply_cut_object_to_model(size_t obj_idx, const ModelObjectPtrs& ne size_t last_id = p->model.objects.size() - 1; for (size_t i = 0; i < new_objects.size(); ++i) { selection.add_object((unsigned int)(last_id - i), i == 0); - const ObjectID instance_id{p->model.objects[last_id - i]->instances.front()->id().id}; - s_multiple_beds.set_instance_bed(instance_id, s_multiple_beds.get_active_bed()); + const ModelInstance* mi = p->model.objects[last_id - i]->instances.front(); + const ObjectID instance_id{mi->id().id}; + s_multiple_beds.set_instance_bed(instance_id, mi->printable, s_multiple_beds.get_active_bed()); } UIThreadWorker w; diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 8816196558..af5058869f 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -117,6 +117,7 @@ public: void convert_gcode_to_ascii(); void convert_gcode_to_binary(); void reload_print(); + void object_list_changed(); std::vector load_files(const std::vector& input_files, bool load_model = true, bool load_config = true, bool imperial_units = false); // To be called when providing a list of files to the GUI slic3r on command line.