Merge branch 'main' into belt/baseChanges

This commit is contained in:
SoftFever
2026-04-06 22:52:31 +08:00
committed by GitHub
27 changed files with 412 additions and 122 deletions
+1 -1
View File
@@ -1654,7 +1654,7 @@ msgid "Based on PrusaSlicer and BambuStudio"
msgstr "Basierend auf PrusaSlicer und BambuStudio" msgstr "Basierend auf PrusaSlicer und BambuStudio"
msgid "STEP files" msgid "STEP files"
msgstr "SETP Dateien" msgstr "STEP Dateien"
msgid "STL files" msgid "STL files"
msgstr "STL Dateien" msgstr "STL Dateien"
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "Creality", "name": "Creality",
"version": "02.03.02.60", "version": "02.03.02.61",
"force_update": "0", "force_update": "0",
"description": "Creality configurations", "description": "Creality configurations",
"machine_model_list": [ "machine_model_list": [
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

@@ -5,9 +5,9 @@
"nozzle_diameter": "0.2;0.4;0.6;0.8", "nozzle_diameter": "0.2;0.4;0.6;0.8",
"machine_tech": "FFF", "machine_tech": "FFF",
"family": "Creality", "family": "Creality",
"bed_model": "creality_k1_buildplate_model.stl", "bed_model": "creality_k2_buildplate_model.stl",
"default_bed_type": "Textured PEI Plate", "default_bed_type": "Textured PEI Plate",
"bed_texture": "creality_k1_buildplate_texture.png", "bed_texture": "creality_k2_buildplate_texture.png",
"hotend_model": "", "hotend_model": "",
"default_materials": "Creality Generic ABS @K2-all;Creality Generic ASA @K2-all;Creality Generic PETG @K2-all;Creality Generic PLA @K2-all;Creality Generic PLA High Speed @K2-all;Creality Generic PLA Matte @K2-all;Creality Generic PLA Silk @K2-all" "default_materials": "Creality Generic ABS @K2-all;Creality Generic ASA @K2-all;Creality Generic PETG @K2-all;Creality Generic PLA @K2-all;Creality Generic PLA High Speed @K2-all;Creality Generic PLA Matte @K2-all;Creality Generic PLA Silk @K2-all"
} }
+45
View File
@@ -0,0 +1,45 @@
#!/bin/bash
# these are the CachyOS Linux specific build functions
# Additional Dev packages for OrcaSlicer
export REQUIRED_DEV_PACKAGES=(
cmake
curl
dbus
eglexternalplatform
extra-cmake-modules
file
gettext
git
glew
gstreamer
gtk3
libmspack
libsecret
libspnav
mesa
ninja
openssl
texinfo
wayland-protocols
webkit2gtk
wget
)
if [[ -n "$UPDATE_LIB" ]]
then
echo -n -e "Updating linux ...\n"
NEEDED_PKGS=()
for PKG in "${REQUIRED_DEV_PACKAGES[@]}"; do
pacman -Q "${PKG}" > /dev/null || NEEDED_PKGS+=("${PKG}")
done
if [[ "${#NEEDED_PKGS[*]}" -gt 0 ]]; then
sudo pacman -Syy --noconfirm "${NEEDED_PKGS[@]}"
fi
echo -e "done\n"
exit 0
fi
export FOUND_GTK3_DEV
FOUND_GTK3_DEV=$(pacman -Q gtk3)
@@ -5,7 +5,7 @@ Icon=OrcaSlicer
Exec=orca-slicer %U Exec=orca-slicer %U
Terminal=false Terminal=false
Type=Application Type=Application
MimeType=model/stl;model/3mf;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;x-scheme-handler/orcaslicer; MimeType=model/stl;model/3mf;application/vnd.ms-3mfdocument;application/prs.wavefront-obj;application/x-amf;x-scheme-handler/orcaslicer;model/step;
Categories=Graphics;3DGraphics;Engineering; Categories=Graphics;3DGraphics;Engineering;
Keywords=3D;Printing;Slicer;slice;3D;printer;convert;gcode;stl;obj;amf;SLA Keywords=3D;Printing;Slicer;slice;3D;printer;convert;gcode;stl;obj;amf;SLA
StartupNotify=false StartupNotify=false
+14 -10
View File
@@ -587,26 +587,30 @@ public:
auto rhs_opt = static_cast<const ConfigOptionVector<T>*>(rhs); auto rhs_opt = static_cast<const ConfigOptionVector<T>*>(rhs);
auto inherits_opt = static_cast<const ConfigOptionVector<T>*>(inherits); auto inherits_opt = static_cast<const ConfigOptionVector<T>*>(inherits);
if (inherits->size() != rhs->size()) if (stride <= 0)
throw ConfigurationError("ConfigOptionVector::set_with_nil(): rhs size different with inherits size"); throw ConfigurationError("ConfigOptionVector::set_with_nil(): invalid stride");
this->values.resize(inherits->size(), this->values.front()); // Tolerate legacy/transitional presets where vector sizes may diverge
// (for example after reducing extruder/variant count).
// Keep rhs as source of truth and nil-mark only on overlapping range.
this->values = rhs_opt->values;
for (size_t i = 0; i < inherits_opt->size(); i= i+stride) { const size_t overlap_size = std::min(rhs_opt->size(), inherits_opt->size());
for (size_t i = 0; i < overlap_size; i += size_t(stride)) {
const size_t group_size = std::min(size_t(stride), overlap_size - i);
bool set_nil = true; bool set_nil = true;
for (size_t j = 0; j < stride; j++) { for (size_t j = 0; j < group_size; ++j) {
if (inherits_opt->values[i +j] != rhs_opt->values[i +j]) { if (inherits_opt->values[i + j] != rhs_opt->values[i + j]) {
set_nil = false; set_nil = false;
break; break;
} }
} }
for (size_t j = 0; j < stride; j++) { for (size_t j = 0; j < group_size; ++j) {
if (set_nil) { if (set_nil) {
this->set_at_to_nil(i +j); this->set_at_to_nil(i + j);
} }
else
this->values[i +j] = rhs_opt->values[i +j];
} }
} }
} }
@@ -196,7 +196,7 @@ void group_region_by_fuzzify(PerimeterGenerator& g)
surfaces.push_back(&surface); surfaces.push_back(&surface);
} }
if (cfg.type != FuzzySkinType::None) { if (cfg.type != FuzzySkinType::None && cfg.type != FuzzySkinType::Disabled_fuzzy) {
g.has_fuzzy_skin = true; g.has_fuzzy_skin = true;
if (cfg.type != FuzzySkinType::External) { if (cfg.type != FuzzySkinType::External) {
g.has_fuzzy_hole = true; g.has_fuzzy_hole = true;
+6 -2
View File
@@ -5461,8 +5461,10 @@ void GCodeProcessor::process_M1020(const GCodeReader::GCodeLine &line)
BOOST_LOG_TRIVIAL(error) << "Invalid M1020 command (" << line.raw() << ")."; BOOST_LOG_TRIVIAL(error) << "Invalid M1020 command (" << line.raw() << ").";
} }
else { else {
if (eid >= m_result.filaments_count) if (eid >= m_result.filaments_count) {
BOOST_LOG_TRIVIAL(error) << "Invalid M1020 command (" << line.raw() << ")."; BOOST_LOG_TRIVIAL(error) << "Invalid M1020 command (" << line.raw() << ").";
return;
}
process_filament_change(eid); process_filament_change(eid);
} }
} }
@@ -5490,8 +5492,10 @@ void GCodeProcessor::process_T(const std::string_view command)
BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ")."; BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ").";
} }
else { else {
if (eid >= m_result.filaments_count) if (eid >= m_result.filaments_count) {
BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ")."; BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ").";
return;
}
process_filament_change(eid); process_filament_change(eid);
} }
} }
+1 -1
View File
@@ -653,7 +653,7 @@ public:
int match_quality = -1; int match_quality = -1;
for (; i < n; ++i) for (; i < n; ++i)
// Since we use the filament selection from Wizard, it's needed to control the preset visibility too // Since we use the filament selection from Wizard, it's needed to control the preset visibility too
if (m_presets[i].is_compatible) { if (m_presets[i].is_compatible && m_presets[i].is_visible) {
int this_match_quality = prefered_condition(m_presets[i]); int this_match_quality = prefered_condition(m_presets[i]);
if (this_match_quality > match_quality) { if (this_match_quality > match_quality) {
if (match_quality == std::numeric_limits<int>::max()) if (match_quality == std::numeric_limits<int>::max())
+17 -4
View File
@@ -734,9 +734,16 @@ void PresetBundle::reset_project_embedded_presets()
Preset& current_printer = this->printers.get_selected_preset(); Preset& current_printer = this->printers.get_selected_preset();
const std::vector<std::string> &prefered_filament_profiles = current_printer.config.option<ConfigOptionStrings>("default_filament_profile")->values; const std::vector<std::string> &prefered_filament_profiles = current_printer.config.option<ConfigOptionStrings>("default_filament_profile")->values;
const std::string prefered_filament_profile = prefered_filament_profiles.empty() ? std::string() : prefered_filament_profiles.front(); const std::string prefered_filament_profile = prefered_filament_profiles.empty() ? std::string() : prefered_filament_profiles.front();
if (!prefered_filament_profile.empty()) if (!prefered_filament_profile.empty()) {
// Check if preferred filament exists and is visible
const Preset* preferred_preset = this->filaments.find_preset(prefered_filament_profile, false);
if (preferred_preset && preferred_preset->is_visible) {
filament_presets[i] = prefered_filament_profile; filament_presets[i] = prefered_filament_profile;
else } else {
// Fall back to first visible filament
filament_presets[i] = this->filaments.first_visible().name;
}
} else
filament_presets[i] = this->filaments.first_visible().name; filament_presets[i] = this->filaments.first_visible().name;
} }
} }
@@ -1970,9 +1977,15 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
initial_print_profile_name = prefered_print_profile; initial_print_profile_name = prefered_print_profile;
const std::vector<std::string>& prefered_filament_profiles = preferred_printer->config.option<ConfigOptionStrings>("default_filament_profile")->values; const std::vector<std::string>& prefered_filament_profiles = preferred_printer->config.option<ConfigOptionStrings>("default_filament_profile")->values;
if ((!initial_filament_profile_name.compare("Default Filament")) && (prefered_filament_profiles.size() > 0)) if ((!initial_filament_profile_name.compare("Default Filament")) && (prefered_filament_profiles.size() > 0)) {
// Check if preferred filament is visible
const Preset* preferred_preset = this->filaments.find_preset(prefered_filament_profiles[0], false);
if (preferred_preset && preferred_preset->is_visible) {
initial_filament_profile_name = prefered_filament_profiles[0]; initial_filament_profile_name = prefered_filament_profiles[0];
} }
// If not visible, keep the default "Default Filament" which will be resolved later
}
}
// Selects the profile, leaves it to -1 if the initial profile name is empty or if it was not found. // Selects the profile, leaves it to -1 if the initial profile name is empty or if it was not found.
prints.select_preset_by_name_strict(initial_print_profile_name); prints.select_preset_by_name_strict(initial_print_profile_name);
@@ -4452,7 +4465,7 @@ void PresetBundle::update_compatible(PresetSelectCompatibleType select_other_pri
int operator()(const Preset &preset) const int operator()(const Preset &preset) const
{ {
// Don't match any properties of the "-- default --" profile or the external profiles when switching printer profile. // Don't match any properties of the "-- default --" profile or the external profiles when switching printer profile.
if (preset.is_default || preset.is_external) if (preset.is_default || preset.is_external || !preset.is_visible)
return 0; return 0;
if (! m_prefered_alias.empty() && m_prefered_alias == preset.alias) if (! m_prefered_alias.empty() && m_prefered_alias == preset.alias)
// Matching an alias, always take this preset with priority. // Matching an alias, always take this preset with priority.
+2 -5
View File
@@ -9338,11 +9338,8 @@ void DynamicPrintConfig::update_values_to_printer_extruders(DynamicPrintConfig&
//variant index //variant index
variant_index[e_index] = get_index_for_extruder(e_index+1, id_name, extruder_type, nozzle_volume_type, variant_name); variant_index[e_index] = get_index_for_extruder(e_index+1, id_name, extruder_type, nozzle_volume_type, variant_name);
if (variant_index[e_index] < 0) { if (variant_index[e_index] < 0) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(", Line %1%: could not found extruder_type %2%, nozzle_volume_type %3%, extruder_index %4%") // Orca: This is expected during transient UI states (e.g. popup windows),
%__LINE__ %s_keys_names_ExtruderType[extruder_type] % s_keys_names_NozzleVolumeType[nozzle_volume_type] % (e_index+1); // fall back to 0 silently.
assert(false);
//for some updates happens in a invalid state(caused by popup window)
//we need to avoid crash
variant_index[e_index] = 0; variant_index[e_index] = 0;
} }
} }
+1 -1
View File
@@ -15,7 +15,7 @@ namespace Slic3r
int m_nozzle_id = -1; int m_nozzle_id = -1;
NozzleFlowType m_nozzle_flow = NozzleFlowType::S_FLOW;// 0-common 1-high flow NozzleFlowType m_nozzle_flow = NozzleFlowType::S_FLOW;// 0-common 1-high flow
NozzleType m_nozzle_type = NozzleType::ntUndefine;// 0-stainless_steel 1-hardened_steel 5-tungsten_carbide NozzleType m_nozzle_type = NozzleType::ntUndefine;// 0-stainless_steel 1-hardened_steel 5-tungsten_carbide
float m_diameter = 0.4f;// 0.2mm 0.4mm 0.6mm 0.8mm float m_diameter = 0.0f;// unknown until reported by the printer
}; };
class DevNozzleSystem class DevNozzleSystem
+24 -5
View File
@@ -4285,7 +4285,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
p = p->GetParent(); p = p->GetParent();
auto *top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p); auto *top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
//Orca: Set focus so hotkeys like 'tab' work when a notification is shown. //Orca: Set focus so hotkeys like 'tab' work when a notification is shown.
if (top_level_wnd != nullptr && top_level_wnd->IsActive()) //But don't steal focus from text input controls.
wxWindow* focused = wxWindow::FindFocus();
bool focus_in_text_ctrl = dynamic_cast<wxTextCtrl*>(focused) != nullptr;
if (top_level_wnd != nullptr && top_level_wnd->IsActive() && !focus_in_text_ctrl)
m_canvas->SetFocus(); m_canvas->SetFocus();
} }
m_mouse.position = pos.cast<double>(); m_mouse.position = pos.cast<double>();
@@ -8485,11 +8488,27 @@ void GLCanvas3D::_render_return_toolbar() const
ImVec2 margin = ImVec2(10.0f, 5.0f); ImVec2 margin = ImVec2(10.0f, 5.0f);
if (ImGui::ImageTextButton(real_size,_utf8(L("Return")).c_str(), m_return_toolbar.get_return_texture_id(), button_icon_size, uv0, uv1, -1, bg_col, tint_col, margin)) { if (ImGui::ImageTextButton(real_size,_utf8(L("Return")).c_str(), m_return_toolbar.get_return_texture_id(), button_icon_size, uv0, uv1, -1, bg_col, tint_col, margin)) {
if (m_canvas != nullptr)
wxPostEvent(m_canvas, SimpleEvent(EVT_GLVIEWTOOLBAR_3D));
const_cast<GLGizmosManager*>(&m_gizmos)->reset_all_states(); const_cast<GLGizmosManager*>(&m_gizmos)->reset_all_states();
wxGetApp().plater()->get_view3D_canvas3D()->get_gizmos_manager().reset_all_states(); if (m_canvas != nullptr && !wxGetApp().is_closing()) {
wxGetApp().plater()->get_view3D_canvas3D()->reload_scene(true); m_canvas->CallAfter([]() {
auto& app = wxGetApp();
if (app.is_closing())
return;
auto* plater = app.plater();
if (plater == nullptr)
return;
plater->select_view_3D("3D");
auto* view3d_canvas = plater->get_view3D_canvas3D();
if (view3d_canvas == nullptr)
return;
view3d_canvas->get_gizmos_manager().reset_all_states();
view3d_canvas->reload_scene(true);
});
}
} }
ImGui::PopStyleColor(5); ImGui::PopStyleColor(5);
ImGui::PopStyleVar(1); ImGui::PopStyleVar(1);
+44 -11
View File
@@ -752,18 +752,51 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_)
wxMenuItem* MenuFactory::append_menu_item_change_type(wxMenu* menu) wxMenuItem* MenuFactory::append_menu_item_change_type(wxMenu* menu)
{ {
return append_menu_item(menu, wxID_ANY, _L("Change type"), "", const wxString menu_name = _L("Change type");
[](wxCommandEvent&) { obj_list()->change_part_type(); }, "", menu,
[]() { // Delete old menu item if exists
wxDataViewItemArray selections; const int item_id = menu->FindItem(menu_name);
obj_list()->GetSelections(selections); if (item_id != wxNOT_FOUND)
if (selections.empty()) return false; menu->Destroy(item_id);
for (const auto& it : selections) {
if (!(obj_list()->GetModel()->GetItemType(it) & itVolume)) // Create submenu
return false; // non-volume present -> disable wxMenu* type_menu = new wxMenu();
struct TypeInfo {
ModelVolumeType type;
wxString label;
};
std::vector<TypeInfo> types = {
{ ModelVolumeType::MODEL_PART, _L("Part") },
{ ModelVolumeType::NEGATIVE_VOLUME, _L("Negative Part") },
{ ModelVolumeType::PARAMETER_MODIFIER, _L("Modifier") },
{ ModelVolumeType::SUPPORT_BLOCKER, _L("Support Blocker") },
{ ModelVolumeType::SUPPORT_ENFORCER, _L("Support Enforcer") }
};
for (const auto& info : types) {
wxMenuItem* item = append_menu_check_item(type_menu, wxID_ANY, info.label, "",
[type = info.type](wxCommandEvent&) { obj_list()->set_volume_type(type); }, type_menu);
// Update checkmark dynamically when menu is shown - check all selected volumes
m_parent->Bind(wxEVT_UPDATE_UI, [type = info.type](wxUpdateUIEvent& evt) {
bool has_type = false;
wxDataViewItemArray sels;
obj_list()->GetSelections(sels);
for (auto item : sels) {
ModelVolumeType vol_type = obj_list()->GetModel()->GetVolumeType(item);
if (vol_type == type) {
has_type = true;
break;
} }
return true; }
}, m_parent); evt.Check(has_type);
}, item->GetId());
}
menu->Append(wxID_ANY, menu_name, type_menu, _L("Change part type"));
return nullptr;
} }
wxMenuItem* MenuFactory::append_menu_item_instance_to_object(wxMenu* menu) wxMenuItem* MenuFactory::append_menu_item_instance_to_object(wxMenu* menu)
+130
View File
@@ -5538,6 +5538,136 @@ void ObjectList::change_part_type()
return; return;
} }
ModelVolumeType ObjectList::get_selected_volume_type()
{
ModelVolume* volume = get_selected_model_volume();
if (volume)
return volume->type();
return ModelVolumeType::INVALID;
}
void ObjectList::set_volume_type(ModelVolumeType new_type)
{
struct VolumeSelection {
int object_idx;
ModelVolume* volume;
};
std::vector<VolumeSelection> volumes;
auto add_volume = [&volumes](int obj_idx, ModelVolume* volume) {
if (volume == nullptr)
return;
auto it = std::find_if(volumes.begin(), volumes.end(), [volume](const VolumeSelection& other) { return other.volume == volume; });
if (it == volumes.end())
volumes.push_back({ obj_idx, volume });
};
wxDataViewItemArray sels;
GetSelections(sels);
for (auto item : sels) {
wxDataViewItem volume_item = item;
ItemType type = m_objects_model->GetItemType(item);
if (!(type & itVolume)) {
if ((type & itSettings) && (m_objects_model->GetItemType(m_objects_model->GetParent(item)) & itVolume))
volume_item = m_objects_model->GetParent(item);
else
continue;
}
const int obj_idx = m_objects_model->GetObjectIdByItem(volume_item);
const int vol_idx = m_objects_model->GetVolumeIdByItem(volume_item);
if (obj_idx < 0 || vol_idx < 0 || obj_idx >= m_objects->size())
continue;
const int real_idx = m_objects_model->get_real_volume_index_in_3d(obj_idx, vol_idx);
if (real_idx < 0 || real_idx >= (*m_objects)[obj_idx]->volumes.size())
continue;
add_volume(obj_idx, (*m_objects)[obj_idx]->volumes[real_idx]);
}
auto collect_from_canvas = [&add_volume](GLCanvas3D* canvas) {
if (canvas == nullptr)
return;
const Selection& selection = canvas->get_selection();
for (auto idx : selection.get_volume_idxs()) {
const GLVolume* gl_volume = selection.get_volume(idx);
if (gl_volume == nullptr || gl_volume->object_idx() < 0)
continue;
ModelVolume* volume = get_model_volume(*gl_volume, selection.get_model()->objects);
add_volume(gl_volume->object_idx(), volume);
}
};
if (volumes.empty()) {
collect_from_canvas(wxGetApp().plater()->canvas3D());
if (volumes.empty()) {
auto canvas_type = wxGetApp().plater()->get_current_canvas3D()->get_canvas_type();
if (canvas_type == GLCanvas3D::ECanvasType::CanvasView3D && is_connectors_item_selected())
collect_from_canvas(wxGetApp().plater()->get_view3D_canvas3D());
}
if (volumes.empty())
return;
}
const bool any_diff = std::any_of(volumes.begin(), volumes.end(),
[new_type](const VolumeSelection& sel) { return sel.volume->type() != new_type; });
if (!any_diff)
return;
if (new_type != ModelVolumeType::MODEL_PART) {
std::map<int, int> total_part_cnt;
std::map<int, int> selected_part_cnt;
for (const auto& sel : volumes) {
if (total_part_cnt.find(sel.object_idx) == total_part_cnt.end()) {
int count = 0;
for (auto vol : (*m_objects)[sel.object_idx]->volumes)
if (vol->type() == ModelVolumeType::MODEL_PART)
++count;
total_part_cnt.emplace(sel.object_idx, count);
}
if (sel.volume->type() == ModelVolumeType::MODEL_PART)
++selected_part_cnt[sel.object_idx];
}
for (const auto& sel : selected_part_cnt) {
auto it = total_part_cnt.find(sel.first);
if (it != total_part_cnt.end() && it->second > 0 && sel.second == it->second) {
Slic3r::GUI::show_error(nullptr, _(L("The type of the last solid object part is not to be changed.")));
return;
}
}
}
take_snapshot("Change part type");
std::set<const ModelVolume*> changed_volumes;
std::set<int> touched_objects;
for (const auto& sel : volumes) {
sel.volume->set_type(new_type);
changed_volumes.insert(sel.volume);
touched_objects.insert(sel.object_idx);
}
wxDataViewItemArray new_selection;
for (int obj_idx : touched_objects) {
wxDataViewItemArray sel_items = reorder_volumes_and_get_selection(obj_idx, [&changed_volumes](const ModelVolume* volume) {
return changed_volumes.find(volume) != changed_volumes.end();
});
for (const auto& item : sel_items)
new_selection.push_back(item);
}
if (!new_selection.IsEmpty()) {
m_prevent_list_events = true;
UnselectAll();
SetSelections(new_selection);
m_prevent_list_events = false;
}
}
void ObjectList::last_volume_is_deleted(const int obj_idx) void ObjectList::last_volume_is_deleted(const int obj_idx)
{ {
// BBS: object (obj_idx calc in obj list) is already removed from m_objects in Plater::priv::remove(). // BBS: object (obj_idx calc in obj list) is already removed from m_objects in Plater::priv::remove().
+2
View File
@@ -414,6 +414,8 @@ public:
ModelVolume* get_selected_model_volume(); ModelVolume* get_selected_model_volume();
void change_part_type(); void change_part_type();
void set_volume_type(ModelVolumeType new_type);
ModelVolumeType get_selected_volume_type();
void last_volume_is_deleted(const int obj_idx); void last_volume_is_deleted(const int obj_idx);
void update_and_show_object_settings_item(); void update_and_show_object_settings_item();
+10
View File
@@ -1,6 +1,7 @@
#include "GUI.hpp" #include "GUI.hpp"
#include "GUI_Utils.hpp" #include "GUI_Utils.hpp"
#include "GUI_App.hpp" #include "GUI_App.hpp"
#include "I18N.hpp"
#include <algorithm> #include <algorithm>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
@@ -32,6 +33,15 @@ wxDEFINE_EVENT(EVT_VOLUME_ATTACHED, VolumeAttachedEvent);
wxDEFINE_EVENT(EVT_VOLUME_DETACHED, VolumeDetachedEvent); wxDEFINE_EVENT(EVT_VOLUME_DETACHED, VolumeDetachedEvent);
#endif // _WIN32 #endif // _WIN32
wxString format_nozzle_diameter(float diameter)
{
if (diameter <= 0.0f) {
return _L("Unknown");
}
return wxString::Format("%smm", wxString::FromDouble(diameter));
}
CopyFileResult copy_file_gui(const std::string &from, const std::string &to, std::string& error_message, const bool with_check) CopyFileResult copy_file_gui(const std::string &from, const std::string &to, std::string& error_message, const bool with_check)
{ {
#ifdef WIN32 #ifdef WIN32
+1
View File
@@ -66,6 +66,7 @@ wxDECLARE_EVENT(EVT_VOLUME_DETACHED, VolumeDetachedEvent);
#endif /* _WIN32 */ #endif /* _WIN32 */
wxTopLevelWindow* find_toplevel_parent(wxWindow *window); wxTopLevelWindow* find_toplevel_parent(wxWindow *window);
wxString format_nozzle_diameter(float diameter);
void on_window_geometry(wxTopLevelWindow *tlw, std::function<void()> callback); void on_window_geometry(wxTopLevelWindow *tlw, std::function<void()> callback);
+2 -2
View File
@@ -4050,8 +4050,8 @@ void Sidebar::auto_calc_flushing_volumes_internal(const int modify_id, const int
const std::vector<int>& min_flush_volumes = get_min_flush_volumes(full_config, extruder_id); const std::vector<int>& min_flush_volumes = get_min_flush_volumes(full_config, extruder_id);
ConfigOptionFloat* flush_multi_opt = project_config.option<ConfigOptionFloat>("flush_multiplier"); const auto* flush_multi_opt = project_config.option<ConfigOptionFloats>("flush_multiplier");
float flush_multiplier = flush_multi_opt ? flush_multi_opt->getFloat() : 1.f; float flush_multiplier = flush_multi_opt ? (float)flush_multi_opt->get_at(extruder_id) : 1.f;
std::vector<double> matrix = init_matrix; std::vector<double> matrix = init_matrix;
int m_max_flush_volume = Slic3r::g_max_flush_volume; int m_max_flush_volume = Slic3r::g_max_flush_volume;
unsigned int m_number_of_extruders = (int)(sqrt(init_matrix.size()) + 0.001); unsigned int m_number_of_extruders = (int)(sqrt(init_matrix.size()) + 0.001);
+7 -7
View File
@@ -1345,7 +1345,7 @@ bool PrinterPartsDialog::Show(bool show)
auto type = obj->GetExtderSystem()->GetNozzleType(MAIN_EXTRUDER_ID); auto type = obj->GetExtderSystem()->GetNozzleType(MAIN_EXTRUDER_ID);
auto diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID); auto diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID);
nozzle_type_checkbox->SetValue(GetString(type)); nozzle_type_checkbox->SetValue(GetString(type));
nozzle_diameter_checkbox->SetValue(GetString(diameter)); nozzle_diameter_checkbox->SetValue(format_nozzle_diameter(diameter));
// nozzle flow type // nozzle flow type
nozzle_flow_type_label->Show(obj->is_nozzle_flow_type_supported()); nozzle_flow_type_label->Show(obj->is_nozzle_flow_type_supported());
@@ -1369,7 +1369,7 @@ bool PrinterPartsDialog::Show(bool show)
auto diameter = obj->GetExtderSystem()->GetNozzleDiameter(DEPUTY_EXTRUDER_ID); auto diameter = obj->GetExtderSystem()->GetNozzleDiameter(DEPUTY_EXTRUDER_ID);
auto flow_type = obj->GetExtderSystem()->GetNozzleFlowType(DEPUTY_EXTRUDER_ID); auto flow_type = obj->GetExtderSystem()->GetNozzleFlowType(DEPUTY_EXTRUDER_ID);
multiple_left_nozzle_type_checkbox->SetValue(GetString(type)); multiple_left_nozzle_type_checkbox->SetValue(GetString(type));
multiple_left_nozzle_diameter_checkbox->SetValue(GetString(diameter)); multiple_left_nozzle_diameter_checkbox->SetValue(format_nozzle_diameter(diameter));
multiple_left_nozzle_flow_checkbox->SetValue(GetString(flow_type)); multiple_left_nozzle_flow_checkbox->SetValue(GetString(flow_type));
//right //right
@@ -1377,7 +1377,7 @@ bool PrinterPartsDialog::Show(bool show)
diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID); diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID);
flow_type = obj->GetExtderSystem()->GetNozzleFlowType(MAIN_EXTRUDER_ID); flow_type = obj->GetExtderSystem()->GetNozzleFlowType(MAIN_EXTRUDER_ID);
multiple_right_nozzle_type_checkbox->SetValue(GetString(type)); multiple_right_nozzle_type_checkbox->SetValue(GetString(type));
multiple_right_nozzle_diameter_checkbox->SetValue(GetString(diameter)); multiple_right_nozzle_diameter_checkbox->SetValue(format_nozzle_diameter(diameter));
multiple_right_nozzle_flow_checkbox->SetValue(GetString(flow_type)); multiple_right_nozzle_flow_checkbox->SetValue(GetString(flow_type));
if (obj->is_support_refresh_nozzle) { if (obj->is_support_refresh_nozzle) {
@@ -1421,7 +1421,7 @@ wxString PrinterPartsDialog::GetString(NozzleType nozzle_type) const {
default: break; default: break;
} }
return wxEmptyString; return _L("Unknown");
} }
wxString PrinterPartsDialog::GetString(NozzleFlowType nozzle_flow_type) const { wxString PrinterPartsDialog::GetString(NozzleFlowType nozzle_flow_type) const {
@@ -1483,7 +1483,7 @@ void PrinterPartsDialog::UpdateNozzleInfo(){
auto type = obj->GetExtderSystem()->GetNozzleType(MAIN_EXTRUDER_ID); auto type = obj->GetExtderSystem()->GetNozzleType(MAIN_EXTRUDER_ID);
auto diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID); auto diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID);
nozzle_type_checkbox->SetValue(GetString(type)); nozzle_type_checkbox->SetValue(GetString(type));
nozzle_diameter_checkbox->SetValue(GetString(diameter)); nozzle_diameter_checkbox->SetValue(format_nozzle_diameter(diameter));
// nozzle flow type // nozzle flow type
nozzle_flow_type_label->Show(obj->is_nozzle_flow_type_supported()); nozzle_flow_type_label->Show(obj->is_nozzle_flow_type_supported());
@@ -1499,7 +1499,7 @@ void PrinterPartsDialog::UpdateNozzleInfo(){
auto diameter = obj->GetExtderSystem()->GetNozzleDiameter(DEPUTY_EXTRUDER_ID); auto diameter = obj->GetExtderSystem()->GetNozzleDiameter(DEPUTY_EXTRUDER_ID);
auto flow_type = obj->GetExtderSystem()->GetNozzleFlowType(DEPUTY_EXTRUDER_ID); auto flow_type = obj->GetExtderSystem()->GetNozzleFlowType(DEPUTY_EXTRUDER_ID);
multiple_left_nozzle_type_checkbox->SetValue(GetString(type)); multiple_left_nozzle_type_checkbox->SetValue(GetString(type));
multiple_left_nozzle_diameter_checkbox->SetValue(GetString(diameter)); multiple_left_nozzle_diameter_checkbox->SetValue(format_nozzle_diameter(diameter));
multiple_left_nozzle_flow_checkbox->SetValue(GetString(flow_type)); multiple_left_nozzle_flow_checkbox->SetValue(GetString(flow_type));
//right //right
@@ -1507,7 +1507,7 @@ void PrinterPartsDialog::UpdateNozzleInfo(){
diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID); diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID);
flow_type = obj->GetExtderSystem()->GetNozzleFlowType(MAIN_EXTRUDER_ID); flow_type = obj->GetExtderSystem()->GetNozzleFlowType(MAIN_EXTRUDER_ID);
multiple_right_nozzle_type_checkbox->SetValue(GetString(type)); multiple_right_nozzle_type_checkbox->SetValue(GetString(type));
multiple_right_nozzle_diameter_checkbox->SetValue(GetString(diameter)); multiple_right_nozzle_diameter_checkbox->SetValue(format_nozzle_diameter(diameter));
multiple_right_nozzle_flow_checkbox->SetValue(GetString(flow_type)); multiple_right_nozzle_flow_checkbox->SetValue(GetString(flow_type));
} }
+1 -2
View File
@@ -68,8 +68,7 @@ private:
wxString GetString(NozzleType nozzle_type) const; wxString GetString(NozzleType nozzle_type) const;
wxString GetString(NozzleFlowType nozzle_flow_type) const; wxString GetString(NozzleFlowType nozzle_flow_type) const;
wxString GetString(float diameter) const { return wxString::FromDouble(diameter); }; };
};
class PrintOptionsDialog : public DPIDialog class PrintOptionsDialog : public DPIDialog
+22 -7
View File
@@ -1823,7 +1823,15 @@ static bool _is_same_nozzle_diameters(MachineObject* obj, float &tag_nozzle_diam
} }
tag_nozzle_diameter = float(opt_nozzle_diameters->get_at(used_nozzle_idx)); tag_nozzle_diameter = float(opt_nozzle_diameters->get_at(used_nozzle_idx));
if (tag_nozzle_diameter != obj->GetExtderSystem()->GetNozzleDiameter(used_nozzle_idx)) auto machine_nozzle_diameter = obj->GetExtderSystem()->GetNozzleDiameter(used_nozzle_idx);
// Assume matching if diameter is unknown
if (machine_nozzle_diameter == 0.0f)
{
continue;
}
if (tag_nozzle_diameter != machine_nozzle_diameter)
{ {
mismatch_nozzle_id = used_nozzle_idx; mismatch_nozzle_id = used_nozzle_idx;
return false; return false;
@@ -1840,7 +1848,16 @@ static bool _is_same_nozzle_diameters(MachineObject* obj, float &tag_nozzle_diam
bool SelectMachineDialog::is_nozzle_hrc_matched(const DevExtder* extruder, std::string& filament_type) const bool SelectMachineDialog::is_nozzle_hrc_matched(const DevExtder* extruder, std::string& filament_type) const
{ {
auto printer_nozzle_hrc = Print::get_hrc_by_nozzle_type(extruder->GetNozzleType()); if (extruder == nullptr) return false;
auto printer_nozzle_type = extruder->GetNozzleType();
// Assume matching if nozzle type unknown
if (printer_nozzle_type == NozzleType::ntUndefine) {
return true;
}
auto printer_nozzle_hrc = Print::get_hrc_by_nozzle_type(printer_nozzle_type);
auto preset_bundle = wxGetApp().preset_bundle; auto preset_bundle = wxGetApp().preset_bundle;
MaterialHash::const_iterator iter = m_materialList.begin(); MaterialHash::const_iterator iter = m_materialList.begin();
@@ -5154,13 +5171,11 @@ static wxString _get_tips(MachineObject* obj_)
wxString ext_diameter; wxString ext_diameter;
if (obj_->GetExtderSystem()->GetTotalExtderCount() == 1) { if (obj_->GetExtderSystem()->GetTotalExtderCount() == 1) {
ext_diameter += wxString::FromDouble(obj_->GetExtderSystem()->GetNozzleDiameter(0)); ext_diameter += format_nozzle_diameter(obj_->GetExtderSystem()->GetNozzleDiameter(0));
ext_diameter += "mm";
} else if (obj_->GetExtderSystem()->GetTotalExtderCount() == 2) { } else if (obj_->GetExtderSystem()->GetTotalExtderCount() == 2) {
ext_diameter += wxString::FromDouble(obj_->GetExtderSystem()->GetNozzleDiameter(1));//Left ext_diameter += format_nozzle_diameter(obj_->GetExtderSystem()->GetNozzleDiameter(1));//Left
ext_diameter += "/"; ext_diameter += "/";
ext_diameter += wxString::FromDouble(obj_->GetExtderSystem()->GetNozzleDiameter(0)); ext_diameter += format_nozzle_diameter(obj_->GetExtderSystem()->GetNozzleDiameter(0));
ext_diameter += "mm";
} else { } else {
assert(0); assert(0);
} }
+58 -48
View File
@@ -7,6 +7,7 @@
#include <string.h> #include <string.h>
#include "I18N.hpp" #include "I18N.hpp"
#include "libslic3r/AppConfig.hpp" #include "libslic3r/AppConfig.hpp"
#include "libslic3r/Config.hpp"
#include "libslic3r/PresetBundle.hpp" #include "libslic3r/PresetBundle.hpp"
#include "slic3r/GUI/wxExtensions.hpp" #include "slic3r/GUI/wxExtensions.hpp"
#include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/GUI_App.hpp"
@@ -438,6 +439,50 @@ void GuideFrame::OnScriptMessage(wxWebViewEvent &evt)
wxString s2 = OneSelect["model"]; wxString s2 = OneSelect["model"];
if (s1.compare(s2) == 0) { if (s1.compare(s2) == 0) {
m_ProfileJson["model"][m]["nozzle_selected"] = m_ProfileJson["model"][m]["nozzle_diameter"]; m_ProfileJson["model"][m]["nozzle_selected"] = m_ProfileJson["model"][m]["nozzle_diameter"];
// Automatically select default materials for this printer model
// This mirrors the behavior of the old ConfigWizard::select_default_materials_for_printer_model()
if (TmpModel.contains("materials") && !TmpModel["materials"].is_null()) {
std::string materials_str;
// Handle both string and JSON array formats for materials
if (TmpModel["materials"].is_string()) {
materials_str = TmpModel["materials"].get<std::string>();
} else if (TmpModel["materials"].is_array()) {
// Convert JSON array to semicolon-separated string for unescape_strings_cstyle
for (const auto& material : TmpModel["materials"]) {
if (!materials_str.empty()) materials_str += ";";
materials_str += material.get<std::string>();
}
} else {
materials_str = "";
}
boost::trim(materials_str);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Processing default_materials for printer: " << s1.ToStdString() << " - materials: " << materials_str;
// Use the same parsing logic as ConfigWizard::select_default_materials_for_printer_model()
// This calls unescape_strings_cstyle() just like Preset.cpp:298 does
std::vector<std::string> materials;
if (Slic3r::unescape_strings_cstyle(materials_str, materials)) {
for (const std::string& material : materials) {
if (!material.empty()) {
// Mark this filament as selected if it exists in our filament list
// This mirrors appconfig_new.set(section, material, "true") from ConfigWizard.cpp:2150
if (m_ProfileJson["filament"].contains(material)) {
m_ProfileJson["filament"][material]["selected"] = 1;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Automatically selected default filament: " << material;
} else {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << " Default filament '" << material << "' not found in available filaments for printer: " << s1.ToStdString();
}
}
}
} else {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " Malformed default_materials field: " << materials_str << " for printer: " << s1.ToStdString();
}
} else {
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " No default_materials defined for printer: " << s1.ToStdString();
}
break; break;
} }
} }
@@ -838,45 +883,8 @@ bool GuideFrame::apply_config(AppConfig *app_config, PresetBundle *preset_bundle
// Not switch filament // Not switch filament
//get_first_added_material_preset(AppConfig::SECTION_FILAMENTS, first_added_filament); //get_first_added_material_preset(AppConfig::SECTION_FILAMENTS, first_added_filament);
// For each @System filament, check if a vendor-specific override exists
// in the loaded profiles. If so, replace the @System variant with the
// override (e.g. replace "Generic ABS @System" with BBL "Generic ABS").
// When printers from the default bundle are also selected, keep @System
// too since those printers need it.
static const std::string system_suffix = " @System";
auto it_default = enabled_vendors.find(PresetBundle::ORCA_DEFAULT_BUNDLE);
bool has_default_bundle_printer = it_default != enabled_vendors.end() && !it_default->second.empty();
bool has_filament_profiles = m_ProfileJson.contains("filament");
// Check if any non-default vendor has selected printers
bool has_vendor_printer = false;
for (const auto& [vendor, models] : enabled_vendors) {
if (vendor != PresetBundle::ORCA_DEFAULT_BUNDLE && !models.empty()) {
has_vendor_printer = true;
break;
}
}
std::map<std::string, std::string> supplemented_filaments;
for (const auto& [name, value] : enabled_filaments) {
if (name.size() > system_suffix.size() &&
name.compare(name.size() - system_suffix.size(), system_suffix.size(), system_suffix) == 0) {
std::string short_name = name.substr(0, name.size() - system_suffix.size());
if (has_vendor_printer && has_filament_profiles && m_ProfileJson["filament"].contains(short_name)) {
supplemented_filaments[short_name] = value;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Replacing @System filament: '" << name << "' -> '" << short_name << "'";
if (has_default_bundle_printer) {
supplemented_filaments[name] = value;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " Also keeping '" << name << "' for default bundle printers";
}
continue;
}
}
supplemented_filaments[name] = value;
}
//update the app_config //update the app_config
app_config->set_section(AppConfig::SECTION_FILAMENTS, supplemented_filaments); app_config->set_section(AppConfig::SECTION_FILAMENTS, enabled_filaments);
app_config->set_vendors(m_appconfig_new); app_config->set_vendors(m_appconfig_new);
if (check_unsaved_preset_changes) if (check_unsaved_preset_changes)
@@ -886,10 +894,10 @@ bool GuideFrame::apply_config(AppConfig *app_config, PresetBundle *preset_bundle
// If the active filament is not in the wizard-selected filaments, switch to the first // If the active filament is not in the wizard-selected filaments, switch to the first
// compatible wizard-selected filament. This handles the first-run case where load_presets // compatible wizard-selected filament. This handles the first-run case where load_presets
// falls back to "Generic PLA" even though the user selected a different filament. // falls back to "Generic PLA" even though the user selected a different filament.
bool active_filament_selected = supplemented_filaments.empty() bool active_filament_selected = enabled_filaments.empty()
|| supplemented_filaments.count(preset_bundle->filament_presets.front()) > 0; || enabled_filaments.count(preset_bundle->filament_presets.front()) > 0;
if (!active_filament_selected) { if (!active_filament_selected) {
for (const auto& [filament_name, _] : supplemented_filaments) { for (const auto& [filament_name, _] : enabled_filaments) {
const Preset* preset = preset_bundle->filaments.find_preset(filament_name); const Preset* preset = preset_bundle->filaments.find_preset(filament_name);
if (preset && preset->is_visible && preset->is_compatible) { if (preset && preset->is_visible && preset->is_compatible) {
preset_bundle->filaments.select_preset_by_name(filament_name, true); preset_bundle->filaments.select_preset_by_name(filament_name, true);
@@ -1124,7 +1132,12 @@ int GuideFrame::LoadProfileData()
return 0; return 0;
} }
//sync to web wxGetApp().CallAfter([this] {
if (!m_destroy) {
//sync to appconfig first to populate current selections
SaveProfileData();
//sync to web after selections are populated
std::string strAll = m_ProfileJson.dump(-1, ' ', false, json::error_handler_t::ignore); std::string strAll = m_ProfileJson.dump(-1, ' ', false, json::error_handler_t::ignore);
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished, json contents: " << std::endl << strAll; BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished, json contents: " << std::endl << strAll;
@@ -1132,13 +1145,10 @@ int GuideFrame::LoadProfileData()
m_Res["command"] = "userguide_profile_load_finish"; m_Res["command"] = "userguide_profile_load_finish";
m_Res["sequence_id"] = "10001"; m_Res["sequence_id"] = "10001";
wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', true)); wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', true));
if (!m_destroy)
wxGetApp().CallAfter([this, strJS] { RunScript(strJS); });
//sync to appconfig
if (!m_destroy)
wxGetApp().CallAfter([this] { SaveProfileData(); });
RunScript(strJS);
}
});
} catch (std::exception& e) { } catch (std::exception& e) {
// wxLogMessage("GUIDE: load_profile_error %s ", e.what()); // wxLogMessage("GUIDE: load_profile_error %s ", e.what());
// wxMessageBox(e.what(), "", MB_OK); // wxMessageBox(e.what(), "", MB_OK);
+6 -2
View File
@@ -420,7 +420,9 @@ int DropDown::hoverIndex()
{ {
if (hover_item < 0) if (hover_item < 0)
return -1; return -1;
if (count == items.size()) // BUG FIX: Can't take the shortcut if subDropDown exists (which means there are groups)
// because we need to detect group headers which return negative indices
if (count == items.size() && subDropDown == nullptr)
return hover_item; return hover_item;
int index = -1; int index = -1;
std::set<wxString> groups; std::set<wxString> groups;
@@ -448,7 +450,9 @@ int DropDown::selectedItem()
{ {
if (selection < 0) if (selection < 0)
return -1; return -1;
if (count == items.size()) // BUG FIX: Can't take the shortcut if subDropDown exists (which means there are groups)
// because the visual position differs from the actual item index when groups are shown
if (count == items.size() && subDropDown == nullptr)
return selection; return selection;
auto & sel = items[selection]; auto & sel = items[selection];
if (group.IsEmpty() ? !sel.group.IsEmpty() : sel.group != group) if (group.IsEmpty() ? !sel.group.IsEmpty() : sel.group != group)
+4
View File
@@ -50,6 +50,10 @@ bool QidiPrinterAgent::fetch_filament_info(std::string dev_id)
series_id = infer_series_id(info.model_id, info.dev_name); series_id = infer_series_id(info.model_id, info.dev_name);
} }
} }
if (series_id.empty()) {
// Fall back to the configured Orca model if Moonraker doesn't expose a usable identifier.
series_id = infer_series_id(device_info.model_id, device_info.model_name);
}
// 2. Fetch filament dictionary // 2. Fetch filament dictionary
QidiFilamentDict dict; QidiFilamentDict dict;