mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-29 03:41:31 +00:00
sublayers and more
This commit is contained in:
@@ -3575,6 +3575,63 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||||||
ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
ConfigOptionStrings *filament_color_type = project_config.option<ConfigOptionStrings>("filament_colour_type");
|
||||||
ConfigOptionInts * filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
ConfigOptionInts * filament_map = project_config.option<ConfigOptionInts>("filament_map");
|
||||||
ConfigOptionInts * filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
ConfigOptionInts * filament_volume_map = project_config.option<ConfigOptionInts>("filament_volume_map");
|
||||||
|
|
||||||
|
// Snapshot and temporarily strip mixed filament slots so AMS sync operates on physical
|
||||||
|
// filaments only. A mixed slot is virtual and has no tray to sync against; leaving it in
|
||||||
|
// would let AMS mapping overwrite it and would break the physical-first slot ordering the
|
||||||
|
// rest of the feature relies on. The slots are re-appended verbatim after the sync.
|
||||||
|
struct MixedSlotSnapshot {
|
||||||
|
std::string preset;
|
||||||
|
std::string color;
|
||||||
|
std::string color_type;
|
||||||
|
std::string mixed_components;
|
||||||
|
std::string mixed_sublayer_ratios;
|
||||||
|
bool mixed_gradient = false;
|
||||||
|
std::string mixed_gradient_range;
|
||||||
|
std::string mixed_gradient_curve;
|
||||||
|
bool mixed_gradient_per_part = false;
|
||||||
|
};
|
||||||
|
std::vector<MixedSlotSnapshot> mixed_snapshots;
|
||||||
|
auto* is_mixed_opt = project_config.option<ConfigOptionBools>("filament_is_mixed");
|
||||||
|
auto* mixed_comp_opt = project_config.option<ConfigOptionStrings>("filament_mixed_components");
|
||||||
|
auto* mixed_ratios_opt = project_config.option<ConfigOptionStrings>("filament_mixed_sublayer_ratios");
|
||||||
|
auto* mixed_gradient_opt = project_config.option<ConfigOptionBools>("filament_mixed_gradient");
|
||||||
|
auto* mixed_grad_range_opt = project_config.option<ConfigOptionStrings>("filament_mixed_gradient_range");
|
||||||
|
auto* mixed_grad_curve_opt = project_config.option<ConfigOptionStrings>("filament_mixed_gradient_curve");
|
||||||
|
auto* mixed_per_part_opt = project_config.option<ConfigOptionBools>("filament_mixed_gradient_per_part");
|
||||||
|
if (is_mixed_opt) {
|
||||||
|
for (size_t i = 0; i < is_mixed_opt->values.size() && i < this->filament_presets.size(); ++i) {
|
||||||
|
if (!is_mixed_opt->values[i])
|
||||||
|
continue;
|
||||||
|
MixedSlotSnapshot snap;
|
||||||
|
snap.preset = this->filament_presets[i];
|
||||||
|
snap.color = (i < filament_color->values.size()) ? filament_color->values[i] : "";
|
||||||
|
snap.color_type = (i < filament_color_type->values.size()) ? filament_color_type->values[i] : "";
|
||||||
|
if (mixed_comp_opt && i < mixed_comp_opt->values.size()) snap.mixed_components = mixed_comp_opt->values[i];
|
||||||
|
if (mixed_ratios_opt && i < mixed_ratios_opt->values.size()) snap.mixed_sublayer_ratios = mixed_ratios_opt->values[i];
|
||||||
|
if (mixed_gradient_opt && i < mixed_gradient_opt->values.size()) snap.mixed_gradient = mixed_gradient_opt->values[i];
|
||||||
|
if (mixed_grad_range_opt && i < mixed_grad_range_opt->values.size()) snap.mixed_gradient_range = mixed_grad_range_opt->values[i];
|
||||||
|
if (mixed_grad_curve_opt && i < mixed_grad_curve_opt->values.size()) snap.mixed_gradient_curve = mixed_grad_curve_opt->values[i];
|
||||||
|
if (mixed_per_part_opt && i < mixed_per_part_opt->values.size()) snap.mixed_gradient_per_part = mixed_per_part_opt->values[i];
|
||||||
|
mixed_snapshots.push_back(snap);
|
||||||
|
}
|
||||||
|
if (!mixed_snapshots.empty()) {
|
||||||
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": stripping " << mixed_snapshots.size() << " mixed filament slot(s) before AMS sync";
|
||||||
|
size_t phys_count = this->filament_presets.size() - mixed_snapshots.size();
|
||||||
|
this->filament_presets.resize(phys_count);
|
||||||
|
filament_color->values.resize(phys_count);
|
||||||
|
filament_color_type->values.resize(phys_count);
|
||||||
|
filament_map->values.resize(phys_count, 1);
|
||||||
|
is_mixed_opt->values.resize(phys_count);
|
||||||
|
if (mixed_comp_opt) mixed_comp_opt->values.resize(phys_count);
|
||||||
|
if (mixed_ratios_opt) mixed_ratios_opt->values.resize(phys_count);
|
||||||
|
if (mixed_gradient_opt) mixed_gradient_opt->values.resize(phys_count);
|
||||||
|
if (mixed_grad_range_opt) mixed_grad_range_opt->values.resize(phys_count);
|
||||||
|
if (mixed_grad_curve_opt) mixed_grad_curve_opt->values.resize(phys_count);
|
||||||
|
if (mixed_per_part_opt) mixed_per_part_opt->values.resize(phys_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (color_only) {
|
if (color_only) {
|
||||||
auto get_map_index = [&ams_infos](const std::vector<AMSMapInfo> &infos, const AMSMapInfo &temp) {
|
auto get_map_index = [&ams_infos](const std::vector<AMSMapInfo> &infos, const AMSMapInfo &temp) {
|
||||||
for (int i = 0; i < infos.size(); i++) {
|
for (int i = 0; i < infos.size(); i++) {
|
||||||
@@ -3830,6 +3887,34 @@ unsigned int PresetBundle::sync_ams_list(std::vector<std::pair<DynamicPrintConfi
|
|||||||
if (support_interface_filament_opt->value > filament_color_type->values.size())
|
if (support_interface_filament_opt->value > filament_color_type->values.size())
|
||||||
support_interface_filament_opt->value = 0;
|
support_interface_filament_opt->value = 0;
|
||||||
}
|
}
|
||||||
|
// Re-append mixed filament slots that were stripped before AMS sync
|
||||||
|
if (!mixed_snapshots.empty()) {
|
||||||
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": re-appending " << mixed_snapshots.size() << " mixed filament slot(s) after AMS sync";
|
||||||
|
size_t new_phys_count = this->filament_presets.size();
|
||||||
|
if (is_mixed_opt) is_mixed_opt->values.resize(new_phys_count, (unsigned char)false);
|
||||||
|
if (mixed_comp_opt) mixed_comp_opt->values.resize(new_phys_count);
|
||||||
|
if (mixed_ratios_opt) mixed_ratios_opt->values.resize(new_phys_count);
|
||||||
|
if (mixed_gradient_opt) mixed_gradient_opt->values.resize(new_phys_count, (unsigned char)false);
|
||||||
|
if (mixed_grad_range_opt) mixed_grad_range_opt->values.resize(new_phys_count);
|
||||||
|
if (mixed_grad_curve_opt) mixed_grad_curve_opt->values.resize(new_phys_count);
|
||||||
|
if (mixed_per_part_opt) mixed_per_part_opt->values.resize(new_phys_count, (unsigned char)false);
|
||||||
|
|
||||||
|
for (auto& snap : mixed_snapshots) {
|
||||||
|
this->filament_presets.push_back(snap.preset);
|
||||||
|
filament_color->values.push_back(snap.color);
|
||||||
|
filament_color_type->values.push_back(snap.color_type);
|
||||||
|
ams_multi_color_filment.push_back({snap.color});
|
||||||
|
filament_map->values.push_back(1);
|
||||||
|
if (is_mixed_opt) is_mixed_opt->values.push_back((unsigned char)true);
|
||||||
|
if (mixed_comp_opt) mixed_comp_opt->values.push_back(snap.mixed_components);
|
||||||
|
if (mixed_ratios_opt) mixed_ratios_opt->values.push_back(snap.mixed_sublayer_ratios);
|
||||||
|
if (mixed_gradient_opt) mixed_gradient_opt->values.push_back((unsigned char)snap.mixed_gradient);
|
||||||
|
if (mixed_grad_range_opt) mixed_grad_range_opt->values.push_back(snap.mixed_gradient_range);
|
||||||
|
if (mixed_grad_curve_opt) mixed_grad_curve_opt->values.push_back(snap.mixed_gradient_curve);
|
||||||
|
if (mixed_per_part_opt) mixed_per_part_opt->values.push_back((unsigned char)snap.mixed_gradient_per_part);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update ams_multi_color_filment
|
// Update ams_multi_color_filment
|
||||||
update_filament_multi_color();
|
update_filament_multi_color();
|
||||||
update_multi_material_filament_presets();
|
update_multi_material_filament_presets();
|
||||||
|
|||||||
@@ -8911,7 +8911,10 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
|
|||||||
m_sel_plate_toolbar.m_items[i]->slice_state = IMToolbarItem::SliceState::SLICE_FAILED;
|
m_sel_plate_toolbar.m_items[i]->slice_state = IMToolbarItem::SliceState::SLICE_FAILED;
|
||||||
}
|
}
|
||||||
else {
|
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;
|
m_sel_plate_toolbar.m_items[i]->slice_state = IMToolbarItem::SliceState::SLICE_FAILED;
|
||||||
else {
|
else {
|
||||||
if (plate_list.get_plate(i)->get_slicing_percent() < 0.0f)
|
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();
|
bool disabled = !wxGetApp().plater()->can_fillcolor();
|
||||||
ColorRGBA rgba;
|
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++) {
|
for (int i = 0; i < extruder_num; i++) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
ImGui::SameLine();
|
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))
|
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));
|
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::IsItemHovered() && i < 9) {
|
||||||
if (!ImGui::IsMouseHoveringRect(left_arrow_button.Min, left_arrow_button.Max) && !ImGui::IsMouseHoveringRect(right_arrow_button.Min, right_arrow_button.Max)) {
|
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 });
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, { 20.0f * f_scale, 10.0f * f_scale });
|
||||||
|
|||||||
@@ -1684,6 +1684,13 @@ void MenuFactory::create_filament_action_menu(bool init, int active_filament_men
|
|||||||
append_submenu(menu, sub_menu, wxID_ANY, _L("Merge with"), "", "",
|
append_submenu(menu, sub_menu, wxID_ANY, _L("Merge with"), "", "",
|
||||||
[filaments_cnt]() { return filaments_cnt > 1; }, m_parent);
|
[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
|
// 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"));
|
const int delete_id = menu->FindItem(_L("Delete"));
|
||||||
if (delete_id != wxNOT_FOUND)
|
if (delete_id != wxNOT_FOUND)
|
||||||
|
|||||||
@@ -78,6 +78,14 @@ void GLGizmoMmuSegmentation::init_extruders_data()
|
|||||||
m_extruders_colors = wxGetApp().plater()->get_extruders_colors();
|
m_extruders_colors = wxGetApp().plater()->get_extruders_colors();
|
||||||
m_selected_extruder_idx = 0;
|
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
|
// keep remap table consistent with current extruder count
|
||||||
m_extruder_remap.resize(m_extruders_colors.size());
|
m_extruder_remap.resize(m_extruders_colors.size());
|
||||||
for (size_t i = 0; i < m_extruder_remap.size(); ++i)
|
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;
|
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);
|
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).
|
// 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.
|
// 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;
|
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; }
|
const float get_cursor_radius_min() const override { return CursorRadiusMin; }
|
||||||
|
|
||||||
// BBS
|
// BBS
|
||||||
@@ -116,6 +124,7 @@ protected:
|
|||||||
|
|
||||||
// Filament remap feature
|
// Filament remap feature
|
||||||
std::vector<size_t> m_extruder_remap; // index → target extruder index
|
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
|
// ORCA: Cache used filaments to filter UI
|
||||||
std::set<size_t> m_used_filaments; // Set of used filament indices (cached)
|
std::set<size_t> m_used_filaments; // Set of used filament indices (cached)
|
||||||
|
|
||||||
|
|||||||
@@ -472,6 +472,32 @@ PlateSettingsDialog::PlateSettingsDialog(wxWindow* parent, const wxString& title
|
|||||||
m_sizer_main->AddSpacer(FromDIP(5));
|
m_sizer_main->AddSpacer(FromDIP(5));
|
||||||
m_sizer_main->Add(m_other_layers_seq_panel, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(30));
|
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"});
|
auto dlg_btns = new DialogButtons(this, {"OK", "Cancel"});
|
||||||
|
|
||||||
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, [this](auto& e) {
|
dlg_btns->GetOK()->Bind(wxEVT_BUTTON, [this](auto& e) {
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ public:
|
|||||||
int get_layers_print_seq_choice() { return m_other_layer_print_seq_choice->GetSelection(); };
|
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; }
|
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:
|
protected:
|
||||||
void append_layer(const LayerSeqInfo* layer_info = nullptr);
|
void append_layer(const LayerSeqInfo* layer_info = nullptr);
|
||||||
|
|||||||
+162
-4
@@ -5355,9 +5355,16 @@ void Sidebar::delete_filament(size_t filament_id, int replace_filament_id) {
|
|||||||
p->editing_filament = -1;
|
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().preset_bundle->update_num_filaments(filament_id);
|
||||||
wxGetApp().plater()->get_partplate_list().on_filament_deleted(filament_count, 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().get_tab(Preset::TYPE_PRINT)->update();
|
||||||
wxGetApp().preset_bundle->export_selections(*wxGetApp().app_config);
|
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)
|
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));
|
delete_filament(from_id, int(to_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9744,7 +9781,11 @@ void Plater::priv::object_list_changed()
|
|||||||
|
|
||||||
// BBS
|
// BBS
|
||||||
//sidebar->enable_buttons(!model.objects.empty() && !export_in_progress && model_fits && part_plate->has_printable_instances());
|
//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();
|
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);
|
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&)
|
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());
|
view3D->enable_layers_editing(!view3D->is_layers_editing_enabled());
|
||||||
notification_manager->set_move_from_overlay(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
|
// only update elements in plater
|
||||||
update_filament_colors_in_full_config();
|
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
|
// 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 (ModelObject *mo : wxGetApp().model().objects) {
|
||||||
for (ModelVolume *mv : mo->volumes) {
|
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
|
std::vector<std::string> Plater::get_filament_colors_render_info() const
|
||||||
{
|
{
|
||||||
const Slic3r::DynamicPrintConfig* config = &wxGetApp().preset_bundle->project_config;
|
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;
|
if (!config->has("filament_multi_colour")) return color_packs;
|
||||||
|
|
||||||
color_packs = (config->option<ConfigOptionStrings>("filament_multi_colour"))->values;
|
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;
|
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;
|
if (!config->has("filament_colour_type")) return ctype;
|
||||||
|
|
||||||
ctype = (config->option<ConfigOptionStrings>("filament_colour_type"))->values;
|
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;
|
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
|
/* 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
|
* It consists of extruder colors and colors, saved in model.custom_gcode_per_print_z
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -591,7 +591,7 @@ public:
|
|||||||
|
|
||||||
void on_filament_change(size_t filament_idx);
|
void on_filament_change(size_t filament_idx);
|
||||||
void on_filament_count_change(size_t extruders_count);
|
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();
|
std::vector<Slic3r::ColorRGBA> get_extruders_colors();
|
||||||
// BBS
|
// BBS
|
||||||
void on_bed_type_change(BedType bed_type);
|
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_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_colors_render_info() const;
|
||||||
std::vector<std::string> get_filament_color_render_type() 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;
|
std::vector<std::string> get_colors_for_color_print(const GCodeProcessorResult* const result = nullptr) const;
|
||||||
|
|
||||||
void set_global_filament_map_mode(FilamentMapMode mode);
|
void set_global_filament_map_mode(FilamentMapMode mode);
|
||||||
|
|||||||
@@ -2575,6 +2575,10 @@ void SyncAmsInfoDialog::reset_and_sync_ams_list()
|
|||||||
m_materialList.clear();
|
m_materialList.clear();
|
||||||
m_filaments.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();
|
bool use_double_extruder = get_is_double_extruder();
|
||||||
if (use_double_extruder) {
|
if (use_double_extruder) {
|
||||||
const auto &project_config = preset_bundle->project_config;
|
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]);
|
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())
|
if (extruder >= materials.size() || extruder < 0 || extruder >= display_materials.size())
|
||||||
continue;
|
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) {
|
if (contronal_index % SYNC_FLEX_GRID_COL == 0) {
|
||||||
wxBoxSizer *ams_tip_sizer = new wxBoxSizer(wxVERTICAL);
|
wxBoxSizer *ams_tip_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
@@ -2793,6 +2799,10 @@ void SyncAmsInfoDialog::generate_override_fix_ams_list()
|
|||||||
m_fix_materialList.clear();
|
m_fix_materialList.clear();
|
||||||
m_fix_filaments.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();
|
bool use_double_extruder = get_is_double_extruder();
|
||||||
if (use_double_extruder) {
|
if (use_double_extruder) {
|
||||||
const auto &project_config = preset_bundle->project_config;
|
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]);
|
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())
|
if (extruder >= extruders.size() || extruder < 0 || extruder >= m_ams_combo_info.ams_filament_colors.size())
|
||||||
continue;
|
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) {
|
if (contronal_index % SYNC_FLEX_GRID_COL == 0) {
|
||||||
wxBoxSizer *ams_tip_sizer = new wxBoxSizer(wxVERTICAL);
|
wxBoxSizer *ams_tip_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|||||||
@@ -2630,6 +2630,7 @@ void TabPrint::build()
|
|||||||
auto optgroup = page->new_optgroup(L("Layer height"), L"param_layer_height");
|
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("layer_height","quality_settings_layer_height");
|
||||||
optgroup->append_single_option_line("initial_layer_print_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 = page->new_optgroup(L("Line width"), L"param_line_width");
|
||||||
optgroup->append_single_option_line("line_width","quality_settings_line_width");
|
optgroup->append_single_option_line("line_width","quality_settings_line_width");
|
||||||
|
|||||||
Reference in New Issue
Block a user