Merge remote-tracking branch 'origin/profile_inheritance' into profile_changes_reset

This commit is contained in:
YuSanka 2018-03-14 16:34:51 +01:00
commit a41e55a773
25 changed files with 688 additions and 10209 deletions

View file

@ -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

View file

@ -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);

View file

@ -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) {}
};
}

View file

@ -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("");

View file

@ -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();

View file

@ -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();

View 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

View 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 */

View file

@ -280,9 +280,7 @@ public:
wxSizer* getSizer() override { return sizer; }
};
#endif
} // GUI
} // Slic3r
#endif /* SLIC3R_GUI_FIELD_HPP */

View file

@ -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;
}

View file

@ -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;

View file

@ -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 &section : 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)

View file

@ -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

View file

@ -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);
}

View file

@ -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();
};

View file

@ -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); %};