diff --git a/src/OrcaSlicer.cpp b/src/OrcaSlicer.cpp index d3e24437fb..499e73d073 100644 --- a/src/OrcaSlicer.cpp +++ b/src/OrcaSlicer.cpp @@ -3846,9 +3846,94 @@ int CLI::run(int argc, char **argv) } } + //ORCA: settings passed on the command line (--sparse-infill-density 25% ...) override the loaded + // presets right here, so they belong in different_settings_to_system just as a preset + // override does. Without them re-opening the exported project in the GUI shows nothing + // modified and reverts those values to the system presets'. + // + // The keys come from m_config, not m_extra_config: read_cli() puts only what the user typed + // into m_config (setup() adds nothing but CLI-own defaults), whereas the CLI writes its own + // values into m_extra_config. Only keys whose value the override actually changed are + // recorded -- a typed value equal to the loaded one modifies nothing -- and each lands in + // the column(s) whose preset type owns it: [0] process, [1..n-2] filaments, [n-1] printer. + // + // "Changed" is judged the way the value is read: a list is compared entry by entry with a + // missing entry read as the first, as get_at() does -- so --nozzle-temperature 245 against + // 245,245,245 is no change, although the two serialize differently. + // + // A key the loaded config does not carry at all is always recorded, even if the typed value + // equals the built-in default. On reopen the GUI restores an unlisted key from the SYSTEM + // preset, which need not match that default: a 3MF written before an option existed leaves + // it absent here, and --sparse-infill-density 20% (the default) against a Prusa system 15% + // would otherwise go unrecorded and be reverted. Over-recording is cosmetic; under-recording + // loses the value. + std::map> cli_override_before; + for (const std::string &key : m_config.keys()) { + if (!m_extra_config.has(key)) + continue; + const ConfigOption *loaded = m_print_config.option(key); + cli_override_before[key].reset(loaded != nullptr ? loaded->clone() : nullptr); // null: always recorded + } + // Apply command line options to a more specific DynamicPrintConfig which provides normalize() // (command line options override --load files) m_print_config.apply(m_extra_config, true); + + if (!cli_override_before.empty()) { + std::vector &columns = m_print_config.option("different_settings_to_system", true)->values; + auto owned_by = [](const std::vector &options, const std::string &key) { + return std::find(options.begin(), options.end(), key) != options.end(); + }; + auto add_to_column = [&columns](size_t index, const std::string &key) { + std::vector keys; + Slic3r::unescape_strings_cstyle(columns[index], keys); + if (std::find(keys.begin(), keys.end(), key) == keys.end()) { + keys.push_back(key); + columns[index] = Slic3r::escape_strings_cstyle(keys); + } + }; + auto same_value = [](const ConfigOption *a, const ConfigOption *b) { + if (a == nullptr || b == nullptr) + return false; + const auto *va = dynamic_cast(a); + const auto *vb = dynamic_cast(b); + if (va == nullptr || vb == nullptr) + return va == vb && a->serialize() == b->serialize(); + const std::vector ea = va->vserialize(), eb = vb->vserialize(); + if (ea.empty() || eb.empty()) + return ea.empty() && eb.empty(); + for (size_t i = 0; i < std::max(ea.size(), eb.size()); ++i) + if (ea[i < ea.size() ? i : 0] != eb[i < eb.size() ? i : 0]) + return false; + return true; + }; + //ORCA: always true after the resize to filament_count + 2 above, and nothing in between can + // shrink the column vector -- different_settings_to_system is not a CLI option. Kept as + // a check rather than an assert: release builds compile asserts out, so an assert would + // protect nothing, while a build with _GLIBCXX_ASSERTIONS would abort on columns[0]. + if (columns.size() >= 2) { + for (const auto &[key, before] : cli_override_before) { + if (same_value(before.get(), m_print_config.option(key))) + continue; + bool recorded = false; + if (owned_by(Preset::print_options(), key)) { + add_to_column(0, key); + recorded = true; + } + if (owned_by(Preset::filament_options(), key)) { + for (size_t i = 1; i + 1 < columns.size(); ++i) + add_to_column(i, key); + recorded = true; + } + if (owned_by(Preset::printer_options(), key)) { + add_to_column(columns.size() - 1, key); + recorded = true; + } + if (recorded) + BOOST_LOG_TRIVIAL(info) << boost::format("CLI: override %1% recorded in different_settings_to_system") % key; + } + } + } // Normalizing after importing the 3MFs / AMFs m_print_config.normalize_fdm();