Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_gcode_viewer

This commit is contained in:
enricoturri1966 2020-08-10 14:22:46 +02:00
commit dea641183c
62 changed files with 3519 additions and 1865 deletions

403
src/libslic3r/AppConfig.cpp Normal file
View file

@ -0,0 +1,403 @@
#include "libslic3r/libslic3r.h"
#include "libslic3r/Utils.hpp"
#include "AppConfig.hpp"
#include <utility>
#include <vector>
#include <stdexcept>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/nowide/cenv.hpp>
#include <boost/nowide/fstream.hpp>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree_fwd.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/format/format_fwd.hpp>
//#include <wx/string.h>
//#include "I18N.hpp"
namespace Slic3r {
static const std::string VENDOR_PREFIX = "vendor:";
static const std::string MODEL_PREFIX = "model:";
static const std::string VERSION_CHECK_URL = "https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/PrusaSlicer.version";
const std::string AppConfig::SECTION_FILAMENTS = "filaments";
const std::string AppConfig::SECTION_MATERIALS = "sla_materials";
void AppConfig::reset()
{
m_storage.clear();
set_defaults();
};
// Override missing or keys with their defaults.
void AppConfig::set_defaults()
{
// Reset the empty fields to defaults.
if (get("autocenter").empty())
set("autocenter", "0");
// Disable background processing by default as it is not stable.
if (get("background_processing").empty())
set("background_processing", "0");
// If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden.
// By default, Prusa has the controller hidden.
if (get("no_controller").empty())
set("no_controller", "1");
// If set, the "- default -" selections of print/filament/printer are suppressed, if there is a valid preset available.
if (get("no_defaults").empty())
set("no_defaults", "1");
if (get("show_incompatible_presets").empty())
set("show_incompatible_presets", "0");
if (get("version_check").empty())
set("version_check", "1");
if (get("preset_update").empty())
set("preset_update", "1");
if (get("export_sources_full_pathnames").empty())
set("export_sources_full_pathnames", "0");
// remove old 'use_legacy_opengl' parameter from this config, if present
if (!get("use_legacy_opengl").empty())
erase("", "use_legacy_opengl");
#ifdef __APPLE__
if (get("use_retina_opengl").empty())
set("use_retina_opengl", "1");
#endif
if (get("single_instance").empty())
set("single_instance", "0");
if (get("remember_output_path").empty())
set("remember_output_path", "1");
if (get("remember_output_path_removable").empty())
set("remember_output_path_removable", "1");
if (get("use_custom_toolbar_size").empty())
set("use_custom_toolbar_size", "0");
if (get("custom_toolbar_size").empty())
set("custom_toolbar_size", "100");
if (get("auto_toolbar_size").empty())
set("auto_toolbar_size", "100");
if (get("use_perspective_camera").empty())
set("use_perspective_camera", "1");
if (get("use_free_camera").empty())
set("use_free_camera", "0");
#if ENABLE_ENVIRONMENT_MAP
if (get("use_environment_map").empty())
set("use_environment_map", "0");
#endif // ENABLE_ENVIRONMENT_MAP
if (get("use_inches").empty())
set("use_inches", "0");
// Remove legacy window positions/sizes
erase("", "main_frame_maximized");
erase("", "main_frame_pos");
erase("", "main_frame_size");
erase("", "object_settings_maximized");
erase("", "object_settings_pos");
erase("", "object_settings_size");
}
std::string AppConfig::load()
{
// 1) Read the complete config file into a boost::property_tree.
namespace pt = boost::property_tree;
pt::ptree tree;
boost::nowide::ifstream ifs(AppConfig::config_path());
try {
pt::read_ini(ifs, tree);
} catch (pt::ptree_error& ex) {
// Error while parsing config file. We'll customize the error message and rethrow to be displayed.
// ! But to avoid the use of _utf8 (related to use of wxWidgets)
// we will rethrow this exception from the place of load() call, if returned value wouldn't be empty
/*
throw std::runtime_error(
_utf8(L("Error parsing PrusaSlicer config file, it is probably corrupted. "
"Try to manually delete the file to recover from the error. Your user profiles will not be affected.")) +
"\n\n" + AppConfig::config_path() + "\n\n" + ex.what());
*/
return ex.what();
}
// 2) Parse the property_tree, extract the sections and key / value pairs.
for (const auto &section : tree) {
if (section.second.empty()) {
// This may be a top level (no section) entry, or an empty section.
std::string data = section.second.data();
if (! data.empty())
// If there is a non-empty data, then it must be a top-level (without a section) config entry.
m_storage[""][section.first] = data;
} else if (boost::starts_with(section.first, VENDOR_PREFIX)) {
// This is a vendor section listing enabled model / variants
const auto vendor_name = section.first.substr(VENDOR_PREFIX.size());
auto &vendor = m_vendors[vendor_name];
for (const auto &kvp : section.second) {
if (! boost::starts_with(kvp.first, MODEL_PREFIX)) { continue; }
const auto model_name = kvp.first.substr(MODEL_PREFIX.size());
std::vector<std::string> variants;
if (! unescape_strings_cstyle(kvp.second.data(), variants)) { continue; }
for (const auto &variant : variants) {
vendor[model_name].insert(variant);
}
}
} else {
// This must be a section name. Read the entries of a section.
std::map<std::string, std::string> &storage = m_storage[section.first];
for (auto &kvp : section.second)
storage[kvp.first] = kvp.second.data();
}
}
// Figure out if datadir has legacy presets
auto ini_ver = Semver::parse(get("version"));
m_legacy_datadir = false;
if (ini_ver) {
m_orig_version = *ini_ver;
// Make 1.40.0 alphas compare well
ini_ver->set_metadata(boost::none);
ini_ver->set_prerelease(boost::none);
m_legacy_datadir = ini_ver < Semver(1, 40, 0);
}
// Override missing or keys with their defaults.
this->set_defaults();
m_dirty = false;
return "";
}
void AppConfig::save()
{
// The config is first written to a file with a PID suffix and then moved
// to avoid race conditions with multiple instances of Slic3r
const auto path = config_path();
std::string path_pid = (boost::format("%1%.%2%") % path % get_current_pid()).str();
boost::nowide::ofstream c;
c.open(path_pid, std::ios::out | std::ios::trunc);
c << "# " << Slic3r::header_slic3r_generated() << std::endl;
// Make sure the "no" category is written first.
for (const std::pair<std::string, std::string> &kvp : m_storage[""])
c << kvp.first << " = " << kvp.second << std::endl;
// Write the other categories.
for (const auto category : m_storage) {
if (category.first.empty())
continue;
c << std::endl << "[" << category.first << "]" << std::endl;
for (const std::pair<std::string, std::string> &kvp : category.second)
c << kvp.first << " = " << kvp.second << std::endl;
}
// Write vendor sections
for (const auto &vendor : m_vendors) {
size_t size_sum = 0;
for (const auto &model : vendor.second) { size_sum += model.second.size(); }
if (size_sum == 0) { continue; }
c << std::endl << "[" << VENDOR_PREFIX << vendor.first << "]" << std::endl;
for (const auto &model : vendor.second) {
if (model.second.size() == 0) { continue; }
const std::vector<std::string> variants(model.second.begin(), model.second.end());
const auto escaped = escape_strings_cstyle(variants);
c << MODEL_PREFIX << model.first << " = " << escaped << std::endl;
}
}
c.close();
rename_file(path_pid, path);
m_dirty = false;
}
bool AppConfig::get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const
{
const auto it_v = m_vendors.find(vendor);
if (it_v == m_vendors.end()) { return false; }
const auto it_m = it_v->second.find(model);
return it_m == it_v->second.end() ? false : it_m->second.find(variant) != it_m->second.end();
}
void AppConfig::set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable)
{
if (enable) {
if (get_variant(vendor, model, variant)) { return; }
m_vendors[vendor][model].insert(variant);
} else {
auto it_v = m_vendors.find(vendor);
if (it_v == m_vendors.end()) { return; }
auto it_m = it_v->second.find(model);
if (it_m == it_v->second.end()) { return; }
auto it_var = it_m->second.find(variant);
if (it_var == it_m->second.end()) { return; }
it_m->second.erase(it_var);
}
// If we got here, there was an update
m_dirty = true;
}
void AppConfig::set_vendors(const AppConfig &from)
{
m_vendors = from.m_vendors;
m_dirty = true;
}
std::string AppConfig::get_last_dir() const
{
const auto it = m_storage.find("recent");
if (it != m_storage.end()) {
{
const auto it2 = it->second.find("skein_directory");
if (it2 != it->second.end() && ! it2->second.empty())
return it2->second;
}
{
const auto it2 = it->second.find("config_directory");
if (it2 != it->second.end() && ! it2->second.empty())
return it2->second;
}
}
return std::string();
}
std::vector<std::string> AppConfig::get_recent_projects() const
{
std::vector<std::string> ret;
const auto it = m_storage.find("recent_projects");
if (it != m_storage.end())
{
for (const std::map<std::string, std::string>::value_type& item : it->second)
{
ret.push_back(item.second);
}
}
return ret;
}
void AppConfig::set_recent_projects(const std::vector<std::string>& recent_projects)
{
auto it = m_storage.find("recent_projects");
if (it == m_storage.end())
it = m_storage.insert(std::map<std::string, std::map<std::string, std::string>>::value_type("recent_projects", std::map<std::string, std::string>())).first;
it->second.clear();
for (unsigned int i = 0; i < (unsigned int)recent_projects.size(); ++i)
{
it->second[std::to_string(i + 1)] = recent_projects[i];
}
}
void AppConfig::set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed, bool swap_yz)
{
std::string key = std::string("mouse_device:") + name;
auto it = m_storage.find(key);
if (it == m_storage.end())
it = m_storage.insert(std::map<std::string, std::map<std::string, std::string>>::value_type(key, std::map<std::string, std::string>())).first;
it->second.clear();
it->second["translation_speed"] = std::to_string(translation_speed);
it->second["translation_deadzone"] = std::to_string(translation_deadzone);
it->second["rotation_speed"] = std::to_string(rotation_speed);
it->second["rotation_deadzone"] = std::to_string(rotation_deadzone);
it->second["zoom_speed"] = std::to_string(zoom_speed);
it->second["swap_yz"] = swap_yz ? "1" : "0";
}
std::vector<std::string> AppConfig::get_mouse_device_names() const
{
static constexpr const char *prefix = "mouse_device:";
static const size_t prefix_len = strlen(prefix);
std::vector<std::string> out;
for (const std::pair<std::string, std::map<std::string, std::string>>& key_value_pair : m_storage)
if (boost::starts_with(key_value_pair.first, prefix) && key_value_pair.first.size() > prefix_len)
out.emplace_back(key_value_pair.first.substr(prefix_len));
return out;
}
void AppConfig::update_config_dir(const std::string &dir)
{
this->set("recent", "config_directory", dir);
}
void AppConfig::update_skein_dir(const std::string &dir)
{
this->set("recent", "skein_directory", dir);
}
/*
std::string AppConfig::get_last_output_dir(const std::string &alt) const
{
const auto it = m_storage.find("");
if (it != m_storage.end()) {
const auto it2 = it->second.find("last_output_path");
const auto it3 = it->second.find("remember_output_path");
if (it2 != it->second.end() && it3 != it->second.end() && ! it2->second.empty() && it3->second == "1")
return it2->second;
}
return alt;
}
void AppConfig::update_last_output_dir(const std::string &dir)
{
this->set("", "last_output_path", dir);
}
*/
std::string AppConfig::get_last_output_dir(const std::string& alt, const bool removable) const
{
std::string s1 = (removable ? "last_output_path_removable" : "last_output_path");
std::string s2 = (removable ? "remember_output_path_removable" : "remember_output_path");
const auto it = m_storage.find("");
if (it != m_storage.end()) {
const auto it2 = it->second.find(s1);
const auto it3 = it->second.find(s2);
if (it2 != it->second.end() && it3 != it->second.end() && !it2->second.empty() && it3->second == "1")
return it2->second;
}
return alt;
}
void AppConfig::update_last_output_dir(const std::string& dir, const bool removable)
{
this->set("", (removable ? "last_output_path_removable" : "last_output_path"), dir);
}
void AppConfig::reset_selections()
{
auto it = m_storage.find("presets");
if (it != m_storage.end()) {
it->second.erase("print");
it->second.erase("filament");
it->second.erase("sla_print");
it->second.erase("sla_material");
it->second.erase("printer");
m_dirty = true;
}
}
std::string AppConfig::config_path()
{
return (boost::filesystem::path(Slic3r::data_dir()) / (SLIC3R_APP_KEY ".ini")).make_preferred().string();
}
std::string AppConfig::version_check_url() const
{
auto from_settings = get("version_check_url");
return from_settings.empty() ? VERSION_CHECK_URL : from_settings;
}
bool AppConfig::exists()
{
return boost::filesystem::exists(AppConfig::config_path());
}
}; // namespace Slic3r

192
src/libslic3r/AppConfig.hpp Normal file
View file

@ -0,0 +1,192 @@
#ifndef slic3r_AppConfig_hpp_
#define slic3r_AppConfig_hpp_
#include <set>
#include <map>
#include <string>
#include <boost/algorithm/string/trim_all.hpp>
#include "libslic3r/Config.hpp"
#include "libslic3r/Semver.hpp"
namespace Slic3r {
class AppConfig
{
public:
AppConfig() :
m_dirty(false),
m_orig_version(Semver::invalid()),
m_legacy_datadir(false)
{
this->reset();
}
// Clear and reset to defaults.
void reset();
// Override missing or keys with their defaults.
void set_defaults();
// Load the slic3r.ini from a user profile directory (or a datadir, if configured).
// return error string or empty strinf
std::string load();
// Store the slic3r.ini into a user profile directory (or a datadir, if configured).
void save();
// Does this config need to be saved?
bool dirty() const { return m_dirty; }
// Const accessor, it will return false if a section or a key does not exist.
bool get(const std::string &section, const std::string &key, std::string &value) const
{
value.clear();
auto it = m_storage.find(section);
if (it == m_storage.end())
return false;
auto it2 = it->second.find(key);
if (it2 == it->second.end())
return false;
value = it2->second;
return true;
}
std::string get(const std::string &section, const std::string &key) const
{ std::string value; this->get(section, key, value); return value; }
std::string get(const std::string &key) const
{ std::string value; this->get("", key, value); return value; }
void set(const std::string &section, const std::string &key, const std::string &value)
{
#ifndef _NDEBUG
std::string key_trimmed = key;
boost::trim_all(key_trimmed);
assert(key_trimmed == key);
assert(! key_trimmed.empty());
#endif // _NDEBUG
std::string &old = m_storage[section][key];
if (old != value) {
old = value;
m_dirty = true;
}
}
void set(const std::string &key, const std::string &value)
{ this->set("", key, value); }
bool has(const std::string &section, const std::string &key) const
{
auto it = m_storage.find(section);
if (it == m_storage.end())
return false;
auto it2 = it->second.find(key);
return it2 != it->second.end() && ! it2->second.empty();
}
bool has(const std::string &key) const
{ return this->has("", key); }
void erase(const std::string &section, const std::string &key)
{
auto it = m_storage.find(section);
if (it != m_storage.end()) {
it->second.erase(key);
}
}
bool has_section(const std::string &section) const
{ return m_storage.find(section) != m_storage.end(); }
const std::map<std::string, std::string>& get_section(const std::string &section) const
{ return m_storage.find(section)->second; }
void set_section(const std::string &section, const std::map<std::string, std::string>& data)
{ m_storage[section] = data; }
void clear_section(const std::string &section)
{ m_storage[section].clear(); }
typedef std::map<std::string, std::map<std::string, std::set<std::string>>> VendorMap;
bool get_variant(const std::string &vendor, const std::string &model, const std::string &variant) const;
void set_variant(const std::string &vendor, const std::string &model, const std::string &variant, bool enable);
void set_vendors(const AppConfig &from);
void set_vendors(const VendorMap &vendors) { m_vendors = vendors; m_dirty = true; }
void set_vendors(VendorMap &&vendors) { m_vendors = std::move(vendors); m_dirty = true; }
const VendorMap& vendors() const { return m_vendors; }
// return recent/skein_directory or recent/config_directory or empty string.
std::string get_last_dir() const;
void update_config_dir(const std::string &dir);
void update_skein_dir(const std::string &dir);
//std::string get_last_output_dir(const std::string &alt) const;
//void update_last_output_dir(const std::string &dir);
std::string get_last_output_dir(const std::string& alt, const bool removable = false) const;
void update_last_output_dir(const std::string &dir, const bool removable = false);
// reset the current print / filament / printer selections, so that
// the PresetBundle::load_selections(const AppConfig &config) call will select
// the first non-default preset when called.
void reset_selections();
// Get the default config path from Slic3r::data_dir().
static std::string config_path();
// Returns true if the user's data directory comes from before Slic3r 1.40.0 (no updating)
bool legacy_datadir() const { return m_legacy_datadir; }
void set_legacy_datadir(bool value) { m_legacy_datadir = value; }
// Get the Slic3r version check url.
// This returns a hardcoded string unless it is overriden by "version_check_url" in the ini file.
std::string version_check_url() const;
// Returns the original Slic3r version found in the ini file before it was overwritten
// by the current version
Semver orig_version() const { return m_orig_version; }
// Does the config file exist?
static bool exists();
std::vector<std::string> get_recent_projects() const;
void set_recent_projects(const std::vector<std::string>& recent_projects);
void set_mouse_device(const std::string& name, double translation_speed, double translation_deadzone, float rotation_speed, float rotation_deadzone, double zoom_speed, bool swap_yz);
std::vector<std::string> get_mouse_device_names() const;
bool get_mouse_device_translation_speed(const std::string& name, double& speed) const
{ return get_3dmouse_device_numeric_value(name, "translation_speed", speed); }
bool get_mouse_device_translation_deadzone(const std::string& name, double& deadzone) const
{ return get_3dmouse_device_numeric_value(name, "translation_deadzone", deadzone); }
bool get_mouse_device_rotation_speed(const std::string& name, float& speed) const
{ return get_3dmouse_device_numeric_value(name, "rotation_speed", speed); }
bool get_mouse_device_rotation_deadzone(const std::string& name, float& deadzone) const
{ return get_3dmouse_device_numeric_value(name, "rotation_deadzone", deadzone); }
bool get_mouse_device_zoom_speed(const std::string& name, double& speed) const
{ return get_3dmouse_device_numeric_value(name, "zoom_speed", speed); }
bool get_mouse_device_swap_yz(const std::string& name, bool& swap) const
{ return get_3dmouse_device_numeric_value(name, "swap_yz", swap); }
static const std::string SECTION_FILAMENTS;
static const std::string SECTION_MATERIALS;
private:
template<typename T>
bool get_3dmouse_device_numeric_value(const std::string &device_name, const char *parameter_name, T &out) const
{
std::string key = std::string("mouse_device:") + device_name;
auto it = m_storage.find(key);
if (it == m_storage.end())
return false;
auto it_val = it->second.find(parameter_name);
if (it_val == it->second.end())
return false;
out = T(::atof(it_val->second.c_str()));
return true;
}
// Map of section, name -> value
std::map<std::string, std::map<std::string, std::string>> m_storage;
// Map of enabled vendors / models / variants
VendorMap m_vendors;
// Has any value been modified since the config.ini has been last saved or loaded?
bool m_dirty;
// Original version found in the ini file before it was overwritten
Semver m_orig_version;
// Whether the existing version is before system profiles & configuration updating
bool m_legacy_datadir;
};
}; // namespace Slic3r
#endif /* slic3r_AppConfig_hpp_ */

View file

@ -149,6 +149,12 @@ add_library(libslic3r STATIC
PolygonTrimmer.hpp
Polyline.cpp
Polyline.hpp
Preset.cpp
Preset.hpp
PresetBundle.cpp
PresetBundle.hpp
AppConfig.cpp
AppConfig.hpp
Print.cpp
Print.hpp
PrintBase.cpp

View file

@ -1878,10 +1878,11 @@ namespace Slic3r {
volume->calculate_convex_hull();
// recreate custom supports from previously loaded attribute
assert(geometry.custom_supports.size() == triangles_count);
for (unsigned i=0; i<triangles_count; ++i) {
if (! geometry.custom_supports[i].empty())
volume->m_supported_facets.set_triangle_from_string(i, geometry.custom_supports[i]);
size_t index = src_start_id/3 + i;
assert(index < geometry.custom_supports.size());
if (! geometry.custom_supports[index].empty())
volume->m_supported_facets.set_triangle_from_string(i, geometry.custom_supports[index]);
}
// apply the remaining volume's metadata

1817
src/libslic3r/Preset.cpp Normal file

File diff suppressed because it is too large Load diff

734
src/libslic3r/Preset.hpp Normal file
View file

@ -0,0 +1,734 @@
#ifndef slic3r_Preset_hpp_
#define slic3r_Preset_hpp_
#include <deque>
#include <set>
#include <unordered_map>
#include <boost/filesystem/path.hpp>
#include <boost/property_tree/ptree_fwd.hpp>
#include "PrintConfig.hpp"
#include "Semver.hpp"
namespace Slic3r {
class AppConfig;
class PresetBundle;
enum ConfigFileType
{
CONFIG_FILE_TYPE_UNKNOWN,
CONFIG_FILE_TYPE_APP_CONFIG,
CONFIG_FILE_TYPE_CONFIG,
CONFIG_FILE_TYPE_CONFIG_BUNDLE,
};
extern ConfigFileType guess_config_file_type(const boost::property_tree::ptree &tree);
class VendorProfile
{
public:
std::string name;
std::string id;
Semver config_version;
std::string config_update_url;
std::string changelog_url;
struct PrinterVariant {
PrinterVariant() {}
PrinterVariant(const std::string &name) : name(name) {}
std::string name;
};
struct PrinterModel {
PrinterModel() {}
std::string id;
std::string name;
PrinterTechnology technology;
std::string family;
std::vector<PrinterVariant> variants;
std::vector<std::string> default_materials;
// Vendor & Printer Model specific print bed model & texture.
std::string bed_model;
std::string bed_texture;
PrinterVariant* variant(const std::string &name) {
for (auto &v : this->variants)
if (v.name == name)
return &v;
return nullptr;
}
const PrinterVariant* variant(const std::string &name) const { return const_cast<PrinterModel*>(this)->variant(name); }
};
std::vector<PrinterModel> models;
std::set<std::string> default_filaments;
std::set<std::string> default_sla_materials;
VendorProfile() {}
VendorProfile(std::string id) : id(std::move(id)) {}
bool valid() const { return ! name.empty() && ! id.empty() && config_version.valid(); }
// Load VendorProfile from an ini file.
// If `load_all` is false, only the header with basic info (name, version, URLs) is loaded.
static VendorProfile from_ini(const boost::filesystem::path &path, bool load_all=true);
static VendorProfile from_ini(const boost::property_tree::ptree &tree, const boost::filesystem::path &path, bool load_all=true);
size_t num_variants() const { size_t n = 0; for (auto &model : models) n += model.variants.size(); return n; }
std::vector<std::string> families() const;
bool operator< (const VendorProfile &rhs) const { return this->id < rhs.id; }
bool operator==(const VendorProfile &rhs) const { return this->id == rhs.id; }
};
class Preset;
// Helper to hold a profile with its vendor definition, where the vendor definition may have been extracted from a parent system preset.
// The parent preset is only accessible through PresetCollection, therefore to allow definition of the various is_compatible_with methods
// outside of the PresetCollection, this composite is returned by PresetCollection::get_preset_with_vendor_profile() when needed.
struct PresetWithVendorProfile {
PresetWithVendorProfile(const Preset &preset, const VendorProfile *vendor) : preset(preset), vendor(vendor) {}
const Preset &preset;
const VendorProfile *vendor;
};
// Note: it is imporant that map is used here rather than unordered_map,
// because we need iterators to not be invalidated,
// because Preset and the ConfigWizard hold pointers to VendorProfiles.
// XXX: maybe set is enough (cf. changes in Wizard)
typedef std::map<std::string, VendorProfile> VendorMap;
class Preset
{
public:
enum Type
{
TYPE_INVALID,
TYPE_PRINT,
TYPE_SLA_PRINT,
TYPE_FILAMENT,
TYPE_SLA_MATERIAL,
TYPE_PRINTER,
TYPE_COUNT,
};
Preset(Type type, const std::string &name, bool is_default = false) : type(type), is_default(is_default), name(name) {}
Type type = TYPE_INVALID;
// The preset represents a "default" set of properties,
// pulled from the default values of the PrintConfig (see PrintConfigDef for their definitions).
bool is_default;
// External preset points to a configuration, which has been loaded but not imported
// into the Slic3r default configuration location.
bool is_external = false;
// System preset is read-only.
bool is_system = false;
// Preset is visible, if it is associated with a printer model / variant that is enabled in the AppConfig
// or if it has no printer model / variant association.
// Also the "default" preset is only visible, if it is the only preset in the list.
bool is_visible = true;
// Has this preset been modified?
bool is_dirty = false;
// Is this preset compatible with the currently active printer?
bool is_compatible = true;
bool is_user() const { return ! this->is_default && ! this->is_system; }
// Name of the preset, usually derived form the file name.
std::string name;
// File name of the preset. This could be a Print / Filament / Printer preset,
// or a Configuration file bundling the Print + Filament + Printer presets (in that case is_external and possibly is_system will be true),
// or it could be a G-code (again, is_external will be true).
std::string file;
// If this is a system profile, then there should be a vendor data available to display at the UI.
const VendorProfile *vendor = nullptr;
// Has this profile been loaded?
bool loaded = false;
// Configuration data, loaded from a file, or set from the defaults.
DynamicPrintConfig config;
// Alias of the preset
std::string alias;
// List of profile names, from which this profile was renamed at some point of time.
// This list is then used to match profiles by their names when loaded from .gcode, .3mf, .amf,
// and to match the "inherits" field of user profiles with updated system profiles.
std::vector<std::string> renamed_from;
void save();
// Return a label of this preset, consisting of a name and a "(modified)" suffix, if this preset is dirty.
std::string label() const;
// Set the is_dirty flag if the provided config is different from the active one.
void set_dirty(const DynamicPrintConfig &config) { this->is_dirty = ! this->config.diff(config).empty(); }
void set_dirty(bool dirty = true) { this->is_dirty = dirty; }
void reset_dirty() { this->is_dirty = false; }
// Returns the name of the preset, from which this preset inherits.
static std::string& inherits(DynamicPrintConfig &cfg) { return cfg.option<ConfigOptionString>("inherits", true)->value; }
std::string& inherits() { return Preset::inherits(this->config); }
const std::string& inherits() const { return Preset::inherits(const_cast<Preset*>(this)->config); }
// Returns the "compatible_prints_condition".
static std::string& compatible_prints_condition(DynamicPrintConfig &cfg) { return cfg.option<ConfigOptionString>("compatible_prints_condition", true)->value; }
std::string& compatible_prints_condition() {
assert(this->type == TYPE_FILAMENT || this->type == TYPE_SLA_MATERIAL);
return Preset::compatible_prints_condition(this->config);
}
const std::string& compatible_prints_condition() const { return const_cast<Preset*>(this)->compatible_prints_condition(); }
// Returns the "compatible_printers_condition".
static std::string& compatible_printers_condition(DynamicPrintConfig &cfg) { return cfg.option<ConfigOptionString>("compatible_printers_condition", true)->value; }
std::string& compatible_printers_condition() {
assert(this->type == TYPE_PRINT || this->type == TYPE_SLA_PRINT || this->type == TYPE_FILAMENT || this->type == TYPE_SLA_MATERIAL);
return Preset::compatible_printers_condition(this->config);
}
const std::string& compatible_printers_condition() const { return const_cast<Preset*>(this)->compatible_printers_condition(); }
// Return a printer technology, return ptFFF if the printer technology is not set.
static PrinterTechnology printer_technology(const DynamicPrintConfig &cfg) {
auto *opt = cfg.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology");
// The following assert may trigger when importing some legacy profile,
// but it is safer to keep it here to capture the cases where the "printer_technology" key is queried, where it should not.
// assert(opt != nullptr);
return (opt == nullptr) ? ptFFF : opt->value;
}
PrinterTechnology printer_technology() const { return Preset::printer_technology(this->config); }
// This call returns a reference, it may add a new entry into the DynamicPrintConfig.
PrinterTechnology& printer_technology_ref() { return this->config.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology", true)->value; }
// Set is_visible according to application config
void set_visible_from_appconfig(const AppConfig &app_config);
// Resize the extruder specific fields, initialize them with the content of the 1st extruder.
void set_num_extruders(unsigned int n) { this->config.set_num_extruders(n); }
// Sort lexicographically by a preset name. The preset name shall be unique across a single PresetCollection.
bool operator<(const Preset &other) const { return this->name < other.name; }
static const std::vector<std::string>& print_options();
static const std::vector<std::string>& filament_options();
// Printer options contain the nozzle options.
static const std::vector<std::string>& printer_options();
// Nozzle options of the printer options.
static const std::vector<std::string>& nozzle_options();
static const std::vector<std::string>& sla_printer_options();
static const std::vector<std::string>& sla_material_options();
static const std::vector<std::string>& sla_print_options();
static void update_suffix_modified(const std::string& new_suffix_modified);
static const std::string& suffix_modified();
static std::string remove_suffix_modified(const std::string& name);
static void normalize(DynamicPrintConfig &config);
// Report configuration fields, which are misplaced into a wrong group, remove them from the config.
static std::string remove_invalid_keys(DynamicPrintConfig &config, const DynamicPrintConfig &default_config);
protected:
friend class PresetCollection;
friend class PresetBundle;
};
bool is_compatible_with_print (const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_print, const PresetWithVendorProfile &active_printer);
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer, const DynamicPrintConfig *extra_config);
bool is_compatible_with_printer(const PresetWithVendorProfile &preset, const PresetWithVendorProfile &active_printer);
enum class PresetSelectCompatibleType {
// Never select a compatible preset if the newly selected profile is not compatible.
Never,
// Only select a compatible preset if the active profile used to be compatible, but it is no more.
OnlyIfWasCompatible,
// Always select a compatible preset if the active profile is no more compatible.
Always
};
// Collections of presets of the same type (one of the Print, Filament or Printer type).
class PresetCollection
{
public:
// Initialize the PresetCollection with the "- default -" preset.
PresetCollection(Preset::Type type, const std::vector<std::string> &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &default_name = "- default -");
~PresetCollection();
typedef std::deque<Preset>::iterator Iterator;
typedef std::deque<Preset>::const_iterator ConstIterator;
Iterator begin() { return m_presets.begin() + m_num_default_presets; }
ConstIterator begin() const { return m_presets.cbegin() + m_num_default_presets; }
ConstIterator cbegin() const { return m_presets.cbegin() + m_num_default_presets; }
Iterator end() { return m_presets.end(); }
ConstIterator end() const { return m_presets.cend(); }
ConstIterator cend() const { return m_presets.cend(); }
void reset(bool delete_files);
Preset::Type type() const { return m_type; }
// Name, to be used on the screen and in error messages. Not localized.
std::string name() const;
// Name, to be used as a section name in config bundle, and as a folder name for presets.
std::string section_name() const;
const std::deque<Preset>& operator()() const { return m_presets; }
// Add default preset at the start of the collection, increment the m_default_preset counter.
void add_default_preset(const std::vector<std::string> &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &preset_name);
// Load ini files of the particular type from the provided directory path.
void load_presets(const std::string &dir_path, const std::string &subdir);
// Load a preset from an already parsed config file, insert it into the sorted sequence of presets
// and select it, losing previous modifications.
Preset& load_preset(const std::string &path, const std::string &name, const DynamicPrintConfig &config, bool select = true);
Preset& load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select = true);
Preset& load_external_preset(
// Path to the profile source file (a G-code, an AMF or 3MF file, a config file)
const std::string &path,
// Name of the profile, derived from the source file name.
const std::string &name,
// Original name of the profile, extracted from the loaded config. Empty, if the name has not been stored.
const std::string &original_name,
// Config to initialize the preset from.
const DynamicPrintConfig &config,
// Select the preset after loading?
bool select = true);
// Save the preset under a new name. If the name is different from the old one,
// a new preset is stored into the list of presets.
// All presets are marked as not modified and the new preset is activated.
void save_current_preset(const std::string &new_name, bool detach = false);
// Delete the current preset, activate the first visible preset.
// returns true if the preset was deleted successfully.
bool delete_current_preset();
// Delete the current preset, activate the first visible preset.
// returns true if the preset was deleted successfully.
bool delete_preset(const std::string& name);
// Enable / disable the "- default -" preset.
void set_default_suppressed(bool default_suppressed);
bool is_default_suppressed() const { return m_default_suppressed; }
// Select a preset. If an invalid index is provided, the first visible preset is selected.
Preset& select_preset(size_t idx);
// Return the selected preset, without the user modifications applied.
Preset& get_selected_preset() { return m_presets[m_idx_selected]; }
const Preset& get_selected_preset() const { return m_presets[m_idx_selected]; }
size_t get_selected_idx() const { return m_idx_selected; }
// Returns the name of the selected preset, or an empty string if no preset is selected.
std::string get_selected_preset_name() const { return (m_idx_selected == size_t(-1)) ? std::string() : this->get_selected_preset().name; }
// For the current edited preset, return the parent preset if there is one.
// If there is no parent preset, nullptr is returned.
// The parent preset may be a system preset or a user preset, which will be
// reflected by the UI.
const Preset* get_selected_preset_parent() const;
// Get parent preset for a child preset, based on the "inherits" field of a child,
// where the "inherits" profile name is searched for in both m_presets and m_map_system_profile_renamed.
const Preset* get_preset_parent(const Preset& child) const;
// Return the selected preset including the user modifications.
Preset& get_edited_preset() { return m_edited_preset; }
const Preset& get_edited_preset() const { return m_edited_preset; }
// Return vendor of the first parent profile, for which the vendor is defined, or null if such profile does not exist.
PresetWithVendorProfile get_preset_with_vendor_profile(const Preset &preset) const;
PresetWithVendorProfile get_edited_preset_with_vendor_profile() const { return this->get_preset_with_vendor_profile(this->get_edited_preset()); }
const std::string& get_preset_name_by_alias(const std::string& alias) const;
const std::string* get_preset_name_renamed(const std::string &old_name) const;
// used to update preset_choice from Tab
const std::deque<Preset>& get_presets() const { return m_presets; }
size_t get_idx_selected() { return m_idx_selected; }
static const std::string& get_suffix_modified();
// Return a preset possibly with modifications.
Preset& default_preset(size_t idx = 0) { assert(idx < m_num_default_presets); return m_presets[idx]; }
const Preset& default_preset(size_t idx = 0) const { assert(idx < m_num_default_presets); return m_presets[idx]; }
virtual const Preset& default_preset_for(const DynamicPrintConfig & /* config */) const { return this->default_preset(); }
// Return a preset by an index. If the preset is active, a temporary copy is returned.
Preset& preset(size_t idx) { return (idx == m_idx_selected) ? m_edited_preset : m_presets[idx]; }
const Preset& preset(size_t idx) const { return const_cast<PresetCollection*>(this)->preset(idx); }
void discard_current_changes() { m_presets[m_idx_selected].reset_dirty(); m_edited_preset = m_presets[m_idx_selected]; }
// Return a preset by its name. If the preset is active, a temporary copy is returned.
// If a preset is not found by its name, null is returned.
Preset* find_preset(const std::string &name, bool first_visible_if_not_found = false);
const Preset* find_preset(const std::string &name, bool first_visible_if_not_found = false) const
{ return const_cast<PresetCollection*>(this)->find_preset(name, first_visible_if_not_found); }
size_t first_visible_idx() const;
// Return index of the first compatible preset. Certainly at least the '- default -' preset shall be compatible.
// If one of the prefered_alternates is compatible, select it.
template<typename PreferedCondition>
size_t first_compatible_idx(PreferedCondition prefered_condition) const
{
size_t i = m_default_suppressed ? m_num_default_presets : 0;
size_t n = this->m_presets.size();
size_t i_compatible = n;
for (; i < n; ++ i)
// Since we use the filament selection from Wizard, it's needed to control the preset visibility too
if (m_presets[i].is_compatible && m_presets[i].is_visible) {
if (prefered_condition(m_presets[i].name))
return i;
if (i_compatible == n)
// Store the first compatible profile into i_compatible.
i_compatible = i;
}
return (i_compatible == n) ? 0 : i_compatible;
}
// Return index of the first compatible preset. Certainly at least the '- default -' preset shall be compatible.
size_t first_compatible_idx() const { return this->first_compatible_idx([](const std::string&){return true;}); }
// Return index of the first visible preset. Certainly at least the '- default -' preset shall be visible.
// Return the first visible preset. Certainly at least the '- default -' preset shall be visible.
Preset& first_visible() { return this->preset(this->first_visible_idx()); }
const Preset& first_visible() const { return this->preset(this->first_visible_idx()); }
Preset& first_compatible() { return this->preset(this->first_compatible_idx()); }
template<typename PreferedCondition>
Preset& first_compatible(PreferedCondition prefered_condition) { return this->preset(this->first_compatible_idx(prefered_condition)); }
const Preset& first_compatible() const { return this->preset(this->first_compatible_idx()); }
// Return number of presets including the "- default -" preset.
size_t size() const { return m_presets.size(); }
bool has_defaults_only() const { return m_presets.size() <= m_num_default_presets; }
// For Print / Filament presets, disable those, which are not compatible with the printer.
template<typename PreferedCondition>
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType select_other_if_incompatible, PreferedCondition prefered_condition)
{
if (this->update_compatible_internal(active_printer, active_print, select_other_if_incompatible) == (size_t)-1)
// Find some other compatible preset, or the "-- default --" preset.
this->select_preset(this->first_compatible_idx(prefered_condition));
}
void update_compatible(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType select_other_if_incompatible)
{ this->update_compatible(active_printer, active_print, select_other_if_incompatible, [](const std::string&){return true;}); }
size_t num_visible() const { return std::count_if(m_presets.begin(), m_presets.end(), [](const Preset &preset){return preset.is_visible;}); }
// Compare the content of get_selected_preset() with get_edited_preset() configs, return true if they differ.
bool current_is_dirty() const { return ! this->current_dirty_options().empty(); }
// Compare the content of get_selected_preset() with get_edited_preset() configs, return the list of keys where they differ.
std::vector<std::string> current_dirty_options(const bool deep_compare = false) const
{ return dirty_options(&this->get_edited_preset(), &this->get_selected_preset(), deep_compare); }
// Compare the content of get_selected_preset() with get_edited_preset() configs, return the list of keys where they differ.
std::vector<std::string> current_different_from_parent_options(const bool deep_compare = false) const
{ return dirty_options(&this->get_edited_preset(), this->get_selected_preset_parent(), deep_compare); }
// Return a sorted list of system preset names.
std::vector<std::string> system_preset_names() const;
// Update a dirty flag of the current preset
// Return true if the dirty flag changed.
bool update_dirty();
// Select a profile by its name. Return true if the selection changed.
// Without force, the selection is only updated if the index changes.
// With force, the changes are reverted if the new index is the same as the old index.
bool select_preset_by_name(const std::string &name, bool force);
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
std::string path_from_name(const std::string &new_name) const;
size_t num_default_presets() { return m_num_default_presets; }
protected:
// Select a preset, if it exists. If it does not exist, select an invalid (-1) index.
// This is a temporary state, which shall be fixed immediately by the following step.
bool select_preset_by_name_strict(const std::string &name);
// Merge one vendor's presets with the other vendor's presets, report duplicates.
std::vector<std::string> merge_presets(PresetCollection &&other, const VendorMap &new_vendors);
// Update m_map_alias_to_profile_name from loaded system profiles.
void update_map_alias_to_profile_name();
// Update m_map_system_profile_renamed from loaded system profiles.
void update_map_system_profile_renamed();
private:
PresetCollection();
PresetCollection(const PresetCollection &other);
PresetCollection& operator=(const PresetCollection &other);
// Find a preset position in the sorted list of presets.
// The "-- default -- " preset is always the first, so it needs
// to be handled differently.
// If a preset does not exist, an iterator is returned indicating where to insert a preset with the same name.
std::deque<Preset>::iterator find_preset_internal(const std::string &name)
{
Preset key(m_type, name);
auto it = std::lower_bound(m_presets.begin() + m_num_default_presets, m_presets.end(), key);
if (it == m_presets.end() || it->name != name) {
// Preset has not been not found in the sorted list of non-default presets. Try the defaults.
for (size_t i = 0; i < m_num_default_presets; ++ i)
if (m_presets[i].name == name) {
it = m_presets.begin() + i;
break;
}
}
return it;
}
std::deque<Preset>::const_iterator find_preset_internal(const std::string &name) const
{ return const_cast<PresetCollection*>(this)->find_preset_internal(name); }
std::deque<Preset>::iterator find_preset_renamed(const std::string &name) {
auto it_renamed = m_map_system_profile_renamed.find(name);
auto it = (it_renamed == m_map_system_profile_renamed.end()) ? m_presets.end() : this->find_preset_internal(it_renamed->second);
assert((it_renamed == m_map_system_profile_renamed.end()) || (it != m_presets.end() && it->name == it_renamed->second));
return it;
}
std::deque<Preset>::const_iterator find_preset_renamed(const std::string &name) const
{ return const_cast<PresetCollection*>(this)->find_preset_renamed(name); }
size_t update_compatible_internal(const PresetWithVendorProfile &active_printer, const PresetWithVendorProfile *active_print, PresetSelectCompatibleType unselect_if_incompatible);
static std::vector<std::string> dirty_options(const Preset *edited, const Preset *reference, const bool is_printer_type = false);
// Type of this PresetCollection: TYPE_PRINT, TYPE_FILAMENT or TYPE_PRINTER.
Preset::Type m_type;
// List of presets, starting with the "- default -" preset.
// Use deque to force the container to allocate an object per each entry,
// so that the addresses of the presets don't change during resizing of the container.
std::deque<Preset> m_presets;
// System profiles may have aliases. Map to the full profile name.
std::vector<std::pair<std::string, std::string>> m_map_alias_to_profile_name;
// Map from old system profile name to a current system profile name.
std::map<std::string, std::string> m_map_system_profile_renamed;
// Initially this preset contains a copy of the selected preset. Later on, this copy may be modified by the user.
Preset m_edited_preset;
// Selected preset.
size_t m_idx_selected;
// Is the "- default -" preset suppressed?
bool m_default_suppressed = true;
size_t m_num_default_presets = 0;
// Path to the directory to store the config files into.
std::string m_dir_path;
// to access select_preset_by_name_strict()
friend class PresetBundle;
};
// Printer supports the FFF and SLA technologies, with different set of configuration values,
// therefore this PresetCollection needs to handle two defaults.
class PrinterPresetCollection : public PresetCollection
{
public:
PrinterPresetCollection(Preset::Type type, const std::vector<std::string> &keys, const Slic3r::StaticPrintConfig &defaults, const std::string &default_name = "- default -") :
PresetCollection(type, keys, defaults, default_name) {}
const Preset& default_preset_for(const DynamicPrintConfig &config) const override;
const Preset* find_by_model_id(const std::string &model_id) const;
};
namespace PresetUtils {
// PrinterModel of a system profile, from which this preset is derived, or null if it is not derived from a system profile.
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset);
} // namespace PresetUtils
//////////////////////////////////////////////////////////////////////
class PhysicalPrinter
{
public:
PhysicalPrinter() {}
PhysicalPrinter(const std::string& name) : name(name){}
PhysicalPrinter(const std::string& name, const Preset& preset);
void set_name(const std::string &name);
// Name of the Physical Printer, usually derived form the file name.
std::string name;
// File name of the Physical Printer.
std::string file;
// Configuration data, loaded from a file, or set from the defaults.
DynamicPrintConfig config;
// set of presets used with this physical printer
std::set<std::string> preset_names;
// Has this profile been loaded?
bool loaded = false;
static std::string separator();
static const std::vector<std::string>& printer_options();
static const std::vector<std::string>& print_host_options();
static std::vector<std::string> presets_with_print_host_information(const PrinterPresetCollection& printer_presets);
static bool has_print_host_information(const DynamicPrintConfig& config);
const std::set<std::string>& get_preset_names() const;
bool has_empty_config() const;
void update_preset_names_in_config();
void save() { this->config.save(this->file); }
void save(const std::string& file_name_from, const std::string& file_name_to);
void update_from_preset(const Preset& preset);
void update_from_config(const DynamicPrintConfig &new_config);
// add preset to the preset_names
// return false, if preset with this name is already exist in the set
bool add_preset(const std::string& preset_name);
bool delete_preset(const std::string& preset_name);
void reset_presets();
// Return a printer technology, return ptFFF if the printer technology is not set.
static PrinterTechnology printer_technology(const DynamicPrintConfig& cfg) {
auto* opt = cfg.option<ConfigOptionEnum<PrinterTechnology>>("printer_technology");
// The following assert may trigger when importing some legacy profile,
// but it is safer to keep it here to capture the cases where the "printer_technology" key is queried, where it should not.
return (opt == nullptr) ? ptFFF : opt->value;
}
PrinterTechnology printer_technology() const { return printer_technology(this->config); }
// Sort lexicographically by a preset name. The preset name shall be unique across a single PresetCollection.
bool operator<(const PhysicalPrinter& other) const { return this->name < other.name; }
// get full printer name included a name of the preset
std::string get_full_name(std::string preset_name) const;
// get printer name from the full name uncluded preset name
static std::string get_short_name(std::string full_name);
// get preset name from the full name uncluded printer name
static std::string get_preset_name(std::string full_name);
protected:
friend class PhysicalPrinterCollection;
};
// ---------------------------------
// *** PhysicalPrinterCollection ***
// ---------------------------------
// Collections of physical printers
class PhysicalPrinterCollection
{
public:
PhysicalPrinterCollection(const std::vector<std::string>& keys);
~PhysicalPrinterCollection() {}
typedef std::deque<PhysicalPrinter>::iterator Iterator;
typedef std::deque<PhysicalPrinter>::const_iterator ConstIterator;
Iterator begin() { return m_printers.begin(); }
ConstIterator begin() const { return m_printers.cbegin(); }
ConstIterator cbegin() const { return m_printers.cbegin(); }
Iterator end() { return m_printers.end(); }
ConstIterator end() const { return m_printers.cend(); }
ConstIterator cend() const { return m_printers.cend(); }
bool empty() const {return m_printers.empty(); }
void reset(bool delete_files) {};
const std::deque<PhysicalPrinter>& operator()() const { return m_printers; }
// Load ini files of the particular type from the provided directory path.
void load_printers(const std::string& dir_path, const std::string& subdir);
void load_printers_from_presets(PrinterPresetCollection &printer_presets);
// Save the printer under a new name. If the name is different from the old one,
// a new printer is stored into the list of printers.
// New printer is activated.
void save_printer(PhysicalPrinter& printer, const std::string& renamed_from = "");
// Delete the current preset, activate the first visible preset.
// returns true if the preset was deleted successfully.
bool delete_printer(const std::string& name);
// Delete the selected preset
// returns true if the preset was deleted successfully.
bool delete_selected_printer();
// Delete preset_name preset from all printers:
// If there is last preset for the printer and first_check== false, then delete this printer
// returns true if all presets were deleted successfully.
bool delete_preset_from_printers(const std::string& preset_name);
// Get list of printers which have more than one preset and "preset_name" preset is one of them
std::vector<std::string> get_printers_with_preset( const std::string &preset_name);
// Get list of printers which has only "preset_name" preset
std::vector<std::string> get_printers_with_only_preset( const std::string &preset_name);
// Return the selected preset, without the user modifications applied.
PhysicalPrinter& get_selected_printer() { return m_printers[m_idx_selected]; }
const PhysicalPrinter& get_selected_printer() const { return m_printers[m_idx_selected]; }
size_t get_selected_idx() const { return m_idx_selected; }
// Returns the name of the selected preset, or an empty string if no preset is selected.
std::string get_selected_printer_name() const { return (m_idx_selected == size_t(-1)) ? std::string() : this->get_selected_printer().name; }
// Returns the config of the selected printer, or nullptr if no printer is selected.
DynamicPrintConfig* get_selected_printer_config() { return (m_idx_selected == size_t(-1)) ? nullptr : &(this->get_selected_printer().config); }
// Returns the config of the selected printer, or nullptr if no printer is selected.
PrinterTechnology get_selected_printer_technology() { return (m_idx_selected == size_t(-1)) ? PrinterTechnology::ptAny : this->get_selected_printer().printer_technology(); }
// Each physical printer can have a several related preset,
// so, use the next functions to get an exact names of selections in the list:
// Returns the full name of the selected printer, or an empty string if no preset is selected.
std::string get_selected_full_printer_name() const;
// Returns the printer model of the selected preset, or an empty string if no preset is selected.
std::string get_selected_printer_preset_name() const { return (m_idx_selected == size_t(-1)) ? std::string() : m_selected_preset; }
// Select printer by the full printer name, which contains name of printer, separator and name of selected preset
// If full_name doesn't contain name of selected preset, then select first preset in the list for this printer
void select_printer(const std::string& full_name);
void select_printer(const PhysicalPrinter& printer);
bool has_selection() const;
void unselect_printer() ;
bool is_selected(ConstIterator it, const std::string &preset_name) const;
// Return a printer by an index. If the printer is active, a temporary copy is returned.
PhysicalPrinter& printer(size_t idx) { return m_printers[idx]; }
const PhysicalPrinter& printer(size_t idx) const { return const_cast<PhysicalPrinterCollection*>(this)->printer(idx); }
// Return a preset by its name. If the preset is active, a temporary copy is returned.
// If a preset is not found by its name, null is returned.
PhysicalPrinter* find_printer(const std::string& name, bool first_visible_if_not_found = false);
const PhysicalPrinter* find_printer(const std::string& name, bool first_visible_if_not_found = false) const
{
return const_cast<PhysicalPrinterCollection*>(this)->find_printer(name, first_visible_if_not_found);
}
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
std::string path_from_name(const std::string& new_name) const;
private:
PhysicalPrinterCollection& operator=(const PhysicalPrinterCollection& other);
// Find a preset position in the sorted list of presets.
// The "-- default -- " preset is always the first, so it needs
// to be handled differently.
// If a preset does not exist, an iterator is returned indicating where to insert a preset with the same name.
std::deque<PhysicalPrinter>::iterator find_printer_internal(const std::string& name)
{
PhysicalPrinter printer(name);
auto it = std::lower_bound(m_printers.begin(), m_printers.end(), printer);
return it;
}
std::deque<PhysicalPrinter>::const_iterator find_printer_internal(const std::string& name) const
{
return const_cast<PhysicalPrinterCollection*>(this)->find_printer_internal(name);
}
PhysicalPrinter* find_printer_with_same_config( const DynamicPrintConfig &config);
// List of printers
// Use deque to force the container to allocate an object per each entry,
// so that the addresses of the presets don't change during resizing of the container.
std::deque<PhysicalPrinter> m_printers;
// Selected printer.
size_t m_idx_selected = size_t(-1);
// The name of the preset which is currently select for this printer
std::string m_selected_preset;
// Path to the directory to store the config files into.
std::string m_dir_path;
};
} // namespace Slic3r
#endif /* slic3r_Preset_hpp_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,162 @@
#ifndef slic3r_PresetBundle_hpp_
#define slic3r_PresetBundle_hpp_
#include "Preset.hpp"
#include "AppConfig.hpp"
#include <memory>
#include <unordered_map>
#include <boost/filesystem/path.hpp>
namespace Slic3r {
// Bundle of Print + Filament + Printer presets.
class PresetBundle
{
public:
PresetBundle();
~PresetBundle();
// Remove all the presets but the "-- default --".
// Optionally remove all the files referenced by the presets from the user profile directory.
void reset(bool delete_files);
void setup_directories();
// Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets.
// Load selections (current print, current filaments, current printer) from config.ini
// This is done just once on application start up.
void load_presets(AppConfig &config, const std::string &preferred_model_id = "");
// Export selections (current print, current filaments, current printer) into config.ini
void export_selections(AppConfig &config);
PresetCollection prints;
PresetCollection sla_prints;
PresetCollection filaments;
PresetCollection sla_materials;
PresetCollection& materials(PrinterTechnology pt) { return pt == ptFFF ? this->filaments : this->sla_materials; }
const PresetCollection& materials(PrinterTechnology pt) const { return pt == ptFFF ? this->filaments : this->sla_materials; }
PrinterPresetCollection printers;
PhysicalPrinterCollection physical_printers;
// Filament preset names for a multi-extruder or multi-material print.
// extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
std::vector<std::string> filament_presets;
// The project configuration values are kept separated from the print/filament/printer preset,
// they are being serialized / deserialized from / to the .amf, .3mf, .config, .gcode,
// and they are being used by slicing core.
DynamicPrintConfig project_config;
// There will be an entry for each system profile loaded,
// and the system profiles will point to the VendorProfile instances owned by PresetBundle::vendors.
VendorMap vendors;
struct ObsoletePresets {
std::vector<std::string> prints;
std::vector<std::string> sla_prints;
std::vector<std::string> filaments;
std::vector<std::string> sla_materials;
std::vector<std::string> printers;
};
ObsoletePresets obsolete_presets;
bool has_defauls_only() const
{ return prints.has_defaults_only() && filaments.has_defaults_only() && printers.has_defaults_only(); }
DynamicPrintConfig full_config() const;
// full_config() with the "printhost_apikey" and "printhost_cafile" removed.
DynamicPrintConfig full_config_secure() const;
// Load user configuration and store it into the user profiles.
// This method is called by the configuration wizard.
void load_config(const std::string &name, DynamicPrintConfig config)
{ this->load_config_file_config(name, false, std::move(config)); }
// Load configuration that comes from a model file containing configuration, such as 3MF et al.
// This method is called by the Plater.
void load_config_model(const std::string &name, DynamicPrintConfig config)
{ this->load_config_file_config(name, true, std::move(config)); }
// Load an external config file containing the print, filament and printer presets.
// Instead of a config file, a G-code may be loaded containing the full set of parameters.
// In the future the configuration will likely be read from an AMF file as well.
// If the file is loaded successfully, its print / filament / printer profiles will be activated.
void load_config_file(const std::string &path);
// Load a config bundle file, into presets and store the loaded presets into separate files
// of the local configuration directory.
// Load settings into the provided settings instance.
// Activate the presets stored in the config bundle.
// Returns the number of presets loaded successfully.
enum {
// Save the profiles, which have been loaded.
LOAD_CFGBNDLE_SAVE = 1,
// Delete all old config profiles before loading.
LOAD_CFGBNDLE_RESET_USER_PROFILE = 2,
// Load a system config bundle.
LOAD_CFGBNDLE_SYSTEM = 4,
LOAD_CFGBUNDLE_VENDOR_ONLY = 8,
};
// Load the config bundle, store it to the user profile directory by default.
size_t load_configbundle(const std::string &path, unsigned int flags = LOAD_CFGBNDLE_SAVE);
// Export a config bundle file containing all the presets and the names of the active presets.
void export_configbundle(const std::string &path, bool export_system_settings = false);
// Enable / disable the "- default -" preset.
void set_default_suppressed(bool default_suppressed);
// Set the filament preset name. As the name could come from the UI selection box,
// an optional "(modified)" suffix will be removed from the filament name.
void set_filament_preset(size_t idx, const std::string &name);
// Read out the number of extruders from an active printer preset,
// update size and content of filament_presets.
void update_multi_material_filament_presets();
// Update the is_compatible flag of all print and filament presets depending on whether they are marked
// as compatible with the currently selected printer (and print in case of filament presets).
// Also updates the is_visible flag of each preset.
// If select_other_if_incompatible is true, then the print or filament preset is switched to some compatible
// preset if the current print or filament preset is not compatible.
void update_compatible(PresetSelectCompatibleType select_other_print_if_incompatible, PresetSelectCompatibleType select_other_filament_if_incompatible);
void update_compatible(PresetSelectCompatibleType select_other_if_incompatible) { this->update_compatible(select_other_if_incompatible, select_other_if_incompatible); }
// Set the is_visible flag for printer vendors, printer models and printer variants
// based on the user configuration.
// If the "vendor" section is missing, enable all models and variants of the particular vendor.
void load_installed_printers(const AppConfig &config);
const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias) const;
static const char *PRUSA_BUNDLE;
private:
std::string load_system_presets();
// Merge one vendor's presets with the other vendor's presets, report duplicates.
std::vector<std::string> merge_presets(PresetBundle &&other);
// Update renamed_from and alias maps of system profiles.
void update_system_maps();
// Set the is_visible flag for filaments and sla materials,
// apply defaults based on enabled printers when no filaments/materials are installed.
void load_installed_filaments(AppConfig &config);
void load_installed_sla_materials(AppConfig &config);
// Load selections (current print, current filaments, current printer) from config.ini
// This is done just once on application start up.
void load_selections(AppConfig &config, const std::string &preferred_model_id = "");
// Load print, filament & printer presets from a config. If it is an external config, then the name is extracted from the external path.
// and the external config is just referenced, not stored into user profile directory.
// If it is not an external config, then the config will be stored into the user profile directory.
void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config);
void load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree);
DynamicPrintConfig full_fff_config() const;
DynamicPrintConfig full_sla_config() const;
};
} // namespace Slic3r
#endif /* slic3r_PresetBundle_hpp_ */

View file

@ -130,6 +130,37 @@ void PrintConfigDef::init_common_params()
def->min = 0;
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionFloat(0.2));
// Options used by physical printers
def = this->add("login", coString);
def->label = L("Login");
// def->tooltip = L("");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("password", coString);
def->label = L("Password");
// def->tooltip = L("");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("preset_name", coString);
def->label = L("Printer preset name");
def->tooltip = L("Related printer preset name");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionString(""));
def = this->add("authorization_type", coEnum);
def->label = L("Authorization Type");
// def->tooltip = L("");
def->enum_keys_map = &ConfigOptionEnum<AuthorizationType>::get_enum_values();
def->enum_values.push_back("key");
def->enum_values.push_back("user");
def->enum_labels.push_back("KeyPassword");
def->enum_labels.push_back("UserPassword");
def->mode = comAdvanced;
def->set_default_value(new ConfigOptionEnum<AuthorizationType>(atKeyPassword));
}
void PrintConfigDef::init_fff_params()

View file

@ -33,6 +33,10 @@ enum PrintHostType {
htOctoPrint, htDuet, htFlashAir, htAstroBox
};
enum AuthorizationType {
atKeyPassword, atUserPassword
};
enum InfillPattern : int {
ipRectilinear, ipMonotonous, ipGrid, ipTriangles, ipStars, ipCubic, ipLine, ipConcentric, ipHoneycomb, ip3DHoneycomb,
ipGyroid, ipHilbertCurve, ipArchimedeanChords, ipOctagramSpiral, ipCount,
@ -109,6 +113,15 @@ template<> inline const t_config_enum_values& ConfigOptionEnum<PrintHostType>::g
return keys_map;
}
template<> inline const t_config_enum_values& ConfigOptionEnum<AuthorizationType>::get_enum_values() {
static t_config_enum_values keys_map;
if (keys_map.empty()) {
keys_map["key"] = atKeyPassword;
keys_map["user"] = atUserPassword;
}
return keys_map;
}
template<> inline const t_config_enum_values& ConfigOptionEnum<InfillPattern>::get_enum_values() {
static t_config_enum_values keys_map;
if (keys_map.empty()) {

View file

@ -5,6 +5,7 @@
// this needs to be included early for MSVC (listing it in Build.PL is not enough)
#include <memory>
#include <array>
#include <algorithm>
#include <ostream>
#include <iostream>