mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-22 08:11:11 -06:00
Merge remote-tracking branch 'origin/profile_inheritance' into profile_changes_reset
This commit is contained in:
commit
a41e55a773
25 changed files with 688 additions and 10209 deletions
|
@ -171,6 +171,8 @@ add_library(libslic3r STATIC
|
|||
add_library(libslic3r_gui STATIC
|
||||
${LIBDIR}/slic3r/GUI/AppConfig.cpp
|
||||
${LIBDIR}/slic3r/GUI/AppConfig.hpp
|
||||
${LIBDIR}/slic3r/GUI/BitmapCache.cpp
|
||||
${LIBDIR}/slic3r/GUI/BitmapCache.hpp
|
||||
${LIBDIR}/slic3r/GUI/3DScene.cpp
|
||||
${LIBDIR}/slic3r/GUI/3DScene.hpp
|
||||
${LIBDIR}/slic3r/GUI/GLShader.cpp
|
||||
|
|
|
@ -185,7 +185,7 @@ void ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys
|
|||
// This is only possible if other is of DynamicConfig type.
|
||||
if (ignore_nonexistent)
|
||||
continue;
|
||||
throw UnknownOptionException();
|
||||
throw UnknownOptionException(opt_key);
|
||||
}
|
||||
const ConfigOption *other_opt = other.option(opt_key);
|
||||
if (other_opt != nullptr)
|
||||
|
@ -232,7 +232,7 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con
|
|||
// Try to deserialize the option by its name.
|
||||
const ConfigDef *def = this->def();
|
||||
if (def == nullptr)
|
||||
throw NoDefinitionException();
|
||||
throw NoDefinitionException(opt_key);
|
||||
const ConfigOptionDef *optdef = def->get(opt_key);
|
||||
if (optdef == nullptr) {
|
||||
// If we didn't find an option, look for any other option having this as an alias.
|
||||
|
@ -248,7 +248,7 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con
|
|||
break;
|
||||
}
|
||||
if (optdef == nullptr)
|
||||
throw UnknownOptionException();
|
||||
throw UnknownOptionException(opt_key);
|
||||
}
|
||||
|
||||
if (! optdef->shortcut.empty()) {
|
||||
|
@ -278,7 +278,7 @@ double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const
|
|||
// Get option definition.
|
||||
const ConfigDef *def = this->def();
|
||||
if (def == nullptr)
|
||||
throw NoDefinitionException();
|
||||
throw NoDefinitionException(opt_key);
|
||||
const ConfigOptionDef *opt_def = def->get(opt_key);
|
||||
assert(opt_def != nullptr);
|
||||
// Compute absolute value over the absolute value of the base option.
|
||||
|
@ -468,7 +468,7 @@ ConfigOption* DynamicConfig::optptr(const t_config_option_key &opt_key, bool cre
|
|||
// Try to create a new ConfigOption.
|
||||
const ConfigDef *def = this->def();
|
||||
if (def == nullptr)
|
||||
throw NoDefinitionException();
|
||||
throw NoDefinitionException(opt_key);
|
||||
const ConfigOptionDef *optdef = def->get(opt_key);
|
||||
if (optdef == nullptr)
|
||||
// throw std::runtime_error(std::string("Invalid option name: ") + opt_key);
|
||||
|
|
|
@ -1232,17 +1232,22 @@ protected:
|
|||
};
|
||||
|
||||
/// Specialization of std::exception to indicate that an unknown config option has been encountered.
|
||||
class UnknownOptionException : public std::exception
|
||||
{
|
||||
class UnknownOptionException : public std::runtime_error {
|
||||
public:
|
||||
const char* what() const noexcept override { return "Unknown config option"; }
|
||||
UnknownOptionException() :
|
||||
std::runtime_error("Unknown option exception") {}
|
||||
UnknownOptionException(const std::string &opt_key) :
|
||||
std::runtime_error(std::string("Unknown option exception: ") + opt_key) {}
|
||||
};
|
||||
|
||||
/// Indicate that the ConfigBase derived class does not provide config definition (the method def() returns null).
|
||||
class NoDefinitionException : public std::exception
|
||||
class NoDefinitionException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
const char* what() const noexcept override { return "No config definition"; }
|
||||
NoDefinitionException() :
|
||||
std::runtime_error("No definition exception") {}
|
||||
NoDefinitionException(const std::string &opt_key) :
|
||||
std::runtime_error(std::string("No definition exception: ") + opt_key) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -176,6 +176,18 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(0);
|
||||
|
||||
def = this->add("default_filament_profile", coStrings);
|
||||
def->label = L("Default filament profile");
|
||||
def->tooltip = L("Default filament profile associated with the current printer profile. "
|
||||
"On selection of the current printer profile, this filament profile will be activated.");
|
||||
def->default_value = new ConfigOptionStrings();
|
||||
|
||||
def = this->add("default_print_profile", coString);
|
||||
def->label = L("Default print profile");
|
||||
def->tooltip = L("Default print profile associated with the current printer profile. "
|
||||
"On selection of the current printer profile, this print profile will be activated.");
|
||||
def->default_value = new ConfigOptionString();
|
||||
|
||||
def = this->add("disable_fan_first_layers", coInts);
|
||||
def->label = L("Disable fan for the first");
|
||||
def->tooltip = L("You can set this to a positive value to disable fan at all "
|
||||
|
@ -753,6 +765,13 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(80);
|
||||
|
||||
def = this->add("inherits", coString);
|
||||
def->label = L("Inherits profile");
|
||||
def->tooltip = L("Name of the profile, from which this profile inherits.");
|
||||
def->full_width = true;
|
||||
def->height = 50;
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("interface_shells", coBool);
|
||||
def->label = L("Interface shells");
|
||||
def->tooltip = L("Force the generation of solid shells between adjacent materials/volumes. "
|
||||
|
@ -1017,6 +1036,11 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->height = 60;
|
||||
def->default_value = new ConfigOptionStrings{ "" };
|
||||
|
||||
def = this->add("printer_model", coString);
|
||||
def->label = L("Printer type");
|
||||
def->tooltip = L("Type of the printer.");
|
||||
def->default_value = new ConfigOptionString();
|
||||
|
||||
def = this->add("printer_notes", coString);
|
||||
def->label = L("Printer notes");
|
||||
def->tooltip = L("You can put your notes regarding the printer here.");
|
||||
|
@ -1026,6 +1050,16 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->height = 130;
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
def = this->add("printer_vendor", coString);
|
||||
def->label = L("Printer vendor");
|
||||
def->tooltip = L("Name of the printer vendor.");
|
||||
def->default_value = new ConfigOptionString();
|
||||
|
||||
def = this->add("printer_variant", coString);
|
||||
def->label = L("Printer variant");
|
||||
def->tooltip = L("Name of the printer variant. For example, the printer variants may be differentiated by a nozzle diameter.");
|
||||
def->default_value = new ConfigOptionString();
|
||||
|
||||
def = this->add("print_settings_id", coString);
|
||||
def->default_value = new ConfigOptionString("");
|
||||
|
||||
|
|
|
@ -145,6 +145,17 @@ void AppConfig::update_last_output_dir(const std::string &dir)
|
|||
this->set("", "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("printer");
|
||||
m_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::string AppConfig::config_path()
|
||||
{
|
||||
return (boost::filesystem::path(Slic3r::data_dir()) / "slic3r.ini").make_preferred().string();
|
||||
|
|
|
@ -73,6 +73,11 @@ public:
|
|||
std::string get_last_output_dir(const std::string &alt) const;
|
||||
void update_last_output_dir(const std::string &dir);
|
||||
|
||||
// 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();
|
||||
|
||||
|
|
120
xs/src/slic3r/GUI/BitmapCache.cpp
Normal file
120
xs/src/slic3r/GUI/BitmapCache.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
#include "BitmapCache.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
void BitmapCache::clear()
|
||||
{
|
||||
for (std::pair<const std::string, wxBitmap*> &bitmap : m_map)
|
||||
delete bitmap.second;
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height)
|
||||
{
|
||||
wxBitmap *bitmap = nullptr;
|
||||
auto it = m_map.find(bitmap_key);
|
||||
if (it == m_map.end()) {
|
||||
bitmap = new wxBitmap(width, height);
|
||||
m_map[bitmap_key] = bitmap;
|
||||
} else {
|
||||
bitmap = it->second;
|
||||
if (bitmap->GetWidth() != width || bitmap->GetHeight() != height)
|
||||
bitmap->Create(width, height);
|
||||
}
|
||||
#if defined(__APPLE__) || defined(_MSC_VER)
|
||||
bitmap->UseAlpha();
|
||||
#endif
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp)
|
||||
{
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth(), bmp.GetHeight());
|
||||
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
memDC.DrawBitmap(bmp, 0, 0, true);
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp, const wxBitmap &bmp2)
|
||||
{
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth() + bmp2.GetWidth(), std::max(bmp.GetHeight(), bmp2.GetHeight()));
|
||||
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
if (bmp.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp, 0, 0, true);
|
||||
if (bmp2.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp2, bmp.GetWidth(), 0, true);
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3)
|
||||
{
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth() + bmp2.GetWidth() + bmp3.GetWidth(), std::max(std::max(bmp.GetHeight(), bmp2.GetHeight()), bmp3.GetHeight()));
|
||||
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
if (bmp.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp, 0, 0, true);
|
||||
if (bmp2.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp2, bmp.GetWidth(), 0, true);
|
||||
if (bmp3.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp3, bmp.GetWidth() + bmp2.GetWidth(), 0, true);
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, std::vector<wxBitmap> &bmps)
|
||||
{
|
||||
size_t width = 0;
|
||||
size_t height = 0;
|
||||
for (wxBitmap &bmp : bmps) {
|
||||
width += bmp.GetWidth();
|
||||
height = std::max<size_t>(height, bmp.GetHeight());
|
||||
}
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, width, height);
|
||||
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
size_t x = 0;
|
||||
for (wxBitmap &bmp : bmps) {
|
||||
if (bmp.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp, x, 0, true);
|
||||
x += bmp.GetWidth();
|
||||
}
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency)
|
||||
{
|
||||
wxImage image(width, height);
|
||||
image.InitAlpha();
|
||||
unsigned char* imgdata = image.GetData();
|
||||
unsigned char* imgalpha = image.GetAlpha();
|
||||
for (size_t i = 0; i < width * height; ++ i) {
|
||||
*imgdata ++ = r;
|
||||
*imgdata ++ = g;
|
||||
*imgdata ++ = b;
|
||||
*imgalpha ++ = transparency;
|
||||
}
|
||||
return wxBitmap(std::move(image));
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
43
xs/src/slic3r/GUI/BitmapCache.hpp
Normal file
43
xs/src/slic3r/GUI/BitmapCache.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef SLIC3R_GUI_BITMAP_CACHE_HPP
|
||||
#define SLIC3R_GUI_BITMAP_CACHE_HPP
|
||||
|
||||
#include <wx/wxprec.h>
|
||||
#ifndef WX_PRECOMP
|
||||
#include <wx/wx.h>
|
||||
#endif
|
||||
|
||||
#include "../../libslic3r/libslic3r.h"
|
||||
#include "../../libslic3r/Config.hpp"
|
||||
|
||||
#include "GUI.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
class BitmapCache
|
||||
{
|
||||
public:
|
||||
BitmapCache() {}
|
||||
~BitmapCache() { clear(); }
|
||||
void clear();
|
||||
|
||||
wxBitmap* find(const std::string &name) { auto it = m_map.find(name); return (it == m_map.end()) ? nullptr : it->second; }
|
||||
const wxBitmap* find(const std::string &name) const { return const_cast<BitmapCache*>(this)->find(name); }
|
||||
|
||||
wxBitmap* insert(const std::string &name, size_t width, size_t height);
|
||||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp);
|
||||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2);
|
||||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3);
|
||||
wxBitmap* insert(const std::string &name, std::vector<wxBitmap> &bmps);
|
||||
|
||||
static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency);
|
||||
static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }
|
||||
static wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); }
|
||||
|
||||
private:
|
||||
std::map<std::string, wxBitmap*> m_map;
|
||||
};
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
#endif /* SLIC3R_GUI_BITMAP_CACHE_HPP */
|
|
@ -280,9 +280,7 @@ public:
|
|||
wxSizer* getSizer() override { return sizer; }
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
|
||||
#endif /* SLIC3R_GUI_FIELD_HPP */
|
||||
|
|
|
@ -80,7 +80,7 @@ void Preset::set_num_extruders(DynamicPrintConfig &config, unsigned int num_extr
|
|||
auto *opt = config.option(key, false);
|
||||
assert(opt != nullptr);
|
||||
assert(opt->is_vector());
|
||||
if (opt != nullptr && opt->is_vector())
|
||||
if (opt != nullptr && opt->is_vector() && key != "default_filament_profile")
|
||||
static_cast<ConfigOptionVectorBase*>(opt)->resize(num_extruders, defaults.option(key));
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +200,7 @@ const std::vector<std::string>& Preset::print_options()
|
|||
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects",
|
||||
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
|
||||
"wipe_tower_width", "wipe_tower_per_color_wipe",
|
||||
"compatible_printers", "compatible_printers_condition"
|
||||
"compatible_printers", "compatible_printers_condition", "inherits"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
@ -213,7 +213,7 @@ const std::vector<std::string>& Preset::filament_options()
|
|||
"first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed",
|
||||
"disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", "start_filament_gcode",
|
||||
"end_filament_gcode",
|
||||
"compatible_printers", "compatible_printers_condition"
|
||||
"compatible_printers", "compatible_printers_condition", "inherits"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
@ -226,13 +226,15 @@ const std::vector<std::string>& Preset::printer_options()
|
|||
"bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
|
||||
"octoprint_host", "octoprint_apikey", "octoprint_cafile", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
||||
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
||||
"between_objects_gcode", "printer_notes"
|
||||
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "default_print_profile", "inherits",
|
||||
};
|
||||
s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
|
||||
}
|
||||
return s_opts;
|
||||
}
|
||||
|
||||
// The following nozzle options of a printer profile will be adjusted to match the size
|
||||
// of the nozzle_diameter vector.
|
||||
const std::vector<std::string>& Preset::nozzle_options()
|
||||
{
|
||||
// ConfigOptionFloats, ConfigOptionPercents, ConfigOptionBools, ConfigOptionStrings
|
||||
|
@ -240,7 +242,8 @@ const std::vector<std::string>& Preset::nozzle_options()
|
|||
"nozzle_diameter", "min_layer_height", "max_layer_height", "extruder_offset",
|
||||
"retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed",
|
||||
"retract_before_wipe", "retract_restart_extra", "retract_before_travel", "wipe",
|
||||
"retract_layer_change", "retract_length_toolchange", "retract_restart_extra_toolchange", "extruder_colour"
|
||||
"retract_layer_change", "retract_length_toolchange", "retract_restart_extra_toolchange", "extruder_colour",
|
||||
"default_filament_profile"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
@ -269,7 +272,7 @@ void PresetCollection::reset(bool delete_files)
|
|||
if (delete_files) {
|
||||
// Erase the preset files.
|
||||
for (Preset &preset : m_presets)
|
||||
if (! preset.is_default && ! preset.is_external)
|
||||
if (! preset.is_default && ! preset.is_external && ! preset.is_system)
|
||||
boost::nowide::remove(preset.file.c_str());
|
||||
}
|
||||
// Don't use m_presets.resize() here as it requires a default constructor for Preset.
|
||||
|
@ -284,7 +287,6 @@ void PresetCollection::load_presets(const std::string &dir_path, const std::stri
|
|||
{
|
||||
boost::filesystem::path dir = boost::filesystem::canonical(boost::filesystem::path(dir_path) / subdir).make_preferred();
|
||||
m_dir_path = dir.string();
|
||||
m_presets.erase(m_presets.begin()+1, m_presets.end());
|
||||
t_config_option_keys keys = this->default_preset().config.keys();
|
||||
std::string errors_cummulative;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
|
||||
|
@ -292,6 +294,10 @@ void PresetCollection::load_presets(const std::string &dir_path, const std::stri
|
|||
std::string name = dir_entry.path().filename().string();
|
||||
// Remove the .ini suffix.
|
||||
name.erase(name.size() - 4);
|
||||
if (this->find_preset(name, false)) {
|
||||
errors_cummulative += "The user preset \"" + name + "\" cannot be loaded. A system preset of the same name has already been loaded.";
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
Preset preset(m_type, name, false);
|
||||
preset.file = dir_entry.path().string();
|
||||
|
@ -342,16 +348,33 @@ void PresetCollection::save_current_preset(const std::string &new_name)
|
|||
if (it != m_presets.end() && it->name == new_name) {
|
||||
// Preset with the same name found.
|
||||
Preset &preset = *it;
|
||||
if (preset.is_default)
|
||||
if (preset.is_default || preset.is_external || preset.is_system)
|
||||
// Cannot overwrite the default preset.
|
||||
return;
|
||||
// Overwriting an existing preset.
|
||||
preset.config = std::move(m_edited_preset.config);
|
||||
} else {
|
||||
// Creating a new preset.
|
||||
Preset &preset = *m_presets.insert(it, m_edited_preset);
|
||||
Preset &preset = *m_presets.insert(it, m_edited_preset);
|
||||
std::string &inherits = preset.config.opt_string("inherits", true);
|
||||
std::string old_name = preset.name;
|
||||
preset.name = new_name;
|
||||
preset.file = this->path_from_name(new_name);
|
||||
preset.vendor = nullptr;
|
||||
if (preset.is_system) {
|
||||
// Inheriting from a system preset.
|
||||
inherits = /* preset.vendor->name + "/" + */ old_name;
|
||||
} else if (inherits.empty()) {
|
||||
// Inheriting from a user preset. Link the new preset to the old preset.
|
||||
// inherits = old_name;
|
||||
} else {
|
||||
// Inherited from a user preset. Just maintain the "inherited" flag,
|
||||
// meaning it will inherit from either the system preset, or the inherited user preset.
|
||||
}
|
||||
preset.inherits = inherits;
|
||||
preset.is_default = false;
|
||||
preset.is_system = false;
|
||||
preset.is_external = false;
|
||||
}
|
||||
// 2) Activate the saved preset.
|
||||
this->select_preset_by_name(new_name, true);
|
||||
|
@ -364,7 +387,7 @@ void PresetCollection::delete_current_preset()
|
|||
const Preset &selected = this->get_selected_preset();
|
||||
if (selected.is_default)
|
||||
return;
|
||||
if (! selected.is_external) {
|
||||
if (! selected.is_external && ! selected.is_system) {
|
||||
// Erase the preset file.
|
||||
boost::nowide::remove(selected.file.c_str());
|
||||
}
|
||||
|
@ -384,6 +407,15 @@ bool PresetCollection::load_bitmap_default(const std::string &file_name)
|
|||
return m_bitmap_main_frame->LoadFile(wxString::FromUTF8(Slic3r::var(file_name).c_str()), wxBITMAP_TYPE_PNG);
|
||||
}
|
||||
|
||||
const Preset* PresetCollection::get_selected_preset_parent() const
|
||||
{
|
||||
auto *inherits = dynamic_cast<const ConfigOptionString*>(this->get_edited_preset().config.option("inherits"));
|
||||
if (inherits == nullptr || inherits->value.empty())
|
||||
return nullptr;
|
||||
const Preset* preset = this->find_preset(inherits->value, false);
|
||||
return (preset == nullptr || preset->is_default || preset->is_external) ? nullptr : preset;
|
||||
}
|
||||
|
||||
// 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* PresetCollection::find_preset(const std::string &name, bool first_visible_if_not_found)
|
||||
|
@ -527,16 +559,19 @@ bool PresetCollection::update_dirty_ui(wxBitmapComboBox *ui)
|
|||
return was_dirty != is_dirty;
|
||||
}
|
||||
|
||||
std::vector<std::string> PresetCollection::current_dirty_options() const
|
||||
{
|
||||
std::vector<std::string> changed = this->get_selected_preset().config.diff(this->get_edited_preset().config);
|
||||
// The "compatible_printers" option key is handled differently from the others:
|
||||
// It is not mandatory. If the key is missing, it means it is compatible with any printer.
|
||||
// If the key exists and it is empty, it means it is compatible with no printer.
|
||||
std::initializer_list<const char*> optional_keys { "compatible_printers", "compatible_printers_condition" };
|
||||
for (auto &opt_key : optional_keys) {
|
||||
if (this->get_selected_preset().config.has(opt_key) != this->get_edited_preset().config.has(opt_key))
|
||||
changed.emplace_back(opt_key);
|
||||
std::vector<std::string> PresetCollection::dirty_options(const Preset *edited, const Preset *reference)
|
||||
{
|
||||
std::vector<std::string> changed;
|
||||
if (edited != nullptr && reference != nullptr) {
|
||||
changed = reference->config.diff(edited->config);
|
||||
// The "compatible_printers" option key is handled differently from the others:
|
||||
// It is not mandatory. If the key is missing, it means it is compatible with any printer.
|
||||
// If the key exists and it is empty, it means it is compatible with no printer.
|
||||
std::initializer_list<const char*> optional_keys { "compatible_printers", "compatible_printers_condition" };
|
||||
for (auto &opt_key : optional_keys) {
|
||||
if (reference->config.has(opt_key) != edited->config.has(opt_key))
|
||||
changed.emplace_back(opt_key);
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,46 @@ enum ConfigFileType
|
|||
|
||||
extern ConfigFileType guess_config_file_type(const boost::property_tree::ptree &tree);
|
||||
|
||||
class VendorProfile
|
||||
{
|
||||
public:
|
||||
std::string name;
|
||||
std::string id;
|
||||
std::string config_version;
|
||||
std::string config_update_url;
|
||||
|
||||
struct PrinterVariant {
|
||||
PrinterVariant() {}
|
||||
PrinterVariant(const std::string &name) : name(name) {}
|
||||
std::string name;
|
||||
bool enabled = true;
|
||||
};
|
||||
|
||||
struct PrinterModel {
|
||||
PrinterModel() {}
|
||||
PrinterModel(const std::string &name) : name(name) {}
|
||||
std::string name;
|
||||
bool enabled = true;
|
||||
std::vector<PrinterVariant> variants;
|
||||
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); }
|
||||
|
||||
bool operator< (const PrinterModel &rhs) const { return this->name < rhs.name; }
|
||||
bool operator==(const PrinterModel &rhs) const { return this->name == rhs.name; }
|
||||
};
|
||||
std::set<PrinterModel> models;
|
||||
|
||||
size_t num_variants() const { size_t n = 0; for (auto &model : models) n += model.variants.size(); return n; }
|
||||
|
||||
bool operator< (const VendorProfile &rhs) const { return this->id < rhs.id; }
|
||||
bool operator==(const VendorProfile &rhs) const { return this->id == rhs.id; }
|
||||
};
|
||||
|
||||
class Preset
|
||||
{
|
||||
public:
|
||||
|
@ -44,6 +84,8 @@ public:
|
|||
// 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 compatible with the active Printer.
|
||||
// Also the "default" preset is only visible, if it is the only preset in the list.
|
||||
bool is_visible = true;
|
||||
|
@ -55,9 +97,14 @@ public:
|
|||
// 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 will be true),
|
||||
// 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;
|
||||
// A user profile may inherit its settings either from a system profile, or from a user profile.
|
||||
// A system profile shall never derive from any other profile, as the system profile hierarchy is being flattened during loading.
|
||||
std::string inherits;
|
||||
// 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;
|
||||
|
@ -144,6 +191,8 @@ public:
|
|||
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items.
|
||||
void set_bitmap_compatible (const wxBitmap *bmp) { m_bitmap_compatible = bmp; }
|
||||
void set_bitmap_incompatible(const wxBitmap *bmp) { m_bitmap_incompatible = bmp; }
|
||||
void set_bitmap_lock (const wxBitmap *bmp) { m_bitmap_lock = bmp; }
|
||||
void set_bitmap_lock_open (const wxBitmap *bmp) { m_bitmap_lock_open = bmp; }
|
||||
|
||||
// Enable / disable the "- default -" preset.
|
||||
void set_default_suppressed(bool default_suppressed);
|
||||
|
@ -155,6 +204,11 @@ public:
|
|||
Preset& get_selected_preset() { return m_presets[m_idx_selected]; }
|
||||
const Preset& get_selected_preset() const { return m_presets[m_idx_selected]; }
|
||||
int get_selected_idx() const { return m_idx_selected; }
|
||||
// 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;
|
||||
// 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; }
|
||||
|
@ -191,7 +245,11 @@ public:
|
|||
// 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;
|
||||
std::vector<std::string> current_dirty_options() const
|
||||
{ return dirty_options(&this->get_edited_preset(), &this->get_selected_preset()); }
|
||||
// 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
|
||||
{ return dirty_options(&this->get_edited_preset(), this->get_selected_preset_parent()); }
|
||||
|
||||
// Update the choice UI from the list of presets.
|
||||
// If show_incompatible, all presets are shown, otherwise only the compatible presets are shown.
|
||||
|
@ -231,6 +289,8 @@ private:
|
|||
std::deque<Preset>::const_iterator find_preset_internal(const std::string &name) const
|
||||
{ return const_cast<PresetCollection*>(this)->find_preset_internal(name); }
|
||||
|
||||
static std::vector<std::string> dirty_options(const Preset *edited, const Preset *reference);
|
||||
|
||||
// Type of this PresetCollection: TYPE_PRINT, TYPE_FILAMENT or TYPE_PRINTER.
|
||||
Preset::Type m_type;
|
||||
// List of presets, starting with the "- default -" preset.
|
||||
|
@ -245,8 +305,10 @@ private:
|
|||
bool m_default_suppressed = true;
|
||||
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items of a Platter.
|
||||
// These bitmaps are not owned by PresetCollection, but by a PresetBundle.
|
||||
const wxBitmap *m_bitmap_compatible = nullptr;
|
||||
const wxBitmap *m_bitmap_compatible = nullptr;
|
||||
const wxBitmap *m_bitmap_incompatible = nullptr;
|
||||
const wxBitmap *m_bitmap_lock = nullptr;
|
||||
const wxBitmap *m_bitmap_lock_open = nullptr;
|
||||
// Marks placed at the wxBitmapComboBox of a MainFrame.
|
||||
// These bitmaps are owned by PresetCollection.
|
||||
wxBitmap *m_bitmap_main_frame;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <cassert>
|
||||
|
||||
#include "PresetBundle.hpp"
|
||||
#include "BitmapCache.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
@ -37,7 +38,10 @@ PresetBundle::PresetBundle() :
|
|||
filaments(Preset::TYPE_FILAMENT, Preset::filament_options()),
|
||||
printers(Preset::TYPE_PRINTER, Preset::printer_options()),
|
||||
m_bitmapCompatible(new wxBitmap),
|
||||
m_bitmapIncompatible(new wxBitmap)
|
||||
m_bitmapIncompatible(new wxBitmap),
|
||||
m_bitmapLock(new wxBitmap),
|
||||
m_bitmapLockOpen(new wxBitmap),
|
||||
m_bitmapCache(new GUI::BitmapCache)
|
||||
{
|
||||
if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
|
||||
wxImage::AddHandler(new wxPNGHandler);
|
||||
|
@ -51,6 +55,14 @@ PresetBundle::PresetBundle() :
|
|||
this->filaments.preset(0).config.optptr("compatible_printers_condition", true);
|
||||
this->prints.preset(0).config.optptr("compatible_printers", true);
|
||||
this->prints.preset(0).config.optptr("compatible_printers_condition", true);
|
||||
// Create the "inherits" keys.
|
||||
this->prints.preset(0).config.optptr("inherits", true);
|
||||
this->filaments.preset(0).config.optptr("inherits", true);
|
||||
this->printers.preset(0).config.optptr("inherits", true);
|
||||
// Create the "printer_vendor", "printer_model" and "printer_variant" keys.
|
||||
this->printers.preset(0).config.optptr("printer_vendor", true);
|
||||
this->printers.preset(0).config.optptr("printer_model", true);
|
||||
this->printers.preset(0).config.optptr("printer_variant", true);
|
||||
|
||||
this->prints .load_bitmap_default("cog.png");
|
||||
this->filaments.load_bitmap_default("spool.png");
|
||||
|
@ -62,12 +74,18 @@ PresetBundle::~PresetBundle()
|
|||
{
|
||||
assert(m_bitmapCompatible != nullptr);
|
||||
assert(m_bitmapIncompatible != nullptr);
|
||||
assert(m_bitmapLock != nullptr);
|
||||
assert(m_bitmapLockOpen != nullptr);
|
||||
delete m_bitmapCompatible;
|
||||
m_bitmapCompatible = nullptr;
|
||||
delete m_bitmapIncompatible;
|
||||
m_bitmapIncompatible = nullptr;
|
||||
for (std::pair<const std::string, wxBitmap*> &bitmap : m_mapColorToBitmap)
|
||||
delete bitmap.second;
|
||||
delete m_bitmapLock;
|
||||
m_bitmapLock = nullptr;
|
||||
delete m_bitmapLockOpen;
|
||||
m_bitmapLockOpen = nullptr;
|
||||
delete m_bitmapCache;
|
||||
m_bitmapCache = nullptr;
|
||||
}
|
||||
|
||||
void PresetBundle::reset(bool delete_files)
|
||||
|
@ -84,7 +102,8 @@ void PresetBundle::setup_directories()
|
|||
{
|
||||
boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
|
||||
std::initializer_list<boost::filesystem::path> paths = {
|
||||
data_dir,
|
||||
data_dir,
|
||||
data_dir / "vendor",
|
||||
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
|
||||
// Store the print/filament/printer presets into a "presets" directory.
|
||||
data_dir / "presets",
|
||||
|
@ -107,10 +126,12 @@ void PresetBundle::setup_directories()
|
|||
}
|
||||
}
|
||||
|
||||
void PresetBundle::load_presets()
|
||||
void PresetBundle::load_presets(const AppConfig &config)
|
||||
{
|
||||
std::string errors_cummulative;
|
||||
const std::string dir_path = data_dir()
|
||||
// First load the vendor specific system presets.
|
||||
std::string errors_cummulative = this->load_system_presets();
|
||||
|
||||
const std::string dir_user_presets = data_dir()
|
||||
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
|
||||
// Store the print/filament/printer presets into a "presets" directory.
|
||||
+ "/presets"
|
||||
|
@ -119,17 +140,17 @@ void PresetBundle::load_presets()
|
|||
#endif
|
||||
;
|
||||
try {
|
||||
this->prints.load_presets(dir_path, "print");
|
||||
this->prints.load_presets(dir_user_presets, "print");
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
}
|
||||
try {
|
||||
this->filaments.load_presets(dir_path, "filament");
|
||||
this->filaments.load_presets(dir_user_presets, "filament");
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
}
|
||||
try {
|
||||
this->printers.load_presets(dir_path, "printer");
|
||||
this->printers.load_presets(dir_user_presets, "printer");
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
}
|
||||
|
@ -137,6 +158,31 @@ void PresetBundle::load_presets()
|
|||
this->update_compatible_with_printer(false);
|
||||
if (! errors_cummulative.empty())
|
||||
throw std::runtime_error(errors_cummulative);
|
||||
|
||||
this->load_selections(config);
|
||||
}
|
||||
|
||||
// Load system presets into this PresetBundle.
|
||||
// For each vendor, there will be a single PresetBundle loaded.
|
||||
std::string PresetBundle::load_system_presets()
|
||||
{
|
||||
// Here the vendor specific read only Config Bundles are stored.
|
||||
boost::filesystem::path dir = (boost::filesystem::path(data_dir()) / "vendor").make_preferred();
|
||||
std::string errors_cummulative;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
|
||||
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini")) {
|
||||
std::string name = dir_entry.path().filename().string();
|
||||
// Remove the .ini suffix.
|
||||
name.erase(name.size() - 4);
|
||||
try {
|
||||
// Load the config bundle, flatten it.
|
||||
this->load_configbundle(dir_entry.path().string(), LOAD_CFGBNDLE_SYSTEM);
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
}
|
||||
}
|
||||
return errors_cummulative;
|
||||
}
|
||||
|
||||
static inline std::string remove_ini_suffix(const std::string &name)
|
||||
|
@ -147,6 +193,14 @@ static inline std::string remove_ini_suffix(const std::string &name)
|
|||
return out;
|
||||
}
|
||||
|
||||
// Set the "enabled" 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 PresetBundle::load_installed_printers(const AppConfig &config)
|
||||
{
|
||||
// m_storage
|
||||
}
|
||||
|
||||
// Load selections (current print, current filaments, current printer) from config.ini
|
||||
// This is done just once on application start up.
|
||||
void PresetBundle::load_selections(const AppConfig &config)
|
||||
|
@ -200,10 +254,16 @@ bool PresetBundle::load_compatible_bitmaps()
|
|||
{
|
||||
const std::string path_bitmap_compatible = "flag-green-icon.png";
|
||||
const std::string path_bitmap_incompatible = "flag-red-icon.png";
|
||||
const std::string path_bitmap_lock = "lock.png";
|
||||
const std::string path_bitmap_lock_open = "lock_open.png";
|
||||
bool loaded_compatible = m_bitmapCompatible ->LoadFile(
|
||||
wxString::FromUTF8(Slic3r::var(path_bitmap_compatible).c_str()), wxBITMAP_TYPE_PNG);
|
||||
bool loaded_incompatible = m_bitmapIncompatible->LoadFile(
|
||||
wxString::FromUTF8(Slic3r::var(path_bitmap_incompatible).c_str()), wxBITMAP_TYPE_PNG);
|
||||
bool loaded_lock = m_bitmapLock->LoadFile(
|
||||
wxString::FromUTF8(Slic3r::var(path_bitmap_lock).c_str()), wxBITMAP_TYPE_PNG);
|
||||
bool loaded_lock_open = m_bitmapLockOpen->LoadFile(
|
||||
wxString::FromUTF8(Slic3r::var(path_bitmap_lock_open).c_str()), wxBITMAP_TYPE_PNG);
|
||||
if (loaded_compatible) {
|
||||
prints .set_bitmap_compatible(m_bitmapCompatible);
|
||||
filaments.set_bitmap_compatible(m_bitmapCompatible);
|
||||
|
@ -214,7 +274,17 @@ bool PresetBundle::load_compatible_bitmaps()
|
|||
filaments.set_bitmap_incompatible(m_bitmapIncompatible);
|
||||
// printers .set_bitmap_incompatible(m_bitmapIncompatible);
|
||||
}
|
||||
return loaded_compatible && loaded_incompatible;
|
||||
if (loaded_lock) {
|
||||
prints .set_bitmap_lock(m_bitmapLock);
|
||||
filaments.set_bitmap_lock(m_bitmapLock);
|
||||
printers .set_bitmap_lock(m_bitmapLock);
|
||||
}
|
||||
if (loaded_lock_open) {
|
||||
prints .set_bitmap_lock_open(m_bitmapLock);
|
||||
filaments.set_bitmap_lock_open(m_bitmapLock);
|
||||
printers .set_bitmap_lock_open(m_bitmapLock);
|
||||
}
|
||||
return loaded_compatible && loaded_incompatible && loaded_lock && loaded_lock_open;
|
||||
}
|
||||
|
||||
DynamicPrintConfig PresetBundle::full_config() const
|
||||
|
@ -594,11 +664,54 @@ static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree)
|
|||
flatten_configbundle_hierarchy(tree, "printer");
|
||||
}
|
||||
|
||||
static void load_vendor_profile(const boost::property_tree::ptree &tree, VendorProfile &vendor_profile)
|
||||
{
|
||||
const std::string printer_model_key = "printer_model:";
|
||||
for (auto §ion : tree)
|
||||
if (section.first == "vendor") {
|
||||
// Load the names of the active presets.
|
||||
for (auto &kvp : section.second) {
|
||||
if (kvp.first == "name")
|
||||
vendor_profile.name = kvp.second.data();
|
||||
else if (kvp.first == "id")
|
||||
vendor_profile.id = kvp.second.data();
|
||||
else if (kvp.first == "config_version")
|
||||
vendor_profile.config_version = kvp.second.data();
|
||||
else if (kvp.first == "config_update_url")
|
||||
vendor_profile.config_update_url = kvp.second.data();
|
||||
}
|
||||
} else if (boost::starts_with(section.first, printer_model_key)) {
|
||||
VendorProfile::PrinterModel model;
|
||||
model.name = section.first.substr(printer_model_key.size());
|
||||
section.second.get<std::string>("variants", "");
|
||||
std::vector<std::string> variants;
|
||||
if (Slic3r::unescape_strings_cstyle(section.second.get<std::string>("variants", ""), variants)) {
|
||||
for (const std::string &variant_name : variants) {
|
||||
if (model.variant(variant_name) == nullptr)
|
||||
model.variants.emplace_back(VendorProfile::PrinterVariant(variant_name));
|
||||
}
|
||||
} else {
|
||||
// Log error?
|
||||
}
|
||||
if (! model.name.empty() && ! model.variants.empty())
|
||||
vendor_profile.models.insert(model);
|
||||
}
|
||||
}
|
||||
|
||||
// Load a config bundle file, into presets and store the loaded presets into separate files
|
||||
// of the local configuration directory.
|
||||
void PresetBundle::install_vendor_configbundle(const std::string &src_path0)
|
||||
{
|
||||
boost::filesystem::path src_path(src_path0);
|
||||
boost::filesystem::copy_file(src_path, (boost::filesystem::path(data_dir()) / "vendor" / src_path.filename()).make_preferred(), boost::filesystem::copy_option::overwrite_if_exists);
|
||||
}
|
||||
|
||||
// Load a config bundle file, into presets and store the loaded presets into separate files
|
||||
// of the local configuration directory.
|
||||
size_t PresetBundle::load_configbundle(const std::string &path, unsigned int flags)
|
||||
{
|
||||
if (flags & LOAD_CFGBNDLE_RESET_USER_PROFILE)
|
||||
if (flags & (LOAD_CFGBNDLE_RESET_USER_PROFILE | LOAD_CFGBNDLE_SYSTEM))
|
||||
// Reset this bundle, delete user profile files if LOAD_CFGBNDLE_SAVE.
|
||||
this->reset(flags & LOAD_CFGBNDLE_SAVE);
|
||||
|
||||
// 1) Read the complete config file into a boost::property_tree.
|
||||
|
@ -609,6 +722,17 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
|
|||
// Flatten the config bundle by applying the inheritance rules. Internal profiles (with names starting with '*') are removed.
|
||||
flatten_configbundle_hierarchy(tree);
|
||||
|
||||
const VendorProfile *vendor_profile = nullptr;
|
||||
if (flags & LOAD_CFGBNDLE_SYSTEM) {
|
||||
VendorProfile vp;
|
||||
load_vendor_profile(tree, vp);
|
||||
if (vp.name.empty())
|
||||
throw std::runtime_error(std::string("Vendor Config Bundle is not valid: Missing vendor name key."));
|
||||
if (vp.num_variants() == 0)
|
||||
return 0;
|
||||
vendor_profile = &(*this->vendors.insert(vp).first);
|
||||
}
|
||||
|
||||
// 2) Parse the property_tree, extract the active preset names and the profiles, save them into local config files.
|
||||
std::vector<std::string> loaded_prints;
|
||||
std::vector<std::string> loaded_filaments;
|
||||
|
@ -622,15 +746,15 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
|
|||
std::vector<std::string> *loaded = nullptr;
|
||||
std::string preset_name;
|
||||
if (boost::starts_with(section.first, "print:")) {
|
||||
presets = &prints;
|
||||
presets = &this->prints;
|
||||
loaded = &loaded_prints;
|
||||
preset_name = section.first.substr(6);
|
||||
} else if (boost::starts_with(section.first, "filament:")) {
|
||||
presets = &filaments;
|
||||
presets = &this->filaments;
|
||||
loaded = &loaded_filaments;
|
||||
preset_name = section.first.substr(9);
|
||||
} else if (boost::starts_with(section.first, "printer:")) {
|
||||
presets = &printers;
|
||||
presets = &this->printers;
|
||||
loaded = &loaded_printers;
|
||||
preset_name = section.first.substr(8);
|
||||
} else if (section.first == "presets") {
|
||||
|
@ -664,6 +788,40 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
|
|||
for (auto &kvp : section.second)
|
||||
config.set_deserialize(kvp.first, kvp.second.data());
|
||||
Preset::normalize(config);
|
||||
if ((flags & LOAD_CFGBNDLE_SYSTEM) && presets == &printers) {
|
||||
// Filter out printer presets, which are not mentioned in the vendor profile.
|
||||
// These presets are considered not installed.
|
||||
auto printer_model = config.opt_string("printer_model");
|
||||
if (printer_model.empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||
section.first << "\" defines no printer model, it will be ignored.";
|
||||
continue;
|
||||
}
|
||||
auto printer_variant = config.opt_string("printer_variant");
|
||||
if (printer_variant.empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||
section.first << "\" defines no printer variant, it will be ignored.";
|
||||
continue;
|
||||
}
|
||||
auto it_model = vendor_profile->models.find(VendorProfile::PrinterModel(printer_model));
|
||||
if (it_model == vendor_profile->models.end()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||
section.first << "\" defines invalid printer model \"" << printer_model << "\", it will be ignored.";
|
||||
continue;
|
||||
}
|
||||
auto it_variant = it_model->variant(printer_variant);
|
||||
if (it_variant == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||
section.first << "\" defines invalid printer variant \"" << printer_variant << "\", it will be ignored.";
|
||||
continue;
|
||||
}
|
||||
const Preset *preset_existing = presets->find_preset(section.first, false);
|
||||
if (preset_existing != nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||
section.first << "\" has already been loaded from another Confing Bundle.";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Decide a full path to this .ini file.
|
||||
auto file_name = boost::algorithm::iends_with(preset_name, ".ini") ? preset_name : preset_name + ".ini";
|
||||
auto file_path = (boost::filesystem::path(data_dir())
|
||||
|
@ -678,24 +836,29 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
|
|||
Preset &loaded = presets->load_preset(file_path.string(), preset_name, std::move(config), false);
|
||||
if (flags & LOAD_CFGBNDLE_SAVE)
|
||||
loaded.save();
|
||||
if (flags & LOAD_CFGBNDLE_SYSTEM) {
|
||||
loaded.is_system = true;
|
||||
loaded.vendor = vendor_profile;
|
||||
}
|
||||
++ presets_loaded;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Activate the presets.
|
||||
if (! active_print.empty())
|
||||
prints.select_preset_by_name(active_print, true);
|
||||
if (! active_printer.empty())
|
||||
printers.select_preset_by_name(active_printer, true);
|
||||
// Activate the first filament preset.
|
||||
if (! active_filaments.empty() && ! active_filaments.front().empty())
|
||||
filaments.select_preset_by_name(active_filaments.front(), true);
|
||||
if ((flags & LOAD_CFGBNDLE_SYSTEM) == 0) {
|
||||
if (! active_print.empty())
|
||||
prints.select_preset_by_name(active_print, true);
|
||||
if (! active_printer.empty())
|
||||
printers.select_preset_by_name(active_printer, true);
|
||||
// Activate the first filament preset.
|
||||
if (! active_filaments.empty() && ! active_filaments.front().empty())
|
||||
filaments.select_preset_by_name(active_filaments.front(), true);
|
||||
this->update_multi_material_filament_presets();
|
||||
for (size_t i = 0; i < std::min(this->filament_presets.size(), active_filaments.size()); ++ i)
|
||||
this->filament_presets[i] = filaments.find_preset(active_filaments[i], true)->name;
|
||||
this->update_compatible_with_printer(false);
|
||||
}
|
||||
|
||||
this->update_multi_material_filament_presets();
|
||||
for (size_t i = 0; i < std::min(this->filament_presets.size(), active_filaments.size()); ++ i)
|
||||
this->filament_presets[i] = filaments.find_preset(active_filaments[i], true)->name;
|
||||
|
||||
this->update_compatible_with_printer(false);
|
||||
return presets_loaded;
|
||||
}
|
||||
|
||||
|
@ -836,49 +999,29 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, wxBitma
|
|||
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
|
||||
// to the filament color image.
|
||||
if (wide_icons)
|
||||
bitmap_key += preset.is_compatible ? "comp" : "notcomp";
|
||||
auto it = m_mapColorToBitmap.find(bitmap_key);
|
||||
wxBitmap *bitmap = (it == m_mapColorToBitmap.end()) ? nullptr : it->second;
|
||||
bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
|
||||
bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
|
||||
if (preset.is_dirty)
|
||||
bitmap_key += ",drty";
|
||||
wxBitmap *bitmap = m_bitmapCache->find(bitmap_key);
|
||||
if (bitmap == nullptr) {
|
||||
// Create the bitmap with color bars.
|
||||
bitmap = new wxBitmap((wide_icons ? 16 : 0) + 24, 16);
|
||||
#if defined(__APPLE__) || defined(_MSC_VER)
|
||||
bitmap->UseAlpha();
|
||||
#endif
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
if (wide_icons && ! preset.is_compatible)
|
||||
// Paint the red flag.
|
||||
memDC.DrawBitmap(*m_bitmapIncompatible, 0, 0, true);
|
||||
std::vector<wxBitmap> bmps;
|
||||
if (wide_icons)
|
||||
// Paint a red flag for incompatible presets.
|
||||
bmps.emplace_back(preset.is_compatible ? m_bitmapCache->mkclear(16, 16) : *m_bitmapIncompatible);
|
||||
// Paint the color bars.
|
||||
parse_color(filament_rgb, rgb);
|
||||
wxImage image(24, 16);
|
||||
image.InitAlpha();
|
||||
unsigned char* imgdata = image.GetData();
|
||||
unsigned char* imgalpha = image.GetAlpha();
|
||||
for (size_t i = 0; i < image.GetWidth() * image.GetHeight(); ++ i) {
|
||||
*imgdata ++ = rgb[0];
|
||||
*imgdata ++ = rgb[1];
|
||||
*imgdata ++ = rgb[2];
|
||||
*imgalpha ++ = wxALPHA_OPAQUE;
|
||||
}
|
||||
bmps.emplace_back(m_bitmapCache->mksolid(single_bar ? 24 : 16, 16, rgb));
|
||||
if (! single_bar) {
|
||||
parse_color(extruder_rgb, rgb);
|
||||
imgdata = image.GetData();
|
||||
for (size_t r = 0; r < 16; ++ r) {
|
||||
imgdata = image.GetData() + r * image.GetWidth() * 3;
|
||||
for (size_t c = 0; c < 16; ++ c) {
|
||||
*imgdata ++ = rgb[0];
|
||||
*imgdata ++ = rgb[1];
|
||||
*imgdata ++ = rgb[2];
|
||||
}
|
||||
}
|
||||
bmps.emplace_back(m_bitmapCache->mksolid(8, 16, rgb));
|
||||
}
|
||||
memDC.DrawBitmap(wxBitmap(image), wide_icons ? 16 : 0, 0, true);
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
m_mapColorToBitmap[bitmap_key] = bitmap;
|
||||
// Paint a lock at the system presets.
|
||||
bmps.emplace_back(m_bitmapCache->mkclear(4, 16));
|
||||
bmps.emplace_back((preset.is_system || preset.is_default) ?
|
||||
(preset.is_dirty ? *m_bitmapLockOpen : *m_bitmapLock) : m_bitmapCache->mkclear(16, 16));
|
||||
bitmap = m_bitmapCache->insert(bitmap_key, bmps);
|
||||
}
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), (bitmap == 0) ? wxNullBitmap : *bitmap);
|
||||
if (selected)
|
||||
|
|
|
@ -4,8 +4,14 @@
|
|||
#include "AppConfig.hpp"
|
||||
#include "Preset.hpp"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace GUI {
|
||||
class BitmapCache;
|
||||
};
|
||||
|
||||
class PlaceholderParser;
|
||||
|
||||
// Bundle of Print + Filament + Printer presets.
|
||||
|
@ -22,11 +28,10 @@ public:
|
|||
void setup_directories();
|
||||
|
||||
// Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets.
|
||||
void load_presets();
|
||||
|
||||
// Load selections (current print, current filaments, current printer) from config.ini
|
||||
// This is done just once on application start up.
|
||||
void load_selections(const AppConfig &config);
|
||||
void load_presets(const AppConfig &config);
|
||||
|
||||
// Export selections (current print, current filaments, current printer) into config.ini
|
||||
void export_selections(AppConfig &config);
|
||||
// Export selections (current print, current filaments, current printer) into a placeholder parser.
|
||||
|
@ -39,6 +44,10 @@ public:
|
|||
// extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
|
||||
std::vector<std::string> filament_presets;
|
||||
|
||||
// There will be an entry for each system profile loaded,
|
||||
// and the system profiles will point to the VendorProfile instances owned by PresetBundle::vendors.
|
||||
std::set<VendorProfile> vendors;
|
||||
|
||||
bool has_defauls_only() const
|
||||
{ return prints.size() <= 1 && filaments.size() <= 1 && printers.size() <= 1; }
|
||||
|
||||
|
@ -69,11 +78,16 @@ public:
|
|||
// 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_CFGBNDLE_RESET_USER_PROFILE = 2,
|
||||
// Load a system config bundle.
|
||||
LOAD_CFGBNDLE_SYSTEM = 4,
|
||||
};
|
||||
// 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);
|
||||
|
||||
// Install the Vendor specific config bundle into user's directory.
|
||||
void install_vendor_configbundle(const std::string &src_path);
|
||||
|
||||
// Export a config bundle file containing all the presets and the names of the active presets.
|
||||
void export_configbundle(const std::string &path); // , const DynamicPrintConfig &settings);
|
||||
|
||||
|
@ -99,6 +113,17 @@ public:
|
|||
void update_compatible_with_printer(bool select_other_if_incompatible);
|
||||
|
||||
private:
|
||||
std::string load_system_presets();
|
||||
|
||||
// Set the "enabled" 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);
|
||||
|
||||
// Load selections (current print, current filaments, current printer) from config.ini
|
||||
// This is done just once on application start up.
|
||||
void load_selections(const AppConfig &config);
|
||||
|
||||
// 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.
|
||||
|
@ -110,8 +135,12 @@ private:
|
|||
wxBitmap *m_bitmapCompatible;
|
||||
// Indicator, that the preset is NOT compatible with the selected printer.
|
||||
wxBitmap *m_bitmapIncompatible;
|
||||
// Caching color bitmaps for the
|
||||
std::map<std::string, wxBitmap*> m_mapColorToBitmap;
|
||||
// Indicator, that the preset is system and not modified.
|
||||
wxBitmap *m_bitmapLock;
|
||||
// Indicator, that the preset is system and user modified.
|
||||
wxBitmap *m_bitmapLockOpen;
|
||||
// Caching color bitmaps for the filament combo box.
|
||||
GUI::BitmapCache *m_bitmapCache;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -1623,7 +1623,7 @@ void Tab::save_preset(std::string name /*= ""*/)
|
|||
std::vector<std::string> values;
|
||||
for (size_t i = 0; i < m_presets->size(); ++i) {
|
||||
const Preset &preset = m_presets->preset(i);
|
||||
if (preset.is_default || preset.is_external)
|
||||
if (preset.is_default || preset.is_system || preset.is_external)
|
||||
continue;
|
||||
values.push_back(preset.name);
|
||||
}
|
||||
|
@ -1637,6 +1637,15 @@ void Tab::save_preset(std::string name /*= ""*/)
|
|||
show_error(this, _(L("The supplied name is empty. It can't be saved.")));
|
||||
return;
|
||||
}
|
||||
const Preset *existing = m_presets->find_preset(name, false);
|
||||
if (existing && (existing->is_default || existing->is_system)) {
|
||||
show_error(this, _(L("Cannot overwrite a system profile.")));
|
||||
return;
|
||||
}
|
||||
if (existing && (existing->is_external)) {
|
||||
show_error(this, _(L("Cannot overwrite an external.")));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Save the preset into Slic3r::data_dir / presets / section_name / preset_name.ini
|
||||
|
@ -1736,7 +1745,7 @@ wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox
|
|||
for (size_t idx = 0; idx < printers->size(); ++idx)
|
||||
{
|
||||
Preset& preset = printers->preset(idx);
|
||||
if (!preset.is_default && !preset.is_external)
|
||||
if (!preset.is_default && !preset.is_external && !preset.is_system)
|
||||
presets.Add(preset.name);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,4 +41,6 @@
|
|||
void update_skein_dir(char *dir);
|
||||
std::string get_last_output_dir(const char *alt = "");
|
||||
void update_last_output_dir(char *dir);
|
||||
|
||||
void reset_selections();
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
bool default() %code%{ RETVAL = THIS->is_default; %};
|
||||
bool external() %code%{ RETVAL = THIS->is_external; %};
|
||||
bool system() %code%{ RETVAL = THIS->is_system; %};
|
||||
bool visible() %code%{ RETVAL = THIS->is_visible; %};
|
||||
bool dirty() %code%{ RETVAL = THIS->is_dirty; %};
|
||||
bool compatible() %code%{ RETVAL = THIS->is_compatible; %};
|
||||
|
@ -110,10 +111,10 @@ PresetCollection::arrayref()
|
|||
croak("Cannot create configuration directories:\n%s\n", e.what());
|
||||
}
|
||||
%};
|
||||
void load_presets()
|
||||
void load_presets(AppConfig *config)
|
||||
%code%{
|
||||
try {
|
||||
THIS->load_presets();
|
||||
THIS->load_presets(*config);
|
||||
} catch (std::exception& e) {
|
||||
croak("Loading of Slic3r presets from %s failed.\n\n%s\n",
|
||||
Slic3r::data_dir().c_str(), e.what());
|
||||
|
@ -143,6 +144,14 @@ PresetCollection::arrayref()
|
|||
croak("Loading of a config bundle %s failed:\n%s\n", path, e.what());
|
||||
}
|
||||
%};
|
||||
void install_vendor_configbundle(const char *path)
|
||||
%code%{
|
||||
try {
|
||||
THIS->install_vendor_configbundle(path);
|
||||
} catch (std::exception& e) {
|
||||
croak("Installing a vendor config bundle %s failed:\n%s\n", path, e.what());
|
||||
}
|
||||
%};
|
||||
void export_configbundle(char *path)
|
||||
%code%{
|
||||
try {
|
||||
|
@ -154,7 +163,6 @@ PresetCollection::arrayref()
|
|||
|
||||
void set_default_suppressed(bool default_suppressed);
|
||||
|
||||
void load_selections (AppConfig *config) %code%{ THIS->load_selections(*config); %};
|
||||
void export_selections(AppConfig *config) %code%{ THIS->export_selections(*config); %};
|
||||
void export_selections_pp(PlaceholderParser *pp) %code%{ THIS->export_selections(*pp); %};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue