Merge remote-tracking branch 'remotes/origin/profile_changes_reset'

This commit is contained in:
bubnikv 2018-04-05 19:53:53 +02:00
commit e37cbdfcfc
33 changed files with 1190 additions and 215 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)
@ -206,6 +206,18 @@ t_config_option_keys ConfigBase::diff(const ConfigBase &other) const
return diff;
}
t_config_option_keys ConfigBase::equal(const ConfigBase &other) const
{
t_config_option_keys equal;
for (const t_config_option_key &opt_key : this->keys()) {
const ConfigOption *this_opt = this->option(opt_key);
const ConfigOption *other_opt = other.option(opt_key);
if (this_opt != nullptr && other_opt != nullptr && *this_opt == *other_opt)
equal.emplace_back(opt_key);
}
return equal;
}
std::string ConfigBase::serialize(const t_config_option_key &opt_key) const
{
const ConfigOption* opt = this->option(opt_key);
@ -232,7 +244,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 +260,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 +290,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 +480,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

@ -1046,6 +1046,7 @@ public:
void apply_only(const ConfigBase &other, const t_config_option_keys &keys, bool ignore_nonexistent = false);
bool equals(const ConfigBase &other) const { return this->diff(other).empty(); }
t_config_option_keys diff(const ConfigBase &other) const;
t_config_option_keys equal(const ConfigBase &other) const;
std::string serialize(const t_config_option_key &opt_key) const;
// Set a configuration value from a string, it will call an overridable handle_legacy()
// to resolve renamed and removed configuration keys.
@ -1232,17 +1233,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 "
@ -406,7 +418,7 @@ PrintConfigDef::PrintConfigDef()
def->tooltip = L("This is only used in the Slic3r interface as a visual help.");
def->cli = "filament-color=s@";
def->gui_type = "color";
def->default_value = new ConfigOptionStrings { "#29b2b2" };
def->default_value = new ConfigOptionStrings { "#29B2B2" };
def = this->add("filament_notes", coStrings);
def->label = L("Filament notes");
@ -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. "
@ -1022,7 +1041,12 @@ PrintConfigDef::PrintConfigDef()
def->multiline = true;
def->full_width = true;
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->label = L("Printer notes");
@ -1033,6 +1057,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

@ -183,7 +183,8 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
vertex_distances.push_back(distance);
avg_dist += distance;
}
avg_dist /= vertex_distances.size();
bool defined_value = true;
for (auto el: vertex_distances)
{

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

@ -19,16 +19,24 @@ namespace Slic3r { namespace GUI {
}
void Field::PostInitialize(){
m_Undo_btn = new wxButton(m_parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER);
// use bouth of temporary_icons till don't have "undo_icon"
auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
if (wxMSW) m_Undo_btn->SetBackgroundColour(color);
m_Undo_btn = new wxButton(m_parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER);
m_Undo_to_sys_btn = new wxButton(m_parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER);
if (wxMSW) {
m_Undo_btn->SetBackgroundColour(color);
m_Undo_to_sys_btn->SetBackgroundColour(color);
}
m_Undo_btn->SetBitmap(wxBitmap(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG));
m_Undo_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent){ on_back_to_initial_value(); }));
m_Undo_to_sys_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent){ on_back_to_sys_value(); }));
BUILD();
}
void Field::set_nonsys_btn_icon(const std::string& icon){
m_Undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var(icon)), wxBITMAP_TYPE_PNG));
}
void Field::on_kill_focus(wxEvent& event) {
// Without this, there will be nasty focus bugs on Windows.
// Also, docs for wxEvent::Skip() say "In general, it is recommended to skip all
@ -45,12 +53,16 @@ namespace Slic3r { namespace GUI {
m_on_change(m_opt_id, get_value());
}
void Field::on_back_to_initial_value()
{
void Field::on_back_to_initial_value(){
if (m_back_to_initial_value != nullptr && m_is_modified_value)
m_back_to_initial_value(m_opt_id);
}
void Field::on_back_to_sys_value(){
if (m_back_to_sys_value != nullptr && m_is_nonsys_value)
m_back_to_sys_value(m_opt_id);
}
wxString Field::get_tooltip_text(const wxString& default_string)
{
wxString tooltip_text("");
@ -161,7 +173,8 @@ namespace Slic3r { namespace GUI {
temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e)
{
on_kill_focus(e);
// on_kill_focus(e);
e.Skip();
temp->GetToolTip()->Enable(true);
}), temp->GetId());
@ -253,8 +266,8 @@ void SpinCtrl::BUILD() {
auto temp = new wxSpinCtrl(m_parent, wxID_ANY, text_value, wxDefaultPosition, size,
0, min_val, max_val, default_value);
temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { tmp_value = undef_spin_val; on_change_field(); }), temp->GetId());
temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { tmp_value = undef_spin_val; on_kill_focus(e); }), temp->GetId());
// temp->Bind(wxEVT_SPINCTRL, ([this](wxCommandEvent e) { tmp_value = undef_spin_val; on_change_field(); }), temp->GetId());
// temp->Bind(wxEVT_KILL_FOCUS, ([this](wxEvent& e) { tmp_value = undef_spin_val; on_kill_focus(e); }), temp->GetId());
temp->Bind(wxEVT_TEXT, ([this](wxCommandEvent e)
{
// # On OSX / Cocoa, wxSpinCtrl::GetValue() doesn't return the new value
@ -392,6 +405,7 @@ void Choice::set_value(boost::any value, bool change_event)
case coInt:
case coFloat:
case coPercent:
case coString:
case coStrings:{
wxString text_value;
if (m_opt.type == coInt)
@ -405,7 +419,6 @@ void Choice::set_value(boost::any value, bool change_event)
break;
++idx;
}
// if (m_opt.type == coPercent) text_value += "%";
idx == m_opt.enum_values.size() ?
dynamic_cast<wxComboBox*>(window)->SetValue(text_value) :
dynamic_cast<wxComboBox*>(window)->SetSelection(idx);
@ -434,6 +447,7 @@ void Choice::set_values(const std::vector<std::string> values)
auto ww = dynamic_cast<wxComboBox*>(window);
auto value = ww->GetValue();
ww->Clear();
ww->Append("");
for (auto el : values)
ww->Append(wxString(el));
ww->SetValue(value);

View file

@ -52,6 +52,8 @@ protected:
void on_change_field();
/// Call the attached m_back_to_initial_value method.
void on_back_to_initial_value();
/// Call the attached m_back_to_sys_value method.
void on_back_to_sys_value();
public:
/// parent wx item, opportunity to refactor (probably not necessary - data duplication)
@ -63,13 +65,14 @@ public:
/// Function object to store callback passed in from owning object.
t_change m_on_change {nullptr};
/// Function object to store callback passed in from owning object.
/// Function object to store callback passed in from owning object.
t_back_to_init m_back_to_initial_value{ nullptr };
t_back_to_init m_back_to_sys_value{ nullptr };
// This is used to avoid recursive invocation of the field change/update by wxWidgets.
bool m_disable_change_event {false};
// This is used to avoid recursive invocation of the field change/update by wxWidgets.
bool m_is_modified_value {false};
bool m_is_nonsys_value {true};
/// Copy of ConfigOption for deduction purposes
const ConfigOptionDef m_opt {ConfigOptionDef()};
@ -89,12 +92,16 @@ public:
wxStaticText* m_Label = nullptr;
wxButton* m_Undo_btn = nullptr;
wxButton* m_Undo_to_sys_btn = nullptr;
/// Fires the enable or disable function, based on the input.
inline void toggle(bool en) { en ? enable() : disable(); }
virtual wxString get_tooltip_text(const wxString& default_string);
// set icon to "UndoToSystemValue" button according to an inheritance of preset
void set_nonsys_btn_icon(const std::string& icon);
Field(const ConfigOptionDef& opt, const t_config_option_key& id) : m_opt(opt), m_opt_id(id) {};
Field(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : m_parent(parent), m_opt(opt), m_opt_id(id) {};
@ -196,11 +203,12 @@ public:
}
void set_value(boost::any value, bool change_event = false) {
m_disable_change_event = !change_event;
dynamic_cast<wxSpinCtrl*>(window)->SetValue(boost::any_cast<int>(value));
tmp_value = boost::any_cast<int>(value);
dynamic_cast<wxSpinCtrl*>(window)->SetValue(tmp_value/*boost::any_cast<int>(value)*/);
m_disable_change_event = false;
}
boost::any get_value() override {
return boost::any(dynamic_cast<wxSpinCtrl*>(window)->GetValue());
return boost::any(tmp_value);
}
void enable() override { dynamic_cast<wxSpinCtrl*>(window)->Enable(); }
@ -280,9 +288,7 @@ public:
wxSizer* getSizer() override { return sizer; }
};
#endif
} // GUI
} // Slic3r
#endif /* SLIC3R_GUI_FIELD_HPP */

View file

@ -428,8 +428,7 @@ void change_opt_value(DynamicPrintConfig& config, t_config_option_key opt_key, b
std::vector<std::string> values = boost::any_cast<std::vector<std::string>>(value);
if (values.size() == 1 && values[0] == "")
break;
for (auto el : values)
config.option<ConfigOptionStrings>(opt_key)->values.push_back(el);
config.option<ConfigOptionStrings>(opt_key)->values = values;
}
else{
ConfigOptionStrings* vec_new = new ConfigOptionStrings{ boost::any_cast<std::string>(value) };
@ -465,6 +464,10 @@ void change_opt_value(DynamicPrintConfig& config, t_config_option_key opt_key, b
}
break;
case coPoints:{
if (opt_key.compare("bed_shape") == 0){
config.option<ConfigOptionPoints>(opt_key)->values = boost::any_cast<std::vector<Pointf>>(value);
break;
}
ConfigOptionPoints* vec_new = new ConfigOptionPoints{ boost::any_cast<Pointf>(value) };
config.option<ConfigOptionPoints>(opt_key)->set_at(vec_new, opt_index, 0);
}
@ -511,11 +514,14 @@ wxApp* get_app(){
return g_wxApp;
}
wxColour* get_modified_label_clr()
{
wxColour* get_modified_label_clr(){
return new wxColour(253, 88, 0);
}
wxColour* get_sys_label_clr(){
return new wxColour(26, 132, 57);
}
void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value)
{
if (comboCtrl == nullptr)

View file

@ -80,6 +80,7 @@ void set_preset_bundle(PresetBundle *preset_bundle);
AppConfig* get_app_config();
wxApp* get_app();
wxColour* get_modified_label_clr();
wxColour* get_sys_label_clr();
void add_debug_menu(wxMenuBar *menu, int event_language_change);

View file

@ -82,7 +82,16 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
if (!this->m_disabled)
this->back_to_initial_value(opt_id);
};
if (!m_is_tab_opt) field->m_Undo_btn->Hide();
field->m_back_to_sys_value = [this](std::string opt_id){
if (!this->m_disabled)
this->back_to_sys_value(opt_id);
};
if (!m_is_tab_opt) {
field->m_Undo_btn->Hide();
field->m_Undo_to_sys_btn->Hide();
}
if (nonsys_btn_icon != nullptr)
field->set_nonsys_btn_icon(nonsys_btn_icon());
// assign function objects for callbacks, etc.
return field;
@ -112,7 +121,10 @@ void OptionsGroup::append_line(const Line& line) {
const auto& option = option_set.front();
const auto& field = build_field(option);
sizer->Add(field->m_Undo_btn);
auto btn_sizer = new wxBoxSizer(wxHORIZONTAL);
btn_sizer->Add(field->m_Undo_to_sys_btn);
btn_sizer->Add(field->m_Undo_btn);
sizer->Add(btn_sizer, 0, wxEXPAND | wxALL, 0);
if (is_window_field(field))
sizer->Add(field->getWindow(), 0, wxEXPAND | wxALL, wxOSX ? 0 : 5);
if (is_sizer_field(field))
@ -149,6 +161,7 @@ void OptionsGroup::append_line(const Line& line) {
const auto& option = option_set.front();
const auto& field = build_field(option, label);
sizer->Add(field->m_Undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL);
sizer->Add(field->m_Undo_btn, 0, wxALIGN_CENTER_VERTICAL);
if (is_window_field(field))
sizer->Add(field->getWindow(), 0, (option.opt.full_width ? wxEXPAND : 0) |
@ -177,6 +190,7 @@ void OptionsGroup::append_line(const Line& line) {
// add field
const Option& opt_ref = opt;
auto& field = build_field(opt_ref, label);
sizer->Add(field->m_Undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL);
sizer->Add(field->m_Undo_btn, 0, wxALIGN_CENTER_VERTICAL, 0);
is_sizer_field(field) ?
sizer->Add(field->getSizer(), 0, wxALIGN_CENTER_VERTICAL, 0) :
@ -287,7 +301,20 @@ void ConfigOptionsGroup::back_to_initial_value(const std::string opt_key)
{
if (m_get_initial_config == nullptr)
return;
DynamicPrintConfig config = m_get_initial_config();
back_to_config_value(m_get_initial_config(), opt_key);
}
void ConfigOptionsGroup::back_to_sys_value(const std::string opt_key)
{
if (m_get_sys_config == nullptr)
return;
if (!have_sys_config())
return;
back_to_config_value(m_get_sys_config(), opt_key);
}
void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, const std::string opt_key)
{
boost::any value;
if (opt_key == "extruders_count"){
auto *nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(config.option("nozzle_diameter"));
@ -300,15 +327,18 @@ void ConfigOptionsGroup::back_to_initial_value(const std::string opt_key)
int opt_index = m_opt_map.at(opt_id).second;
value = get_config_value(config, opt_short_key, opt_index);
}
else
else{
value = get_config_value(config, opt_key);
change_opt_value(*m_config, opt_key, value);
return;
}
set_value(opt_key, value);
on_change_OG(opt_key, get_value(opt_key));
}
void ConfigOptionsGroup::reload_config(){
for (std::map< std::string, std::pair<std::string, int> >::iterator it = m_opt_map.begin(); it != m_opt_map.end(); ++it) {
for (t_opt_map::iterator it = m_opt_map.begin(); it != m_opt_map.end(); ++it) {
auto opt_id = it->first;
std::string opt_key = m_opt_map.at(opt_id).first;
int opt_index = m_opt_map.at(opt_id).second;
@ -335,7 +365,7 @@ boost::any ConfigOptionsGroup::config_value(std::string opt_key, int opt_index,
}
}
boost::any ConfigOptionsGroup::get_config_value(DynamicPrintConfig& config, std::string opt_key, int opt_index/* = -1*/)
boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config, std::string opt_key, int opt_index /*= -1*/)
{
size_t idx = opt_index == -1 ? 0 : opt_index;
@ -379,8 +409,9 @@ boost::any ConfigOptionsGroup::get_config_value(DynamicPrintConfig& config, std:
ret = text_value;
else if (opt->gui_flags.compare("serialized") == 0){
std::vector<std::string> values = config.option<ConfigOptionStrings>(opt_key)->values;
for (auto el : values)
text_value += el + ";";
if (!values.empty() && values[0].compare("") != 0)
for (auto el : values)
text_value += el + ";";
ret = text_value;
}
else
@ -414,7 +445,10 @@ boost::any ConfigOptionsGroup::get_config_value(DynamicPrintConfig& config, std:
}
break;
case coPoints:
ret = config.option<ConfigOptionPoints>(opt_key)->get_at(idx);
if (opt_key.compare("bed_shape") == 0)
ret = config.option<ConfigOptionPoints>(opt_key)->values;
else
ret = config.option<ConfigOptionPoints>(opt_key)->get_at(idx);
break;
case coNone:
default:
@ -428,7 +462,7 @@ Field* ConfigOptionsGroup::get_fieldc(t_config_option_key opt_key, int opt_index
if (field != nullptr)
return field;
std::string opt_id = "";
for (std::map< std::string, std::pair<std::string, int> >::iterator it = m_opt_map.begin(); it != m_opt_map.end(); ++it) {
for (t_opt_map::iterator it = m_opt_map.begin(); it != m_opt_map.end(); ++it) {
if (opt_key == m_opt_map.at(it->first).first && opt_index == m_opt_map.at(it->first).second){
opt_id = it->first;
break;

View file

@ -69,6 +69,7 @@ private:
};
using t_optionfield_map = std::map<t_config_option_key, t_field>;
using t_opt_map = std::map< std::string, std::pair<std::string, int> >;
class OptionsGroup {
public:
@ -79,10 +80,14 @@ public:
column_t extra_column {nullptr};
t_change m_on_change {nullptr};
std::function<DynamicPrintConfig()> m_get_initial_config{ nullptr };
std::function<DynamicPrintConfig()> m_get_sys_config{ nullptr };
std::function<bool()> have_sys_config{ nullptr };
wxFont sidetext_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
wxFont label_font {wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) };
std::function<std::string()> nonsys_btn_icon{ nullptr };
/// Returns a copy of the pointer of the parent wxWindow.
/// Accessor function is because users are not allowed to change the parent
/// but defining it as const means a lot of const_casts to deal with wx functions.
@ -149,6 +154,7 @@ protected:
virtual void on_kill_focus (){};
virtual void on_change_OG(t_config_option_key opt_id, boost::any value);
virtual void back_to_initial_value(const std::string opt_key){};
virtual void back_to_sys_value(const std::string opt_key){};
};
class ConfigOptionsGroup: public OptionsGroup {
@ -159,7 +165,7 @@ public:
/// reference to libslic3r config, non-owning pointer (?).
DynamicPrintConfig* m_config {nullptr};
bool m_full_labels {0};
std::map< std::string, std::pair<std::string, int> > m_opt_map;
t_opt_map m_opt_map;
Option get_option(const std::string opt_key, int opt_index = -1);
Line create_single_option_line(const std::string title, int idx = -1) /*const*/{
@ -177,11 +183,13 @@ public:
void on_change_OG(t_config_option_key opt_id, boost::any value) override;
void back_to_initial_value(const std::string opt_key) override;
void back_to_sys_value(const std::string opt_key) override;
void back_to_config_value(const DynamicPrintConfig& config, const std::string opt_key);
void on_kill_focus() override{ reload_config();}
void reload_config();
boost::any config_value(std::string opt_key, int opt_index, bool deserialize);
// return option value from config
boost::any get_config_value(DynamicPrintConfig& config, std::string opt_key, int opt_index = -1);
boost::any get_config_value(const DynamicPrintConfig& config, std::string opt_key, int opt_index = -1);
Field* get_fieldc(t_config_option_key opt_key, int opt_index);
};

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,16 @@ 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", "max_print_height"
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "max_print_height",
"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 +243,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 +273,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 +288,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 +295,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 +349,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 +388,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 +408,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 this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr; // 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,20 +560,34 @@ 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;
}
std::vector<std::string> PresetCollection::system_equal_options() const
{
const Preset *edited = &this->get_edited_preset();
const Preset *reference = this->get_selected_preset_parent();
std::vector<std::string> equal;
if (edited != nullptr && reference != nullptr) {
equal = reference->config.equal(edited->config);
}
return equal;
}
// Select a new preset. This resets all the edits done to the currently selected preset.
// If the preset with index idx does not exist, a first visible preset is selected.
Preset& PresetCollection::select_preset(size_t idx)

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,13 @@ 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()); }
// Compare the content of get_selected_preset() with get_selected_preset_parent() configs, return the list of keys where they equal.
std::vector<std::string> system_equal_options() const;
// 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 +291,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 +307,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

@ -59,6 +59,17 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle)
m_btn_delete_preset->SetToolTip(_(L("Delete this preset")));
m_btn_delete_preset->Disable();
m_undo_btn = new wxButton(panel, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER);
m_undo_to_sys_btn = new wxButton(panel, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT | wxNO_BORDER);
if (wxMSW) {
m_undo_btn->SetBackgroundColour(color);
m_undo_to_sys_btn->SetBackgroundColour(color);
}
m_undo_btn->SetBitmap(wxBitmap(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG));
m_undo_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent){ on_back_to_initial_value(); }));
m_undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG));
m_undo_to_sys_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent){ on_back_to_sys_value(); }));
m_hsizer = new wxBoxSizer(wxHORIZONTAL);
sizer->Add(m_hsizer, 0, wxBOTTOM, 3);
m_hsizer->Add(m_presets_choice, 1, wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL, 3);
@ -68,6 +79,9 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle)
m_hsizer->Add(m_btn_delete_preset, 0, wxALIGN_CENTER_VERTICAL);
m_hsizer->AddSpacer(16);
m_hsizer->Add(m_btn_hide_incompatible_presets, 0, wxALIGN_CENTER_VERTICAL);
m_hsizer->AddSpacer(64);
m_hsizer->Add(m_undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL);
m_hsizer->Add(m_undo_btn, 0, wxALIGN_CENTER_VERTICAL);
//Horizontal sizer to hold the tree and the selected page.
m_hsizer = new wxBoxSizer(wxHORIZONTAL);
@ -101,7 +115,6 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle)
if (selected_item >= 0){
std::string selected_string = m_presets_choice->GetString(selected_item).ToUTF8().data();
select_preset(selected_string);
update_changed_ui();
}
}));
@ -117,6 +130,14 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle)
update();
}
void Tab::load_initial_data()
{
m_config = &m_presets->get_edited_preset().config;
m_nonsys_btn_icon = m_presets->get_selected_preset_parent() == nullptr ?
"bullet_white.png" :
wxMSW ? "sys_unlock.png" : "lock_open.png";
}
PageShp Tab::add_options_page(wxString title, std::string icon, bool is_extruder_pages/* = false*/)
{
// Index of icon in an icon list $self->{icons}.
@ -157,6 +178,23 @@ void add_correct_opts_to_dirty_options(const std::string &opt_key, std::vector<s
}
}
template<class T>
void add_correct_opts_to_sys_options(const std::string &opt_key, std::vector<std::string> *vec, TabPrinter *tab)
{
const Preset* sys_preset = tab->m_presets->get_selected_preset_parent();
if (sys_preset == nullptr)
return;
T *opt_cur = static_cast<T*>(tab->m_config->option(opt_key));
const T *opt_sys = static_cast<const T*>(sys_preset->config.option(opt_key));
int opt_max_id = opt_sys->values.size()-1;
for (int i = 0; i < opt_cur->values.size(); i++)
{
int init_id = i <= opt_max_id ? i : 0;
if (opt_cur->values[i] == opt_sys->values[init_id])
vec->emplace_back(opt_key + "#" + std::to_string(i));
}
}
// Update UI according to changes
void Tab::update_changed_ui()
{
@ -165,63 +203,273 @@ void Tab::update_changed_ui()
if (name() == "printer"){
// Update dirty_options in case changes of Extruder's options
TabPrinter* tab = static_cast<TabPrinter*>(this);
std::vector<std::string> new_dirty;
m_dirty_options.resize(0);
for (auto opt_key : dirty_options)
{
if (opt_key == "bed_shape"){ m_dirty_options.emplace_back(opt_key); continue; }
switch (m_config->option(opt_key)->type())
{
case coInts: add_correct_opts_to_dirty_options<ConfigOptionInts >(opt_key, &new_dirty, tab); break;
case coBools: add_correct_opts_to_dirty_options<ConfigOptionBools >(opt_key, &new_dirty, tab); break;
case coFloats: add_correct_opts_to_dirty_options<ConfigOptionFloats >(opt_key, &new_dirty, tab); break;
case coStrings: add_correct_opts_to_dirty_options<ConfigOptionStrings >(opt_key, &new_dirty, tab); break;
case coPercents:add_correct_opts_to_dirty_options<ConfigOptionPercents >(opt_key, &new_dirty, tab); break;
case coPoints: add_correct_opts_to_dirty_options<ConfigOptionPoints >(opt_key, &new_dirty, tab); break;
default: new_dirty.emplace_back(opt_key); break;
case coInts: add_correct_opts_to_dirty_options<ConfigOptionInts >(opt_key, &m_dirty_options, tab); break;
case coBools: add_correct_opts_to_dirty_options<ConfigOptionBools >(opt_key, &m_dirty_options, tab); break;
case coFloats: add_correct_opts_to_dirty_options<ConfigOptionFloats >(opt_key, &m_dirty_options, tab); break;
case coStrings: add_correct_opts_to_dirty_options<ConfigOptionStrings >(opt_key, &m_dirty_options, tab); break;
case coPercents:add_correct_opts_to_dirty_options<ConfigOptionPercents >(opt_key, &m_dirty_options, tab); break;
case coPoints: add_correct_opts_to_dirty_options<ConfigOptionPoints >(opt_key, &m_dirty_options, tab); break;
default: m_dirty_options.emplace_back(opt_key); break;
}
}
if (tab->m_initial_extruders_count != tab->m_extruders_count)
m_dirty_options.emplace_back("extruders_count");
dirty_options.resize(0);
dirty_options = new_dirty;
if (tab->m_initial_extruders_count != tab->m_extruders_count){
dirty_options.emplace_back("extruders_count");
}
}
// Add new dirty options to m_dirty_options
for (auto opt_key : dirty_options){
Field* field = get_field(opt_key);
if (field != nullptr && find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) == m_dirty_options.end()){
if (field->m_Label != nullptr){
field->m_Label->SetForegroundColour(*get_modified_label_clr());
field->m_Label->Refresh(true);
m_sys_options.resize(0);
const auto sys_preset = m_presets->get_selected_preset_parent();
if (sys_preset){
for (auto opt_key : m_config->keys())
{
if (opt_key == "bed_shape"){
if (*tab->m_config->option(opt_key) == *sys_preset->config.option(opt_key))
m_sys_options.emplace_back(opt_key);
continue;
}
switch (m_config->option(opt_key)->type())
{
case coInts: add_correct_opts_to_sys_options<ConfigOptionInts >(opt_key, &m_sys_options, tab); break;
case coBools: add_correct_opts_to_sys_options<ConfigOptionBools >(opt_key, &m_sys_options, tab); break;
case coFloats: add_correct_opts_to_sys_options<ConfigOptionFloats >(opt_key, &m_sys_options, tab); break;
case coStrings: add_correct_opts_to_sys_options<ConfigOptionStrings >(opt_key, &m_sys_options, tab); break;
case coPercents:add_correct_opts_to_sys_options<ConfigOptionPercents>(opt_key, &m_sys_options, tab); break;
case coPoints: add_correct_opts_to_sys_options<ConfigOptionPoints >(opt_key, &m_sys_options, tab); break;
default:{
const ConfigOption *opt_cur = tab->m_config->option(opt_key);
const ConfigOption *opt_sys = sys_preset->config.option(opt_key);
if (opt_cur != nullptr && opt_sys != nullptr && *opt_cur == *opt_sys)
m_sys_options.emplace_back(opt_key);
break;
}
}
}
field->m_Undo_btn->SetBitmap(wxBitmap(from_u8(wxMSW ? var("action_undo.png") : var("arrow_undo.png")), wxBITMAP_TYPE_PNG));
field->m_is_modified_value = true;
m_dirty_options.push_back(opt_key);
if (tab->m_sys_extruders_count == tab->m_extruders_count)
m_sys_options.emplace_back("extruders_count");
}
}
else{
m_sys_options = m_presets->system_equal_options();
m_dirty_options = dirty_options;
}
// Delete clear options from m_dirty_options
for (auto i = 0; i < m_dirty_options.size(); ++i)
//update options "decoration"
for (const auto opt_key : m_full_options_list)
{
const std::string &opt_key = m_dirty_options[i];
Field* field = get_field(opt_key);
if (field != nullptr && find(dirty_options.begin(), dirty_options.end(), opt_key) == dirty_options.end())
bool is_nonsys_value = false;
bool is_modified_value = true;
std::string sys_icon = wxMSW ? "sys_lock.png" : "lock.png";
std::string icon = wxMSW ? "action_undo.png" : "arrow_undo.png";
wxColour& color = *get_sys_label_clr();
if (find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end()) {
is_nonsys_value = true;
sys_icon = m_nonsys_btn_icon;
if(find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) == m_dirty_options.end())
color = wxSYS_COLOUR_WINDOWTEXT;
else
color = *get_modified_label_clr();
}
if (find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) == m_dirty_options.end())
{
field->m_Undo_btn->SetBitmap(wxBitmap(from_u8(var("bullet_white.png")), wxBITMAP_TYPE_PNG));
is_modified_value = false;
icon = "bullet_white.png";
}
Field* field = get_field(opt_key);
if (field == nullptr) continue;
field->m_is_nonsys_value = is_nonsys_value;
field->m_is_modified_value = is_modified_value;
field->m_Undo_btn->SetBitmap(wxBitmap(from_u8(var(icon)), wxBITMAP_TYPE_PNG));
field->m_Undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var(sys_icon)), wxBITMAP_TYPE_PNG));
if (field->m_Label != nullptr){
field->m_Label->SetForegroundColour(color);
field->m_Label->Refresh(true);
}
}
wxTheApp->CallAfter([this]() {
update_changed_tree_ui();
});
}
template<class T>
void add_correct_opts_to_full_options_list(const std::string &opt_key, std::vector<std::string> *vec, TabPrinter *tab)
{
T *opt_cur = static_cast<T*>(tab->m_config->option(opt_key));
for (int i = 0; i < opt_cur->values.size(); i++)
vec->emplace_back(opt_key + "#" + std::to_string(i));
}
void Tab::update_full_options_list()
{
if (!m_full_options_list.empty())
m_full_options_list.resize(0);
if (m_name != "printer"){
m_full_options_list = m_config->keys();
return;
}
TabPrinter* tab = static_cast<TabPrinter*>(this);
for (const auto opt_key : m_config->keys())
{
if (opt_key == "bed_shape"){
m_full_options_list.emplace_back(opt_key);
continue;
}
switch (m_config->option(opt_key)->type())
{
case coInts: add_correct_opts_to_full_options_list<ConfigOptionInts >(opt_key, &m_full_options_list, tab); break;
case coBools: add_correct_opts_to_full_options_list<ConfigOptionBools >(opt_key, &m_full_options_list, tab); break;
case coFloats: add_correct_opts_to_full_options_list<ConfigOptionFloats >(opt_key, &m_full_options_list, tab); break;
case coStrings: add_correct_opts_to_full_options_list<ConfigOptionStrings >(opt_key, &m_full_options_list, tab); break;
case coPercents:add_correct_opts_to_full_options_list<ConfigOptionPercents >(opt_key, &m_full_options_list, tab); break;
case coPoints: add_correct_opts_to_full_options_list<ConfigOptionPoints >(opt_key, &m_full_options_list, tab); break;
default: m_full_options_list.emplace_back(opt_key); break;
}
}
m_full_options_list.emplace_back("extruders_count");
}
void Tab::update_sys_ui_after_sel_preset()
{
for (const auto opt_key : m_full_options_list){
Field* field = get_field(opt_key);
if (field != nullptr){
field->m_Undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var(m_nonsys_btn_icon)), wxBITMAP_TYPE_PNG));
field->m_is_nonsys_value = true;
if (field->m_Label != nullptr){
field->m_Label->SetForegroundColour(wxSYS_COLOUR_WINDOWTEXT);
field->m_Label->Refresh(true);
}
field->m_is_modified_value = false;
std::vector<std::string>::iterator itr = find(m_dirty_options.begin(), m_dirty_options.end(), opt_key);
if (itr != m_dirty_options.end()){
m_dirty_options.erase(itr);
--i;
}
}
}
m_sys_options.resize(0);
}
void Tab::update_changed_tree_ui()
{
auto cur_item = m_treectrl->GetFirstVisibleItem();
auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection());
while (cur_item){
auto title = m_treectrl->GetItemText(cur_item);
int i=0;
for (auto page : m_pages)
{
if (page->title() != title)
continue;
bool sys_page = true;
bool modified_page = false;
if (title == _("General")){
std::initializer_list<const char*> optional_keys{ "extruders_count", "bed_shape" };
for (auto &opt_key : optional_keys) {
if (sys_page && find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end())
sys_page = false;
if (!modified_page && find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) != m_dirty_options.end())
modified_page = true;
}
}
for (auto group : page->m_optgroups)
{
for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) {
const std::string& opt_key = it->first;
if (sys_page && find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end())
sys_page = false;
if (!modified_page && find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) != m_dirty_options.end())
modified_page = true;
}
if (!sys_page && modified_page)
break;
}
if (sys_page)
m_treectrl->SetItemTextColour(cur_item, *get_sys_label_clr());
else if (modified_page)
m_treectrl->SetItemTextColour(cur_item, *get_modified_label_clr());
else
m_treectrl->SetItemTextColour(cur_item, wxSYS_COLOUR_WINDOWTEXT);
page->m_is_nonsys_values = !sys_page;
page->m_is_modified_values = modified_page;
if (selection == title){
m_is_nonsys_values = page->m_is_nonsys_values;
m_is_modified_values = page->m_is_modified_values;
}
break;
}
auto next_item = m_treectrl->GetNextVisible(cur_item);
cur_item = next_item;
}
update_undo_buttons();
}
void Tab::update_undo_buttons()
{
const std::string& undo_icon = !m_is_modified_values ? "bullet_white.png" :
wxMSW ? "action_undo.png" : "arrow_undo.png";
const std::string& undo_to_sys_icon = m_is_nonsys_values ? m_nonsys_btn_icon :
wxMSW ? "sys_lock.png" : "lock.png";
m_undo_btn->SetBitmap(wxBitmap(from_u8(var(undo_icon)), wxBITMAP_TYPE_PNG));
m_undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var(undo_to_sys_icon)), wxBITMAP_TYPE_PNG));
}
void Tab::on_back_to_initial_value()
{
if (!m_is_modified_values) return;
auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection());
for (auto page : m_pages)
if (page->title() == selection) {
for (auto group : page->m_optgroups){
if (group->title == _("Capabilities")){
if (find(m_dirty_options.begin(), m_dirty_options.end(), "extruders_count") != m_dirty_options.end())
group->back_to_initial_value("extruders_count");
}
if (group->title == _("Size and coordinates")){
if (find(m_dirty_options.begin(), m_dirty_options.end(), "bed_shape") != m_dirty_options.end())
group->back_to_initial_value("bed_shape");
}
for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) {
const std::string& opt_key = it->first;
if (find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) != m_dirty_options.end())
group->back_to_initial_value(opt_key);
}
}
break;
}
update_changed_ui();
}
void Tab::on_back_to_sys_value()
{
if (!m_is_nonsys_values) return;
auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection());
for (auto page : m_pages)
if (page->title() == selection) {
for (auto group : page->m_optgroups) {
if (group->title == _("Capabilities")){
if (find(m_sys_options.begin(), m_sys_options.end(), "extruders_count") == m_sys_options.end())
group->back_to_sys_value("extruders_count");
}
if (group->title == _("Size and coordinates")){
if (find(m_sys_options.begin(), m_sys_options.end(), "bed_shape") == m_sys_options.end())
group->back_to_sys_value("bed_shape");
}
for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) {
const std::string& opt_key = it->first;
if (find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end())
group->back_to_sys_value(opt_key);
}
}
break;
}
update_changed_ui();
}
// Update the combo box label of the selected preset based on its "dirty" state,
@ -350,6 +598,13 @@ void Tab::on_presets_changed()
event.SetString(m_name);
g_wxMainFrame->ProcessWindowEvent(event);
}
const Preset* parent = m_presets->get_selected_preset_parent();
const wxString description_line = parent == nullptr ?
_(L("It's default preset")) : parent == &m_presets->get_selected_preset() ?
_(L("It's system preset")) :
_(L("Current preset is inherited from")) + ":\n" + parent->name;
m_parent_preset_description_line->SetText(description_line);
}
void Tab::update_frequently_changed_parameters()
@ -379,7 +634,7 @@ void Tab::reload_compatible_printers_widget()
void TabPrint::build()
{
m_presets = &m_preset_bundle->prints;
m_config = &m_presets->get_edited_preset().config;
load_initial_data();
auto page = add_options_page(_(L("Layers and perimeters")), "layers.png");
auto optgroup = page->new_optgroup(_(L("Layer height")));
@ -521,7 +776,7 @@ void TabPrint::build()
optgroup->append_single_option_line("interface_shells");
page = add_options_page(_(L("Advanced")), "wrench.png");
optgroup = page->new_optgroup(_(L("Extrusion width")), 180);
optgroup = page->new_optgroup(_(L("Extrusion width")));
optgroup->append_single_option_line("extrusion_width");
optgroup->append_single_option_line("first_layer_extrusion_width");
optgroup->append_single_option_line("perimeter_extrusion_width");
@ -586,6 +841,13 @@ void TabPrint::build()
option = optgroup->get_option("compatible_printers_condition");
option.opt.full_width = true;
optgroup->append_single_option_line(option);
line = Line{ "", "" };
line.full_width = 1;
line.widget = [this](wxWindow* parent) {
return description_line_widget(parent, &m_parent_preset_description_line);
};
optgroup->append_line(line);
}
// Reload current config (aka presets->edited_preset->config) into the UI fields.
@ -598,9 +860,11 @@ void TabPrint::update()
{
Freeze();
double fill_density = m_config->option<ConfigOptionPercent>("fill_density")->value;
if (m_config->opt_bool("spiral_vase") &&
!(m_config->opt_int("perimeters") == 1 && m_config->opt_int("top_solid_layers") == 0 &&
m_config->option<ConfigOptionPercent>("fill_density")->value == 0)) {
fill_density == 0)) {
wxString msg_text = _(L("The Spiral Vase mode requires:\n"
"- one perimeter\n"
"- no top solid layers\n"
@ -617,11 +881,13 @@ void TabPrint::update()
new_conf.set_key_value("support_material", new ConfigOptionBool(false));
new_conf.set_key_value("support_material_enforce_layers", new ConfigOptionInt(0));
new_conf.set_key_value("ensure_vertical_shell_thickness", new ConfigOptionBool(false));
fill_density = 0;
}
else {
new_conf.set_key_value("spiral_vase", new ConfigOptionBool(false));
}
load_config(new_conf);
on_value_change("fill_density", fill_density);
}
auto first_layer_height = m_config->option<ConfigOptionFloatOrPercent>("first_layer_height")->value;
@ -735,7 +1001,6 @@ void TabPrint::update()
"\nShall I switch to rectilinear fill pattern?"));
auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Infill")), wxICON_WARNING | wxYES | wxNO);
DynamicPrintConfig new_conf = *m_config;
double fill_density;
if (dialog->ShowModal() == wxID_YES) {
new_conf.set_key_value("fill_pattern", new ConfigOptionEnum<InfillPattern>(ipRectilinear));
fill_density = 100;
@ -856,7 +1121,7 @@ void TabPrint::OnActivate()
void TabFilament::build()
{
m_presets = &m_preset_bundle->filaments;
m_config = &m_preset_bundle->filaments.get_edited_preset().config;
load_initial_data();
auto page = add_options_page(_(L("Filament")), "spool.png");
auto optgroup = page->new_optgroup(_(L("Filament")));
@ -950,6 +1215,13 @@ void TabFilament::build()
option = optgroup->get_option("compatible_printers_condition");
option.opt.full_width = true;
optgroup->append_single_option_line(option);
line = Line{ "", "" };
line.full_width = 1;
line.widget = [this](wxWindow* parent) {
return description_line_widget(parent, &m_parent_preset_description_line);
};
optgroup->append_line(line);
}
// Reload current config (aka presets->edited_preset->config) into the UI fields.
@ -1003,11 +1275,13 @@ bool Tab::current_preset_is_dirty()
void TabPrinter::build()
{
m_presets = &m_preset_bundle->printers;
m_config = &m_preset_bundle->printers.get_edited_preset().config;
auto default_config = m_preset_bundle->full_config();
load_initial_data();
auto *nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"));
m_initial_extruders_count = m_extruders_count = nozzle_diameter->values.size();
const Preset* parent_preset = m_presets->get_selected_preset_parent();
m_sys_extruders_count = parent_preset == nullptr ? 0 :
static_cast<const ConfigOptionFloats*>(parent_preset->config.option("nozzle_diameter"))->values.size();
auto page = add_options_page(_(L("General")), "printer_empty.png");
auto optgroup = page->new_optgroup(_(L("Size and coordinates")));
@ -1025,8 +1299,10 @@ void TabPrinter::build()
{
auto dlg = new BedShapeDialog(this);
dlg->build_dialog(m_config->option<ConfigOptionPoints>("bed_shape"));
if (dlg->ShowModal() == wxID_OK)
if (dlg->ShowModal() == wxID_OK){
load_key_value("bed_shape", dlg->GetValue());
update_changed_ui();
}
}));
return sizer;
@ -1244,6 +1520,15 @@ void TabPrinter::build()
option.opt.height = 250;
optgroup->append_single_option_line(option);
page = add_options_page(_(L("Dependencies")), "wrench.png");
optgroup = page->new_optgroup(_(L("Profile dependencies")));
line = Line{ "", "" };
line.full_width = 1;
line.widget = [this](wxWindow* parent) {
return description_line_widget(parent, &m_parent_preset_description_line);
};
optgroup->append_line(line);
build_extruder_pages();
if (!m_no_controller)
@ -1420,12 +1705,17 @@ void TabPrinter::update(){
void Tab::load_current_preset()
{
auto preset = m_presets->get_edited_preset();
preset.is_default ? m_btn_delete_preset->Disable() : m_btn_delete_preset->Enable(true);
update();
// For the printer profile, generate the extruder pages.
on_preset_loaded();
// Reload preset pages with the new configuration values.
reload_config();
const Preset* parent = m_presets->get_selected_preset_parent();
m_nonsys_btn_icon = parent == nullptr ?
"bullet_white.png" :
wxMSW ? "sys_unlock.png" : "lock_open.png";
// use CallAfter because some field triggers schedule on_change calls using CallAfter,
// and we don't want them to be called after this update_dirty() as they would mark the
@ -1440,8 +1730,14 @@ void Tab::load_current_preset()
if (name() == "print")
update_frequently_changed_parameters();
if (m_name == "printer")
if (m_name == "printer"){
static_cast<TabPrinter*>(this)->m_initial_extruders_count = static_cast<TabPrinter*>(this)->m_extruders_count;
const Preset* parent_preset = m_presets->get_selected_preset_parent();
static_cast<TabPrinter*>(this)->m_sys_extruders_count = parent_preset == nullptr ? 0 :
static_cast<const ConfigOptionFloats*>(parent_preset->config.option("nozzle_diameter"))->values.size();
}
update_sys_ui_after_sel_preset();
update_full_options_list();
update_changed_ui();
});
}
@ -1587,6 +1883,8 @@ void Tab::OnTreeSelChange(wxTreeEvent& event)
if (p->title() == selection)
{
page = p.get();
m_is_nonsys_values = page->m_is_nonsys_values;
m_is_modified_values = page->m_is_modified_values;
break;
}
if (page == nullptr) return;
@ -1596,6 +1894,8 @@ void Tab::OnTreeSelChange(wxTreeEvent& event)
page->Show();
m_hsizer->Layout();
Refresh();
update_undo_buttons();
}
void Tab::OnKeyDown(wxKeyEvent& event)
@ -1631,7 +1931,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);
}
@ -1645,6 +1945,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
@ -1655,6 +1964,10 @@ void Tab::save_preset(std::string name /*= ""*/)
update_tab_ui();
// Update the selection boxes at the platter.
on_presets_changed();
if (m_name == "printer")
static_cast<TabPrinter*>(this)->m_initial_extruders_count = static_cast<TabPrinter*>(this)->m_extruders_count;
update_changed_ui();
}
// Called for a currently selected preset.
@ -1744,7 +2057,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);
}
@ -1830,6 +2143,19 @@ ConfigOptionsGroupShp Page::new_optgroup(wxString title, int noncommon_label_wid
return config;
};
optgroup->m_get_sys_config = [this](){
DynamicPrintConfig config = static_cast<Tab*>(GetParent())->m_presets->get_selected_preset_parent()->config;
return config;
};
optgroup->have_sys_config = [this](){
return static_cast<Tab*>(GetParent())->m_presets->get_selected_preset_parent() != nullptr;
};
optgroup->nonsys_btn_icon = [this](){
return static_cast<Tab*>(GetParent())->m_nonsys_btn_icon;
};
vsizer()->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 10);
m_optgroups.push_back(optgroup);

View file

@ -54,6 +54,9 @@ public:
}
~Page(){}
bool m_is_modified_values{ false };
bool m_is_nonsys_values{ true };
public:
std::vector <ConfigOptionsGroupShp> m_optgroups;
DynamicPrintConfig* m_config;
@ -90,26 +93,35 @@ protected:
wxImageList* m_icons;
wxCheckBox* m_compatible_printers_checkbox;
wxButton* m_compatible_printers_btn;
wxButton* m_undo_btn;
wxButton* m_undo_to_sys_btn;
int m_icon_count;
std::map<std::string, size_t> m_icon_index; // Map from an icon file name to its index in $self->{icons}.
std::vector<PageShp> m_pages; // $self->{pages} = [];
std::map<std::string, size_t> m_icon_index; // Map from an icon file name to its index
std::vector<PageShp> m_pages;
bool m_disable_tree_sel_changed_event;
bool m_show_incompatible_presets;
bool m_no_controller;
std::vector<std::string> m_reload_dependent_tabs = {};
std::vector<std::string> m_dirty_options = {};
std::vector<std::string> m_sys_options = {};
std::vector<std::string> m_full_options_list = {};
// The two following two event IDs are generated at Plater.pm by calling Wx::NewEventType.
wxEventType m_event_value_change = 0;
wxEventType m_event_presets_changed = 0;
bool m_is_modified_values{ false };
bool m_is_nonsys_values{ true };
public:
PresetBundle* m_preset_bundle;
bool m_show_btn_incompatible_presets = false;
PresetCollection* m_presets;
DynamicPrintConfig* m_config;
std::string m_nonsys_btn_icon;
ogStaticText* m_parent_preset_description_line;
public:
Tab() {}
@ -147,13 +159,21 @@ public:
void update_show_hide_incompatible_button();
void update_ui_from_settings();
void update_changed_ui();
void update_full_options_list();
void update_sys_ui_after_sel_preset();
void update_changed_tree_ui();
void update_undo_buttons();
void on_back_to_initial_value();
void on_back_to_sys_value();
PageShp add_options_page(wxString title, std::string icon, bool is_extruder_pages = false);
virtual void OnActivate(){}
virtual void on_preset_loaded(){}
virtual void build() = 0;
virtual void update() = 0;
void load_initial_data();
void update_dirty();
void update_tab_ui();
void load_config(DynamicPrintConfig config);
@ -220,6 +240,7 @@ public:
size_t m_extruders_count;
size_t m_initial_extruders_count;
size_t m_sys_extruders_count;
std::vector<PageShp> m_extruder_pages;
TabPrinter() {}

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