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

27
My Settings Normal file
View File

@ -0,0 +1,27 @@
# generated by Slic3r Prusa Edition 1.38.4 on 2017-12-20 at 11:02:03
bed_temperature = 0
bridge_fan_speed = 100
compatible_printers =
compatible_printers_condition =
cooling = 1
disable_fan_first_layers = 3
end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n"
extrusion_multiplier = 1
fan_always_on = 0
fan_below_layer_time = 60
filament_colour = #29b2b2
filament_cost = 0
filament_density = 0
filament_diameter = 3
filament_max_volumetric_speed = 0
filament_notes = ""
filament_soluble = 0
filament_type = PLA
first_layer_bed_temperature = 0
first_layer_temperature = 205
max_fan_speed = 100
min_fan_speed = 35
min_print_speed = 10
slowdown_below_layer_time = 5
start_filament_gcode = "; Filament gcode\n"
temperature = 200

View File

@ -110,12 +110,11 @@ sub OnInit {
# Suppress the '- default -' presets. # Suppress the '- default -' presets.
$self->{preset_bundle}->set_default_suppressed($self->{app_config}->get('no_defaults') ? 1 : 0); $self->{preset_bundle}->set_default_suppressed($self->{app_config}->get('no_defaults') ? 1 : 0);
eval { $self->{preset_bundle}->load_presets }; eval { $self->{preset_bundle}->load_presets($self->{app_config}); };
if ($@) { if ($@) {
warn $@ . "\n"; warn $@ . "\n";
show_error(undef, $@); show_error(undef, $@);
} }
eval { $self->{preset_bundle}->load_selections($self->{app_config}) };
$run_wizard = 1 if $self->{preset_bundle}->has_defauls_only; $run_wizard = 1 if $self->{preset_bundle}->has_defauls_only;
Slic3r::GUI::set_preset_bundle($self->{preset_bundle}); Slic3r::GUI::set_preset_bundle($self->{preset_bundle});

View File

@ -722,7 +722,13 @@ sub config_wizard {
wxTheApp->{preset_bundle}->load_config('My Settings', $result->{config}); wxTheApp->{preset_bundle}->load_config('My Settings', $result->{config});
} else { } else {
# Wizard returned a name of a preset bundle bundled with the installation. Unpack it. # Wizard returned a name of a preset bundle bundled with the installation. Unpack it.
wxTheApp->{preset_bundle}->load_configbundle($directory . '/' . $result->{preset_name} . '.ini'); wxTheApp->{preset_bundle}->install_vendor_configbundle($directory . '/' . $result->{preset_name} . '.ini');
# Reset the print / filament / printer selections, so that following line will select some sensible defaults.
if ($fresh_start) {
wxTheApp->{app_config}->reset_selections;
}
# Reload all presets after the vendor config bundle has been installed.
wxTheApp->{preset_bundle}->load_presets(wxTheApp->{app_config});
} }
}; };
Slic3r::GUI::catch_error($self) and return; Slic3r::GUI::catch_error($self) and return;

BIN
resources/icons/lock.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,28 @@
# generated by Slic3r Prusa Edition 1.39.0.29-prusa3d-win64 on 2018-01-22 at 14:53:14 # Print profiles for the Prusa Research printers.
[vendor]
# Vendor name will be shown by the Config Wizard.
name = Prusa Research
# Configuration version of this file. Config file will only be installed, if the config_version differs.
# This means, the server may force the Slic3r configuration to be downgraded.
config_version = 0.1
# Where to get the updates from?
config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch.ini
# The printer models will be shown by the Configuration Wizard in this order,
# also the first model installed & the first nozzle installed will be activated after install.
#TODO: One day we may differentiate variants of the nozzles / hot ends,
#for example by the melt zone size, or whether the nozzle is hardened.
[printer_model:MK3]
variants = 0.4; 0.25; 0.6
[printer_model:MK2S]
variants = 0.4; 0.25; 0.6
[printer_model:MK2SMM]
# Printer model name will be shown by the installation wizard.
name = MK2S Multi Material
variants = 0.4; 0.6
# All presets starting with asterisk, for example *common*, are intermediate and they will # All presets starting with asterisk, for example *common*, are intermediate and they will
# not make it into the user interface. # not make it into the user interface.
@ -898,6 +922,10 @@ use_volumetric_e = 0
variable_layer_height = 1 variable_layer_height = 1
wipe = 1 wipe = 1
z_offset = 0 z_offset = 0
printer_model = MK2S
printer_variant = 0.4
default_print_profile = 0.15mm OPTIMAL
default_filament_profile = Prusa PLA
[printer:*multimaterial*] [printer:*multimaterial*]
inherits = *common* inherits = *common*
@ -914,6 +942,7 @@ retract_restart_extra = 0
retract_restart_extra_toolchange = 0 retract_restart_extra_toolchange = 0
retract_speed = 80 retract_speed = 80
single_extruder_multi_material = 1 single_extruder_multi_material = 1
printer_model = MK2SMM
[printer:*mm-single*] [printer:*mm-single*]
inherits = *multimaterial* inherits = *multimaterial*
@ -941,12 +970,15 @@ nozzle_diameter = 0.25
retract_length = 1 retract_length = 1
retract_speed = 50 retract_speed = 50
variable_layer_height = 0 variable_layer_height = 0
printer_variant = 0.25
default_print_profile = 0.10mm DETAIL 0.25 nozzle
[printer:Original Prusa i3 MK2 0.6 nozzle] [printer:Original Prusa i3 MK2 0.6 nozzle]
inherits = *common* inherits = *common*
max_layer_height = 0.35 max_layer_height = 0.35
min_layer_height = 0.1 min_layer_height = 0.1
nozzle_diameter = 0.6 nozzle_diameter = 0.6
printer_variant = 0.6
[printer:Original Prusa i3 MK2 MM Single Mode] [printer:Original Prusa i3 MK2 MM Single Mode]
inherits = *mm-single* inherits = *mm-single*
@ -954,6 +986,7 @@ inherits = *mm-single*
[printer:Original Prusa i3 MK2 MM Single Mode 0.6 nozzle] [printer:Original Prusa i3 MK2 MM Single Mode 0.6 nozzle]
inherits = *mm-single* inherits = *mm-single*
nozzle_diameter = 0.6 nozzle_diameter = 0.6
printer_variant = 0.6
[printer:Original Prusa i3 MK2 MultiMaterial] [printer:Original Prusa i3 MK2 MultiMaterial]
inherits = *mm-multi* inherits = *mm-multi*
@ -962,6 +995,7 @@ nozzle_diameter = 0.4,0.4,0.4,0.4
[printer:Original Prusa i3 MK2 MultiMaterial 0.6 nozzle] [printer:Original Prusa i3 MK2 MultiMaterial 0.6 nozzle]
inherits = *mm-multi* inherits = *mm-multi*
nozzle_diameter = 0.6,0.6,0.6,0.6 nozzle_diameter = 0.6,0.6,0.6,0.6
printer_variant = 0.6
[printer:Original Prusa i3 MK3] [printer:Original Prusa i3 MK3]
inherits = *common* inherits = *common*
@ -969,8 +1003,5 @@ end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
retract_lift_below = 209 retract_lift_below = 209
start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif} start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
printer_model = MK3
[presets] default_print_profile = 0.15mm OPTIMAL MK3
print = 0.15mm OPTIMAL MK3
printer = Original Prusa i3 MK3
filament = Prusa PLA

View File

@ -171,6 +171,8 @@ add_library(libslic3r STATIC
add_library(libslic3r_gui STATIC add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/GUI/AppConfig.cpp ${LIBDIR}/slic3r/GUI/AppConfig.cpp
${LIBDIR}/slic3r/GUI/AppConfig.hpp ${LIBDIR}/slic3r/GUI/AppConfig.hpp
${LIBDIR}/slic3r/GUI/BitmapCache.cpp
${LIBDIR}/slic3r/GUI/BitmapCache.hpp
${LIBDIR}/slic3r/GUI/3DScene.cpp ${LIBDIR}/slic3r/GUI/3DScene.cpp
${LIBDIR}/slic3r/GUI/3DScene.hpp ${LIBDIR}/slic3r/GUI/3DScene.hpp
${LIBDIR}/slic3r/GUI/GLShader.cpp ${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. // This is only possible if other is of DynamicConfig type.
if (ignore_nonexistent) if (ignore_nonexistent)
continue; continue;
throw UnknownOptionException(); throw UnknownOptionException(opt_key);
} }
const ConfigOption *other_opt = other.option(opt_key); const ConfigOption *other_opt = other.option(opt_key);
if (other_opt != nullptr) 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. // Try to deserialize the option by its name.
const ConfigDef *def = this->def(); const ConfigDef *def = this->def();
if (def == nullptr) if (def == nullptr)
throw NoDefinitionException(); throw NoDefinitionException(opt_key);
const ConfigOptionDef *optdef = def->get(opt_key); const ConfigOptionDef *optdef = def->get(opt_key);
if (optdef == nullptr) { if (optdef == nullptr) {
// If we didn't find an option, look for any other option having this as an alias. // 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; break;
} }
if (optdef == nullptr) if (optdef == nullptr)
throw UnknownOptionException(); throw UnknownOptionException(opt_key);
} }
if (! optdef->shortcut.empty()) { if (! optdef->shortcut.empty()) {
@ -278,7 +278,7 @@ double ConfigBase::get_abs_value(const t_config_option_key &opt_key) const
// Get option definition. // Get option definition.
const ConfigDef *def = this->def(); const ConfigDef *def = this->def();
if (def == nullptr) if (def == nullptr)
throw NoDefinitionException(); throw NoDefinitionException(opt_key);
const ConfigOptionDef *opt_def = def->get(opt_key); const ConfigOptionDef *opt_def = def->get(opt_key);
assert(opt_def != nullptr); assert(opt_def != nullptr);
// Compute absolute value over the absolute value of the base option. // 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. // Try to create a new ConfigOption.
const ConfigDef *def = this->def(); const ConfigDef *def = this->def();
if (def == nullptr) if (def == nullptr)
throw NoDefinitionException(); throw NoDefinitionException(opt_key);
const ConfigOptionDef *optdef = def->get(opt_key); const ConfigOptionDef *optdef = def->get(opt_key);
if (optdef == nullptr) if (optdef == nullptr)
// throw std::runtime_error(std::string("Invalid option name: ") + opt_key); // 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. /// 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: 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). /// 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: 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->min = 0;
def->default_value = new ConfigOptionFloat(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 = this->add("disable_fan_first_layers", coInts);
def->label = L("Disable fan for the first"); def->label = L("Disable fan for the first");
def->tooltip = L("You can set this to a positive value to disable fan at all " 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->min = 0;
def->default_value = new ConfigOptionFloat(80); 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 = this->add("interface_shells", coBool);
def->label = L("Interface shells"); def->label = L("Interface shells");
def->tooltip = L("Force the generation of solid shells between adjacent materials/volumes. " def->tooltip = L("Force the generation of solid shells between adjacent materials/volumes. "
@ -1017,6 +1036,11 @@ PrintConfigDef::PrintConfigDef()
def->height = 60; def->height = 60;
def->default_value = new ConfigOptionStrings{ "" }; 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 = this->add("printer_notes", coString);
def->label = L("Printer notes"); def->label = L("Printer notes");
def->tooltip = L("You can put your notes regarding the printer here."); def->tooltip = L("You can put your notes regarding the printer here.");
@ -1026,6 +1050,16 @@ PrintConfigDef::PrintConfigDef()
def->height = 130; def->height = 130;
def->default_value = new ConfigOptionString(""); 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 = this->add("print_settings_id", coString);
def->default_value = new ConfigOptionString(""); 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); 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() std::string AppConfig::config_path()
{ {
return (boost::filesystem::path(Slic3r::data_dir()) / "slic3r.ini").make_preferred().string(); 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; std::string get_last_output_dir(const std::string &alt) const;
void update_last_output_dir(const std::string &dir); 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(). // Get the default config path from Slic3r::data_dir().
static std::string config_path(); 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; } wxSizer* getSizer() override { return sizer; }
}; };
#endif
} // GUI } // GUI
} // Slic3r } // 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); auto *opt = config.option(key, false);
assert(opt != nullptr); assert(opt != nullptr);
assert(opt->is_vector()); 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)); 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", "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", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
"wipe_tower_width", "wipe_tower_per_color_wipe", "wipe_tower_width", "wipe_tower_per_color_wipe",
"compatible_printers", "compatible_printers_condition" "compatible_printers", "compatible_printers_condition", "inherits"
}; };
return s_opts; 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", "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", "disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", "start_filament_gcode",
"end_filament_gcode", "end_filament_gcode",
"compatible_printers", "compatible_printers_condition" "compatible_printers", "compatible_printers_condition", "inherits"
}; };
return s_opts; 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", "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", "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", "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()); s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
} }
return s_opts; 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() const std::vector<std::string>& Preset::nozzle_options()
{ {
// ConfigOptionFloats, ConfigOptionPercents, ConfigOptionBools, ConfigOptionStrings // 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", "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_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed",
"retract_before_wipe", "retract_restart_extra", "retract_before_travel", "wipe", "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; return s_opts;
} }
@ -269,7 +272,7 @@ void PresetCollection::reset(bool delete_files)
if (delete_files) { if (delete_files) {
// Erase the preset files. // Erase the preset files.
for (Preset &preset : m_presets) 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()); boost::nowide::remove(preset.file.c_str());
} }
// Don't use m_presets.resize() here as it requires a default constructor for Preset. // 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(); boost::filesystem::path dir = boost::filesystem::canonical(boost::filesystem::path(dir_path) / subdir).make_preferred();
m_dir_path = dir.string(); 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(); t_config_option_keys keys = this->default_preset().config.keys();
std::string errors_cummulative; std::string errors_cummulative;
for (auto &dir_entry : boost::filesystem::directory_iterator(dir)) 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(); std::string name = dir_entry.path().filename().string();
// Remove the .ini suffix. // Remove the .ini suffix.
name.erase(name.size() - 4); 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 { try {
Preset preset(m_type, name, false); Preset preset(m_type, name, false);
preset.file = dir_entry.path().string(); 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) { if (it != m_presets.end() && it->name == new_name) {
// Preset with the same name found. // Preset with the same name found.
Preset &preset = *it; Preset &preset = *it;
if (preset.is_default) if (preset.is_default || preset.is_external || preset.is_system)
// Cannot overwrite the default preset. // Cannot overwrite the default preset.
return; return;
// Overwriting an existing preset. // Overwriting an existing preset.
preset.config = std::move(m_edited_preset.config); preset.config = std::move(m_edited_preset.config);
} else { } else {
// Creating a new preset. // 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.name = new_name;
preset.file = this->path_from_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. // 2) Activate the saved preset.
this->select_preset_by_name(new_name, true); this->select_preset_by_name(new_name, true);
@ -364,7 +387,7 @@ void PresetCollection::delete_current_preset()
const Preset &selected = this->get_selected_preset(); const Preset &selected = this->get_selected_preset();
if (selected.is_default) if (selected.is_default)
return; return;
if (! selected.is_external) { if (! selected.is_external && ! selected.is_system) {
// Erase the preset file. // Erase the preset file.
boost::nowide::remove(selected.file.c_str()); 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); 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. // 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. // 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) 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; return was_dirty != is_dirty;
} }
std::vector<std::string> PresetCollection::current_dirty_options() const std::vector<std::string> PresetCollection::dirty_options(const Preset *edited, const Preset *reference)
{ {
std::vector<std::string> changed = this->get_selected_preset().config.diff(this->get_edited_preset().config); std::vector<std::string> changed;
// The "compatible_printers" option key is handled differently from the others: if (edited != nullptr && reference != nullptr) {
// It is not mandatory. If the key is missing, it means it is compatible with any printer. changed = reference->config.diff(edited->config);
// If the key exists and it is empty, it means it is compatible with no printer. // The "compatible_printers" option key is handled differently from the others:
std::initializer_list<const char*> optional_keys { "compatible_printers", "compatible_printers_condition" }; // It is not mandatory. If the key is missing, it means it is compatible with any printer.
for (auto &opt_key : optional_keys) { // If the key exists and it is empty, it means it is compatible with no printer.
if (this->get_selected_preset().config.has(opt_key) != this->get_edited_preset().config.has(opt_key)) std::initializer_list<const char*> optional_keys { "compatible_printers", "compatible_printers_condition" };
changed.emplace_back(opt_key); for (auto &opt_key : optional_keys) {
if (reference->config.has(opt_key) != edited->config.has(opt_key))
changed.emplace_back(opt_key);
}
} }
return changed; return changed;
} }

View File

@ -23,6 +23,46 @@ enum ConfigFileType
extern ConfigFileType guess_config_file_type(const boost::property_tree::ptree &tree); 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 class Preset
{ {
public: public:
@ -44,6 +84,8 @@ public:
// External preset points to a configuration, which has been loaded but not imported // External preset points to a configuration, which has been loaded but not imported
// into the Slic3r default configuration location. // into the Slic3r default configuration location.
bool is_external = false; bool is_external = false;
// System preset is read-only.
bool is_system = false;
// Preset is visible, if it is compatible with the active Printer. // 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. // Also the "default" preset is only visible, if it is the only preset in the list.
bool is_visible = true; bool is_visible = true;
@ -55,9 +97,14 @@ public:
// Name of the preset, usually derived form the file name. // Name of the preset, usually derived form the file name.
std::string name; std::string name;
// File name of the preset. This could be a Print / Filament / Printer preset, // 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). // or it could be a G-code (again, is_external will be true).
std::string file; 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? // Has this profile been loaded?
bool loaded = false; bool loaded = false;
@ -144,6 +191,8 @@ public:
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items. // Compatible & incompatible marks, to be placed at the wxBitmapComboBox items.
void set_bitmap_compatible (const wxBitmap *bmp) { m_bitmap_compatible = bmp; } 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_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. // Enable / disable the "- default -" preset.
void set_default_suppressed(bool default_suppressed); void set_default_suppressed(bool default_suppressed);
@ -155,6 +204,11 @@ public:
Preset& get_selected_preset() { return m_presets[m_idx_selected]; } Preset& get_selected_preset() { return m_presets[m_idx_selected]; }
const Preset& get_selected_preset() const { 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; } 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. // Return the selected preset including the user modifications.
Preset& get_edited_preset() { return m_edited_preset; } Preset& get_edited_preset() { return m_edited_preset; }
const Preset& get_edited_preset() const { 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. // 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(); } 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. // 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. // Update the choice UI from the list of presets.
// If show_incompatible, all presets are shown, otherwise only the compatible presets are shown. // 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 std::deque<Preset>::const_iterator find_preset_internal(const std::string &name) const
{ return const_cast<PresetCollection*>(this)->find_preset_internal(name); } { 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. // Type of this PresetCollection: TYPE_PRINT, TYPE_FILAMENT or TYPE_PRINTER.
Preset::Type m_type; Preset::Type m_type;
// List of presets, starting with the "- default -" preset. // List of presets, starting with the "- default -" preset.
@ -245,8 +305,10 @@ private:
bool m_default_suppressed = true; bool m_default_suppressed = true;
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items of a Platter. // Compatible & incompatible marks, to be placed at the wxBitmapComboBox items of a Platter.
// These bitmaps are not owned by PresetCollection, but by a PresetBundle. // 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_incompatible = nullptr;
const wxBitmap *m_bitmap_lock = nullptr;
const wxBitmap *m_bitmap_lock_open = nullptr;
// Marks placed at the wxBitmapComboBox of a MainFrame. // Marks placed at the wxBitmapComboBox of a MainFrame.
// These bitmaps are owned by PresetCollection. // These bitmaps are owned by PresetCollection.
wxBitmap *m_bitmap_main_frame; wxBitmap *m_bitmap_main_frame;

View File

@ -2,6 +2,7 @@
#include <cassert> #include <cassert>
#include "PresetBundle.hpp" #include "PresetBundle.hpp"
#include "BitmapCache.hpp"
#include <fstream> #include <fstream>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
@ -37,7 +38,10 @@ PresetBundle::PresetBundle() :
filaments(Preset::TYPE_FILAMENT, Preset::filament_options()), filaments(Preset::TYPE_FILAMENT, Preset::filament_options()),
printers(Preset::TYPE_PRINTER, Preset::printer_options()), printers(Preset::TYPE_PRINTER, Preset::printer_options()),
m_bitmapCompatible(new wxBitmap), 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) if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
wxImage::AddHandler(new wxPNGHandler); wxImage::AddHandler(new wxPNGHandler);
@ -51,6 +55,14 @@ PresetBundle::PresetBundle() :
this->filaments.preset(0).config.optptr("compatible_printers_condition", true); 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", true);
this->prints.preset(0).config.optptr("compatible_printers_condition", 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->prints .load_bitmap_default("cog.png");
this->filaments.load_bitmap_default("spool.png"); this->filaments.load_bitmap_default("spool.png");
@ -62,12 +74,18 @@ PresetBundle::~PresetBundle()
{ {
assert(m_bitmapCompatible != nullptr); assert(m_bitmapCompatible != nullptr);
assert(m_bitmapIncompatible != nullptr); assert(m_bitmapIncompatible != nullptr);
assert(m_bitmapLock != nullptr);
assert(m_bitmapLockOpen != nullptr);
delete m_bitmapCompatible; delete m_bitmapCompatible;
m_bitmapCompatible = nullptr; m_bitmapCompatible = nullptr;
delete m_bitmapIncompatible; delete m_bitmapIncompatible;
m_bitmapIncompatible = nullptr; m_bitmapIncompatible = nullptr;
for (std::pair<const std::string, wxBitmap*> &bitmap : m_mapColorToBitmap) delete m_bitmapLock;
delete bitmap.second; m_bitmapLock = nullptr;
delete m_bitmapLockOpen;
m_bitmapLockOpen = nullptr;
delete m_bitmapCache;
m_bitmapCache = nullptr;
} }
void PresetBundle::reset(bool delete_files) 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()); boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
std::initializer_list<boost::filesystem::path> paths = { std::initializer_list<boost::filesystem::path> paths = {
data_dir, data_dir,
data_dir / "vendor",
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR #ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
// Store the print/filament/printer presets into a "presets" directory. // Store the print/filament/printer presets into a "presets" directory.
data_dir / "presets", 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; // First load the vendor specific system presets.
const std::string dir_path = data_dir() std::string errors_cummulative = this->load_system_presets();
const std::string dir_user_presets = data_dir()
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR #ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
// Store the print/filament/printer presets into a "presets" directory. // Store the print/filament/printer presets into a "presets" directory.
+ "/presets" + "/presets"
@ -119,17 +140,17 @@ void PresetBundle::load_presets()
#endif #endif
; ;
try { try {
this->prints.load_presets(dir_path, "print"); this->prints.load_presets(dir_user_presets, "print");
} catch (const std::runtime_error &err) { } catch (const std::runtime_error &err) {
errors_cummulative += err.what(); errors_cummulative += err.what();
} }
try { try {
this->filaments.load_presets(dir_path, "filament"); this->filaments.load_presets(dir_user_presets, "filament");
} catch (const std::runtime_error &err) { } catch (const std::runtime_error &err) {
errors_cummulative += err.what(); errors_cummulative += err.what();
} }
try { try {
this->printers.load_presets(dir_path, "printer"); this->printers.load_presets(dir_user_presets, "printer");
} catch (const std::runtime_error &err) { } catch (const std::runtime_error &err) {
errors_cummulative += err.what(); errors_cummulative += err.what();
} }
@ -137,6 +158,31 @@ void PresetBundle::load_presets()
this->update_compatible_with_printer(false); this->update_compatible_with_printer(false);
if (! errors_cummulative.empty()) if (! errors_cummulative.empty())
throw std::runtime_error(errors_cummulative); 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) 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; 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 // Load selections (current print, current filaments, current printer) from config.ini
// This is done just once on application start up. // This is done just once on application start up.
void PresetBundle::load_selections(const AppConfig &config) 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_compatible = "flag-green-icon.png";
const std::string path_bitmap_incompatible = "flag-red-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( bool loaded_compatible = m_bitmapCompatible ->LoadFile(
wxString::FromUTF8(Slic3r::var(path_bitmap_compatible).c_str()), wxBITMAP_TYPE_PNG); wxString::FromUTF8(Slic3r::var(path_bitmap_compatible).c_str()), wxBITMAP_TYPE_PNG);
bool loaded_incompatible = m_bitmapIncompatible->LoadFile( bool loaded_incompatible = m_bitmapIncompatible->LoadFile(
wxString::FromUTF8(Slic3r::var(path_bitmap_incompatible).c_str()), wxBITMAP_TYPE_PNG); 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) { if (loaded_compatible) {
prints .set_bitmap_compatible(m_bitmapCompatible); prints .set_bitmap_compatible(m_bitmapCompatible);
filaments.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); filaments.set_bitmap_incompatible(m_bitmapIncompatible);
// printers .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 DynamicPrintConfig PresetBundle::full_config() const
@ -594,11 +664,54 @@ static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree)
flatten_configbundle_hierarchy(tree, "printer"); 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 // Load a config bundle file, into presets and store the loaded presets into separate files
// of the local configuration directory. // of the local configuration directory.
size_t PresetBundle::load_configbundle(const std::string &path, unsigned int flags) 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); this->reset(flags & LOAD_CFGBNDLE_SAVE);
// 1) Read the complete config file into a boost::property_tree. // 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 the config bundle by applying the inheritance rules. Internal profiles (with names starting with '*') are removed.
flatten_configbundle_hierarchy(tree); 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. // 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_prints;
std::vector<std::string> loaded_filaments; 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::vector<std::string> *loaded = nullptr;
std::string preset_name; std::string preset_name;
if (boost::starts_with(section.first, "print:")) { if (boost::starts_with(section.first, "print:")) {
presets = &prints; presets = &this->prints;
loaded = &loaded_prints; loaded = &loaded_prints;
preset_name = section.first.substr(6); preset_name = section.first.substr(6);
} else if (boost::starts_with(section.first, "filament:")) { } else if (boost::starts_with(section.first, "filament:")) {
presets = &filaments; presets = &this->filaments;
loaded = &loaded_filaments; loaded = &loaded_filaments;
preset_name = section.first.substr(9); preset_name = section.first.substr(9);
} else if (boost::starts_with(section.first, "printer:")) { } else if (boost::starts_with(section.first, "printer:")) {
presets = &printers; presets = &this->printers;
loaded = &loaded_printers; loaded = &loaded_printers;
preset_name = section.first.substr(8); preset_name = section.first.substr(8);
} else if (section.first == "presets") { } 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) for (auto &kvp : section.second)
config.set_deserialize(kvp.first, kvp.second.data()); config.set_deserialize(kvp.first, kvp.second.data());
Preset::normalize(config); 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. // 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_name = boost::algorithm::iends_with(preset_name, ".ini") ? preset_name : preset_name + ".ini";
auto file_path = (boost::filesystem::path(data_dir()) 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); Preset &loaded = presets->load_preset(file_path.string(), preset_name, std::move(config), false);
if (flags & LOAD_CFGBNDLE_SAVE) if (flags & LOAD_CFGBNDLE_SAVE)
loaded.save(); loaded.save();
if (flags & LOAD_CFGBNDLE_SYSTEM) {
loaded.is_system = true;
loaded.vendor = vendor_profile;
}
++ presets_loaded; ++ presets_loaded;
} }
} }
// 3) Activate the presets. // 3) Activate the presets.
if (! active_print.empty()) if ((flags & LOAD_CFGBNDLE_SYSTEM) == 0) {
prints.select_preset_by_name(active_print, true); if (! active_print.empty())
if (! active_printer.empty()) prints.select_preset_by_name(active_print, true);
printers.select_preset_by_name(active_printer, true); if (! active_printer.empty())
// Activate the first filament preset. printers.select_preset_by_name(active_printer, true);
if (! active_filaments.empty() && ! active_filaments.front().empty()) // Activate the first filament preset.
filaments.select_preset_by_name(active_filaments.front(), true); 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; 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 // If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
// to the filament color image. // to the filament color image.
if (wide_icons) if (wide_icons)
bitmap_key += preset.is_compatible ? "comp" : "notcomp"; bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
auto it = m_mapColorToBitmap.find(bitmap_key); bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
wxBitmap *bitmap = (it == m_mapColorToBitmap.end()) ? nullptr : it->second; if (preset.is_dirty)
bitmap_key += ",drty";
wxBitmap *bitmap = m_bitmapCache->find(bitmap_key);
if (bitmap == nullptr) { if (bitmap == nullptr) {
// Create the bitmap with color bars. // Create the bitmap with color bars.
bitmap = new wxBitmap((wide_icons ? 16 : 0) + 24, 16); std::vector<wxBitmap> bmps;
#if defined(__APPLE__) || defined(_MSC_VER) if (wide_icons)
bitmap->UseAlpha(); // Paint a red flag for incompatible presets.
#endif bmps.emplace_back(preset.is_compatible ? m_bitmapCache->mkclear(16, 16) : *m_bitmapIncompatible);
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);
// Paint the color bars. // Paint the color bars.
parse_color(filament_rgb, rgb); parse_color(filament_rgb, rgb);
wxImage image(24, 16); bmps.emplace_back(m_bitmapCache->mksolid(single_bar ? 24 : 16, 16, rgb));
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;
}
if (! single_bar) { if (! single_bar) {
parse_color(extruder_rgb, rgb); parse_color(extruder_rgb, rgb);
imgdata = image.GetData(); bmps.emplace_back(m_bitmapCache->mksolid(8, 16, rgb));
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];
}
}
} }
memDC.DrawBitmap(wxBitmap(image), wide_icons ? 16 : 0, 0, true); // Paint a lock at the system presets.
memDC.SelectObject(wxNullBitmap); bmps.emplace_back(m_bitmapCache->mkclear(4, 16));
m_mapColorToBitmap[bitmap_key] = bitmap; 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); ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), (bitmap == 0) ? wxNullBitmap : *bitmap);
if (selected) if (selected)

View File

@ -4,8 +4,14 @@
#include "AppConfig.hpp" #include "AppConfig.hpp"
#include "Preset.hpp" #include "Preset.hpp"
#include <set>
namespace Slic3r { namespace Slic3r {
namespace GUI {
class BitmapCache;
};
class PlaceholderParser; class PlaceholderParser;
// Bundle of Print + Filament + Printer presets. // Bundle of Print + Filament + Printer presets.
@ -22,11 +28,10 @@ public:
void setup_directories(); void setup_directories();
// Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets. // 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 // Load selections (current print, current filaments, current printer) from config.ini
// This is done just once on application start up. // 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 // Export selections (current print, current filaments, current printer) into config.ini
void export_selections(AppConfig &config); void export_selections(AppConfig &config);
// Export selections (current print, current filaments, current printer) into a placeholder parser. // 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() // extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
std::vector<std::string> filament_presets; 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 bool has_defauls_only() const
{ return prints.size() <= 1 && filaments.size() <= 1 && printers.size() <= 1; } { return prints.size() <= 1 && filaments.size() <= 1 && printers.size() <= 1; }
@ -69,11 +78,16 @@ public:
// Save the profiles, which have been loaded. // Save the profiles, which have been loaded.
LOAD_CFGBNDLE_SAVE = 1, LOAD_CFGBNDLE_SAVE = 1,
// Delete all old config profiles before loading. // 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. // 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); 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. // 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); 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); void update_compatible_with_printer(bool select_other_if_incompatible);
private: 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. // 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. // 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. // 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; wxBitmap *m_bitmapCompatible;
// Indicator, that the preset is NOT compatible with the selected printer. // Indicator, that the preset is NOT compatible with the selected printer.
wxBitmap *m_bitmapIncompatible; wxBitmap *m_bitmapIncompatible;
// Caching color bitmaps for the // Indicator, that the preset is system and not modified.
std::map<std::string, wxBitmap*> m_mapColorToBitmap; 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 } // namespace Slic3r

View File

@ -1623,7 +1623,7 @@ void Tab::save_preset(std::string name /*= ""*/)
std::vector<std::string> values; std::vector<std::string> values;
for (size_t i = 0; i < m_presets->size(); ++i) { for (size_t i = 0; i < m_presets->size(); ++i) {
const Preset &preset = m_presets->preset(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; continue;
values.push_back(preset.name); 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."))); show_error(this, _(L("The supplied name is empty. It can't be saved.")));
return; 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 // 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) for (size_t idx = 0; idx < printers->size(); ++idx)
{ {
Preset& preset = printers->preset(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); presets.Add(preset.name);
} }

View File

@ -41,4 +41,6 @@
void update_skein_dir(char *dir); void update_skein_dir(char *dir);
std::string get_last_output_dir(const char *alt = ""); std::string get_last_output_dir(const char *alt = "");
void update_last_output_dir(char *dir); void update_last_output_dir(char *dir);
void reset_selections();
}; };

View File

@ -12,6 +12,7 @@
bool default() %code%{ RETVAL = THIS->is_default; %}; bool default() %code%{ RETVAL = THIS->is_default; %};
bool external() %code%{ RETVAL = THIS->is_external; %}; bool external() %code%{ RETVAL = THIS->is_external; %};
bool system() %code%{ RETVAL = THIS->is_system; %};
bool visible() %code%{ RETVAL = THIS->is_visible; %}; bool visible() %code%{ RETVAL = THIS->is_visible; %};
bool dirty() %code%{ RETVAL = THIS->is_dirty; %}; bool dirty() %code%{ RETVAL = THIS->is_dirty; %};
bool compatible() %code%{ RETVAL = THIS->is_compatible; %}; bool compatible() %code%{ RETVAL = THIS->is_compatible; %};
@ -110,10 +111,10 @@ PresetCollection::arrayref()
croak("Cannot create configuration directories:\n%s\n", e.what()); croak("Cannot create configuration directories:\n%s\n", e.what());
} }
%}; %};
void load_presets() void load_presets(AppConfig *config)
%code%{ %code%{
try { try {
THIS->load_presets(); THIS->load_presets(*config);
} catch (std::exception& e) { } catch (std::exception& e) {
croak("Loading of Slic3r presets from %s failed.\n\n%s\n", croak("Loading of Slic3r presets from %s failed.\n\n%s\n",
Slic3r::data_dir().c_str(), e.what()); 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()); 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) void export_configbundle(char *path)
%code%{ %code%{
try { try {
@ -154,7 +163,6 @@ PresetCollection::arrayref()
void set_default_suppressed(bool default_suppressed); 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(AppConfig *config) %code%{ THIS->export_selections(*config); %};
void export_selections_pp(PlaceholderParser *pp) %code%{ THIS->export_selections(*pp); %}; void export_selections_pp(PlaceholderParser *pp) %code%{ THIS->export_selections(*pp); %};