sublayers and more

This commit is contained in:
Ian Bassi
2026-08-23 22:11:48 +08:00
committed by SoftFever
parent 76f23396ea
commit ccd34ab03a
11 changed files with 355 additions and 7 deletions
+18 -1
View File
@@ -8911,7 +8911,10 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
m_sel_plate_toolbar.m_items[i]->slice_state = IMToolbarItem::SliceState::SLICE_FAILED;
}
else {
if ((!is_empty && !can_slice) || (plate_list.get_plate(i)->has_printable_instances() && !plate_list.get_plate(i)->can_slice()))
// A plate using a mixed filament whose components are broken cannot be sliced,
// so surface that on the plate toolbar the same way an unsliceable plate is.
if ((!is_empty && !can_slice) || (plate_list.get_plate(i)->has_printable_instances() && !plate_list.get_plate(i)->can_slice())
|| wxGetApp().plater()->sidebar().has_broken_mixed_filament(plate_list.get_plate(i)))
m_sel_plate_toolbar.m_items[i]->slice_state = IMToolbarItem::SliceState::SLICE_FAILED;
else {
if (plate_list.get_plate(i)->get_slicing_percent() < 0.0f)
@@ -9707,6 +9710,10 @@ void GLCanvas3D::_render_paint_toolbar() const
bool disabled = !wxGetApp().plater()->can_fillcolor();
ColorRGBA rgba;
// Gradient mixed filaments fade between two colours over Z, so their swatch is drawn as a
// two-tone fade rather than the single blended colour in `colors`.
auto gradient_info = wxGetApp().plater()->get_filament_gradient_info();
for (int i = 0; i < extruder_num; i++) {
if (i > 0)
ImGui::SameLine();
@@ -9720,6 +9727,16 @@ void GLCanvas3D::_render_paint_toolbar() const
if (!ImGui::IsMouseHoveringRect(left_arrow_button.Min, left_arrow_button.Max) && !ImGui::IsMouseHoveringRect(right_arrow_button.Min, right_arrow_button.Max))
wxPostEvent(m_canvas, IntEvent(EVT_GLTOOLBAR_FILLCOLOR, i + 1));
}
if (i < (int) gradient_info.size() && gradient_info[i].is_gradient) {
auto to_imu32 = [](const std::array<float, 4> &c) -> ImU32 {
return IM_COL32(uint8_t(c[0]*255.f), uint8_t(c[1]*255.f), uint8_t(c[2]*255.f), uint8_t(c[3]*255.f));
};
ImVec2 r_min = ImGui::GetItemRectMin();
ImVec2 r_max = ImGui::GetItemRectMax();
ImU32 col_from = to_imu32(gradient_info[i].color_from);
ImU32 col_to = to_imu32(gradient_info[i].color_to);
ImGui::GetWindowDrawList()->AddRectFilledMultiColor(r_min, r_max, col_from, col_to, col_to, col_from);
}
if (ImGui::IsItemHovered() && i < 9) {
if (!ImGui::IsMouseHoveringRect(left_arrow_button.Min, left_arrow_button.Max) && !ImGui::IsMouseHoveringRect(right_arrow_button.Min, right_arrow_button.Max)) {
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 20.0f * f_scale, 10.0f * f_scale });
+8 -1
View File
@@ -1684,11 +1684,18 @@ void MenuFactory::create_filament_action_menu(bool init, int active_filament_men
append_submenu(menu, sub_menu, wxID_ANY, _L("Merge with"), "", "",
[filaments_cnt]() { return filaments_cnt > 1; }, m_parent);
// Decompose a target colour into a printable mix of the loaded filaments. Placed before the
// Delete entry below so Orca's "delete last" ordering is preserved (BBS appends it after).
append_menu_item(
menu, wxID_ANY, _L("Decompose Color"), "", [](wxCommandEvent&) {
plater()->sidebar().decompose_filament_color(kSidebarContextMenuFilamentId); }, "", nullptr,
[]() { return plater()->sidebar().combos_filament().size() >= 2; }, m_parent);
// ORCA use delete item on end of menu to prevent accidental clicks. clicking to submenus(merge) already not allowed by OS
const int delete_id = menu->FindItem(_L("Delete"));
if (delete_id != wxNOT_FOUND)
menu->Destroy(delete_id);
append_menu_item(
menu, wxID_ANY, _L("Delete"), _L("Delete this filament"), [](wxCommandEvent&) {
plater()->sidebar().delete_filament(-2); }, "", nullptr,
@@ -78,6 +78,14 @@ void GLGizmoMmuSegmentation::init_extruders_data()
m_extruders_colors = wxGetApp().plater()->get_extruders_colors();
m_selected_extruder_idx = 0;
auto plater_grad = wxGetApp().plater()->get_filament_gradient_info();
m_gradient_info.resize(m_extruders_colors.size());
for (size_t i = 0; i < m_gradient_info.size() && i < plater_grad.size(); ++i) {
m_gradient_info[i].is_gradient = plater_grad[i].is_gradient;
m_gradient_info[i].color_from = plater_grad[i].color_from;
m_gradient_info[i].color_to = plater_grad[i].color_to;
}
// keep remap table consistent with current extruder count
m_extruder_remap.resize(m_extruders_colors.size());
for (size_t i = 0; i < m_extruder_remap.size(); ++i)
@@ -433,6 +441,19 @@ void GLGizmoMmuSegmentation::on_render_input_window(float x, float y, float bott
m_selected_extruder_idx = extruder_idx;
}
// Overlay a two-tone fade for gradient mixed filaments; a single flat colour would
// misrepresent a slot that fades between two filaments over Z.
if (extruder_idx < (int) m_gradient_info.size() && m_gradient_info[extruder_idx].is_gradient) {
auto to_imu32 = [](const std::array<float, 4> &c) -> ImU32 {
return IM_COL32(uint8_t(c[0]*255.f), uint8_t(c[1]*255.f), uint8_t(c[2]*255.f), uint8_t(c[3]*255.f));
};
ImVec2 r_min = ImGui::GetItemRectMin();
ImVec2 r_max = ImGui::GetItemRectMax();
ImU32 col_from = to_imu32(m_gradient_info[extruder_idx].color_from);
ImU32 col_to = to_imu32(m_gradient_info[extruder_idx].color_to);
ImGui::GetWindowDrawList()->AddRectFilledMultiColor(r_min, r_max, col_from, col_to, col_to, col_from);
}
if (extruder_idx < 16 && ImGui::IsItemHovered()) m_imgui->tooltip(_L("Shortcut Key ") + std::to_string(extruder_idx + 1), max_tooltip_width);
}
// ORCA: Remap filaments section (Border only, Title in border).
@@ -79,6 +79,14 @@ public:
// will be also extended to support additional states, requiring at least one state to remain free out of 19 states.
static const constexpr size_t EXTRUDERS_LIMIT = 16;
// Endpoint colours for gradient mixed filaments, mirrored from Plater so the extruder
// swatches below can be drawn as a two-tone fade instead of a single blended colour.
struct GradientInfo {
bool is_gradient = false;
std::array<float, 4> color_from = {0.5f, 0.5f, 0.5f, 1.0f};
std::array<float, 4> color_to = {0.5f, 0.5f, 0.5f, 1.0f};
};
const float get_cursor_radius_min() const override { return CursorRadiusMin; }
// BBS
@@ -116,6 +124,7 @@ protected:
// Filament remap feature
std::vector<size_t> m_extruder_remap; // index → target extruder index
std::vector<GradientInfo> m_gradient_info; // per-slot gradient endpoints, empty entries for plain filaments
// ORCA: Cache used filaments to filter UI
std::set<size_t> m_used_filaments; // Set of used filament indices (cached)
+26
View File
@@ -472,6 +472,32 @@ PlateSettingsDialog::PlateSettingsDialog(wxWindow* parent, const wxString& title
m_sizer_main->AddSpacer(FromDIP(5));
m_sizer_main->Add(m_other_layers_seq_panel, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30));
// A mixed-color slot resolves to a different physical filament per layer, so a user-defined
// filament order cannot be honoured. Disable the choice and say why. BBS puts this warning
// inside its button sizer; Orca builds the buttons with DialogButtons, so it gets its own row.
{
auto &proj_cfg = wxGetApp().preset_bundle->project_config;
auto *is_mixed_opt = proj_cfg.option<ConfigOptionBools>("filament_is_mixed");
if (is_mixed_opt && Slic3r::has_any_mixed_filament(is_mixed_opt->values)) {
m_first_layer_print_seq_choice->Enable(false);
m_other_layers_seq_panel->enable_seq_choice(false);
auto *warn_sizer = new wxBoxSizer(wxHORIZONTAL);
auto *warn_icon = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("warning", this, 16),
wxDefaultPosition, wxSize(FromDIP(16), FromDIP(16)));
auto *warn_text = new wxStaticText(this, wxID_ANY,
_L("The filament list contains mixed filaments. Custom filament sequence will not take effect."));
warn_text->SetForegroundColour(wxColour(255, 111, 0));
warn_text->SetFont(Label::Body_12);
warn_text->Wrap(FromDIP(300));
warn_sizer->Add(warn_icon, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(5));
warn_sizer->Add(warn_text, 1, wxALIGN_CENTER_VERTICAL, 0);
m_sizer_main->AddSpacer(FromDIP(5));
m_sizer_main->Add(warn_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30));
}
}
auto dlg_btns = new DialogButtons(this, {"OK", "Cancel"});
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, [this](auto& e) {
+3
View File
@@ -62,6 +62,9 @@ public:
int get_layers_print_seq_choice() { return m_other_layer_print_seq_choice->GetSelection(); };
std::vector<LayerSeqInfo> get_layers_print_seq_infos() { return m_layer_seq_infos; }
// Lets callers grey out the sequence choice (e.g. when a mixed filament makes a
// user-defined filament order impossible).
void enable_seq_choice(bool enable) { m_other_layer_print_seq_choice->Enable(enable); }
protected:
void append_layer(const LayerSeqInfo* layer_info = nullptr);
+162 -4
View File
@@ -5355,9 +5355,16 @@ void Sidebar::delete_filament(size_t filament_id, int replace_filament_id) {
p->editing_filament = -1;
}
// update_num_filaments() shrinks filament_is_mixed along with the other per-filament arrays,
// so snapshot it first — the paint cleanup below needs to know which slots were mixed
// *before* the delete to avoid discarding assignments to still-valid mixed slots.
std::vector<unsigned char> is_mixed_snapshot;
if (auto* opt = wxGetApp().preset_bundle->project_config.option<ConfigOptionBools>("filament_is_mixed"))
is_mixed_snapshot = opt->values;
wxGetApp().preset_bundle->update_num_filaments(filament_id);
wxGetApp().plater()->get_partplate_list().on_filament_deleted(filament_count, filament_id);
wxGetApp().plater()->on_filaments_delete(filament_count, filament_id, replace_filament_id > (int)filament_id ? (replace_filament_id - 1) : replace_filament_id);
wxGetApp().plater()->on_filaments_delete(filament_count, filament_id, replace_filament_id > (int)filament_id ? (replace_filament_id - 1) : replace_filament_id, is_mixed_snapshot);
wxGetApp().get_tab(Preset::TYPE_PRINT)->update();
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
@@ -5374,6 +5381,36 @@ void Sidebar::delete_filament(size_t filament_id, int replace_filament_id) {
void Sidebar::change_filament(size_t from_id, size_t to_id)
{
// Merging a physical filament into a mixed one that lists it as a component would delete
// the very filament the mix depends on, leaving it broken. Warn before doing so.
auto& pb = *wxGetApp().preset_bundle;
bool from_is_physical = !pb.is_mixed_filament(from_id);
bool to_is_mixed = pb.is_mixed_filament(to_id);
if (from_is_physical && to_is_mixed) {
auto* comp_opt = pb.project_config.option<ConfigOptionStrings>("filament_mixed_components");
if (comp_opt && to_id < comp_opt->values.size()) {
auto comps = Slic3r::parse_mixed_components(comp_opt->values[to_id]);
unsigned int from_1based = (unsigned int)from_id + 1;
bool target_uses_source = false;
for (unsigned int c : comps) {
if (c == from_1based) {
target_uses_source = true;
break;
}
}
if (target_uses_source) {
int ret = wxMessageBox(
_L("The target mixed filament uses this physical filament as a component. "
"Merging will remove this physical filament and may invalidate the mixed filament. Continue?"),
_L("Warning"),
wxOK | wxCANCEL | wxICON_WARNING);
if (ret != wxOK)
return;
}
}
}
delete_filament(from_id, int(to_id));
}
@@ -9744,7 +9781,11 @@ void Plater::priv::object_list_changed()
// BBS
//sidebar->enable_buttons(!model.objects.empty() && !export_in_progress && model_fits && part_plate->has_printable_instances());
bool can_slice = !model.objects.empty() && !export_in_progress && model_fits && part_plate->has_printable_instances();
// A mixed filament with deleted or type-mismatched components cannot be resolved at slicing
// time, so block the slice buttons the same way MainFrame::get_enable_slice_status() does.
bool mixed_broken = sidebar->has_broken_mixed_filament();
bool can_slice = !model.objects.empty() && !export_in_progress && model_fits && part_plate->has_printable_instances()
&& !mixed_broken;
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": can_slice %1%, model_fits= %2%, export_in_progress %3%, has_printable_instances %4% ")%can_slice %model_fits %export_in_progress %part_plate->has_printable_instances();
main_frame->update_slice_print_status(MainFrame::eEventObjectUpdate, can_slice);
@@ -13963,6 +14004,25 @@ bool Plater::priv::can_layers_editing() const
void Plater::priv::on_action_layersediting(SimpleEvent&)
{
// Sub-layer splitting divides each layer by the mix ratio, so an adaptive layer profile makes
// those sub-layer heights vary and degrades the blend. ConfigManipulation warns when the
// option is switched on with a variable profile already present; this is the other direction,
// warning when variable layer editing is switched on while the option is active. Both honour
// the same do-not-show-again flag.
if (!view3D->is_layers_editing_enabled()) {
const auto& print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
if (print_config.opt_bool("enable_mixed_color_sublayer")) {
if (wxGetApp().app_config->get("no_warn_mixed_sublayer_variable_layer") != "1") {
MessageDialog dlg(q,
_L("Using variable layer height together with mixed color sublayer may result in poor color mixing quality."),
_L("Warning"), wxICON_WARNING | wxOK);
dlg.show_dsa_button();
dlg.ShowModal();
if (dlg.get_checkbox_state())
wxGetApp().app_config->set("no_warn_mixed_sublayer_variable_layer", "1");
}
}
}
view3D->enable_layers_editing(!view3D->is_layers_editing_enabled());
notification_manager->set_move_from_overlay(view3D->is_layers_editing_enabled());
}
@@ -19385,7 +19445,7 @@ void Plater::on_filament_count_change(size_t num_filaments)
}
}
void Plater::on_filaments_delete(size_t num_filaments, size_t filament_id, int replace_filament_id)
void Plater::on_filaments_delete(size_t num_filaments, size_t filament_id, int replace_filament_id, const std::vector<unsigned char>& is_mixed_before_delete)
{
// only update elements in plater
update_filament_colors_in_full_config();
@@ -19399,9 +19459,15 @@ void Plater::on_filaments_delete(size_t num_filaments, size_t filament_id, int r
}*/
// update mmu info
// A volume assigned to a mixed slot legitimately sits past the physical filament count, so
// the paint cleanup must know which slots were mixed. Callers that already shrank the arrays
// pass the pre-delete flags; otherwise read the current ones.
const auto &is_mixed = is_mixed_before_delete.empty()
? wxGetApp().preset_bundle->project_config.option<ConfigOptionBools>("filament_is_mixed")->values
: is_mixed_before_delete;
for (ModelObject *mo : wxGetApp().model().objects) {
for (ModelVolume *mv : mo->volumes) {
mv->update_extruder_count_when_delete_filament(num_filaments, filament_id + 1, replace_filament_id + 1); // this function is 1 base
mv->update_extruder_count_when_delete_filament(num_filaments, filament_id + 1, replace_filament_id + 1, is_mixed); // this function is 1 base
}
}
@@ -19740,6 +19806,63 @@ std::vector<std::string> Plater::get_extruder_colors_from_plater_config(const GC
}
}
namespace {
// A gradient mixed filament fades between its two components over Z, so the UI shows it as a
// two-tone swatch rather than one blended colour. Resolve each slot to its from/to endpoint
// colours; non-gradient slots are left untouched.
struct MixedGradientSlot {
bool is_gradient = false;
std::string color_from;
std::string color_to;
};
std::vector<MixedGradientSlot> parse_mixed_gradient_slots(const Slic3r::DynamicPrintConfig& config, size_t slot_count)
{
std::vector<MixedGradientSlot> result(slot_count);
const auto* is_mixed = config.option<ConfigOptionBools>("filament_is_mixed");
const auto* mixed_grad = config.option<ConfigOptionBools>("filament_mixed_gradient");
const auto* mixed_comp = config.option<ConfigOptionStrings>("filament_mixed_components");
const auto* grad_range = config.option<ConfigOptionStrings>("filament_mixed_gradient_range");
const auto* fil_colour = config.option<ConfigOptionStrings>("filament_colour");
if (!is_mixed || !mixed_grad || !mixed_comp || !fil_colour) return result;
for (size_t i = 0; i < slot_count && i < is_mixed->values.size(); ++i) {
if (!is_mixed->values[i]) continue;
if (i >= mixed_grad->values.size() || !mixed_grad->values[i]) continue;
if (i >= mixed_comp->values.size()) continue;
std::vector<unsigned int> comp_ids;
std::istringstream iss(mixed_comp->values[i]);
std::string tok;
while (std::getline(iss, tok, ',')) {
unsigned int v = 0;
if (std::sscanf(tok.c_str(), "%u", &v) == 1)
comp_ids.push_back(v);
}
if (comp_ids.size() != 2) continue;
int direction = 0;
if (grad_range && i < grad_range->values.size()) {
CNumericLocalesSetter c_locale_setter;
float v0 = 0, v1 = 0;
if (std::sscanf(grad_range->values[i].c_str(), "%f,%f", &v0, &v1) == 2)
direction = (v0 > v1) ? 0 : 1;
}
unsigned int from_id = (direction == 0) ? comp_ids[0] : comp_ids[1];
unsigned int to_id = (direction == 0) ? comp_ids[1] : comp_ids[0];
result[i].is_gradient = true;
result[i].color_from = (from_id >= 1 && from_id <= fil_colour->values.size())
? fil_colour->values[from_id - 1] : "#D9D9D9";
result[i].color_to = (to_id >= 1 && to_id <= fil_colour->values.size())
? fil_colour->values[to_id - 1] : "#D9D9D9";
}
return result;
}
} // anonymous namespace
std::vector<std::string> Plater::get_filament_colors_render_info() const
{
const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->project_config;
@@ -19747,6 +19870,13 @@ std::vector<std::string> Plater::get_filament_colors_render_info() const
if (!config->has("filament_multi_colour")) return color_packs;
color_packs = (config->option<ConfigOptionStrings>("filament_multi_colour"))->values;
auto slots = parse_mixed_gradient_slots(*config, color_packs.size());
for (size_t i = 0; i < color_packs.size(); ++i) {
if (slots[i].is_gradient)
color_packs[i] = slots[i].color_from + " " + slots[i].color_to;
}
return color_packs;
}
@@ -19757,9 +19887,37 @@ std::vector<std::string> Plater::get_filament_color_render_type() const
if (!config->has("filament_colour_type")) return ctype;
ctype = (config->option<ConfigOptionStrings>("filament_colour_type"))->values;
auto slots = parse_mixed_gradient_slots(*config, ctype.size());
while (ctype.size() < slots.size()) ctype.push_back("1");
for (size_t i = 0; i < ctype.size() && i < slots.size(); ++i) {
if (slots[i].is_gradient)
ctype[i] = "0";
}
return ctype;
}
std::vector<Plater::FilamentGradientInfo> Plater::get_filament_gradient_info() const
{
const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->project_config;
size_t n = get_extruder_colors_from_plater_config().size();
std::vector<FilamentGradientInfo> info(n);
auto slots = parse_mixed_gradient_slots(*config, n);
unsigned char rgba[4] = {};
for (size_t i = 0; i < n; ++i) {
if (!slots[i].is_gradient) continue;
info[i].is_gradient = true;
Slic3r::GUI::BitmapCache::parse_color4(slots[i].color_from, rgba);
info[i].color_from = {rgba[0] / 255.f, rgba[1] / 255.f, rgba[2] / 255.f, rgba[3] / 255.f};
Slic3r::GUI::BitmapCache::parse_color4(slots[i].color_to, rgba);
info[i].color_to = {rgba[0] / 255.f, rgba[1] / 255.f, rgba[2] / 255.f, rgba[3] / 255.f};
}
return info;
}
/* Get vector of colors used for rendering of a Preview scene in "Color print" mode
* It consists of extruder colors and colors, saved in model.custom_gcode_per_print_z
*/
+10 -1
View File
@@ -591,7 +591,7 @@ public:
void on_filament_change(size_t filament_idx);
void on_filament_count_change(size_t extruders_count);
void on_filaments_delete(size_t extruders_count, size_t filament_id, int replace_filament_id = -1);
void on_filaments_delete(size_t extruders_count, size_t filament_id, int replace_filament_id = -1, const std::vector<unsigned char>& is_mixed_before_delete = {});
std::vector<Slic3r::ColorRGBA> get_extruders_colors();
// BBS
void on_bed_type_change(BedType bed_type);
@@ -606,6 +606,15 @@ public:
std::vector<std::string> get_extruder_colors_from_plater_config(const GCodeProcessorResult* const result = nullptr) const;
std::vector<std::string> get_filament_colors_render_info() const;
std::vector<std::string> get_filament_color_render_type() const;
// Endpoint colours for gradient mixed filaments, so the 3D scene and the paint gizmo can
// draw a two-tone swatch. is_gradient is false for every ordinary filament slot.
struct FilamentGradientInfo {
bool is_gradient = false;
std::array<float, 4> color_from = {0.5f, 0.5f, 0.5f, 1.0f};
std::array<float, 4> color_to = {0.5f, 0.5f, 0.5f, 1.0f};
};
std::vector<FilamentGradientInfo> get_filament_gradient_info() const;
std::vector<std::string> get_colors_for_color_print(const GCodeProcessorResult* const result = nullptr) const;
void set_global_filament_map_mode(FilamentMapMode mode);
+12
View File
@@ -2575,6 +2575,10 @@ void SyncAmsInfoDialog::reset_and_sync_ams_list()
m_materialList.clear();
m_filaments.clear();
// Mixed-color slots are virtual: they never occupy a tray, so they must not appear as
// AMS sync targets. Look the flags up once and skip those slots in the loop below.
auto* is_mixed_opt = preset_bundle->project_config.option<ConfigOptionBools>("filament_is_mixed");
bool use_double_extruder = get_is_double_extruder();
if (use_double_extruder) {
const auto &project_config = preset_bundle->project_config;
@@ -2592,6 +2596,8 @@ void SyncAmsInfoDialog::reset_and_sync_ams_list()
auto colour_rgb = wxColour((int) rgb[0], (int) rgb[1], (int) rgb[2], (int) rgb[3]);
if (extruder >= materials.size() || extruder < 0 || extruder >= display_materials.size())
continue;
if (is_mixed_opt && extruder < (int) is_mixed_opt->values.size() && is_mixed_opt->values[extruder])
continue;
if (contronal_index % SYNC_FLEX_GRID_COL == 0) {
wxBoxSizer *ams_tip_sizer = new wxBoxSizer(wxVERTICAL);
@@ -2793,6 +2799,10 @@ void SyncAmsInfoDialog::generate_override_fix_ams_list()
m_fix_materialList.clear();
m_fix_filaments.clear();
// Mixed-color slots are virtual: they never occupy a tray, so they must not appear as
// AMS sync targets. Look the flags up once and skip those slots in the loop below.
auto* is_mixed_opt = preset_bundle->project_config.option<ConfigOptionBools>("filament_is_mixed");
bool use_double_extruder = get_is_double_extruder();
if (use_double_extruder) {
const auto &project_config = preset_bundle->project_config;
@@ -2810,6 +2820,8 @@ void SyncAmsInfoDialog::generate_override_fix_ams_list()
auto colour_rgb = wxColour((int) rgb[0], (int) rgb[1], (int) rgb[2], (int) rgb[3]);
if (extruder >= extruders.size() || extruder < 0 || extruder >= m_ams_combo_info.ams_filament_colors.size())
continue;
if (is_mixed_opt && extruder < (int) is_mixed_opt->values.size() && is_mixed_opt->values[extruder])
continue;
if (contronal_index % SYNC_FLEX_GRID_COL == 0) {
wxBoxSizer *ams_tip_sizer = new wxBoxSizer(wxVERTICAL);
+1
View File
@@ -2630,6 +2630,7 @@ void TabPrint::build()
auto optgroup = page->new_optgroup(L("Layer height"), L"param_layer_height");
optgroup->append_single_option_line("layer_height","quality_settings_layer_height");
optgroup->append_single_option_line("initial_layer_print_height","quality_settings_layer_height");
optgroup->append_single_option_line("enable_mixed_color_sublayer");
optgroup = page->new_optgroup(L("Line width"), L"param_line_width");
optgroup->append_single_option_line("line_width","quality_settings_line_width");