Updated Config Handling

This commit is contained in:
Dark98
2026-02-15 22:19:31 +00:00
parent 213e723276
commit 2b8c182516
3 changed files with 134 additions and 46 deletions
@@ -258,7 +258,11 @@ public class FilamentConfigFragment extends ProfileListFragment {
@Override @Override
protected void onResetConfig() { protected void onResetConfig() {
currentConfig = new ConfigObject(Santoku.CONFIG.findFilament(Santoku.CONFIG.presets.get("filament"))); ConfigObject base = Santoku.CONFIG.findFilament(Santoku.CONFIG.presets.get("filament"));
if (base == null && Santoku.CONFIG.filamentConfigs != null && !Santoku.CONFIG.filamentConfigs.isEmpty()) {
base = Santoku.CONFIG.filamentConfigs.get(0);
}
currentConfig = base != null ? new ConfigObject(base) : ConfigObject.createCustomFilamentProfile();
} }
@Override @Override
+92 -10
View File
@@ -52,6 +52,7 @@
#include <chrono> #include <chrono>
#include <math.h> #include <math.h>
#include <optional> #include <optional>
#include <regex>
#include <string> #include <string>
#include <string_view> #include <string_view>
@@ -105,6 +106,29 @@ namespace Slic3r {
gcode += '\n'; gcode += '\n';
} }
static std::string rewrite_simple_curly_placeholders_to_legacy(const std::string &templ)
{
// Convert {name} or {name[0]} to legacy [name] / [name_0].
// Only touches simple, standalone placeholders to avoid breaking control macros.
static const std::regex pattern(R"(\{([A-Za-z_][A-Za-z0-9_]*)(?:\[(\d+)\])?\})");
std::string out;
out.reserve(templ.size());
size_t last_pos = 0;
for (auto it = std::sregex_iterator(templ.begin(), templ.end(), pattern); it != std::sregex_iterator(); ++it) {
const std::smatch &m = *it;
out.append(templ, last_pos, m.position() - last_pos);
const std::string &name = m[1].str();
const std::string &idx = m[2].str();
if (! idx.empty())
out += "[" + name + "_" + idx + "]";
else
out += "[" + name + "]";
last_pos = m.position() + m.length();
}
out.append(templ, last_pos, std::string::npos);
return out;
}
// Return true if tch_prefix is found in custom_gcode // Return true if tch_prefix is found in custom_gcode
static bool custom_gcode_changes_tool(const std::string& custom_gcode, const std::string& tch_prefix, unsigned next_extruder) static bool custom_gcode_changes_tool(const std::string& custom_gcode, const std::string& tch_prefix, unsigned next_extruder)
{ {
@@ -1087,6 +1111,8 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
// Prepare the helper object for replacing placeholders in custom G-code and output filename. // Prepare the helper object for replacing placeholders in custom G-code and output filename.
m_placeholder_parser_integration.parser = print.placeholder_parser(); m_placeholder_parser_integration.parser = print.placeholder_parser();
// Ensure all print config options are available for { } placeholder expressions.
m_placeholder_parser_integration.parser.apply_config(print.full_print_config());
m_placeholder_parser_integration.parser.update_timestamp(); m_placeholder_parser_integration.parser.update_timestamp();
m_placeholder_parser_integration.context.rng = std::mt19937(std::chrono::high_resolution_clock::now().time_since_epoch().count()); m_placeholder_parser_integration.context.rng = std::mt19937(std::chrono::high_resolution_clock::now().time_since_epoch().count());
// Enable passing global variables between PlaceholderParser invocations. // Enable passing global variables between PlaceholderParser invocations.
@@ -1181,6 +1207,29 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
this->placeholder_parser().set("has_wipe_tower", has_wipe_tower); this->placeholder_parser().set("has_wipe_tower", has_wipe_tower);
this->placeholder_parser().set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming); this->placeholder_parser().set("has_single_extruder_multi_material_priming", has_wipe_tower && print.config().single_extruder_multi_material_priming);
this->placeholder_parser().set("total_toolchanges", tool_ordering.toolchanges_count()); this->placeholder_parser().set("total_toolchanges", tool_ordering.toolchanges_count());
{
const DynamicPrintConfig &cfg = print.full_print_config();
if (const ConfigOption *opt = cfg.optptr("first_layer_temperature")) {
this->placeholder_parser().set("first_layer_temperature", opt->clone());
} else {
this->placeholder_parser().set("first_layer_temperature", new ConfigOptionInts(print.config().first_layer_temperature.values));
}
if (const ConfigOption *opt = cfg.optptr("temperature")) {
this->placeholder_parser().set("temperature", opt->clone());
} else {
this->placeholder_parser().set("temperature", new ConfigOptionInts(print.config().temperature.values));
}
if (const ConfigOption *opt = cfg.optptr("first_layer_bed_temperature")) {
this->placeholder_parser().set("first_layer_bed_temperature", opt->clone());
} else {
this->placeholder_parser().set("first_layer_bed_temperature", new ConfigOptionInts(print.config().first_layer_bed_temperature.values));
}
if (const ConfigOption *opt = cfg.optptr("chamber_temperature")) {
this->placeholder_parser().set("chamber_temperature", opt->clone());
} else {
this->placeholder_parser().set("chamber_temperature", new ConfigOptionInts(print.config().chamber_temperature.values));
}
}
{ {
const char *bed_type_label = (print.config().elegoolink_bed_type.value == ElegooBedType::PTE) ? "Side A" : "Side B"; const char *bed_type_label = (print.config().elegoolink_bed_type.value == ElegooBedType::PTE) ? "Side A" : "Side B";
this->placeholder_parser().set("curr_bed_type", new ConfigOptionString(bed_type_label)); this->placeholder_parser().set("curr_bed_type", new ConfigOptionString(bed_type_label));
@@ -1214,7 +1263,7 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
this->placeholder_parser().set("print_bed_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() })); this->placeholder_parser().set("print_bed_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() }));
this->placeholder_parser().set("print_bed_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() })); this->placeholder_parser().set("print_bed_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() }));
} }
if (host_is_klipper) { {
// Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line. // Convex hull of the 1st layer extrusions, for bed leveling and placing the initial purge line.
// It encompasses the object extrusions, support extrusions, skirt, brim, wipe tower. // It encompasses the object extrusions, support extrusions, skirt, brim, wipe tower.
// It does NOT encompass user extrusions generated by custom G-code, // It does NOT encompass user extrusions generated by custom G-code,
@@ -1224,21 +1273,22 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
pts->values.reserve(print.first_layer_convex_hull().size()); pts->values.reserve(print.first_layer_convex_hull().size());
for (const Point &pt : print.first_layer_convex_hull().points) for (const Point &pt : print.first_layer_convex_hull().points)
pts->values.emplace_back(unscale(pt)); pts->values.emplace_back(unscale(pt));
BoundingBoxf bbox(pts->values); BoundingBoxf first_layer_bbox(pts->values);
this->placeholder_parser().set("first_layer_print_convex_hull", pts.release()); this->placeholder_parser().set("first_layer_print_convex_hull", pts.release());
this->placeholder_parser().set("first_layer_print_min", new ConfigOptionFloats({ bbox.min.x(), bbox.min.y() })); this->placeholder_parser().set("first_layer_print_min", new ConfigOptionFloats({ first_layer_bbox.min.x(), first_layer_bbox.min.y() }));
this->placeholder_parser().set("first_layer_print_max", new ConfigOptionFloats({ bbox.max.x(), bbox.max.y() })); this->placeholder_parser().set("first_layer_print_max", new ConfigOptionFloats({ first_layer_bbox.max.x(), first_layer_bbox.max.y() }));
this->placeholder_parser().set("first_layer_print_size", new ConfigOptionFloats({ bbox.size().x(), bbox.size().y() })); this->placeholder_parser().set("first_layer_print_size", new ConfigOptionFloats({ first_layer_bbox.size().x(), first_layer_bbox.size().y() }));
this->placeholder_parser().set("num_extruders", int(print.config().nozzle_diameter.values.size())); this->placeholder_parser().set("num_extruders", int(print.config().nozzle_diameter.values.size()));
if (host_is_klipper) {
BoundingBoxf bed_bbox(print.config().bed_shape.values); BoundingBoxf bed_bbox(print.config().bed_shape.values);
BoundingBoxf mesh_bbox = bbox; BoundingBoxf mesh_bbox = first_layer_bbox;
if (bed_bbox.defined) { if (bed_bbox.defined) {
const double margin = print.config().adaptive_bed_mesh_margin.value; const double margin = print.config().adaptive_bed_mesh_margin.value;
double min_x = bbox.min.x() - margin; double min_x = first_layer_bbox.min.x() - margin;
double min_y = bbox.min.y() - margin; double min_y = first_layer_bbox.min.y() - margin;
double max_x = bbox.max.x() + margin; double max_x = first_layer_bbox.max.x() + margin;
double max_y = bbox.max.y() + margin; double max_y = first_layer_bbox.max.y() + margin;
min_x = std::max(min_x, bed_bbox.min.x()); min_x = std::max(min_x, bed_bbox.min.x());
min_y = std::max(min_y, bed_bbox.min.y()); min_y = std::max(min_y, bed_bbox.min.y());
@@ -1277,6 +1327,10 @@ void GCodeGenerator::_do_export(Print& print, GCodeOutputStream &file, Thumbnail
this->placeholder_parser().set("bed_mesh_probe_count", new ConfigOptionInts({ probe_count_x, probe_count_y })); this->placeholder_parser().set("bed_mesh_probe_count", new ConfigOptionInts({ probe_count_x, probe_count_y }));
adaptive_bed_mesh_algo = (probe_count_x < 4 || probe_count_y < 4) ? "lagrange" : "bicubic"; adaptive_bed_mesh_algo = (probe_count_x < 4 || probe_count_y < 4) ? "lagrange" : "bicubic";
this->placeholder_parser().set("bed_mesh_algo", new ConfigOptionString(adaptive_bed_mesh_algo)); this->placeholder_parser().set("bed_mesh_algo", new ConfigOptionString(adaptive_bed_mesh_algo));
}
}
{
// PlaceholderParser currently substitues non-existent vector values with the zero'th value, which is harmful in the case of "is_extruder_used[]" // PlaceholderParser currently substitues non-existent vector values with the zero'th value, which is harmful in the case of "is_extruder_used[]"
// as Slicer may lie about availability of such non-existent extruder. // as Slicer may lie about availability of such non-existent extruder.
// We rather sacrifice 256B of memory before we change the behavior of the PlaceholderParser, which should really only fill in the non-existent // We rather sacrifice 256B of memory before we change the behavior of the PlaceholderParser, which should really only fill in the non-existent
@@ -1829,6 +1883,34 @@ std::string GCodeGenerator::placeholder_parser_process(
} }
catch (std::runtime_error &err) catch (std::runtime_error &err)
{ {
// Retry with legacy placeholders for simple {name} / {name[idx]} patterns.
if (std::string(err.what()).find("Not a variable name") != std::string::npos) {
const std::string compat_templ = rewrite_simple_curly_placeholders_to_legacy(templ);
if (compat_templ != templ) {
ppi.update_from_gcodewriter(m_writer, m_print->wipe_tower_data());
std::string output = ppi.parser.process(compat_templ, current_extruder_id, config_override, &ppi.output_config, &ppi.context);
ppi.validate_output_vector_variables();
if (const std::vector<double> &pos = ppi.opt_position->values; ppi.position != pos) {
m_writer.update_position({ pos[0], pos[1], pos[2] });
this->last_position = this->gcode_to_point({ pos[0], pos[1] });
}
for (const Extruder &e : m_writer.extruders()) {
unsigned int eid = e.id();
assert(eid < ppi.num_extruders);
if ( eid < ppi.num_extruders) {
if (! m_writer.config.use_relative_e_distances && ! is_approx(ppi.e_position[eid], ppi.opt_e_position->values[eid]))
const_cast<Extruder&>(e).set_position(ppi.opt_e_position->values[eid]);
if (! is_approx(ppi.e_retracted[eid], ppi.opt_e_retracted->values[eid]) ||
! is_approx(ppi.e_restart_extra[eid], ppi.opt_e_restart_extra->values[eid]))
const_cast<Extruder&>(e).set_retracted(ppi.opt_e_retracted->values[eid], ppi.opt_e_restart_extra->values[eid]);
}
}
return output;
}
}
// Collect the names of failed template substitutions for error reporting. // Collect the names of failed template substitutions for error reporting.
auto it = ppi.failed_templates.find(name); auto it = ppi.failed_templates.find(name);
if (it == ppi.failed_templates.end()) if (it == ppi.failed_templates.end())
@@ -1022,6 +1022,8 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone()); m_placeholder_parser.set("filament_preset", new_full_config.option("filament_settings_id")->clone());
m_placeholder_parser.set("printer_preset", new_full_config.option("printer_settings_id")->clone()); m_placeholder_parser.set("printer_preset", new_full_config.option("printer_settings_id")->clone());
m_placeholder_parser.set("physical_printer_preset", new_full_config.option("physical_printer_settings_id")->clone()); m_placeholder_parser.set("physical_printer_preset", new_full_config.option("physical_printer_settings_id")->clone());
// Make all config options available to the PlaceholderParser.
m_placeholder_parser.apply_config(new_full_config);
// We want the filament overrides to be applied over their respective extruder parameters by the PlaceholderParser. // We want the filament overrides to be applied over their respective extruder parameters by the PlaceholderParser.
// see "Placeholders do not respect filament overrides." GH issue #3649 // see "Placeholders do not respect filament overrides." GH issue #3649
m_placeholder_parser.apply_config(filament_overrides); m_placeholder_parser.apply_config(filament_overrides);