Add extrusion role change G-code in Process and Filament (#11784)

* Add extrusion role change G-code options

Introduces new G-code options for handling extrusion role changes at the process and filament levels. Updates configuration, GUI, and GCode logic to support 'process_change_extrusion_role_gcode' and 'filament_change_extrusion_role_gcode', allowing custom G-code insertion when the extrusion role changes.

Co-Authored-By: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>

* Optimize extrusion role-change gcode handling

Cache gcode template strings and current filament id, and guard creation of DynamicConfig/placeholder processing behind a check that at least one role-change gcode is non-empty. This avoids redundant config lookups and DynamicConfig/placeholder parsing when no custom role-change gcode is defined, improving clarity and performance without changing behavior.

---------

Co-authored-by: Rodrigo Faselli <162915171+RF47@users.noreply.github.com>
This commit is contained in:
Ian Bassi
2026-04-24 03:25:04 -03:00
committed by GitHub
parent fd1aece9c7
commit dee9c0d72c
5 changed files with 79 additions and 8 deletions

View File

@@ -1946,6 +1946,7 @@ namespace DoExport {
//if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value);
//Orca
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Change extrusion role G-code")), config.change_extrusion_role_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Process change extrusion role G-code")), config.process_change_extrusion_role_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Pause G-code")), config.machine_pause_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) check(_(L("Template Custom G-code")), config.template_custom_gcode.value);
if (ret.size() < MAX_TAGS_COUNT) {
@@ -1962,6 +1963,13 @@ namespace DoExport {
break;
}
}
if (ret.size() < MAX_TAGS_COUNT) {
for (const std::string& value : config.filament_change_extrusion_role_gcode.values) {
check(_(L("Filament change extrusion role G-code")), value);
if (ret.size() == MAX_TAGS_COUNT)
break;
}
}
//BBS: no custom_gcode_per_print_z, don't need to check
//if (ret.size() < MAX_TAGS_COUNT) {
// const CustomGCode::Info& custom_gcode_per_print_z = print.model().custom_gcode_per_print_z;
@@ -5423,6 +5431,7 @@ void GCode::apply_print_config(const PrintConfig &print_config)
&m_config.time_lapse_gcode,
&m_config.change_filament_gcode,
&m_config.change_extrusion_role_gcode,
&m_config.process_change_extrusion_role_gcode,
&m_config.printing_by_object_gcode,
&m_config.machine_pause_gcode,
&m_config.template_custom_gcode,
@@ -5432,7 +5441,8 @@ void GCode::apply_print_config(const PrintConfig &print_config)
}
for (auto opt : std::initializer_list<ConfigOptionStrings*>{
&m_config.filament_start_gcode,
&m_config.filament_end_gcode
&m_config.filament_end_gcode,
&m_config.filament_change_extrusion_role_gcode
}) {
if (opt->empty())
for (int i = 0; i < opt->size(); ++i)
@@ -6551,15 +6561,29 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
// Orca: End of dynamic PA trigger flag segment
//Orca: process custom gcode for extrusion role change
if (path.role() != m_last_extrusion_role && !m_config.change_extrusion_role_gcode.value.empty()) {
if (path.role() != m_last_extrusion_role) {
const auto current_filament_id = m_writer.filament()->id();
const std::string& machine_role_change_gcode = m_config.change_extrusion_role_gcode.value;
const std::string& filament_role_change_gcode = m_config.filament_change_extrusion_role_gcode.get_at(current_filament_id);
const std::string& process_role_change_gcode = m_config.process_change_extrusion_role_gcode.value;
if (!machine_role_change_gcode.empty() || !filament_role_change_gcode.empty() || !process_role_change_gcode.empty()) {
DynamicConfig config;
config.set_key_value("extrusion_role", new ConfigOptionString(extrusion_role_to_string_for_parser(path.role())));
config.set_key_value("last_extrusion_role", new ConfigOptionString(extrusion_role_to_string_for_parser(m_last_extrusion_role)));
config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1));
config.set_key_value("layer_z", new ConfigOptionFloat(m_layer == nullptr ? m_last_height : m_layer->print_z));
gcode += this->placeholder_parser_process("change_extrusion_role_gcode",
m_config.change_extrusion_role_gcode.value, m_writer.filament()->id(), &config)
+ "\n";
const auto append_role_gcode = [this, current_filament_id, &config, &gcode](const std::string& key, const std::string& templ) {
if (templ.empty())
return;
gcode += this->placeholder_parser_process(key, templ, current_filament_id, &config) + "\n";
};
append_role_gcode("change_extrusion_role_gcode", machine_role_change_gcode);
append_role_gcode("filament_change_extrusion_role_gcode", filament_role_change_gcode);
append_role_gcode("process_change_extrusion_role_gcode", process_role_change_gcode);
}
}
// extrude arc or line

View File

@@ -934,8 +934,8 @@ static std::vector<std::string> s_Preset_print_options {
"support_bottom_interface_spacing", "enable_overhang_speed", "slowdown_for_curled_perimeters", "overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed",
"initial_layer_infill_speed", "only_one_wall_top",
"timelapse_type",
"wall_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
"wall_distribution_count", "min_feature_size", "min_bead_width", "post_process", "min_length_factor",
"wall_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
"wall_distribution_count", "min_feature_size", "min_bead_width", "post_process", "process_change_extrusion_role_gcode", "min_length_factor",
"small_perimeter_speed", "small_perimeter_threshold","bridge_angle","internal_bridge_angle", "filter_out_gap_fill", "travel_acceleration","inner_wall_acceleration", "min_width_top_surface",
"default_jerk", "outer_wall_jerk", "inner_wall_jerk", "infill_jerk", "top_surface_jerk", "initial_layer_jerk","travel_jerk","default_junction_deviation",
"top_solid_infill_flow_ratio","bottom_solid_infill_flow_ratio","only_one_wall_first_layer", "print_flow_ratio", "seam_gap",
@@ -970,7 +970,7 @@ static std::vector<std::string> s_Preset_filament_options {/*"filament_colour",
//BBS:temperature_vitrification
"temperature_vitrification", "reduce_fan_stop_start_freq","dont_slow_down_outer_wall", "slow_down_for_layer_cooling", "fan_min_speed",
"fan_max_speed", "enable_overhang_bridge_fan", "overhang_fan_speed", "overhang_fan_threshold", "close_fan_the_first_x_layers", "full_fan_speed_layer", "fan_cooling_layer_time", "slow_down_layer_time", "slow_down_min_speed",
"filament_start_gcode", "filament_end_gcode",
"filament_start_gcode", "filament_end_gcode", "filament_change_extrusion_role_gcode",
//exhaust fan control
"activate_air_filtration","activate_air_filtration_during_print","activate_air_filtration_on_completion","during_print_exhaust_fan_speed","complete_print_exhaust_fan_speed",
// Retract overrides

View File

@@ -4674,6 +4674,15 @@ void PrintConfigDef::init_fff_params()
def->height = 6;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionStrings());
def = this->add("process_change_extrusion_role_gcode", coString);
def->label = L("Change extrusion role G-code (process)");
def->tooltip = L("This G-code is inserted when the extrusion role is changed. It runs after the machine and filament extrusion role G-code.");
def->multiline = true;
def->full_width = true;
def->height = 5;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString());
def = this->add("printer_model", coString);
def->label = L("Printer type");
@@ -6234,6 +6243,15 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString());
def = this->add("filament_change_extrusion_role_gcode", coStrings);
def->label = L("Change extrusion role G-code (filament)");
def->tooltip = L("This G-code is inserted when the extrusion role is changed for the active filament.");
def->multiline = true;
def->full_width = true;
def->height = 5;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionStrings{ "" });
def = this->add("top_surface_line_width", coFloatOrPercent);
def->label = L("Top surface");
def->category = L("Quality");
@@ -10707,6 +10725,8 @@ static std::map<t_custom_gcode_key, t_config_option_keys> s_CustomGcodeSpecificP
"travel_point_1_x", "travel_point_1_y", "travel_point_2_x", "travel_point_2_y", "travel_point_3_x",
"travel_point_3_y", "x_after_toolchange", "y_after_toolchange", "z_after_toolchange"}},
{"change_extrusion_role_gcode", {"layer_num", "layer_z", "extrusion_role", "last_extrusion_role"}},
{"filament_change_extrusion_role_gcode", {"layer_num", "layer_z", "extrusion_role", "last_extrusion_role"}},
{"process_change_extrusion_role_gcode", {"layer_num", "layer_z", "extrusion_role", "last_extrusion_role"}},
{"printing_by_object_gcode", {}},
{"machine_pause_gcode", {}},
{"template_custom_gcode", {}},

View File

@@ -1336,6 +1336,8 @@ PRINT_CONFIG_CLASS_DEFINE(
((ConfigOptionBool, wipe_tower_no_sparse_layers))
((ConfigOptionString, change_filament_gcode))
((ConfigOptionString, change_extrusion_role_gcode))
((ConfigOptionString, process_change_extrusion_role_gcode))
((ConfigOptionStrings, filament_change_extrusion_role_gcode))
((ConfigOptionFloat, travel_speed))
((ConfigOptionFloat, travel_speed_z))
((ConfigOptionBool, silent_mode))

View File

@@ -67,6 +67,9 @@ namespace GUI {
#define DISABLE_UNDO_SYS
// Forward declaration for early use; definitions live later in this translation unit.
static void validate_custom_gcode_cb(Tab* tab, const wxString& title, const t_config_option_key& opt_key, const boost::any& value);
static const std::vector<std::string> plate_keys = { "curr_bed_type", "skirt_start_angle", "first_layer_print_sequence", "first_layer_sequence_choice", "other_layers_print_sequence", "other_layers_sequence_choice", "print_sequence", "spiral_mode"};
void Tab::Highlighter::set_timer_owner(wxEvtHandler* owner, int timerid/* = wxID_ANY*/)
@@ -2702,6 +2705,17 @@ void TabPrint::build()
// option.opt.height = 5;
optgroup->append_single_option_line(option, "others_settings_g_code_output#filename-format");
optgroup = page->new_optgroup(L("Change extrusion role G-code"), L"param_gcode", 0);
optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
validate_custom_gcode_cb(this, optgroup_title, opt_key, value);
};
optgroup->edit_custom_gcode = [this](const t_config_option_key& opt_key) { edit_custom_gcode(opt_key); };
option = optgroup->get_option("process_change_extrusion_role_gcode");
option.opt.full_width = true;
option.opt.is_code = true;
option.opt.height = 15;
optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Post-processing Scripts"), L"param_gcode", 0);
option = optgroup->get_option("post_process");
option.opt.full_width = true;
@@ -4052,6 +4066,17 @@ void TabFilament::build()
option.opt.height = gcode_field_height;// 150;
optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Change extrusion role G-code"), L"param_gcode", 0);
optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
validate_custom_gcode_cb(this, optgroup_title, opt_key, value);
};
optgroup->edit_custom_gcode = edit_custom_gcode_fn;
option = optgroup->get_option("filament_change_extrusion_role_gcode");
option.opt.full_width = true;
option.opt.is_code = true;
option.opt.height = gcode_field_height;// 150;
optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Filament end G-code"), L"param_gcode", 0);
optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) {
validate_custom_gcode_cb(this, optgroup_title, opt_key, value);