diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 6d082a431a..f74775a9a9 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -498,7 +498,7 @@ Point SeamPlacer::calculate_seam(const Layer& layer, const SeamPosition seam_pos else if (seam_position == spRear) { // Object is centered around (0,0) in its current coordinate system. last_pos.x() = 0; - last_pos.y() += coord_t(3. * po->bounding_box().radius()); + last_pos.y() = coord_t(3. * po->bounding_box().radius()); last_pos_weight = 5.f; } if (seam_position == spNearest) { // last_pos already contains current nozzle position diff --git a/src/libslic3r/Layer.cpp b/src/libslic3r/Layer.cpp index 5c661ed68b..d273fde963 100644 --- a/src/libslic3r/Layer.cpp +++ b/src/libslic3r/Layer.cpp @@ -92,6 +92,25 @@ void Layer::restore_untyped_slices() } } +// Similar to Layer::restore_untyped_slices() +// To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442. +// Only resetting layerm->slices if Slice::extra_perimeters is always zero or it will not be used anymore +// after the perimeter generator. +void Layer::restore_untyped_slices_no_extra_perimeters() +{ + if (layer_needs_raw_backup(this)) { + for (LayerRegion *layerm : m_regions) + if (! layerm->region().config().extra_perimeters.value) + layerm->slices.set(layerm->raw_slices, stInternal); + } else { + assert(m_regions.size() == 1); + LayerRegion *layerm = m_regions.front(); + // This optimization is correct, as extra_perimeters are only reused by prepare_infill() with multi-regions. + //if (! layerm->region().config().extra_perimeters.value) + layerm->slices.set(this->lslices, stInternal); + } +} + ExPolygons Layer::merged(float offset_scaled) const { assert(offset_scaled >= 0.f); @@ -179,7 +198,7 @@ void Layer::make_perimeters() // group slices (surfaces) according to number of extra perimeters std::map slices; // extra_perimeters => [ surface, surface... ] for (LayerRegion *layerm : layerms) { - for (Surface &surface : layerm->slices.surfaces) + for (const Surface &surface : layerm->slices.surfaces) slices[surface.extra_perimeters].emplace_back(surface); if (layerm->region().config().fill_density > layerm_config->region().config().fill_density) layerm_config = layerm; diff --git a/src/libslic3r/Layer.hpp b/src/libslic3r/Layer.hpp index 516b6da9b1..0071c7f6e1 100644 --- a/src/libslic3r/Layer.hpp +++ b/src/libslic3r/Layer.hpp @@ -137,6 +137,8 @@ public: //FIXME Review whether not to simplify the code by keeping the raw_slices all the time. void backup_untyped_slices(); void restore_untyped_slices(); + // To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442. + void restore_untyped_slices_no_extra_perimeters(); // Slices merged into islands, to be used by the elephant foot compensation to trim the individual surfaces with the shrunk merged slices. ExPolygons merged(float offset) const; template bool any_internal_region_slice_contains(const T &item) const { diff --git a/src/libslic3r/LayerRegion.cpp b/src/libslic3r/LayerRegion.cpp index 4dbffe7b0f..fd29d6d54c 100644 --- a/src/libslic3r/LayerRegion.cpp +++ b/src/libslic3r/LayerRegion.cpp @@ -51,8 +51,7 @@ void LayerRegion::slices_to_fill_surfaces_clipped() // so we're safe. This guarantees idempotence of prepare_infill() also in case // that combine_infill() turns some fill_surface into VOID surfaces. // Collect polygons per surface type. - std::vector by_surface; - by_surface.assign(size_t(stCount), SurfacesPtr()); + std::array by_surface; for (Surface &surface : this->slices.surfaces) by_surface[size_t(surface.surface_type)].emplace_back(&surface); // Trim surfaces by the fill_boundaries. diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 11e741ec61..b2e6457143 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -3773,7 +3773,7 @@ void PrintConfigDef::init_sla_params() def->enum_labels.push_back(L("Slow")); def->enum_labels.push_back(L("Fast")); def->mode = comAdvanced; - def->set_default_value(new ConfigOptionEnum(slamsSlow)); + def->set_default_value(new ConfigOptionEnum(slamsFast)); } void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 97d13af75d..05b8c9eb68 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -227,6 +227,17 @@ void PrintObject::prepare_infill() m_print->set_status(30, L("Preparing infill")); + if (m_typed_slices) { + // To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442. + // The preceding step (perimeter generator) only modifies extra_perimeters and the extra perimeters are only used by discover_vertical_shells() + // with more than a single region. If this step does not use Surface::extra_perimeters or Surface::extra_perimeters is always zero, it is safe + // to reset to the untyped slices before re-runnning detect_surfaces_type(). + for (Layer* layer : m_layers) { + layer->restore_untyped_slices_no_extra_perimeters(); + m_print->throw_if_canceled(); + } + } + // This will assign a type (top/bottom/internal) to $layerm->slices. // Then the classifcation of $layerm->slices is transfered onto // the $layerm->fill_surfaces by clipping $layerm->fill_surfaces diff --git a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp index 614e838114..691a867063 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoHollow.cpp @@ -550,24 +550,24 @@ RENDER_AGAIN: ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); ImGui::PushItemWidth(window_width - settings_sliders_left); m_imgui->slider_float("##offset", &offset, offset_min, offset_max, "%.1f mm"); - if (ImGui::IsItemHovered()) + if (m_imgui->get_last_slider_status().hovered) m_imgui->tooltip((_utf8(opts[0].second->tooltip)).c_str(), max_tooltip_width); - bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider - bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider - bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider + bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider + bool slider_edited =m_imgui->get_last_slider_status().edited; // someone is dragging the slider + bool slider_released =m_imgui->get_last_slider_status().deactivated_after_edit; // someone has just released the slider if (current_mode >= quality_mode) { ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("quality")); ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); m_imgui->slider_float("##quality", &quality, quality_min, quality_max, "%.1f"); - if (ImGui::IsItemHovered()) + if (m_imgui->get_last_slider_status().hovered) m_imgui->tooltip((_utf8(opts[1].second->tooltip)).c_str(), max_tooltip_width); - slider_clicked |= ImGui::IsItemClicked(); - slider_edited |= ImGui::IsItemEdited(); - slider_released |= ImGui::IsItemDeactivatedAfterEdit(); + slider_clicked |= m_imgui->get_last_slider_status().clicked; + slider_edited |= m_imgui->get_last_slider_status().edited; + slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit; } if (current_mode >= closing_d_mode) { @@ -575,12 +575,12 @@ RENDER_AGAIN: m_imgui->text(m_desc.at("closing_distance")); ImGui::SameLine(settings_sliders_left, m_imgui->get_item_spacing().x); m_imgui->slider_float("##closing_distance", &closing_d, closing_d_min, closing_d_max, "%.1f mm"); - if (ImGui::IsItemHovered()) + if (m_imgui->get_last_slider_status().hovered) m_imgui->tooltip((_utf8(opts[2].second->tooltip)).c_str(), max_tooltip_width); - slider_clicked |= ImGui::IsItemClicked(); - slider_edited |= ImGui::IsItemEdited(); - slider_released |= ImGui::IsItemDeactivatedAfterEdit(); + slider_clicked |= m_imgui->get_last_slider_status().clicked; + slider_edited |= m_imgui->get_last_slider_status().edited; + slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit; } if (slider_clicked) { @@ -627,9 +627,9 @@ RENDER_AGAIN: //complete non-sense. diam = std::clamp(diam, 0.1f, diameter_upper_cap); m_new_hole_radius = diam / 2.f; - bool clicked = ImGui::IsItemClicked(); - bool edited = ImGui::IsItemEdited(); - bool deactivated = ImGui::IsItemDeactivatedAfterEdit(); + bool clicked = m_imgui->get_last_slider_status().clicked; + bool edited = m_imgui->get_last_slider_status().edited; + bool deactivated = m_imgui->get_last_slider_status().deactivated_after_edit; ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc["hole_depth"]); @@ -638,9 +638,9 @@ RENDER_AGAIN: // Same as above: m_new_hole_height = std::clamp(m_new_hole_height, 0.f, 100.f); - clicked |= ImGui::IsItemClicked(); - edited |= ImGui::IsItemEdited(); - deactivated |= ImGui::IsItemDeactivatedAfterEdit(); + clicked |= m_imgui->get_last_slider_status().clicked; + edited |= m_imgui->get_last_slider_status().edited; + deactivated |= m_imgui->get_last_slider_status().deactivated_after_edit;; // Following is a nasty way to: // - save the initial value of the slider before one starts messing with it diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index e164caee6d..8b866c7c99 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -859,9 +859,9 @@ void GLPaintContour::finalize_geometry() if (!this->contour_indices.empty()) { glsafe(::glGenBuffers(1, &this->m_contour_EBO_id)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->m_contour_EBO_id)); - glsafe(::glBufferData(GL_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW)); - glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_contour_EBO_id)); + glsafe(::glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->contour_indices.size() * sizeof(unsigned int), this->contour_indices.data(), GL_STATIC_DRAW)); + glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); this->contour_indices.clear(); } } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 9170db6039..29e1fd2f30 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -687,16 +687,16 @@ RENDER_AGAIN: // - take correct undo/redo snapshot after the user is done with moving the slider float initial_value = m_new_point_head_diameter; m_imgui->slider_float("##head_diameter", &m_new_point_head_diameter, 0.1f, diameter_upper_cap, "%.1f"); - if (ImGui::IsItemClicked()) { + if (m_imgui->get_last_slider_status().clicked) { if (m_old_point_head_diameter == 0.f) m_old_point_head_diameter = initial_value; } - if (ImGui::IsItemEdited()) { + if (m_imgui->get_last_slider_status().edited) { for (auto& cache_entry : m_editing_cache) if (cache_entry.selected) cache_entry.support_point.head_front_radius = m_new_point_head_diameter / 2.f; } - if (ImGui::IsItemDeactivatedAfterEdit()) { + if (m_imgui->get_last_slider_status().deactivated_after_edit) { // momentarily restore the old value to take snapshot for (auto& cache_entry : m_editing_cache) if (cache_entry.selected) @@ -747,18 +747,18 @@ RENDER_AGAIN: float minimal_point_distance = static_cast(opts[1])->value; m_imgui->slider_float("##minimal_point_distance", &minimal_point_distance, 0.f, 20.f, "%.f mm"); - bool slider_clicked = ImGui::IsItemClicked(); // someone clicked the slider - bool slider_edited = ImGui::IsItemEdited(); // someone is dragging the slider - bool slider_released = ImGui::IsItemDeactivatedAfterEdit(); // someone has just released the slider + bool slider_clicked = m_imgui->get_last_slider_status().clicked; // someone clicked the slider + bool slider_edited = m_imgui->get_last_slider_status().edited; // someone is dragging the slider + bool slider_released = m_imgui->get_last_slider_status().deactivated_after_edit; // someone has just released the slider ImGui::AlignTextToFramePadding(); m_imgui->text(m_desc.at("points_density")); ImGui::SameLine(settings_sliders_left); m_imgui->slider_float("##points_density", &density, 0.f, 200.f, "%.f %%"); - slider_clicked |= ImGui::IsItemClicked(); - slider_edited |= ImGui::IsItemEdited(); - slider_released |= ImGui::IsItemDeactivatedAfterEdit(); + slider_clicked |= m_imgui->get_last_slider_status().clicked; + slider_edited |= m_imgui->get_last_slider_status().edited; + slider_released |= m_imgui->get_last_slider_status().deactivated_after_edit; if (slider_clicked) { // stash the values of the settings so we know what to revert to after undo m_minimal_point_distance_stash = minimal_point_distance; diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 48186cde91..62af8012bd 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -551,6 +551,12 @@ bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float bool slider_editing = ImGui::GetCurrentWindow()->GetID(str_label.c_str()) == ImGui::GetActiveID(); bool ret = ImGui::SliderFloat(str_label.c_str(), v, v_min, v_max, format, power); + + m_last_slider_status.hovered = ImGui::IsItemHovered(); + m_last_slider_status.edited = ImGui::IsItemEdited(); + m_last_slider_status.clicked = ImGui::IsItemClicked(); + m_last_slider_status.deactivated_after_edit = ImGui::IsItemDeactivatedAfterEdit(); + if (!tooltip.empty() && ImGui::IsItemHovered()) this->tooltip(into_u8(tooltip).c_str(), max_tooltip_width); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index a1ecc6712f..d85d6b387b 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -45,6 +45,13 @@ class ImGuiWrapper std::string m_clipboard_text; public: + struct LastSliderStatus { + bool hovered { false }; + bool edited { false }; + bool clicked { false }; + bool deactivated_after_edit { false }; + }; + ImGuiWrapper(); ~ImGuiWrapper(); @@ -69,6 +76,7 @@ public: ImVec2 get_item_spacing() const; float get_slider_float_height() const; + const LastSliderStatus& get_last_slider_status() const { return m_last_slider_status; } void set_next_window_pos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f); void set_next_window_bg_alpha(float alpha); @@ -161,6 +169,8 @@ private: static const char* clipboard_get(void* user_data); static void clipboard_set(void* user_data, const char* text); + + LastSliderStatus m_last_slider_status; }; diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 84bfd1f9f6..6039dcbcb9 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -2,11 +2,13 @@ #include "ConfigExceptions.hpp" #include "Plater.hpp" #include "GUI_App.hpp" +#include "MainFrame.hpp" #include "OG_CustomCtrl.hpp" #include "MsgDialog.hpp" #include "format.hpp" #include +#include #include #include #include @@ -978,7 +980,8 @@ bool OptionsGroup::launch_browser(const std::string& path_end) bool launch = true; if (get_app_config()->get("suppress_hyperlinks").empty()) { - RichMessageDialog dialog(nullptr, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxYES_NO); + wxWindow* parent = wxGetApp().mainframe->m_tabpanel; + RichMessageDialog dialog(parent, _L("Open hyperlink in default browser?"), _L("PrusaSlicer: Open hyperlink"), wxYES_NO); dialog.ShowCheckBox(_L("Remember my choice")); int answer = dialog.ShowModal(); @@ -989,7 +992,7 @@ bool OptionsGroup::launch_browser(const std::string& path_end) _L("You will not be asked about it again on label hovering.") + "\n\n" + format_wxstr(_L("Visit \"Preferences\" and check \"%1%\"\nto changes your choice."), preferences_item); - MessageDialog msg_dlg(nullptr, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION); + MessageDialog msg_dlg(parent, msg, _L("PrusaSlicer: Don't ask me again"), wxOK | wxCANCEL | wxICON_INFORMATION); if (msg_dlg.ShowModal() == wxID_CANCEL) return false; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 3172e22c3c..335dd6619a 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -885,6 +885,10 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/) } m_postpone_update_ui = false; + + // When all values are rolled, then we hane to update whole tab in respect to the reverted values + update(); + update_changed_ui(); } @@ -1148,6 +1152,13 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) if (opt_key == "extruders_count") wxGetApp().plater()->on_extruders_change(boost::any_cast(value)); + if (m_postpone_update_ui) { + // It means that not all values are rolled to the system/last saved values jet. + // And call of the update() can causes a redundant check of the config values, + // see https://github.com/prusa3d/PrusaSlicer/issues/7146 + return; + } + update(); }