Merge branch 'master' into fs_dir_per_glyph_SPE-1597

This commit is contained in:
Filip Sykala - NTB T15p 2023-06-05 13:04:21 +02:00
commit 4532a27f82
8 changed files with 264 additions and 107 deletions

View File

@ -5091,7 +5091,7 @@ msgstr "Äußere Perimeter"
#: src/libslic3r/PrintConfig.cpp:861 #: src/libslic3r/PrintConfig.cpp:861
msgid "External perimeters first" msgid "External perimeters first"
msgstr "ßere Perimeter zuerst drucken" msgstr "Äußere Perimeter zuerst drucken"
#: src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp:294 #: src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp:294
msgid "Extra high" msgid "Extra high"

View File

@ -1,4 +1,5 @@
#include "ExPolygon.hpp" #include "ExPolygon.hpp"
#include "Flow.hpp"
#include "Layer.hpp" #include "Layer.hpp"
#include "BridgeDetector.hpp" #include "BridgeDetector.hpp"
#include "ClipperUtils.hpp" #include "ClipperUtils.hpp"
@ -169,7 +170,8 @@ static ExPolygons fill_surfaces_extract_expolygons(Surfaces &surfaces, std::init
Surfaces expand_bridges_detect_orientations( Surfaces expand_bridges_detect_orientations(
Surfaces &surfaces, Surfaces &surfaces,
ExPolygons &shells, ExPolygons &shells,
const Algorithm::RegionExpansionParameters &expansion_params) const Algorithm::RegionExpansionParameters &expansion_params,
const float closing_radius)
{ {
using namespace Slic3r::Algorithm; using namespace Slic3r::Algorithm;
@ -309,8 +311,13 @@ Surfaces expand_bridges_detect_orientations(
} }
//FIXME try to be smart and pick the best bridging angle for all? //FIXME try to be smart and pick the best bridging angle for all?
templ.bridge_angle = bridges[bridge_id].angle; templ.bridge_angle = bridges[bridge_id].angle;
//NOTE: The current regularization of the shells can create small unasigned regions in the object (E.G. benchy)
// without the following closing operation, those regions will stay unfilled and cause small holes in the expanded surface.
// look for narrow_ensure_vertical_wall_thickness_region_radius filter.
ExPolygons final = closing_ex(acc, closing_radius);
// without safety offset, artifacts are generated (GH #2494) // without safety offset, artifacts are generated (GH #2494)
for (ExPolygon &ex : union_safety_offset_ex(acc)) // union_safety_offset_ex(acc)
for (ExPolygon &ex : final)
out.emplace_back(templ, std::move(ex)); out.emplace_back(templ, std::move(ex));
} }
} }
@ -327,6 +334,7 @@ static Surfaces expand_merge_surfaces(
SurfaceType surface_type, SurfaceType surface_type,
ExPolygons &shells, ExPolygons &shells,
const Algorithm::RegionExpansionParameters &params, const Algorithm::RegionExpansionParameters &params,
const float closing_radius,
const double bridge_angle = -1.) const double bridge_angle = -1.)
{ {
double thickness; double thickness;
@ -335,6 +343,10 @@ static Surfaces expand_merge_surfaces(
return {}; return {};
std::vector<ExPolygon> expanded = expand_merge_expolygons(std::move(src), shells, params); std::vector<ExPolygon> expanded = expand_merge_expolygons(std::move(src), shells, params);
//NOTE: The current regularization of the shells can create small unasigned regions in the object (E.G. benchy)
// without the following closing operation, those regions will stay unfilled and cause small holes in the expanded surface.
// look for narrow_ensure_vertical_wall_thickness_region_radius filter.
expanded = closing_ex(expanded, closing_radius);
// Trim the shells by the expanded expolygons. // Trim the shells by the expanded expolygons.
shells = diff_ex(shells, expanded); shells = diff_ex(shells, expanded);
@ -373,6 +385,8 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
static constexpr const float expansion_step = scaled<float>(0.1); static constexpr const float expansion_step = scaled<float>(0.1);
// Don't take more than max_nr_steps for small expansion_step. // Don't take more than max_nr_steps for small expansion_step.
static constexpr const size_t max_nr_expansion_steps = 5; static constexpr const size_t max_nr_expansion_steps = 5;
// Radius (with added epsilon) to absorb empty regions emering from regularization of ensuring, viz const float narrow_ensure_vertical_wall_thickness_region_radius = 0.5f * 0.65f * min_perimeter_infill_spacing;
const float closing_radius = 0.55f * 0.65f * 1.05f * this->flow(frSolidInfill).scaled_spacing();
// Expand the top / bottom / bridge surfaces into the shell thickness solid infills. // Expand the top / bottom / bridge surfaces into the shell thickness solid infills.
double layer_thickness; double layer_thickness;
@ -384,8 +398,8 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
const double custom_angle = this->region().config().bridge_angle.value; const double custom_angle = this->region().config().bridge_angle.value;
const auto params = Algorithm::RegionExpansionParameters::build(expansion_bottom_bridge, expansion_step, max_nr_expansion_steps); const auto params = Algorithm::RegionExpansionParameters::build(expansion_bottom_bridge, expansion_step, max_nr_expansion_steps);
bridges.surfaces = custom_angle > 0 ? bridges.surfaces = custom_angle > 0 ?
expand_merge_surfaces(m_fill_surfaces.surfaces, stBottomBridge, shells, params, Geometry::deg2rad(custom_angle)) : expand_merge_surfaces(m_fill_surfaces.surfaces, stBottomBridge, shells, params, closing_radius, Geometry::deg2rad(custom_angle)) :
expand_bridges_detect_orientations(m_fill_surfaces.surfaces, shells, params); expand_bridges_detect_orientations(m_fill_surfaces.surfaces, shells, params, closing_radius);
BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges - done"; BOOST_LOG_TRIVIAL(trace) << "Processing external surface, detecting bridges - done";
#if 0 #if 0
{ {
@ -396,9 +410,9 @@ void LayerRegion::process_external_surfaces(const Layer *lower_layer, const Poly
} }
Surfaces bottoms = expand_merge_surfaces(m_fill_surfaces.surfaces, stBottom, shells, Surfaces bottoms = expand_merge_surfaces(m_fill_surfaces.surfaces, stBottom, shells,
Algorithm::RegionExpansionParameters::build(expansion_bottom, expansion_step, max_nr_expansion_steps)); Algorithm::RegionExpansionParameters::build(expansion_bottom, expansion_step, max_nr_expansion_steps), closing_radius);
Surfaces tops = expand_merge_surfaces(m_fill_surfaces.surfaces, stTop, shells, Surfaces tops = expand_merge_surfaces(m_fill_surfaces.surfaces, stTop, shells,
Algorithm::RegionExpansionParameters::build(expansion_top, expansion_step, max_nr_expansion_steps)); Algorithm::RegionExpansionParameters::build(expansion_top, expansion_step, max_nr_expansion_steps), closing_radius);
m_fill_surfaces.remove_types({ stBottomBridge, stBottom, stTop, stInternalSolid }); m_fill_surfaces.remove_types({ stBottomBridge, stBottom, stTop, stInternalSolid });
reserve_more(m_fill_surfaces.surfaces, shells.size() + bridges.size() + bottoms.size() + tops.size()); reserve_more(m_fill_surfaces.surfaces, shells.size() + bridges.size() + bottoms.size() + tops.size());

View File

@ -10,6 +10,7 @@
#include <boost/format.hpp> #include <boost/format.hpp>
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/nowide/convert.hpp> #include <boost/nowide/convert.hpp>
#include <boost/dll/runtime_symbol_info.hpp> #include <boost/dll/runtime_symbol_info.hpp>
@ -1162,7 +1163,7 @@ void PageMaterials::sort_list_data(StringList* list, bool add_All_item, bool mat
// in alphabetical order // in alphabetical order
std::vector<std::reference_wrapper<const std::string>> prusa_profiles; std::vector<std::reference_wrapper<const std::string>> prusa_profiles;
std::vector<std::reference_wrapper<const std::string>> other_profiles; std::vector<std::pair<std::wstring ,std::reference_wrapper<const std::string>>> other_profiles; // first is lower case id for sorting
bool add_TEMPLATES_item = false; bool add_TEMPLATES_item = false;
for (int i = 0 ; i < list->size(); ++i) { for (int i = 0 ; i < list->size(); ++i) {
const std::string& data = list->get_data(i); const std::string& data = list->get_data(i);
@ -1175,7 +1176,7 @@ void PageMaterials::sort_list_data(StringList* list, bool add_All_item, bool mat
if (!material_type_ordering && data.find("Prusa") != std::string::npos) if (!material_type_ordering && data.find("Prusa") != std::string::npos)
prusa_profiles.push_back(data); prusa_profiles.push_back(data);
else else
other_profiles.push_back(data); other_profiles.emplace_back(boost::algorithm::to_lower_copy(boost::nowide::widen(data)),data);
} }
if (material_type_ordering) { if (material_type_ordering) {
@ -1185,10 +1186,10 @@ void PageMaterials::sort_list_data(StringList* list, bool add_All_item, bool mat
for (size_t profs = end_of_sorted; profs < other_profiles.size(); profs++) for (size_t profs = end_of_sorted; profs < other_profiles.size(); profs++)
{ {
// find instead compare because PET vs PETG // find instead compare because PET vs PETG
if (other_profiles[profs].get().find(value) != std::string::npos) { if (other_profiles[profs].second.get().find(value) != std::string::npos) {
//swap //swap
if(profs != end_of_sorted) { if(profs != end_of_sorted) {
std::reference_wrapper<const std::string> aux = other_profiles[end_of_sorted]; std::pair<std::wstring, std::reference_wrapper<const std::string>> aux = other_profiles[end_of_sorted];
other_profiles[end_of_sorted] = other_profiles[profs]; other_profiles[end_of_sorted] = other_profiles[profs];
other_profiles[profs] = aux; other_profiles[profs] = aux;
} }
@ -1201,8 +1202,8 @@ void PageMaterials::sort_list_data(StringList* list, bool add_All_item, bool mat
std::sort(prusa_profiles.begin(), prusa_profiles.end(), [](std::reference_wrapper<const std::string> a, std::reference_wrapper<const std::string> b) { std::sort(prusa_profiles.begin(), prusa_profiles.end(), [](std::reference_wrapper<const std::string> a, std::reference_wrapper<const std::string> b) {
return a.get() < b.get(); return a.get() < b.get();
}); });
std::sort(other_profiles.begin(), other_profiles.end(), [](std::reference_wrapper<const std::string> a, std::reference_wrapper<const std::string> b) { std::sort(other_profiles.begin(), other_profiles.end(), [](const std::pair<std::wstring, std::reference_wrapper<const std::string>>& a, const std::pair<std::wstring, std::reference_wrapper<const std::string>>& b) {
return a.get() < b.get(); return a.first <b.first;
}); });
} }
@ -1214,7 +1215,7 @@ void PageMaterials::sort_list_data(StringList* list, bool add_All_item, bool mat
for (const auto& item : prusa_profiles) for (const auto& item : prusa_profiles)
list->append(item, &const_cast<std::string&>(item.get())); list->append(item, &const_cast<std::string&>(item.get()));
for (const auto& item : other_profiles) for (const auto& item : other_profiles)
list->append(item, &const_cast<std::string&>(item.get())); list->append(item.second, &const_cast<std::string&>(item.second.get()));
} }
@ -1225,20 +1226,19 @@ void PageMaterials::sort_list_data(PresetList* list, const std::vector<ProfilePr
// then the rest // then the rest
// in alphabetical order // in alphabetical order
std::vector<ProfilePrintData> prusa_profiles; std::vector<ProfilePrintData> prusa_profiles;
std::vector<ProfilePrintData> other_profiles; std::vector<std::pair<std::wstring, ProfilePrintData>> other_profiles; // first is lower case id for sorting
//for (int i = 0; i < data.size(); ++i) {
for (const auto& item : data) { for (const auto& item : data) {
const std::string& name = item.name; const std::string& name = item.name;
if (name.find("Prusa") != std::string::npos) if (name.find("Prusa") != std::string::npos)
prusa_profiles.emplace_back(item); prusa_profiles.emplace_back(item);
else else
other_profiles.emplace_back(item); other_profiles.emplace_back(boost::algorithm::to_lower_copy(boost::nowide::widen(name)), item);
} }
std::sort(prusa_profiles.begin(), prusa_profiles.end(), [](ProfilePrintData a, ProfilePrintData b) { std::sort(prusa_profiles.begin(), prusa_profiles.end(), [](ProfilePrintData a, ProfilePrintData b) {
return a.name.get() < b.name.get(); return a.name.get() < b.name.get();
}); });
std::sort(other_profiles.begin(), other_profiles.end(), [](ProfilePrintData a, ProfilePrintData b) { std::sort(other_profiles.begin(), other_profiles.end(), [](const std::pair<std::wstring, ProfilePrintData>& a, const std::pair<std::wstring, ProfilePrintData>& b) {
return a.name.get() < b.name.get(); return a.first < b.first;
}); });
list->Clear(); list->Clear();
for (size_t i = 0; i < prusa_profiles.size(); ++i) { for (size_t i = 0; i < prusa_profiles.size(); ++i) {
@ -1246,8 +1246,8 @@ void PageMaterials::sort_list_data(PresetList* list, const std::vector<ProfilePr
list->Check(i, prusa_profiles[i].checked); list->Check(i, prusa_profiles[i].checked);
} }
for (size_t i = 0; i < other_profiles.size(); ++i) { for (size_t i = 0; i < other_profiles.size(); ++i) {
list->append(std::string(other_profiles[i].name) + (other_profiles[i].omnipresent || template_shown ? "" : " *"), &const_cast<std::string&>(other_profiles[i].name.get())); list->append(std::string(other_profiles[i].second.name) + (other_profiles[i].second.omnipresent || template_shown ? "" : " *"), &const_cast<std::string&>(other_profiles[i].second.name.get()));
list->Check(i + prusa_profiles.size(), other_profiles[i].checked); list->Check(i + prusa_profiles.size(), other_profiles[i].second.checked);
} }
} }
@ -1670,9 +1670,17 @@ PageVendors::PageVendors(ConfigWizard *parent)
auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); auto boldfont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
boldfont.SetWeight(wxFONTWEIGHT_BOLD); boldfont.SetWeight(wxFONTWEIGHT_BOLD);
// Copy vendors from bundle map to vector, so we can sort it without case sensitivity
std::vector<std::pair<std::wstring, const VendorProfile*>> vendors;
for (const auto& pair : wizard_p()->bundles) {
vendors.emplace_back(boost::algorithm::to_lower_copy(boost::nowide::widen(pair.second.vendor_profile->name)),pair.second.vendor_profile);
}
std::sort(vendors.begin(), vendors.end(), [](const std::pair<std::wstring, const VendorProfile*>& a, const std::pair<std::wstring, const VendorProfile*>& b) {
return a.first < b.first;
});
for (const auto &pair : wizard_p()->bundles) { for (const std::pair<std::wstring, const VendorProfile*>& v : vendors) {
const VendorProfile *vendor = pair.second.vendor_profile; const VendorProfile* vendor = v.second;
if (vendor->id == PresetBundle::PRUSA_BUNDLE) { continue; } if (vendor->id == PresetBundle::PRUSA_BUNDLE) { continue; }
if (vendor && vendor->templates_profile) if (vendor && vendor->templates_profile)
continue; continue;
@ -1682,8 +1690,8 @@ PageVendors::PageVendors(ConfigWizard *parent)
wizard_p()->on_3rdparty_install(vendor, cbox->IsChecked()); wizard_p()->on_3rdparty_install(vendor, cbox->IsChecked());
}); });
const auto &vendors = appconfig.vendors(); const auto &acvendors = appconfig.vendors();
const bool enabled = vendors.find(pair.first) != vendors.end(); const bool enabled = acvendors.find(vendor->id) != acvendors.end();
if (enabled) { if (enabled) {
cbox->SetValue(true); cbox->SetValue(true);
@ -2316,8 +2324,21 @@ void ConfigWizard::priv::load_pages()
index->add_page(page_msla); index->add_page(page_msla);
if (!only_sla_mode) { if (!only_sla_mode) {
index->add_page(page_vendors); index->add_page(page_vendors);
for (const auto &pages : pages_3rdparty) {
for ( PagePrinters* page : { pages.second.first, pages.second.second }) // Copy pages names from map to vector, so we can sort it without case sensitivity
std::vector<std::pair<std::wstring, std::string>> sorted_vendors;
for (const auto& pages : pages_3rdparty) {
sorted_vendors.emplace_back(boost::algorithm::to_lower_copy(boost::nowide::widen(pages.first)), pages.first);
}
std::sort(sorted_vendors.begin(), sorted_vendors.end(), [](const std::pair<std::wstring, std::string>& a, const std::pair<std::wstring, std::string>& b) {
return a.first < b.first;
});
for (const std::pair<std::wstring, std::string> v : sorted_vendors) {
const auto& pages = pages_3rdparty.find(v.second);
if (pages == pages_3rdparty.end())
continue; // Should not happen
for ( PagePrinters* page : { pages->second.first, pages->second.second })
if (page && page->install) if (page && page->install)
index->add_page(page); index->add_page(page);
} }

View File

@ -177,7 +177,7 @@ void ImGuiWrapper::set_language(const std::string &language)
m_font_cjk = false; m_font_cjk = false;
if (lang == "cs" || lang == "pl" || lang == "hu") { if (lang == "cs" || lang == "pl" || lang == "hu") {
ranges = ranges_latin2; ranges = ranges_latin2;
} else if (lang == "ru" || lang == "uk") { } else if (lang == "ru" || lang == "uk" || lang == "be") {
ranges = ImGui::GetIO().Fonts->GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters ranges = ImGui::GetIO().Fonts->GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters
} else if (lang == "tr") { } else if (lang == "tr") {
ranges = ranges_turkish; ranges = ranges_turkish;

View File

@ -246,8 +246,15 @@ void PresetComboBox::update(std::string select_preset_name)
const std::deque<Preset>& presets = m_collection->get_presets(); const std::deque<Preset>& presets = m_collection->get_presets();
std::map<wxString, std::pair<wxBitmapBundle*, bool>> nonsys_presets; struct PresetData {
std::map<wxString, wxBitmapBundle*> incomp_presets; wxString name;
wxString lower_name;
wxBitmapBundle* bitmap;
bool enabled; // not used in incomp_presets
};
std::vector<PresetData> system_presets;
std::vector<PresetData> nonsys_presets;
std::vector<PresetData> incomp_presets;
wxString selected = ""; wxString selected = "";
if (!presets.front().is_visible) if (!presets.front().is_visible)
@ -276,28 +283,31 @@ void PresetComboBox::update(std::string select_preset_name)
assert(bmp); assert(bmp);
if (!is_enabled) { if (!is_enabled) {
incomp_presets.emplace(get_preset_name(preset), bmp); incomp_presets.push_back({get_preset_name(preset), get_preset_name(preset).Lower(), bmp, false});
if (preset.is_dirty && m_show_modif_preset_separately) if (preset.is_dirty && m_show_modif_preset_separately)
incomp_presets.emplace(get_preset_name_with_suffix(preset), bmp); incomp_presets.push_back({get_preset_name_with_suffix(preset), get_preset_name_with_suffix(preset).Lower(), bmp, false});
} }
else if (preset.is_default || preset.is_system) else if (preset.is_default || preset.is_system)
{ {
Append(get_preset_name(preset), *bmp); system_presets.push_back({get_preset_name(preset), get_preset_name(preset).Lower(), bmp, is_enabled});
validate_selection(preset.name == select_preset_name); if (preset.name == select_preset_name)
selected = preset.name;
if (preset.is_dirty && m_show_modif_preset_separately) { if (preset.is_dirty && m_show_modif_preset_separately) {
wxString preset_name = get_preset_name_with_suffix(preset); wxString preset_name = get_preset_name_with_suffix(preset);
Append(preset_name, *bmp); system_presets.push_back({preset_name, preset_name.Lower(), bmp, is_enabled});
validate_selection(into_u8(preset_name) == select_preset_name); if (into_u8(preset_name) == select_preset_name)
selected = preset_name;
} }
} }
else else
{ {
nonsys_presets.emplace(get_preset_name(preset), std::pair<wxBitmapBundle*, bool>(bmp, is_enabled)); nonsys_presets.push_back({get_preset_name(preset), get_preset_name(preset).Lower(), bmp, is_enabled});
if (preset.name == select_preset_name || (select_preset_name.empty() && is_enabled)) if (preset.name == select_preset_name || (select_preset_name.empty() && is_enabled))
selected = get_preset_name(preset); selected = get_preset_name(preset);
if (preset.is_dirty && m_show_modif_preset_separately) { if (preset.is_dirty && m_show_modif_preset_separately) {
wxString preset_name = get_preset_name_with_suffix(preset); wxString preset_name = get_preset_name_with_suffix(preset);
nonsys_presets.emplace(preset_name, std::pair<wxBitmapBundle*, bool>(bmp, is_enabled)); nonsys_presets.push_back({preset_name, preset_name.Lower(), bmp, is_enabled});
if (preset_name == select_preset_name || (select_preset_name.empty() && is_enabled)) if (preset_name == select_preset_name || (select_preset_name.empty() && is_enabled))
selected = preset_name; selected = preset_name;
} }
@ -305,25 +315,46 @@ void PresetComboBox::update(std::string select_preset_name)
if (i + 1 == m_collection->num_default_presets()) if (i + 1 == m_collection->num_default_presets())
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl())); set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
} }
if (!system_presets.empty())
{
std::sort(system_presets.begin(), system_presets.end(), [](const PresetData& a, const PresetData& b) {
return a.lower_name < b.lower_name;
});
for (std::vector<PresetData>::iterator it = system_presets.begin(); it != system_presets.end(); ++it) {
int item_id = Append(it->name, *it->bitmap);
if (!it->enabled)
set_label_marker(item_id, LABEL_ITEM_DISABLED);
validate_selection(it->name == selected);
}
}
if (!nonsys_presets.empty()) if (!nonsys_presets.empty())
{ {
std::sort(nonsys_presets.begin(), nonsys_presets.end(), [](const PresetData& a, const PresetData& b) {
return a.lower_name < b.lower_name;
});
set_label_marker(Append(separator(L("User presets")), NullBitmapBndl())); set_label_marker(Append(separator(L("User presets")), NullBitmapBndl()));
for (std::map<wxString, std::pair<wxBitmapBundle*, bool>>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) { for (std::vector<PresetData>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
int item_id = Append(it->first, *it->second.first); int item_id = Append(it->name, *it->bitmap);
bool is_enabled = it->second.second; if (!it->enabled)
if (!is_enabled)
set_label_marker(item_id, LABEL_ITEM_DISABLED); set_label_marker(item_id, LABEL_ITEM_DISABLED);
validate_selection(it->first == selected); validate_selection(it->name == selected);
} }
} }
if (!incomp_presets.empty()) if (!incomp_presets.empty())
{ {
std::sort(incomp_presets.begin(), incomp_presets.end(), [](const PresetData& a, const PresetData& b) {
return a.lower_name < b.lower_name;
});
set_label_marker(Append(separator(L("Incompatible presets")), NullBitmapBndl())); set_label_marker(Append(separator(L("Incompatible presets")), NullBitmapBndl()));
for (std::map<wxString, wxBitmapBundle*>::iterator it = incomp_presets.begin(); it != incomp_presets.end(); ++it) { for (std::vector<PresetData> ::iterator it = incomp_presets.begin(); it != incomp_presets.end(); ++it) {
set_label_marker(Append(it->first, *it->second), LABEL_ITEM_DISABLED); set_label_marker(Append(it->name, *it->bitmap), LABEL_ITEM_DISABLED);
} }
} }
update_selection(); update_selection();
Thaw(); Thaw();
} }
@ -833,8 +864,14 @@ void PlaterPresetComboBox::update()
null_icon_width = (wide_icons ? 3 : 2) * norm_icon_width + thin_space_icon_width + wide_space_icon_width; null_icon_width = (wide_icons ? 3 : 2) * norm_icon_width + thin_space_icon_width + wide_space_icon_width;
std::map<wxString, wxBitmapBundle*> nonsys_presets; struct PresetData {
std::map<wxString, wxBitmapBundle*> template_presets; wxString name;
wxString lower_name;
wxBitmapBundle* bitmap;
};
std::vector<PresetData> system_presets;
std::vector<PresetData> nonsys_presets;
std::vector<PresetData> template_presets;
const bool allow_templates = !wxGetApp().app_config->get_bool("no_templates"); const bool allow_templates = !wxGetApp().app_config->get_bool("no_templates");
@ -888,22 +925,23 @@ void PlaterPresetComboBox::update()
if (preset.is_default || preset.is_system) { if (preset.is_default || preset.is_system) {
if (preset.vendor && preset.vendor->templates_profile) { if (preset.vendor && preset.vendor->templates_profile) {
if (allow_templates) { if (allow_templates) {
template_presets.emplace(get_preset_name(preset), bmp); template_presets.push_back({get_preset_name(preset), get_preset_name(preset).Lower(), bmp});
if (is_selected) { if (is_selected) {
selected_user_preset = get_preset_name(preset); selected_user_preset = get_preset_name(preset);
tooltip = from_u8(preset.name); tooltip = from_u8(preset.name);
} }
} }
} else { } else {
Append(get_preset_name(preset), *bmp); system_presets.push_back({ get_preset_name(preset), get_preset_name(preset).Lower(), bmp });
validate_selection(is_selected); if (is_selected) {
if (is_selected) selected_user_preset = get_preset_name(preset);
tooltip = from_u8(preset.name); tooltip = from_u8(preset.name);
}
} }
} }
else else
{ {
nonsys_presets.emplace(get_preset_name(preset), bmp); nonsys_presets.push_back({ get_preset_name(preset), get_preset_name(preset).Lower(), bmp });
if (is_selected) { if (is_selected) {
selected_user_preset = get_preset_name(preset); selected_user_preset = get_preset_name(preset);
tooltip = from_u8(preset.name); tooltip = from_u8(preset.name);
@ -912,22 +950,41 @@ void PlaterPresetComboBox::update()
if (i + 1 == m_collection->num_default_presets()) if (i + 1 == m_collection->num_default_presets())
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl())); set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
} }
if(!system_presets.empty())
{
std::sort(system_presets.begin(), system_presets.end(), [](const PresetData& a, const PresetData& b) {
return a.lower_name < b.lower_name;
});
for (std::vector<PresetData>::iterator it = system_presets.begin(); it != system_presets.end(); ++it) {
Append(it->name, *it->bitmap);
validate_selection(it->name == selected_user_preset);
}
}
if (!nonsys_presets.empty()) if (!nonsys_presets.empty())
{ {
std::sort(nonsys_presets.begin(), nonsys_presets.end(), [](const PresetData& a, const PresetData& b) {
return a.lower_name < b.lower_name;
});
set_label_marker(Append(separator(L("User presets")), NullBitmapBndl())); set_label_marker(Append(separator(L("User presets")), NullBitmapBndl()));
for (std::map<wxString, wxBitmapBundle*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) { for (std::vector<PresetData>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
Append(it->first, *it->second); Append(it->name, *it->bitmap);
validate_selection(it->first == selected_user_preset); validate_selection(it->name == selected_user_preset);
} }
} }
if (!template_presets.empty()) { if (!template_presets.empty()) {
std::sort(template_presets.begin(), template_presets.end(), [](const PresetData& a, const PresetData& b) {
return a.lower_name < b.lower_name;
});
set_label_marker(Append(separator(L("Template presets")), wxNullBitmap)); set_label_marker(Append(separator(L("Template presets")), wxNullBitmap));
for (std::map<wxString, wxBitmapBundle*>::iterator it = template_presets.begin(); it != template_presets.end(); ++it) { for (std::vector<PresetData>::iterator it = template_presets.begin(); it != template_presets.end(); ++it) {
Append(it->first, *it->second); Append(it->name, *it->bitmap);
validate_selection(it->first == selected_user_preset); validate_selection(it->name == selected_user_preset);
} }
} }
@ -938,19 +995,37 @@ void PlaterPresetComboBox::update()
set_label_marker(Append(separator(L("Physical printers")), NullBitmapBndl())); set_label_marker(Append(separator(L("Physical printers")), NullBitmapBndl()));
const PhysicalPrinterCollection& ph_printers = m_preset_bundle->physical_printers; const PhysicalPrinterCollection& ph_printers = m_preset_bundle->physical_printers;
// Sort Physical printers in preset_data vector and than Append it in correct order
struct PhysicalPrinterPresetData
{
wxString lower_name; // just for sorting
std::string name; // preset_name
std::string fullname; // full name
bool selected; // is selected
};
std::vector<PhysicalPrinterPresetData> preset_data;
for (PhysicalPrinterCollection::ConstIterator it = ph_printers.begin(); it != ph_printers.end(); ++it) { for (PhysicalPrinterCollection::ConstIterator it = ph_printers.begin(); it != ph_printers.end(); ++it) {
for (const std::string& preset_name : it->get_preset_names()) { for (const std::string& preset_name : it->get_preset_names()) {
Preset* preset = m_collection->find_preset(preset_name); preset_data.push_back({ wxString::FromUTF8(it->get_full_name(preset_name)).Lower(), preset_name, it->get_full_name(preset_name), ph_printers.is_selected(it, preset_name) });
if (!preset || !preset->is_visible)
continue;
std::string main_icon_name, bitmap_key = main_icon_name = preset->printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name;
auto bmp = get_bmp(main_icon_name, wide_icons, main_icon_name);
assert(bmp);
set_label_marker(Append(from_u8(it->get_full_name(preset_name) + suffix(preset)), *bmp), LABEL_ITEM_PHYSICAL_PRINTER);
validate_selection(ph_printers.is_selected(it, preset_name));
} }
} }
std::sort(preset_data.begin(), preset_data.end(), [](const PhysicalPrinterPresetData& a, const PhysicalPrinterPresetData& b) {
return a.lower_name < b.lower_name;
});
for (const PhysicalPrinterPresetData& data : preset_data)
{
Preset* preset = m_collection->find_preset(data.name);
if (!preset || !preset->is_visible)
continue;
std::string main_icon_name = preset->printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name;
auto bmp = get_bmp(main_icon_name, main_icon_name, "", true, true, false);
assert(bmp);
set_label_marker(Append(from_u8(data.fullname + suffix(preset)), *bmp), LABEL_ITEM_PHYSICAL_PRINTER);
validate_selection(data.selected);
}
} }
} }
@ -1069,12 +1144,18 @@ void TabPresetComboBox::update()
const ExtruderFilaments& extruder_filaments = m_preset_bundle->extruders_filaments[m_active_extruder_idx]; const ExtruderFilaments& extruder_filaments = m_preset_bundle->extruders_filaments[m_active_extruder_idx];
const std::deque<Preset>& presets = m_collection->get_presets(); const std::deque<Preset>& presets = m_collection->get_presets();
std::map<wxString, std::pair<wxBitmapBundle*, bool>> nonsys_presets; struct PresetData {
std::map<wxString, std::pair<wxBitmapBundle*, bool>> template_presets; wxString name;
wxString lower_name;
wxBitmapBundle* bitmap;
bool enabled;
};
std::vector<PresetData> system_presets;
std::vector<PresetData> nonsys_presets;
std::vector<PresetData> template_presets;
const bool allow_templates = !wxGetApp().app_config->get_bool("no_templates"); const bool allow_templates = !wxGetApp().app_config->get_bool("no_templates");
wxString selected = ""; wxString selected = "";
if (!presets.front().is_visible) if (!presets.front().is_visible)
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl())); set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
@ -1113,23 +1194,20 @@ void TabPresetComboBox::update()
if (preset.is_default || preset.is_system) { if (preset.is_default || preset.is_system) {
if (preset.vendor && preset.vendor->templates_profile) { if (preset.vendor && preset.vendor->templates_profile) {
if (allow_templates) { if (allow_templates) {
template_presets.emplace(get_preset_name(preset), std::pair<wxBitmapBundle*, bool>(bmp, is_enabled)); template_presets.push_back({get_preset_name(preset), get_preset_name(preset).Lower(), bmp, is_enabled});
if (i == idx_selected) if (i == idx_selected)
selected = get_preset_name(preset); selected = get_preset_name(preset);
} }
} else { } else {
int item_id = Append(get_preset_name(preset), *bmp); system_presets.push_back({get_preset_name(preset), get_preset_name(preset).Lower(), bmp, is_enabled});
if (!is_enabled) if (i == idx_selected)
set_label_marker(item_id, LABEL_ITEM_DISABLED); selected = get_preset_name(preset);
validate_selection(i == idx_selected);
} }
} }
else else
{ {
std::pair<wxBitmapBundle*, bool> pair(bmp, is_enabled); std::pair<wxBitmapBundle*, bool> pair(bmp, is_enabled);
nonsys_presets.emplace(get_preset_name(preset), std::pair<wxBitmapBundle*, bool>(bmp, is_enabled)); nonsys_presets.push_back({get_preset_name(preset), get_preset_name(preset).Lower(), bmp, is_enabled});
if (i == idx_selected) if (i == idx_selected)
selected = get_preset_name(preset); selected = get_preset_name(preset);
} }
@ -1137,26 +1215,47 @@ void TabPresetComboBox::update()
set_label_marker(Append(separator(L("System presets")), NullBitmapBndl())); set_label_marker(Append(separator(L("System presets")), NullBitmapBndl()));
} }
if (!system_presets.empty())
{
std::sort(system_presets.begin(), system_presets.end(), [](const PresetData& a, const PresetData& b) {
return a.lower_name < b.lower_name;
});
for (std::vector<PresetData>::iterator it = system_presets.begin(); it != system_presets.end(); ++it) {
int item_id = Append(it->name, *it->bitmap);
if (!it->enabled)
set_label_marker(item_id, LABEL_ITEM_DISABLED);
validate_selection(it->name == selected);
}
}
if (!nonsys_presets.empty()) if (!nonsys_presets.empty())
{ {
std::sort(nonsys_presets.begin(), nonsys_presets.end(), [](const PresetData& a, const PresetData& b) {
return a.lower_name < b.lower_name;
});
set_label_marker(Append(separator(L("User presets")), NullBitmapBndl())); set_label_marker(Append(separator(L("User presets")), NullBitmapBndl()));
for (std::map<wxString, std::pair<wxBitmapBundle*, bool>>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) { for (std::vector<PresetData>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
int item_id = Append(it->first, *it->second.first); int item_id = Append(it->name, *it->bitmap);
bool is_enabled = it->second.second; if (!it->enabled)
if (!is_enabled)
set_label_marker(item_id, LABEL_ITEM_DISABLED); set_label_marker(item_id, LABEL_ITEM_DISABLED);
validate_selection(it->first == selected); validate_selection(it->name == selected);
} }
} }
if (!template_presets.empty()) { if (!template_presets.empty())
{
std::sort(template_presets.begin(), template_presets.end(), [](const PresetData& a, const PresetData& b) {
return a.lower_name < b.lower_name;
});
set_label_marker(Append(separator(L("Template presets")), wxNullBitmap)); set_label_marker(Append(separator(L("Template presets")), wxNullBitmap));
for (std::map<wxString, std::pair<wxBitmapBundle*, bool>>::iterator it = template_presets.begin(); it != template_presets.end(); ++it) { for (std::vector<PresetData>::iterator it = template_presets.begin(); it != template_presets.end(); ++it) {
int item_id = Append(it->first, *it->second.first); int item_id = Append(it->name, *it->bitmap);
bool is_enabled = it->second.second; if (!it->enabled)
if (!is_enabled)
set_label_marker(item_id, LABEL_ITEM_DISABLED); set_label_marker(item_id, LABEL_ITEM_DISABLED);
validate_selection(it->first == selected); validate_selection(it->name == selected);
} }
} }
@ -1167,20 +1266,36 @@ void TabPresetComboBox::update()
set_label_marker(Append(separator(L("Physical printers")), NullBitmapBndl())); set_label_marker(Append(separator(L("Physical printers")), NullBitmapBndl()));
const PhysicalPrinterCollection& ph_printers = m_preset_bundle->physical_printers; const PhysicalPrinterCollection& ph_printers = m_preset_bundle->physical_printers;
// Sort Physical printers in preset_data vector and than Append it in correct order
struct PhysicalPrinterPresetData
{
wxString lower_name; // just for sorting
std::string name; // preset_name
std::string fullname; // full name
bool selected; // is selected
};
std::vector<PhysicalPrinterPresetData> preset_data;
for (PhysicalPrinterCollection::ConstIterator it = ph_printers.begin(); it != ph_printers.end(); ++it) { for (PhysicalPrinterCollection::ConstIterator it = ph_printers.begin(); it != ph_printers.end(); ++it) {
for (const std::string& preset_name : it->get_preset_names()) { for (const std::string& preset_name : it->get_preset_names()) {
Preset* preset = m_collection->find_preset(preset_name); preset_data.push_back({wxString::FromUTF8(it->get_full_name(preset_name)).Lower(), preset_name, it->get_full_name(preset_name), ph_printers.is_selected(it, preset_name)});
if (!preset || !preset->is_visible)
continue;
std::string main_icon_name = preset->printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name;
auto bmp = get_bmp(main_icon_name, main_icon_name, "", true, true, false);
assert(bmp);
set_label_marker(Append(from_u8(it->get_full_name(preset_name) + suffix(preset)), *bmp), LABEL_ITEM_PHYSICAL_PRINTER);
validate_selection(ph_printers.is_selected(it, preset_name));
} }
} }
std::sort(preset_data.begin(), preset_data.end(), [](const PhysicalPrinterPresetData& a, const PhysicalPrinterPresetData& b) {
return a.lower_name < b.lower_name;
});
for (const PhysicalPrinterPresetData& data : preset_data)
{
Preset* preset = m_collection->find_preset(data.name);
if (!preset || !preset->is_visible)
continue;
std::string main_icon_name = preset->printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name;
auto bmp = get_bmp(main_icon_name, main_icon_name, "", true, true, false);
assert(bmp);
set_label_marker(Append(from_u8(data.fullname + suffix(preset)), *bmp), LABEL_ITEM_PHYSICAL_PRINTER);
validate_selection(data.selected);
}
} }
// add "Add/Remove printers" item // add "Add/Remove printers" item

View File

@ -32,6 +32,7 @@ namespace pt = boost::property_tree;
namespace Slic3r { namespace Slic3r {
namespace { namespace {
#ifdef WIN32
std::string get_host_from_url(const std::string& url_in) std::string get_host_from_url(const std::string& url_in)
{ {
std::string url = url_in; std::string url = url_in;
@ -63,7 +64,7 @@ std::string get_host_from_url(const std::string& url_in)
BOOST_LOG_TRIVIAL(error) << "OctoPrint get_host_from_url: failed to allocate curl_url"; BOOST_LOG_TRIVIAL(error) << "OctoPrint get_host_from_url: failed to allocate curl_url";
return out; return out;
} }
#ifdef WIN32
// Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail. // Workaround for Windows 10/11 mDNS resolve issue, where two mDNS resolves in succession fail.
std::string substitute_host(const std::string& orig_addr, std::string sub_addr) std::string substitute_host(const std::string& orig_addr, std::string sub_addr)
{ {
@ -470,15 +471,17 @@ bool OctoPrint::upload_inner_with_host(PrintHostUpload upload_data, ProgressFn p
% upload_parent_path.string() % upload_parent_path.string()
% (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false"); % (upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false");
std::string host = get_host_from_url(m_host);
auto http = Http::post(std::move(url)); auto http = Http::post(std::move(url));
#ifdef WIN32
// "Host" header is necessary here. In the workaround above (two mDNS..) we have got IP address from test connection and subsituted it into "url" variable. // "Host" header is necessary here. In the workaround above (two mDNS..) we have got IP address from test connection and subsituted it into "url" variable.
// And when creating Http object above, libcurl automatically includes "Host" header from address it got. // And when creating Http object above, libcurl automatically includes "Host" header from address it got.
// Thus "Host" is set to the resolved IP instead of host filled by user. We need to change it back. // Thus "Host" is set to the resolved IP instead of host filled by user. We need to change it back.
// Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734). // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734).
// Also when allow_ip_resolve = 0, this is not needed, but it should not break anything if it stays. // Also when allow_ip_resolve = 0, this is not needed, but it should not break anything if it stays.
// https://www.rfc-editor.org/rfc/rfc7230#section-5.4 // https://www.rfc-editor.org/rfc/rfc7230#section-5.4
std::string host = get_host_from_url(m_host);
http.header("Host", host); http.header("Host", host);
#endif // _WIN32
set_auth(http); set_auth(http);
http.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false") http.form_add("print", upload_data.post_action == PrintHostPostUploadAction::StartPrint ? "true" : "false")
.form_add("path", upload_parent_path.string()) // XXX: slashes on windows ??? .form_add("path", upload_parent_path.string()) // XXX: slashes on windows ???
@ -1036,14 +1039,16 @@ bool PrusaLink::put_inner(PrintHostUpload upload_data, std::string url, const st
bool res = true; bool res = true;
// Percent escape all filenames in on path and add it to the url. This is different from POST. // Percent escape all filenames in on path and add it to the url. This is different from POST.
url += "/" + escape_path_by_element(upload_data.upload_path); url += "/" + escape_path_by_element(upload_data.upload_path);
std::string host = get_host_from_url(m_host);
Http http = Http::put(std::move(url)); Http http = Http::put(std::move(url));
#ifdef WIN32
// "Host" header is necessary here. We have resolved IP address and subsituted it into "url" variable. // "Host" header is necessary here. We have resolved IP address and subsituted it into "url" variable.
// And when creating Http object above, libcurl automatically includes "Host" header from address it got. // And when creating Http object above, libcurl automatically includes "Host" header from address it got.
// Thus "Host" is set to the resolved IP instead of host filled by user. We need to change it back. // Thus "Host" is set to the resolved IP instead of host filled by user. We need to change it back.
// Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734). // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734).
// https://www.rfc-editor.org/rfc/rfc7230#section-5.4 // https://www.rfc-editor.org/rfc/rfc7230#section-5.4
std::string host = get_host_from_url(m_host);
http.header("Host", host); http.header("Host", host);
#endif // _WIN32
set_auth(http); set_auth(http);
// This is ugly, but works. There was an error at PrusaLink side that accepts any string at Print-After-Upload as true, thus False was also triggering print after upload. // This is ugly, but works. There was an error at PrusaLink side that accepts any string at Print-After-Upload as true, thus False was also triggering print after upload.
if (upload_data.post_action == PrintHostPostUploadAction::StartPrint) if (upload_data.post_action == PrintHostPostUploadAction::StartPrint)
@ -1083,15 +1088,17 @@ bool PrusaLink::post_inner(PrintHostUpload upload_data, std::string url, const s
bool res = true; bool res = true;
const auto upload_filename = upload_data.upload_path.filename(); const auto upload_filename = upload_data.upload_path.filename();
const auto upload_parent_path = upload_data.upload_path.parent_path(); const auto upload_parent_path = upload_data.upload_path.parent_path();
std::string host = get_host_from_url(m_host);
Http http = Http::post(std::move(url)); Http http = Http::post(std::move(url));
#ifdef WIN32
// "Host" header is necessary here. We have resolved IP address and subsituted it into "url" variable. // "Host" header is necessary here. We have resolved IP address and subsituted it into "url" variable.
// And when creating Http object above, libcurl automatically includes "Host" header from address it got. // And when creating Http object above, libcurl automatically includes "Host" header from address it got.
// Thus "Host" is set to the resolved IP instead of host filled by user. We need to change it back. // Thus "Host" is set to the resolved IP instead of host filled by user. We need to change it back.
// Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734). // Not changing the host would work on the most cases (where there is 1 service on 1 hostname) but would break when f.e. reverse proxy is used (issue #9734).
// https://www.rfc-editor.org/rfc/rfc7230#section-5.4 // https://www.rfc-editor.org/rfc/rfc7230#section-5.4
std::string host = get_host_from_url(m_host);
http.header("Host", host); http.header("Host", host);
#endif // _WIN32
set_auth(http); set_auth(http);
set_http_post_header_args(http, upload_data.post_action); set_http_post_header_args(http, upload_data.post_action);
http.form_add("path", upload_parent_path.string()) // XXX: slashes on windows ??? http.form_add("path", upload_parent_path.string()) // XXX: slashes on windows ???

View File

@ -3,7 +3,7 @@
set(SLIC3R_APP_NAME "PrusaSlicer") set(SLIC3R_APP_NAME "PrusaSlicer")
set(SLIC3R_APP_KEY "PrusaSlicer") set(SLIC3R_APP_KEY "PrusaSlicer")
set(SLIC3R_VERSION "2.6.0-beta3") set(SLIC3R_VERSION "2.6.0-beta4")
set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN") set(SLIC3R_BUILD_ID "PrusaSlicer-${SLIC3R_VERSION}+UNKNOWN")
set(SLIC3R_RC_VERSION "2,6,0,0") set(SLIC3R_RC_VERSION "2,6,0,0")
set(SLIC3R_RC_VERSION_DOTS "2.6.0.0") set(SLIC3R_RC_VERSION_DOTS "2.6.0.0")