Merge branch 'main' into feature/wipetower-option

This commit is contained in:
SoftFever
2026-03-16 17:41:00 +08:00
committed by GitHub
135 changed files with 930 additions and 437 deletions
@@ -23,10 +23,11 @@ template<> struct hash<Slic3r::GridPoint3>
namespace Slic3r {
void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_object)
void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_object, const std::function<void()>& throw_on_cancel)
{
const auto& config = print_object->config();
if (!config.interlocking_beam) {
// Check if interlocking is enabled, and avoid errors like division by zero due to invalid configuration.
if (!config.interlocking_beam || config.interlocking_beam_layer_count < 1 || config.interlocking_depth < 1 || config.interlocking_beam_width < EPSILON ) {
return;
}
@@ -55,8 +56,10 @@ void InterlockingGenerator::generate_interlocking_structure(PrintObject* print_o
continue;
}
throw_on_cancel();
InterlockingGenerator gen(*print_object, region_a_index, region_b_index, beam_width, boundary_avoidance, rotation, cell_size, beam_layer_count,
interface_dilation, air_dilation, air_filtering);
interface_dilation, air_dilation, air_filtering, throw_on_cancel);
gen.generateInterlockingStructure();
}
}
@@ -108,12 +111,14 @@ void InterlockingGenerator::handleThinAreas(const std::unordered_set<GridPoint3>
}
}
for (auto& near_interlock : near_interlock_per_layer) {
throw_on_cancel();
near_interlock = offset(union_(closing(near_interlock, rounding_errors)), detect);
polygons_rotate(near_interlock, rotation);
}
// Only alter layers when they are present in both meshes, zip should take care if that.
for (size_t layer_nr = 0; layer_nr < print_object.layer_count(); layer_nr++){
throw_on_cancel();
auto layer = print_object.get_layer(layer_nr);
ExPolygons polys_a = to_expolygons(layer->get_region(region_a_index)->slices.surfaces);
ExPolygons polys_b = to_expolygons(layer->get_region(region_b_index)->slices.surfaces);
@@ -199,7 +204,8 @@ void InterlockingGenerator::addBoundaryCells(const std::vector<ExPolygons>& lay
const DilationKernel& kernel,
std::unordered_set<GridPoint3>& cells) const
{
auto voxel_emplacer = [&cells](GridPoint3 p) {
auto voxel_emplacer = [this, &cells](GridPoint3 p) {
this->throw_on_cancel();
if (p.z() < 0) {
return true;
}
@@ -313,6 +319,7 @@ void InterlockingGenerator::applyMicrostructureToOutlines(const std::unordered_s
for (size_t region_idx = 0; region_idx < 2; region_idx++) {
const size_t region = (region_idx == 0) ? region_a_index : region_b_index;
for (size_t layer_nr = 0; layer_nr < max_layer_count; layer_nr++) {
throw_on_cancel();
ExPolygons layer_outlines = layer_regions[layer_nr];
expolygons_rotate(layer_outlines, unapply_rotation);
@@ -45,7 +45,7 @@ public:
/*!
* Generate an interlocking structure between each two adjacent meshes.
*/
static void generate_interlocking_structure(PrintObject* print_object);
static void generate_interlocking_structure(PrintObject* print_object, const std::function<void()>& throw_on_cancel);
private:
/*!
@@ -75,7 +75,8 @@ private:
const coord_t beam_layer_count,
const DilationKernel& interface_dilation,
const DilationKernel& air_dilation,
const bool air_filtering)
const bool air_filtering,
const std::function<void()>& throw_on_cancel)
: print_object(print_object)
, region_a_index(region_a_index)
, region_b_index(region_b_index)
@@ -88,6 +89,7 @@ private:
, interface_dilation(interface_dilation)
, air_dilation(air_dilation)
, air_filtering(air_filtering)
, throw_on_cancel(throw_on_cancel)
{}
/*! Given two polygons, return the parts that border on air, and grow 'perpendicular' up to 'detect' distance.
@@ -165,6 +167,8 @@ private:
// Whether to fully remove all of the interlocking cells which would be visible on the outside. If no air filtering then those cells
// will be cut off midway in a beam.
const bool air_filtering;
const std::function<void()>& throw_on_cancel;
};
} // namespace Slic3r
+1
View File
@@ -882,6 +882,7 @@ std::vector<SurfaceFill> group_fills(const Layer &layer, LockRegionParam &lock_p
if (surface.is_top()) {
params.pattern = region_config.top_surface_pattern.value;
params.density = float(region_config.top_surface_density);
if (params.density <= 0.0f) continue;
} else { // Surface is bottom
params.pattern = region_config.bottom_surface_pattern.value;
params.density = float(region_config.bottom_surface_density);
+5 -9
View File
@@ -1321,19 +1321,18 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first
return false;
};
if (m_print->is_BBL_printer() || number_of_extruders == 1){
auto maps_without_group = filament_maps;
for (auto& item : maps_without_group)
item = 0;
reorder_filaments_for_minimum_flush_volume(
filament_lists,
filament_maps,
m_print->is_BBL_printer() ? filament_maps : maps_without_group, // non-bbl printers do not support filament group yet
layer_filaments,
nozzle_flush_mtx,
get_custom_seq,
&filament_sequences
);
} else {
// For non-bbl multi-extruder printers we don't support filament group yet, so we keep the layer sequence because we don't flush based on order
filament_sequences = layer_filaments;
}
auto curr_flush_info = calc_filament_change_info_by_toolorder(print_config, filament_maps, nozzle_flush_mtx, filament_sequences);
if (nozzle_nums <= 1)
@@ -1349,9 +1348,6 @@ void ToolOrdering::reorder_extruders_for_minimum_flush_volume(bool reorder_first
// always calculate the info by one extruder
{
std::vector<std::vector<unsigned int>>filament_sequences_one_extruder;
auto maps_without_group = filament_maps;
for (auto& item : maps_without_group)
item = 0;
reorder_filaments_for_minimum_flush_volume(
filament_lists,
maps_without_group,
+7 -7
View File
@@ -3979,7 +3979,7 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back(L("No ironing"));
def->enum_labels.push_back(L("Top surfaces"));
def->enum_labels.push_back(L("Topmost surface"));
def->enum_labels.push_back(L("All solid layer"));
def->enum_labels.push_back(L("All solid layers"));
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<IroningType>(IroningType::NoIroning));
@@ -4561,7 +4561,7 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionFloat(0.));
def = this->add("detect_overhang_wall", coBool);
def->label = L("Detect overhang wall");
def->label = L("Detect overhang walls");
def->category = L("Quality");
def->tooltip = L("Detect the overhang percentage relative to line width and use different speed to print. "
"For 100%% overhang, bridge speed is used.");
@@ -5311,7 +5311,7 @@ void PrintConfigDef::init_fff_params()
def = this->add("minimum_sparse_infill_area", coFloat);
def->label = L("Minimum sparse infill threshold");
def->category = L("Strength");
def->tooltip = L("Sparse infill area which is smaller than threshold value is replaced by internal solid infill.");
def->tooltip = L("Sparse infill areas smaller than this threshold value are replaced by internal solid infill.");
def->sidetext = L(u8"mm²"); // square milimeters, CIS languages need translation
def->min = 0;
def->mode = comAdvanced;
@@ -6163,10 +6163,10 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionPoints{});
def = this->add("detect_thin_wall", coBool);
def->label = L("Detect thin wall");
def->label = L("Detect thin walls");
def->category = L("Strength");
def->tooltip = L("Detect thin wall which can't contain two line width. And use single line to print. "
"Maybe printed not very well, because it's not closed loop.");
def->tooltip = L("Detect thin walls which can't contain two line widths, and use single line to print. "
"Maybe not printed very well, because it's not a closed loop.");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionBool(false));
@@ -6777,7 +6777,7 @@ void PrintConfigDef::init_fff_params()
}
def = this->add("detect_narrow_internal_solid_infill", coBool);
def->label = L("Detect narrow internal solid infill");
def->label = L("Detect narrow internal solid infills");
def->category = L("Strength");
def->tooltip = L("This option will auto-detect narrow internal solid infill areas. "
"If enabled, the concentric pattern will be used for the area to speed up printing. "
+1 -1
View File
@@ -1212,7 +1212,7 @@ void PrintObject::slice_volumes()
apply_fuzzy_skin_segmentation(*this, [print]() { print->throw_if_canceled(); });
}
InterlockingGenerator::generate_interlocking_structure(this);
InterlockingGenerator::generate_interlocking_structure(this, [print]() { print->throw_if_canceled(); });
m_print->throw_if_canceled();
BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - make_slices in parallel - begin";
+82 -50
View File
@@ -6199,7 +6199,7 @@ static const wxLanguageInfo* linux_get_existing_locale_language(const wxLanguage
if (! it->empty()) {
const std::string &locale = *it;
const wxLanguageInfo* lang = wxLocale::FindLanguageInfo(from_u8(locale));
if (wxLocale::IsAvailable(lang->Language))
if (lang != nullptr && wxLocale::IsAvailable(lang->Language))
return lang;
}
return language;
@@ -6241,7 +6241,10 @@ bool GUI_App::select_language()
names.Alloc(language_infos.size());
// Some valid language should be selected since the application start up.
const wxLanguage current_language = wxLanguage(m_wxLocale->GetLanguage());
const wxString active_language_code = current_language_code();
const wxLanguageInfo* active_language_info = wxLocale::FindLanguageInfo(active_language_code);
const wxLanguage current_language = active_language_info != nullptr ? wxLanguage(active_language_info->Language) : wxLanguage(m_wxLocale->GetLanguage());
const wxString active_lang_prefix = active_language_code.BeforeFirst('_');
int init_selection = -1;
int init_selection_alt = -1;
int init_selection_default = -1;
@@ -6249,9 +6252,9 @@ bool GUI_App::select_language()
if (wxLanguage(language_infos[i]->Language) == current_language)
// The dictionary matches the active language and country.
init_selection = i;
else if ((language_infos[i]->CanonicalName.BeforeFirst('_') == m_wxLocale->GetCanonicalName().BeforeFirst('_')) ||
else if ((language_infos[i]->CanonicalName.BeforeFirst('_') == active_lang_prefix) ||
// if the active language is Slovak, mark the Czech language as active.
(language_infos[i]->CanonicalName.BeforeFirst('_') == "cs" && m_wxLocale->GetCanonicalName().BeforeFirst('_') == "sk"))
(language_infos[i]->CanonicalName.BeforeFirst('_') == "cs" && active_lang_prefix == "sk"))
// The dictionary matches the active language, it does not necessarily match the country.
init_selection_alt = i;
if (language_infos[i]->CanonicalName.BeforeFirst('_') == "en")
@@ -6369,7 +6372,10 @@ bool GUI_App::load_language(wxString language, bool initial)
language_info = wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_US);
}
BOOST_LOG_TRIVIAL(trace) << boost::format("Switching wxLocales to %1%") % language_info->CanonicalName.ToUTF8().data();
const wxLanguageInfo *translation_language_info = language_info;
const wxString requested_language_code = translation_language_info->CanonicalName;
const wxLanguageInfo *locale_language_info = translation_language_info;
BOOST_LOG_TRIVIAL(trace) << boost::format("Requested translation language %1%") % requested_language_code.ToUTF8().data();
// Select language for locales. This language may be different from the language of the dictionary.
//if (language_info == m_language_info_best || language_info == m_language_info_system) {
@@ -6382,8 +6388,8 @@ bool GUI_App::load_language(wxString language, bool initial)
// language_info = m_language_info_system;
// Alternate language code.
wxLanguage language_dict = wxLanguage(language_info->Language);
if (language_info->CanonicalName.BeforeFirst('_') == "sk") {
wxLanguage language_dict = wxLanguage(translation_language_info->Language);
if (translation_language_info->CanonicalName.BeforeFirst('_') == "sk") {
// Slovaks understand Czech well. Give them the Czech translation.
language_dict = wxLANGUAGE_CZECH;
BOOST_LOG_TRIVIAL(info) << "Using Czech dictionaries for Slovak language";
@@ -6392,19 +6398,34 @@ bool GUI_App::load_language(wxString language, bool initial)
#ifdef __linux__
// If we can't find this locale , try to use different one for the language
// instead of just reporting that it is impossible to switch.
if (! wxLocale::IsAvailable(language_info->Language) && m_language_info_system) {
std::string original_lang = into_u8(language_info->CanonicalName);
language_info = linux_get_existing_locale_language(language_info, m_language_info_system);
BOOST_LOG_TRIVIAL(info) << boost::format("Can't switch language to %1% (missing locales). Using %2% instead.")
% original_lang % language_info->CanonicalName.ToUTF8().data();
if (!wxLocale::IsAvailable(locale_language_info->Language) && m_language_info_system) {
std::string original_lang = into_u8(locale_language_info->CanonicalName);
locale_language_info = linux_get_existing_locale_language(locale_language_info, m_language_info_system);
if (locale_language_info != nullptr && locale_language_info != translation_language_info) {
BOOST_LOG_TRIVIAL(info) << boost::format("Can't use locale %1% directly (missing locales). Using locale %2% instead.")
% original_lang % locale_language_info->CanonicalName.ToUTF8().data();
}
}
if (locale_language_info == nullptr || !wxLocale::IsAvailable(locale_language_info->Language)) {
auto try_locale = [](const wxLanguageInfo* candidate) -> const wxLanguageInfo* {
return (candidate && wxLocale::IsAvailable(candidate->Language)) ? candidate : nullptr;
};
const wxLanguageInfo* fallback_locale_info =
try_locale(m_wxLocale ? wxLocale::GetLanguageInfo(wxLanguage(m_wxLocale->GetLanguage())) : nullptr);
if (!fallback_locale_info) fallback_locale_info = try_locale(m_language_info_system);
if (!fallback_locale_info) fallback_locale_info = try_locale(m_language_info_best);
if (!fallback_locale_info) fallback_locale_info = try_locale(wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_US));
if (!fallback_locale_info) fallback_locale_info = try_locale(wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_UK));
if (fallback_locale_info != nullptr) {
BOOST_LOG_TRIVIAL(info) << boost::format("Using fallback locale %1% while keeping translation dictionary %2%.")
% fallback_locale_info->CanonicalName.ToUTF8().data() % requested_language_code.ToUTF8().data();
locale_language_info = fallback_locale_info;
}
}
#endif
if (! wxLocale::IsAvailable(language_info->Language)&&initial) {
language_info = wxLocale::GetLanguageInfo(wxLANGUAGE_ENGLISH_UK);
app_config->set("language", language_info->CanonicalName.ToUTF8().data());
}
else if (initial) {
if (initial) {
// bbs supported languages
//TODO: use a global one with Preference
//wxLanguage supported_languages[]{
@@ -6438,9 +6459,11 @@ bool GUI_App::load_language(wxString language, bool initial)
//}
}
if (! wxLocale::IsAvailable(language_info->Language)) {
BOOST_LOG_TRIVIAL(trace) << boost::format("Switching wxLocales to %1%") % locale_language_info->CanonicalName.ToUTF8().data();
if (!wxLocale::IsAvailable(locale_language_info->Language)) {
// Loading the language dictionary failed.
wxString message = "Switching Orca Slicer to language " + language_info->CanonicalName + " failed.";
wxString message = "Switching Orca Slicer to language " + requested_language_code + " failed.";
#if !defined(_WIN32) && !defined(__APPLE__)
// likely some linux system
message += "\nYou may need to reconfigure the missing locales, likely by running the \"locale-gen\" and \"dpkg-reconfigure locales\" commands.\n";
@@ -6458,12 +6481,13 @@ bool GUI_App::load_language(wxString language, bool initial)
//FIXME wxWidgets cause havoc if the current locale is deleted. We just forget it causing memory leaks for now.
m_wxLocale.release();
m_wxLocale = Slic3r::make_unique<wxLocale>();
m_wxLocale->Init(language_info->Language);
m_wxLocale->Init(locale_language_info->Language);
// Override language at the active wxTranslations class (which is stored in the active m_wxLocale)
// to load possibly different dictionary, for example, load Czech dictionary for Slovak language.
wxTranslations::Get()->SetLanguage(language_dict);
m_wxLocale->AddCatalog(SLIC3R_APP_KEY);
m_imgui->set_language(into_u8(language_info->CanonicalName));
m_active_language_code = requested_language_code;
m_imgui->set_language(into_u8(requested_language_code));
//FIXME This is a temporary workaround, the correct solution is to switch to "C" locale during file import / export only.
//wxSetlocale(LC_NUMERIC, "C");
@@ -6751,49 +6775,57 @@ void GUI_App::show_ip_address_enter_dialog_handler(wxCommandEvent& evt)
void GUI_App::open_preferences(size_t open_on_tab, const std::string& highlight_option)
{
bool app_layout_changed = false;
bool need_recreate_gui = false;
std::string pending_language;
{
// the dialog needs to be destroyed before the call to recreate_GUI()
// or sometimes the application crashes into wxDialogBase() destructor
// so we put it into an inner scope
PreferencesDialog dlg(mainframe, open_on_tab, highlight_option);
dlg.ShowModal();
this->plater_->get_current_canvas3D()->force_set_focus();
// BBS
//app_layout_changed = dlg.settings_layout_changed();
need_recreate_gui = dlg.recreate_GUI();
pending_language = dlg.pending_language();
if (!need_recreate_gui) {
this->plater_->get_current_canvas3D()->force_set_focus();
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
if (dlg.seq_top_layer_only_changed() || dlg.seq_seq_top_gcode_indices_changed())
if (dlg.seq_top_layer_only_changed() || dlg.seq_seq_top_gcode_indices_changed())
#else
if (dlg.seq_top_layer_only_changed())
if (dlg.seq_top_layer_only_changed())
#endif // ENABLE_GCODE_LINES_ID_IN_H_SLIDER
this->plater_->reload_print();
this->plater_->reload_print();
#ifdef _WIN32
if (is_editor()) {
if (app_config->get("associate_3mf") == "true")
associate_files(L"3mf");
if (app_config->get("associate_stl") == "true")
associate_files(L"stl");
if (app_config->get("associate_step") == "true") {
associate_files(L"step");
associate_files(L"stp");
if (is_editor()) {
if (app_config->get("associate_3mf") == "true")
associate_files(L"3mf");
if (app_config->get("associate_stl") == "true")
associate_files(L"stl");
if (app_config->get("associate_step") == "true") {
associate_files(L"step");
associate_files(L"stp");
}
associate_url(L"orcaslicer");
}
else {
if (app_config->get("associate_gcode") == "true")
associate_files(L"gcode");
}
associate_url(L"orcaslicer");
}
else {
if (app_config->get("associate_gcode") == "true")
associate_files(L"gcode");
}
#endif // _WIN32
}
}
// BBS
/*
if (app_layout_changed) {
// hide full main_sizer for mainFrame
mainframe->GetSizer()->Show(false);
mainframe->update_layout();
mainframe->select_tab(size_t(0));
}*/
if (!pending_language.empty()) {
const std::string previous_language = app_config->get("language");
app_config->set("language", pending_language);
if (!load_language(wxString::FromUTF8(pending_language), false)) {
app_config->set("language", previous_language);
if (this->plater_)
this->plater_->get_current_canvas3D()->force_set_focus();
return;
}
}
if (need_recreate_gui)
recreate_GUI(_L("Changing application language"));
}
bool GUI_App::has_unsaved_preset_changes() const
+2 -1
View File
@@ -273,6 +273,7 @@ private:
const wxLanguageInfo *m_language_info_system = nullptr;
// Best translation language, provided by Windows or OSX, owned by wxWidgets.
const wxLanguageInfo *m_language_info_best = nullptr;
wxString m_active_language_code;
OpenGLManager m_opengl_mgr;
std::unique_ptr<RemovableDriveManager> m_removable_drive_manager;
@@ -563,7 +564,7 @@ public:
void preset_deleted_from_cloud(std::string setting_id);
wxString filter_string(wxString str);
wxString current_language_code() const { return m_wxLocale->GetCanonicalName(); }
wxString current_language_code() const { return m_active_language_code.empty() && m_wxLocale ? m_wxLocale->GetCanonicalName() : m_active_language_code; }
// Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US".
wxString current_language_code_safe() const;
bool is_localized() const { return m_wxLocale->GetLocale() != "English"; }
+7 -16
View File
@@ -2485,7 +2485,7 @@ static wxMenu* generate_help_menu()
// //TODO
// });
// Check New Version
append_menu_item(helpMenu, wxID_ANY, _L("Check for Update"), _L("Check for Update"),
append_menu_item(helpMenu, wxID_ANY, _L("Check for Updates"), _L("Check for Updates"),
[](wxCommandEvent&) {
wxGetApp().check_new_version_sf(true, 1);
}, "", nullptr, []() {
@@ -3145,15 +3145,7 @@ void MainFrame::init_menubar_as_editor()
append_menu_item(
parent_menu, wxID_ANY, _L("Preferences") + "\t" + ctrl + ",", "",
[this](wxCommandEvent &) {
PreferencesDialog dlg(this);
dlg.ShowModal();
plater()->get_current_canvas3D()->force_set_focus();
#if ENABLE_GCODE_LINES_ID_IN_H_SLIDER
if (dlg.seq_top_layer_only_changed() || dlg.seq_seq_top_gcode_indices_changed())
#else
if (dlg.seq_top_layer_only_changed())
#endif
plater()->reload_print();
wxGetApp().open_preferences();
},
"", nullptr, []() { return true; }, this, 1);
//parent_menu->Insert(1, preference_item);
@@ -3174,7 +3166,6 @@ void MainFrame::init_menubar_as_editor()
[this](wxCommandEvent &) {
// Orca: Use GUI_App::open_preferences instead of direct call so windows associations are updated on exit
wxGetApp().open_preferences();
plater()->get_current_canvas3D()->force_set_focus();
},
"", nullptr, []() { return true; }, this);
//m_topbar->AddDropDownMenuItem(preference_item);
@@ -3215,20 +3206,20 @@ void MainFrame::init_menubar_as_editor()
// Flow rate (with submenu)
auto flowrate_menu = new wxMenu();
append_menu_item(
flowrate_menu, wxID_ANY, _L("Pass 1"), _L("Flow rate test - Pass 1"),
flowrate_menu, wxID_ANY, _L("Pass 1"), _L("Flow ratio test - Pass 1"),
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(false, 1); }, "", nullptr,
[this]() {return m_plater->is_view3D_shown();; }, this);
append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 2"), _L("Flow rate test - Pass 2"),
append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 2"), _L("Flow ratio test - Pass 2"),
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(false, 2); }, "", nullptr,
[this]() {return m_plater->is_view3D_shown();; }, this);
flowrate_menu->AppendSeparator();
append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (Recommended)"), _L("Orca YOLO flowrate calibration, 0.01 step"),
append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (Recommended)"), _L("Orca YOLO flowratio calibration, 0.01 step"),
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(true, 1); }, "", nullptr,
[this]() {return m_plater->is_view3D_shown();; }, this);
append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (perfectionist version)"), _L("Orca YOLO flowrate calibration, 0.005 step"),
append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (perfectionist version)"), _L("Orca YOLO flowratio calibration, 0.005 step"),
[this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(true, 2); }, "", nullptr,
[this]() {return m_plater->is_view3D_shown();; }, this);
m_topbar->GetCalibMenu()->AppendSubMenu(flowrate_menu, _L("Flow rate"));
m_topbar->GetCalibMenu()->AppendSubMenu(flowrate_menu, _L("Flow ratio"));
// Retraction test
append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Retraction test"), _L("Retraction test"),
+28 -23
View File
@@ -469,7 +469,6 @@ struct Sidebar::priv
ScalableButton * m_bpButton_ams_filament;
ScalableButton * m_bpButton_set_filament;
int m_menu_filament_id = -1;
int filament_area_height;
wxScrolledWindow* m_panel_filament_content;
wxScrolledWindow* m_scrolledWindow_filament_content;
wxStaticLine* m_staticline2;
@@ -2106,14 +2105,10 @@ Sidebar::Sidebar(Plater *parent)
bSizer39->AddSpacer(FromDIP(SidebarProps::TitlebarMargin()));
// add filament content
// ORCA use a height with user preference
int filament_count_user = std::stoi(wxGetApp().app_config->get("filaments_area_preferred_count"));
p->filament_area_height = std::ceil(filament_count_user * 0.5) * (30 + SidebarProps::ElementSpacing()) - SidebarProps::ElementSpacing();
p->m_panel_filament_content = new wxScrolledWindow( p->scrolled, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
p->m_panel_filament_content->SetScrollbars(0, 100, 1, 2);
p->m_panel_filament_content->SetScrollRate(0, 5);
p->m_panel_filament_content->SetMaxSize(wxSize{-1, FromDIP(p->filament_area_height)}); // ORCA
//p->m_panel_filament_content->SetMaxSize(wxSize{-1, FromDIP(174)});
p->m_panel_filament_content->SetBackgroundColour(wxColour(255, 255, 255));
//wxBoxSizer* bSizer_filament_content;
@@ -2135,10 +2130,9 @@ Sidebar::Sidebar(Plater *parent)
sizer_filaments2->Add(p->sizer_filaments, 0, wxEXPAND, 0);
p->m_panel_filament_content->SetSizer(sizer_filaments2);
p->m_panel_filament_content->Layout();
auto min_size = sizer_filaments2->GetMinSize();
if (min_size.y > p->m_panel_filament_content->GetMaxHeight())
min_size.y = p->m_panel_filament_content->GetMaxHeight();
p->m_panel_filament_content->SetMinSize(min_size);
update_filaments_area_height(); // ORCA
scrolled_sizer->Add(p->m_panel_filament_content, 0, wxEXPAND | wxTOP | wxBOTTOM, FromDIP(SidebarProps::ContentMarginV())); // ORCA use vertical margin on parent otherwise it shows scrollbar even on 1 filament
}
@@ -2776,6 +2770,23 @@ void Sidebar::change_top_border_for_mode_sizer(bool increase_border)
#endif
}
void Sidebar::update_filaments_area_height()
// ORCA
{
// ORCA use a height with user preference
auto left_sizer = p->sizer_filaments->GetItem((size_t) 0)->GetSizer();
auto combo_sizer = left_sizer->GetItem((size_t) 0)->GetSizer();
int preferred_rows = std::ceil(0.5 * std::stoi(wxGetApp().app_config->get("filaments_area_preferred_count")));
auto height_with_borders = combo_sizer->GetSize().GetHeight(); // gets height from sizer instead static numbers
p->m_panel_filament_content->SetMaxSize(wxSize{-1, preferred_rows * height_with_borders});
// fixes wxScrolledWindow not shrinks its height to content size
auto min_size = p->m_panel_filament_content->GetSizer()->GetMinSize();
if (min_size.y > p->m_panel_filament_content->GetMaxHeight())
min_size.y = p->m_panel_filament_content->GetMaxHeight();
p->m_panel_filament_content->SetMinSize({-1, min_size.y});
}
void Sidebar::msw_rescale()
{
SetMinSize(wxSize(42 * wxGetApp().em_unit(), -1));
@@ -2846,6 +2857,9 @@ void Sidebar::msw_rescale()
for (PlaterPresetComboBox* combo : p->combos_filament)
combo->msw_rescale();
p->m_panel_filament_content->Layout();
update_filaments_area_height(); // ORCA resize after combos scaled
// BBS
//p->frequently_changed_parameters->msw_rescale();
//obj_list()->msw_rescale();
@@ -3024,10 +3038,7 @@ void Sidebar::on_filament_count_change(size_t num_filaments)
}
}
auto min_size = p->m_panel_filament_content->GetSizer()->GetMinSize();
if (min_size.y > p->m_panel_filament_content->GetMaxHeight())
min_size.y = p->m_panel_filament_content->GetMaxHeight();
p->m_panel_filament_content->SetMinSize(min_size);
update_filaments_area_height(); // ORCA
Layout();
p->m_panel_filament_title->Refresh();
@@ -3087,10 +3098,7 @@ void Sidebar::on_filaments_delete(size_t filament_id)
p->combos_filament[idx]->update();
}
auto min_size = p->m_panel_filament_content->GetSizer()->GetMinSize();
if (min_size.y > p->m_panel_filament_content->GetMaxHeight())
min_size.y = p->m_panel_filament_content->GetMaxHeight();
p->m_panel_filament_content->SetMinSize(min_size);
update_filaments_area_height(); // ORCA
Layout();
p->m_panel_filament_title->Refresh();
@@ -3524,11 +3532,8 @@ void Sidebar::sync_ams_list(bool is_from_big_sync_btn)
for (auto& c : p->combos_filament)
c->update();
// Expand filament list
p->m_panel_filament_content->SetMaxSize({-1, FromDIP(p->filament_area_height)}); // ORCA
auto min_size = p->m_panel_filament_content->GetSizer()->GetMinSize();
if (min_size.y > p->m_panel_filament_content->GetMaxHeight())
min_size.y = p->m_panel_filament_content->GetMaxHeight();
p->m_panel_filament_content->SetMinSize({-1, min_size.y});
update_filaments_area_height(); // ORCA
// BBS:Synchronized consumables information
// auto calculation of flushing volumes
for (int i = 0; i < p->combos_filament.size(); ++i) {
+1
View File
@@ -172,6 +172,7 @@ public:
void set_bed_type_accord_combox(BedType bed_type);
bool reset_bed_type_combox_choices(bool is_sidebar_init = false);
void change_top_border_for_mode_sizer(bool increase_border);
void update_filaments_area_height();
void msw_rescale();
void sys_color_changed();
void search();
+37 -8
View File
@@ -318,13 +318,10 @@ wxBoxSizer *PreferencesDialog::create_item_language_combobox(wxString title, wxS
m_current_language_selected = combobox->GetSelection();
if (m_current_language_selected >= 0 && m_current_language_selected < vlist.size()) {
app_config->set(param, vlist[m_current_language_selected]->CanonicalName.ToUTF8().data());
wxGetApp().load_language(vlist[m_current_language_selected]->CanonicalName, false);
Close();
// Reparent(nullptr);
GetParent()->RemoveChild(this);
wxGetApp().recreate_GUI(_L("Changing application language"));
m_pending_language = vlist[m_current_language_selected]->CanonicalName.ToUTF8().data();
m_recreate_GUI = true;
EndModal(wxID_OK);
return;
}
}
@@ -592,6 +589,14 @@ wxBoxSizer *PreferencesDialog::create_item_spinctrl(wxString title, wxString tit
e.Skip();
});
input->Bind(wxEVT_SPINCTRL, [this, param, input, onchange](wxCommandEvent& e) {
auto value = input->GetValue();
app_config->set(param, std::to_string(value));
app_config->save();
if (onchange != nullptr) onchange(value);
e.Skip();
});
input->Bind(wxEVT_KILL_FOCUS, [this, param, input, onchange](wxFocusEvent &e) {
auto value = input->GetValue();
app_config->set(param, std::to_string(value));
@@ -1398,7 +1403,13 @@ void PreferencesDialog::create_items()
"group_filament_presets", {_L("All"), _L("None"), _L("By type"), _L("By vendor")}, [](wxString value) {wxGetApp().plater()->sidebar().update_presets(Preset::TYPE_FILAMENT);});
g_sizer->Add(item_filament_preset_grouping);
auto item_filament_area_height = create_item_spinctrl(_L("Optimize filaments area height for..."), _L("(Requires restart)"), _L("filaments"), _L("Optimizes filament area maximum height by chosen filament count."), "filaments_area_preferred_count", 8, 99);
// prevent burst calling on keyboard / spin events
m_filament_height_timer.Bind(wxEVT_TIMER, [this](wxTimerEvent&) {
wxGetApp().plater()->sidebar().update_filaments_area_height();
UpdateSidebarLayout();
});
auto item_filament_area_height = create_item_spinctrl(_L("Optimize filaments area height for..."), "", _L("filaments"), _L("Optimizes filament area maximum height by chosen filament count."),
"filaments_area_preferred_count", 8, 99, [this](int value) {m_filament_height_timer.StartOnce(500);});
g_sizer->Add(item_filament_area_height);
//// GENERAL > Features
@@ -1950,4 +1961,22 @@ wxBoxSizer* PreferencesDialog::create_debug_page()
return bSizer;
}
void PreferencesDialog::UpdateSidebarLayout()
{
Plater* plater = wxGetApp().plater();
if (!plater) return;
Sidebar& sidebar = plater->sidebar();
sidebar.Freeze();
sidebar.Layout();
//plater->Layout();
//wxGetApp().mainframe->Layout();
sidebar.Thaw();
plater->PostSizeEvent();
}
}} // namespace Slic3r::GUI
+6
View File
@@ -6,6 +6,7 @@
#include <wx/dialog.h>
#include <wx/timer.h>
#include <string>
#include <vector>
#include <list>
#include <map>
@@ -43,10 +44,12 @@ protected:
// bool m_settings_layout_changed {false};
bool m_seq_top_layer_only_changed{false};
bool m_recreate_GUI{false};
std::string m_pending_language;
public:
bool seq_top_layer_only_changed() const { return m_seq_top_layer_only_changed; }
bool recreate_GUI() const { return m_recreate_GUI; }
const std::string& pending_language() const { return m_pending_language; }
void on_dpi_changed(const wxRect &suggested_rect) override;
public:
@@ -60,6 +63,7 @@ public:
~PreferencesDialog();
wxString m_backup_interval_time;
wxTimer m_filament_height_timer;
void create();
@@ -106,6 +110,8 @@ public:
void create_shortcuts_page();
wxBoxSizer* create_debug_page();
void UpdateSidebarLayout();
// BBS
void create_select_domain_widget();
+1 -1
View File
@@ -639,7 +639,7 @@ wxBoxSizer* PrintOptionsDialog::create_settings_group(wxWindow* parent)
ai_refine_sizer->Add(line_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(18));
line_sizer = new wxBoxSizer(wxHORIZONTAL);
text_spaghetti_detection_caption0 = new Label(ai_refine_panel, _L("Detect spaghetti failure(scattered lose filament)."));
text_spaghetti_detection_caption0 = new Label(ai_refine_panel, _L("Detect spaghetti failures (scattered lose filament)."));
text_spaghetti_detection_caption0->SetFont(Label::Body_12);
text_spaghetti_detection_caption0->SetForegroundColour(STATIC_TEXT_CAPTION_COL);
text_spaghetti_detection_caption0->Wrap(-1);
+2 -2
View File
@@ -1668,7 +1668,7 @@ void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* pres
// process changes of extruders count
if (type == Preset::TYPE_PRINTER && old_pt == ptFFF &&
old_config.opt<ConfigOptionFloats>("nozzle_diameter")->values.size() != new_config.opt<ConfigOptionFloats>("nozzle_diameter")->values.size()) {
wxString local_label = _L("Extruders count");
wxString local_label = _L("Extruder count");
wxString old_val = from_u8((boost::format("%1%") % old_config.opt<ConfigOptionFloats>("nozzle_diameter")->values.size()).str());
wxString new_val = from_u8((boost::format("%1%") % new_config.opt<ConfigOptionFloats>("nozzle_diameter")->values.size()).str());
@@ -2228,7 +2228,7 @@ void DiffPresetDialog::update_tree()
// process changes of extruders count
if (type == Preset::TYPE_PRINTER && left_pt == ptFFF &&
left_config.opt<ConfigOptionStrings>("extruder_colour")->values.size() != right_congig.opt<ConfigOptionStrings>("extruder_colour")->values.size()) {
wxString local_label = _L("Extruders count");
wxString local_label = _L("Extruder count");
wxString left_val = from_u8((boost::format("%1%") % left_config.opt<ConfigOptionStrings>("extruder_colour")->values.size()).str());
wxString right_val = from_u8((boost::format("%1%") % right_congig.opt<ConfigOptionStrings>("extruder_colour")->values.size()).str());
+40 -18
View File
@@ -5,6 +5,9 @@
#include <wx/dcclient.h>
#include <wx/settings.h>
#include <boost/log/trivial.hpp>
#ifdef __linux__
#include <fontconfig/fontconfig.h>
#endif
wxFont Label::sysFont(int size, bool bold)
@@ -58,27 +61,46 @@ wxFont Label::Body_10;
wxFont Label::Body_9;
wxFont Label::Body_8;
// Check if a font family is already available via fontconfig.
#ifdef __linux__
static bool fc_font_available(const char *family_name)
{
FcPattern *pat = FcPatternCreate();
if (!pat)
return false;
FcPatternAddString(pat, FC_FAMILY, (const FcChar8 *) family_name);
FcResult res;
FcPattern *match = FcFontMatch(nullptr, pat, &res);
bool available = false;
if (match) {
FcChar8 *matched_family = nullptr;
if (FcPatternGetString(match, FC_FAMILY, 0, &matched_family) == FcResultMatch && matched_family)
available = (strcasecmp((const char *) matched_family, family_name) == 0);
FcPatternDestroy(match);
}
FcPatternDestroy(pat);
return available;
}
#endif
void Label::initSysFont()
{
#if defined(__linux__) || defined(_WIN32)
const std::string &resource_path = Slic3r::resources_dir();
wxString font_path = wxString::FromUTF8(resource_path + "/fonts/HarmonyOS_Sans_SC_Bold.ttf");
bool result = wxFont::AddPrivateFont(font_path);
// BOOST_LOG_TRIVIAL(info) << boost::format("add font of HarmonyOS_Sans_SC_Bold returns %1%")%result;
// printf("add font of HarmonyOS_Sans_SC_Bold returns %d\n", result);
font_path = wxString::FromUTF8(resource_path + "/fonts/HarmonyOS_Sans_SC_Regular.ttf");
result = wxFont::AddPrivateFont(font_path);
// BOOST_LOG_TRIVIAL(info) << boost::format("add font of HarmonyOS_Sans_SC_Regular returns %1%")%result;
// printf("add font of HarmonyOS_Sans_SC_Regular returns %d\n", result);
// Adding NanumGothic Regular and Bold
font_path = wxString::FromUTF8(resource_path + "/fonts/NanumGothic-Regular.ttf");
result = wxFont::AddPrivateFont(font_path);
// BOOST_LOG_TRIVIAL(info) << boost::format("add font of NanumGothic-Regular returns %1%")%result;
// printf("add font of NanumGothic-Regular returns %d\n", result);
font_path = wxString::FromUTF8(resource_path + "/fonts/NanumGothic-Bold.ttf");
result = wxFont::AddPrivateFont(font_path);
// BOOST_LOG_TRIVIAL(info) << boost::format("add font of NanumGothic-Bold returns %1%")%result;
// printf("add font of NanumGothic-Bold returns %d\n", result);
// On Linux, skip AddPrivateFont for fonts already known to fontconfig
// (e.g. installed system-wide in a Flatpak). Calling AddPrivateFont
// triggers a Pango crash in ensure_faces() on Pango >= 1.48 (GNOME 49+),
// because FcConfigAppFontAddFile invalidates Pango's cached font map.
bool load_fonts = true;
#ifdef __linux__
load_fonts = !fc_font_available("HarmonyOS Sans SC") || !fc_font_available("NanumGothic");
#endif
if (load_fonts) {
const std::string &resource_path = Slic3r::resources_dir();
wxFont::AddPrivateFont(wxString::FromUTF8(resource_path + "/fonts/HarmonyOS_Sans_SC_Bold.ttf"));
wxFont::AddPrivateFont(wxString::FromUTF8(resource_path + "/fonts/HarmonyOS_Sans_SC_Regular.ttf"));
wxFont::AddPrivateFont(wxString::FromUTF8(resource_path + "/fonts/NanumGothic-Regular.ttf"));
wxFont::AddPrivateFont(wxString::FromUTF8(resource_path + "/fonts/NanumGothic-Bold.ttf"));
}
#endif
Head_48 = Label::sysFont(48, true);
Head_32 = Label::sysFont(32, true);
+16 -8
View File
@@ -67,7 +67,7 @@ std::vector<wxString> make_shaper_type_labels()
}
PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
: DPIDialog(parent, id, _L("PA Calibration"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE), m_plater(plater)
: DPIDialog(parent, id, _L("PA Calibration"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE), m_plater(plater)
{
SetBackgroundColour(*wxWHITE); // make sure background color set for dialog
SetForegroundColour(wxColour("#363636"));
@@ -196,6 +196,7 @@ PA_Calibration_Dlg::PA_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater*
Layout();
Fit();
v_sizer->SetSizeHints(this);
}
PA_Calibration_Dlg::~PA_Calibration_Dlg() {
@@ -328,7 +329,7 @@ enum FILAMENT_TYPE : int
};
Temp_Calibration_Dlg::Temp_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
: DPIDialog(parent, id, _L("Temperature calibration"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE), m_plater(plater)
: DPIDialog(parent, id, _L("Temperature calibration"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE), m_plater(plater)
{
SetBackgroundColour(*wxWHITE); // make sure background color set for dialog
SetForegroundColour(wxColour("#363636"));
@@ -409,6 +410,7 @@ Temp_Calibration_Dlg::Temp_Calibration_Dlg(wxWindow* parent, wxWindowID id, Plat
Layout();
Fit();
v_sizer->SetSizeHints(this);
auto validate_text = [](TextInput* ti){
unsigned long t = 0;
@@ -518,7 +520,7 @@ void Temp_Calibration_Dlg::on_dpi_changed(const wxRect& suggested_rect) {
//
MaxVolumetricSpeed_Test_Dlg::MaxVolumetricSpeed_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
: DPIDialog(parent, id, _L("Max volumetric speed test"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE), m_plater(plater)
: DPIDialog(parent, id, _L("Max volumetric speed test"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE), m_plater(plater)
{
SetBackgroundColour(*wxWHITE); // make sure background color set for dialog
SetForegroundColour(wxColour("#363636"));
@@ -587,6 +589,7 @@ MaxVolumetricSpeed_Test_Dlg::MaxVolumetricSpeed_Test_Dlg(wxWindow* parent, wxWin
Layout();
Fit();
v_sizer->SetSizeHints(this);
}
MaxVolumetricSpeed_Test_Dlg::~MaxVolumetricSpeed_Test_Dlg() {
@@ -622,7 +625,7 @@ void MaxVolumetricSpeed_Test_Dlg::on_dpi_changed(const wxRect& suggested_rect) {
//
VFA_Test_Dlg::VFA_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
: DPIDialog(parent, id, _L("VFA test"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE)
: DPIDialog(parent, id, _L("VFA test"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE)
, m_plater(plater)
{
SetBackgroundColour(*wxWHITE); // make sure background color set for dialog
@@ -694,6 +697,7 @@ VFA_Test_Dlg::VFA_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
Layout();
Fit();
v_sizer->SetSizeHints(this);
}
VFA_Test_Dlg::~VFA_Test_Dlg()
@@ -731,7 +735,7 @@ void VFA_Test_Dlg::on_dpi_changed(const wxRect& suggested_rect)
//
Retraction_Test_Dlg::Retraction_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
: DPIDialog(parent, id, _L("Retraction test"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE), m_plater(plater)
: DPIDialog(parent, id, _L("Retraction test"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE), m_plater(plater)
{
SetBackgroundColour(*wxWHITE); // make sure background color set for dialog
SetForegroundColour(wxColour("#363636"));
@@ -802,6 +806,7 @@ Retraction_Test_Dlg::Retraction_Test_Dlg(wxWindow* parent, wxWindowID id, Plater
Layout();
Fit();
v_sizer->SetSizeHints(this);
}
Retraction_Test_Dlg::~Retraction_Test_Dlg() {
@@ -836,7 +841,7 @@ void Retraction_Test_Dlg::on_dpi_changed(const wxRect& suggested_rect) {
//
Input_Shaping_Freq_Test_Dlg::Input_Shaping_Freq_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
: DPIDialog(parent, id, _L("Input shaping Frequency test"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE), m_plater(plater)
: DPIDialog(parent, id, _L("Input shaping Frequency test"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE), m_plater(plater)
{
SetBackgroundColour(*wxWHITE); // make sure background color set for dialog
SetForegroundColour(wxColour("#363636"));
@@ -981,6 +986,7 @@ Input_Shaping_Freq_Test_Dlg::Input_Shaping_Freq_Test_Dlg(wxWindow* parent, wxWin
Layout();
Fit();
v_sizer->SetSizeHints(this);
}
Input_Shaping_Freq_Test_Dlg::~Input_Shaping_Freq_Test_Dlg() {
@@ -1053,7 +1059,7 @@ void Input_Shaping_Freq_Test_Dlg::on_dpi_changed(const wxRect& suggested_rect) {
//
Input_Shaping_Damp_Test_Dlg::Input_Shaping_Damp_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
: DPIDialog(parent, id, _L("Input shaping Damp test"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE), m_plater(plater)
: DPIDialog(parent, id, _L("Input shaping Damp test"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE), m_plater(plater)
{
SetBackgroundColour(*wxWHITE); // make sure background color set for dialog
SetForegroundColour(wxColour("#363636"));
@@ -1179,6 +1185,7 @@ Input_Shaping_Damp_Test_Dlg::Input_Shaping_Damp_Test_Dlg(wxWindow* parent, wxWin
Layout();
Fit();
v_sizer->SetSizeHints(this);
}
Input_Shaping_Damp_Test_Dlg::~Input_Shaping_Damp_Test_Dlg() {
@@ -1246,7 +1253,7 @@ void Input_Shaping_Damp_Test_Dlg::on_dpi_changed(const wxRect& suggested_rect) {
//
Cornering_Test_Dlg::Cornering_Test_Dlg(wxWindow* parent, wxWindowID id, Plater* plater)
: DPIDialog(parent, id, _L("Cornering test"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE), m_plater(plater)
: DPIDialog(parent, id, _L("Cornering test"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE), m_plater(plater)
{
SetBackgroundColour(*wxWHITE); // make sure background color set for dialog
SetForegroundColour(wxColour("#363636"));
@@ -1374,6 +1381,7 @@ Cornering_Test_Dlg::Cornering_Test_Dlg(wxWindow* parent, wxWindowID id, Plater*
Layout();
Fit();
v_sizer->SetSizeHints(this);
}
Cornering_Test_Dlg::~Cornering_Test_Dlg() {
+20 -18
View File
@@ -571,7 +571,18 @@ bool MoonrakerPrinterAgent::fetch_filament_info(std::string dev_id)
std::vector<AmsTrayData> trays;
int max_lane_index = 0;
// Try Happy Hare first (more widely adopted, supports more filament changers)
// Try Moonraker filament data (more generic, supports any filament changer
// software that reports lane data to Moonraker like AFC and recent Happy
// Hare as of Feb 15, 2026)
if (fetch_moonraker_filament_data(trays, max_lane_index)) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: Detected Moonraker filament system with "
<< (max_lane_index + 1) << " lanes";
int ams_count = (max_lane_index + 4) / 4;
build_ams_payload(ams_count, max_lane_index, trays);
return true;
}
// Attempt Happy Hare first (more widely adopted, supports more filament changers)
if (fetch_hh_filament_info(trays, max_lane_index)) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: Detected Happy Hare MMU with "
<< (max_lane_index + 1) << " gates";
@@ -580,17 +591,8 @@ bool MoonrakerPrinterAgent::fetch_filament_info(std::string dev_id)
return true;
}
// Fallback to AFC
if (fetch_afc_filament_info(trays, max_lane_index)) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: Detected AFC with "
<< (max_lane_index + 1) << " lanes";
int ams_count = (max_lane_index + 4) / 4;
build_ams_payload(ams_count, max_lane_index, trays);
return true;
}
// No MMU detected - this is normal for printers without MMU, not an error
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: No MMU system detected (neither HH nor AFC)";
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_filament_info: No MMU system detected (neither HH nor Moonraker)";
return false;
}
@@ -721,10 +723,10 @@ std::string MoonrakerPrinterAgent::normalize_color_value(const std::string& colo
return normalized;
}
// Fetch filament info from Armored Turtle AFC
bool MoonrakerPrinterAgent::fetch_afc_filament_info(std::vector<AmsTrayData>& trays, int& max_lane_index)
// Fetch filament info from moonraker database
bool MoonrakerPrinterAgent::fetch_moonraker_filament_data(std::vector<AmsTrayData>& trays, int& max_lane_index)
{
// Fetch AFC lane data from Moonraker database
// Fetch lane data from Moonraker database
std::string url = join_url(device_info.base_url, "/server/database/item?namespace=lane_data");
std::string response_body;
@@ -754,19 +756,19 @@ bool MoonrakerPrinterAgent::fetch_afc_filament_info(std::vector<AmsTrayData>& tr
.perform_sync();
if (!success) {
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_afc_filament_info: Failed to fetch lane data: " << http_error;
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_moonraker_filament_data: Failed to fetch lane data: " << http_error;
return false;
}
auto json = nlohmann::json::parse(response_body, nullptr, false, true);
if (json.is_discarded()) {
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_afc_filament_info: Invalid JSON response";
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_moonraker_filament_data: Invalid JSON response";
return false;
}
// Expected structure: { "result": { "namespace": "lane_data", "value": { "lane1": {...}, ... } } }
if (!json.contains("result") || !json["result"].contains("value") || !json["result"]["value"].is_object()) {
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_afc_filament_info: Unexpected JSON structure or no lane_data found";
BOOST_LOG_TRIVIAL(warning) << "MoonrakerPrinterAgent::fetch_moonraker_filament_data: Unexpected JSON structure or no lane_data found";
return false;
}
@@ -812,7 +814,7 @@ bool MoonrakerPrinterAgent::fetch_afc_filament_info(std::vector<AmsTrayData>& tr
}
if (trays.empty()) {
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_afc_filament_info: No AFC lanes found";
BOOST_LOG_TRIVIAL(info) << "MoonrakerPrinterAgent::fetch_moonraker_filament_data: No lanes found";
return false;
}
+1 -1
View File
@@ -162,7 +162,7 @@ private:
// System-specific filament fetch methods
bool fetch_hh_filament_info(std::vector<AmsTrayData>& trays, int& max_lane_index);
bool fetch_afc_filament_info(std::vector<AmsTrayData>& trays, int& max_lane_index);
bool fetch_moonraker_filament_data(std::vector<AmsTrayData>& trays, int& max_lane_index);
// JSON helper methods
static std::string safe_json_string(const nlohmann::json& obj, const char* key);