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"
msgid "STEP files"
msgstr "SETP Dateien"
msgstr "STEP Dateien"
msgid "STL files"
msgstr "STL Dateien"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "Creality",
"version": "02.03.02.60",
"version": "02.03.02.61",
"force_update": "0",
"description": "Creality configurations",
"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",
"machine_tech": "FFF",
"family": "Creality",
"bed_model": "creality_k1_buildplate_model.stl",
"bed_model": "creality_k2_buildplate_model.stl",
"default_bed_type": "Textured PEI Plate",
"bed_texture": "creality_k1_buildplate_texture.png",
"bed_texture": "creality_k2_buildplate_texture.png",
"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"
}
+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
Terminal=false
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;
Keywords=3D;Printing;Slicer;slice;3D;printer;convert;gcode;stl;obj;amf;SLA
StartupNotify=false
+14 -10
View File
@@ -587,26 +587,30 @@ public:
auto rhs_opt = static_cast<const ConfigOptionVector<T>*>(rhs);
auto inherits_opt = static_cast<const ConfigOptionVector<T>*>(inherits);
if (inherits->size() != rhs->size())
throw ConfigurationError("ConfigOptionVector::set_with_nil(): rhs size different with inherits size");
if (stride <= 0)
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;
for (size_t j = 0; j < stride; j++) {
if (inherits_opt->values[i +j] != rhs_opt->values[i +j]) {
for (size_t j = 0; j < group_size; ++j) {
if (inherits_opt->values[i + j] != rhs_opt->values[i + j]) {
set_nil = false;
break;
}
}
for (size_t j = 0; j < stride; j++) {
for (size_t j = 0; j < group_size; ++j) {
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);
}
if (cfg.type != FuzzySkinType::None) {
if (cfg.type != FuzzySkinType::None && cfg.type != FuzzySkinType::Disabled_fuzzy) {
g.has_fuzzy_skin = true;
if (cfg.type != FuzzySkinType::External) {
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() << ").";
}
else {
if (eid >= m_result.filaments_count)
if (eid >= m_result.filaments_count) {
BOOST_LOG_TRIVIAL(error) << "Invalid M1020 command (" << line.raw() << ").";
return;
}
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 << ").";
}
else {
if (eid >= m_result.filaments_count)
if (eid >= m_result.filaments_count) {
BOOST_LOG_TRIVIAL(error) << "Invalid T command (" << command << ").";
return;
}
process_filament_change(eid);
}
}
+1 -1
View File
@@ -653,7 +653,7 @@ public:
int match_quality = -1;
for (; i < n; ++i)
// 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]);
if (this_match_quality > match_quality) {
if (match_quality == std::numeric_limits<int>::max())
+20 -7
View File
@@ -734,10 +734,17 @@ void PresetBundle::reset_project_embedded_presets()
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::string prefered_filament_profile = prefered_filament_profiles.empty() ? std::string() : prefered_filament_profiles.front();
if (!prefered_filament_profile.empty())
filament_presets[i] = prefered_filament_profile;
else
filament_presets[i] = this->filaments.first_visible().name;
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;
} else {
// Fall back to first visible filament
filament_presets[i] = this->filaments.first_visible().name;
}
} else
filament_presets[i] = this->filaments.first_visible().name;
}
}
}
@@ -1970,8 +1977,14 @@ void PresetBundle::load_selections(AppConfig &config, const PresetPreferences& p
initial_print_profile_name = prefered_print_profile;
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))
initial_filament_profile_name = prefered_filament_profiles[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];
}
// 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.
@@ -4452,7 +4465,7 @@ void PresetBundle::update_compatible(PresetSelectCompatibleType select_other_pri
int operator()(const Preset &preset) const
{
// 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;
if (! m_prefered_alias.empty() && m_prefered_alias == preset.alias)
// 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[e_index] = get_index_for_extruder(e_index+1, id_name, extruder_type, nozzle_volume_type, variant_name);
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%")
%__LINE__ %s_keys_names_ExtruderType[extruder_type] % s_keys_names_NozzleVolumeType[nozzle_volume_type] % (e_index+1);
assert(false);
//for some updates happens in a invalid state(caused by popup window)
//we need to avoid crash
// Orca: This is expected during transient UI states (e.g. popup windows),
// fall back to 0 silently.
variant_index[e_index] = 0;
}
}
+1 -1
View File
@@ -15,7 +15,7 @@ namespace Slic3r
int m_nozzle_id = -1;
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
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
+24 -5
View File
@@ -4285,7 +4285,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
p = p->GetParent();
auto *top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
//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_mouse.position = pos.cast<double>();
@@ -8485,11 +8488,27 @@ void GLCanvas3D::_render_return_toolbar() const
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 (m_canvas != nullptr)
wxPostEvent(m_canvas, SimpleEvent(EVT_GLVIEWTOOLBAR_3D));
const_cast<GLGizmosManager*>(&m_gizmos)->reset_all_states();
wxGetApp().plater()->get_view3D_canvas3D()->get_gizmos_manager().reset_all_states();
wxGetApp().plater()->get_view3D_canvas3D()->reload_scene(true);
if (m_canvas != nullptr && !wxGetApp().is_closing()) {
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::PopStyleVar(1);
+45 -12
View File
@@ -752,18 +752,51 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_)
wxMenuItem* MenuFactory::append_menu_item_change_type(wxMenu* menu)
{
return append_menu_item(menu, wxID_ANY, _L("Change type"), "",
[](wxCommandEvent&) { obj_list()->change_part_type(); }, "", menu,
[]() {
wxDataViewItemArray selections;
obj_list()->GetSelections(selections);
if (selections.empty()) return false;
for (const auto& it : selections) {
if (!(obj_list()->GetModel()->GetItemType(it) & itVolume))
return false; // non-volume present -> disable
}
return true;
}, m_parent);
const wxString menu_name = _L("Change type");
// Delete old menu item if exists
const int item_id = menu->FindItem(menu_name);
if (item_id != wxNOT_FOUND)
menu->Destroy(item_id);
// Create submenu
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;
}
}
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)
+130
View File
@@ -5538,6 +5538,136 @@ void ObjectList::change_part_type()
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)
{
// 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();
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 update_and_show_object_settings_item();
+10
View File
@@ -1,6 +1,7 @@
#include "GUI.hpp"
#include "GUI_Utils.hpp"
#include "GUI_App.hpp"
#include "I18N.hpp"
#include <algorithm>
#include <boost/lexical_cast.hpp>
@@ -32,6 +33,15 @@ wxDEFINE_EVENT(EVT_VOLUME_ATTACHED, VolumeAttachedEvent);
wxDEFINE_EVENT(EVT_VOLUME_DETACHED, VolumeDetachedEvent);
#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)
{
#ifdef WIN32
+1
View File
@@ -66,6 +66,7 @@ wxDECLARE_EVENT(EVT_VOLUME_DETACHED, VolumeDetachedEvent);
#endif /* _WIN32 */
wxTopLevelWindow* find_toplevel_parent(wxWindow *window);
wxString format_nozzle_diameter(float diameter);
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);
ConfigOptionFloat* flush_multi_opt = project_config.option<ConfigOptionFloat>("flush_multiplier");
float flush_multiplier = flush_multi_opt ? flush_multi_opt->getFloat() : 1.f;
const auto* flush_multi_opt = project_config.option<ConfigOptionFloats>("flush_multiplier");
float flush_multiplier = flush_multi_opt ? (float)flush_multi_opt->get_at(extruder_id) : 1.f;
std::vector<double> matrix = init_matrix;
int m_max_flush_volume = Slic3r::g_max_flush_volume;
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 diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID);
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_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 flow_type = obj->GetExtderSystem()->GetNozzleFlowType(DEPUTY_EXTRUDER_ID);
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));
//right
@@ -1377,7 +1377,7 @@ bool PrinterPartsDialog::Show(bool show)
diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID);
flow_type = obj->GetExtderSystem()->GetNozzleFlowType(MAIN_EXTRUDER_ID);
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));
if (obj->is_support_refresh_nozzle) {
@@ -1421,7 +1421,7 @@ wxString PrinterPartsDialog::GetString(NozzleType nozzle_type) const {
default: break;
}
return wxEmptyString;
return _L("Unknown");
}
wxString PrinterPartsDialog::GetString(NozzleFlowType nozzle_flow_type) const {
@@ -1483,7 +1483,7 @@ void PrinterPartsDialog::UpdateNozzleInfo(){
auto type = obj->GetExtderSystem()->GetNozzleType(MAIN_EXTRUDER_ID);
auto diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID);
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_label->Show(obj->is_nozzle_flow_type_supported());
@@ -1499,7 +1499,7 @@ void PrinterPartsDialog::UpdateNozzleInfo(){
auto diameter = obj->GetExtderSystem()->GetNozzleDiameter(DEPUTY_EXTRUDER_ID);
auto flow_type = obj->GetExtderSystem()->GetNozzleFlowType(DEPUTY_EXTRUDER_ID);
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));
//right
@@ -1507,7 +1507,7 @@ void PrinterPartsDialog::UpdateNozzleInfo(){
diameter = obj->GetExtderSystem()->GetNozzleDiameter(MAIN_EXTRUDER_ID);
flow_type = obj->GetExtderSystem()->GetNozzleFlowType(MAIN_EXTRUDER_ID);
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));
}
+1 -2
View File
@@ -68,8 +68,7 @@ private:
wxString GetString(NozzleType nozzle_type) const;
wxString GetString(NozzleFlowType nozzle_flow_type) const;
wxString GetString(float diameter) const { return wxString::FromDouble(diameter); };
};
};
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));
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;
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
{
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;
MaterialHash::const_iterator iter = m_materialList.begin();
@@ -5154,13 +5171,11 @@ static wxString _get_tips(MachineObject* obj_)
wxString ext_diameter;
if (obj_->GetExtderSystem()->GetTotalExtderCount() == 1) {
ext_diameter += wxString::FromDouble(obj_->GetExtderSystem()->GetNozzleDiameter(0));
ext_diameter += "mm";
ext_diameter += format_nozzle_diameter(obj_->GetExtderSystem()->GetNozzleDiameter(0));
} 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 += wxString::FromDouble(obj_->GetExtderSystem()->GetNozzleDiameter(0));
ext_diameter += "mm";
ext_diameter += format_nozzle_diameter(obj_->GetExtderSystem()->GetNozzleDiameter(0));
} else {
assert(0);
}
+63 -53
View File
@@ -7,6 +7,7 @@
#include <string.h>
#include "I18N.hpp"
#include "libslic3r/AppConfig.hpp"
#include "libslic3r/Config.hpp"
#include "libslic3r/PresetBundle.hpp"
#include "slic3r/GUI/wxExtensions.hpp"
#include "slic3r/GUI/GUI_App.hpp"
@@ -438,6 +439,50 @@ void GuideFrame::OnScriptMessage(wxWebViewEvent &evt)
wxString s2 = OneSelect["model"];
if (s1.compare(s2) == 0) {
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;
}
}
@@ -838,45 +883,8 @@ bool GuideFrame::apply_config(AppConfig *app_config, PresetBundle *preset_bundle
// Not switch 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
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);
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
// 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.
bool active_filament_selected = supplemented_filaments.empty()
|| supplemented_filaments.count(preset_bundle->filament_presets.front()) > 0;
bool active_filament_selected = enabled_filaments.empty()
|| enabled_filaments.count(preset_bundle->filament_presets.front()) > 0;
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);
if (preset && preset->is_visible && preset->is_compatible) {
preset_bundle->filaments.select_preset_by_name(filament_name, true);
@@ -1124,21 +1132,23 @@ int GuideFrame::LoadProfileData()
return 0;
}
//sync to web
std::string strAll = m_ProfileJson.dump(-1, ' ', false, json::error_handler_t::ignore);
wxGetApp().CallAfter([this] {
if (!m_destroy) {
//sync to appconfig first to populate current selections
SaveProfileData();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished, json contents: " << std::endl << strAll;
json m_Res = json::object();
m_Res["command"] = "userguide_profile_load_finish";
m_Res["sequence_id"] = "10001";
wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', true));
if (!m_destroy)
wxGetApp().CallAfter([this, strJS] { RunScript(strJS); });
//sync to web after selections are populated
std::string strAll = m_ProfileJson.dump(-1, ' ', false, json::error_handler_t::ignore);
//sync to appconfig
if (!m_destroy)
wxGetApp().CallAfter([this] { SaveProfileData(); });
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ", finished, json contents: " << std::endl << strAll;
json m_Res = json::object();
m_Res["command"] = "userguide_profile_load_finish";
m_Res["sequence_id"] = "10001";
wxString strJS = wxString::Format("HandleStudio(%s)", m_Res.dump(-1, ' ', true));
RunScript(strJS);
}
});
} catch (std::exception& e) {
// wxLogMessage("GUIDE: load_profile_error %s ", e.what());
// wxMessageBox(e.what(), "", MB_OK);
+6 -2
View File
@@ -420,7 +420,9 @@ int DropDown::hoverIndex()
{
if (hover_item < 0)
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;
int index = -1;
std::set<wxString> groups;
@@ -448,7 +450,9 @@ int DropDown::selectedItem()
{
if (selection < 0)
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;
auto & sel = items[selection];
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);
}
}
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
QidiFilamentDict dict;