mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-22 08:11:11 -06:00
Merge remote-tracking branch 'remotes/origin/profile_changes_reset'
This commit is contained in:
commit
e37cbdfcfc
33 changed files with 1190 additions and 215 deletions
|
@ -171,6 +171,8 @@ add_library(libslic3r STATIC
|
|||
add_library(libslic3r_gui STATIC
|
||||
${LIBDIR}/slic3r/GUI/AppConfig.cpp
|
||||
${LIBDIR}/slic3r/GUI/AppConfig.hpp
|
||||
${LIBDIR}/slic3r/GUI/BitmapCache.cpp
|
||||
${LIBDIR}/slic3r/GUI/BitmapCache.hpp
|
||||
${LIBDIR}/slic3r/GUI/3DScene.cpp
|
||||
${LIBDIR}/slic3r/GUI/3DScene.hpp
|
||||
${LIBDIR}/slic3r/GUI/GLShader.cpp
|
||||
|
|
|
@ -185,7 +185,7 @@ void ConfigBase::apply_only(const ConfigBase &other, const t_config_option_keys
|
|||
// This is only possible if other is of DynamicConfig type.
|
||||
if (ignore_nonexistent)
|
||||
continue;
|
||||
throw UnknownOptionException();
|
||||
throw UnknownOptionException(opt_key);
|
||||
}
|
||||
const ConfigOption *other_opt = other.option(opt_key);
|
||||
if (other_opt != nullptr)
|
||||
|
@ -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);
|
||||
|
|
|
@ -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) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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("");
|
||||
|
||||
|
|
|
@ -145,6 +145,17 @@ void AppConfig::update_last_output_dir(const std::string &dir)
|
|||
this->set("", "last_output_path", dir);
|
||||
}
|
||||
|
||||
void AppConfig::reset_selections()
|
||||
{
|
||||
auto it = m_storage.find("presets");
|
||||
if (it != m_storage.end()) {
|
||||
it->second.erase("print");
|
||||
it->second.erase("filament");
|
||||
it->second.erase("printer");
|
||||
m_dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::string AppConfig::config_path()
|
||||
{
|
||||
return (boost::filesystem::path(Slic3r::data_dir()) / "slic3r.ini").make_preferred().string();
|
||||
|
|
|
@ -73,6 +73,11 @@ public:
|
|||
std::string get_last_output_dir(const std::string &alt) const;
|
||||
void update_last_output_dir(const std::string &dir);
|
||||
|
||||
// reset the current print / filament / printer selections, so that
|
||||
// the PresetBundle::load_selections(const AppConfig &config) call will select
|
||||
// the first non-default preset when called.
|
||||
void reset_selections();
|
||||
|
||||
// Get the default config path from Slic3r::data_dir().
|
||||
static std::string config_path();
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
120
xs/src/slic3r/GUI/BitmapCache.cpp
Normal file
120
xs/src/slic3r/GUI/BitmapCache.cpp
Normal file
|
@ -0,0 +1,120 @@
|
|||
#include "BitmapCache.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
void BitmapCache::clear()
|
||||
{
|
||||
for (std::pair<const std::string, wxBitmap*> &bitmap : m_map)
|
||||
delete bitmap.second;
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height)
|
||||
{
|
||||
wxBitmap *bitmap = nullptr;
|
||||
auto it = m_map.find(bitmap_key);
|
||||
if (it == m_map.end()) {
|
||||
bitmap = new wxBitmap(width, height);
|
||||
m_map[bitmap_key] = bitmap;
|
||||
} else {
|
||||
bitmap = it->second;
|
||||
if (bitmap->GetWidth() != width || bitmap->GetHeight() != height)
|
||||
bitmap->Create(width, height);
|
||||
}
|
||||
#if defined(__APPLE__) || defined(_MSC_VER)
|
||||
bitmap->UseAlpha();
|
||||
#endif
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp)
|
||||
{
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth(), bmp.GetHeight());
|
||||
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
memDC.DrawBitmap(bmp, 0, 0, true);
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp, const wxBitmap &bmp2)
|
||||
{
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth() + bmp2.GetWidth(), std::max(bmp.GetHeight(), bmp2.GetHeight()));
|
||||
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
if (bmp.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp, 0, 0, true);
|
||||
if (bmp2.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp2, bmp.GetWidth(), 0, true);
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3)
|
||||
{
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth() + bmp2.GetWidth() + bmp3.GetWidth(), std::max(std::max(bmp.GetHeight(), bmp2.GetHeight()), bmp3.GetHeight()));
|
||||
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
if (bmp.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp, 0, 0, true);
|
||||
if (bmp2.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp2, bmp.GetWidth(), 0, true);
|
||||
if (bmp3.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp3, bmp.GetWidth() + bmp2.GetWidth(), 0, true);
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, std::vector<wxBitmap> &bmps)
|
||||
{
|
||||
size_t width = 0;
|
||||
size_t height = 0;
|
||||
for (wxBitmap &bmp : bmps) {
|
||||
width += bmp.GetWidth();
|
||||
height = std::max<size_t>(height, bmp.GetHeight());
|
||||
}
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, width, height);
|
||||
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
size_t x = 0;
|
||||
for (wxBitmap &bmp : bmps) {
|
||||
if (bmp.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp, x, 0, true);
|
||||
x += bmp.GetWidth();
|
||||
}
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency)
|
||||
{
|
||||
wxImage image(width, height);
|
||||
image.InitAlpha();
|
||||
unsigned char* imgdata = image.GetData();
|
||||
unsigned char* imgalpha = image.GetAlpha();
|
||||
for (size_t i = 0; i < width * height; ++ i) {
|
||||
*imgdata ++ = r;
|
||||
*imgdata ++ = g;
|
||||
*imgdata ++ = b;
|
||||
*imgalpha ++ = transparency;
|
||||
}
|
||||
return wxBitmap(std::move(image));
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
43
xs/src/slic3r/GUI/BitmapCache.hpp
Normal file
43
xs/src/slic3r/GUI/BitmapCache.hpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef SLIC3R_GUI_BITMAP_CACHE_HPP
|
||||
#define SLIC3R_GUI_BITMAP_CACHE_HPP
|
||||
|
||||
#include <wx/wxprec.h>
|
||||
#ifndef WX_PRECOMP
|
||||
#include <wx/wx.h>
|
||||
#endif
|
||||
|
||||
#include "../../libslic3r/libslic3r.h"
|
||||
#include "../../libslic3r/Config.hpp"
|
||||
|
||||
#include "GUI.hpp"
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
class BitmapCache
|
||||
{
|
||||
public:
|
||||
BitmapCache() {}
|
||||
~BitmapCache() { clear(); }
|
||||
void clear();
|
||||
|
||||
wxBitmap* find(const std::string &name) { auto it = m_map.find(name); return (it == m_map.end()) ? nullptr : it->second; }
|
||||
const wxBitmap* find(const std::string &name) const { return const_cast<BitmapCache*>(this)->find(name); }
|
||||
|
||||
wxBitmap* insert(const std::string &name, size_t width, size_t height);
|
||||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp);
|
||||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2);
|
||||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3);
|
||||
wxBitmap* insert(const std::string &name, std::vector<wxBitmap> &bmps);
|
||||
|
||||
static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency);
|
||||
static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }
|
||||
static wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); }
|
||||
|
||||
private:
|
||||
std::map<std::string, wxBitmap*> m_map;
|
||||
};
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
#endif /* SLIC3R_GUI_BITMAP_CACHE_HPP */
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <cassert>
|
||||
|
||||
#include "PresetBundle.hpp"
|
||||
#include "BitmapCache.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
@ -37,7 +38,10 @@ PresetBundle::PresetBundle() :
|
|||
filaments(Preset::TYPE_FILAMENT, Preset::filament_options()),
|
||||
printers(Preset::TYPE_PRINTER, Preset::printer_options()),
|
||||
m_bitmapCompatible(new wxBitmap),
|
||||
m_bitmapIncompatible(new wxBitmap)
|
||||
m_bitmapIncompatible(new wxBitmap),
|
||||
m_bitmapLock(new wxBitmap),
|
||||
m_bitmapLockOpen(new wxBitmap),
|
||||
m_bitmapCache(new GUI::BitmapCache)
|
||||
{
|
||||
if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr)
|
||||
wxImage::AddHandler(new wxPNGHandler);
|
||||
|
@ -51,6 +55,14 @@ PresetBundle::PresetBundle() :
|
|||
this->filaments.preset(0).config.optptr("compatible_printers_condition", true);
|
||||
this->prints.preset(0).config.optptr("compatible_printers", true);
|
||||
this->prints.preset(0).config.optptr("compatible_printers_condition", true);
|
||||
// Create the "inherits" keys.
|
||||
this->prints.preset(0).config.optptr("inherits", true);
|
||||
this->filaments.preset(0).config.optptr("inherits", true);
|
||||
this->printers.preset(0).config.optptr("inherits", true);
|
||||
// Create the "printer_vendor", "printer_model" and "printer_variant" keys.
|
||||
this->printers.preset(0).config.optptr("printer_vendor", true);
|
||||
this->printers.preset(0).config.optptr("printer_model", true);
|
||||
this->printers.preset(0).config.optptr("printer_variant", true);
|
||||
|
||||
this->prints .load_bitmap_default("cog.png");
|
||||
this->filaments.load_bitmap_default("spool.png");
|
||||
|
@ -62,12 +74,18 @@ PresetBundle::~PresetBundle()
|
|||
{
|
||||
assert(m_bitmapCompatible != nullptr);
|
||||
assert(m_bitmapIncompatible != nullptr);
|
||||
assert(m_bitmapLock != nullptr);
|
||||
assert(m_bitmapLockOpen != nullptr);
|
||||
delete m_bitmapCompatible;
|
||||
m_bitmapCompatible = nullptr;
|
||||
delete m_bitmapIncompatible;
|
||||
m_bitmapIncompatible = nullptr;
|
||||
for (std::pair<const std::string, wxBitmap*> &bitmap : m_mapColorToBitmap)
|
||||
delete bitmap.second;
|
||||
delete m_bitmapLock;
|
||||
m_bitmapLock = nullptr;
|
||||
delete m_bitmapLockOpen;
|
||||
m_bitmapLockOpen = nullptr;
|
||||
delete m_bitmapCache;
|
||||
m_bitmapCache = nullptr;
|
||||
}
|
||||
|
||||
void PresetBundle::reset(bool delete_files)
|
||||
|
@ -84,7 +102,8 @@ void PresetBundle::setup_directories()
|
|||
{
|
||||
boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir());
|
||||
std::initializer_list<boost::filesystem::path> paths = {
|
||||
data_dir,
|
||||
data_dir,
|
||||
data_dir / "vendor",
|
||||
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
|
||||
// Store the print/filament/printer presets into a "presets" directory.
|
||||
data_dir / "presets",
|
||||
|
@ -107,10 +126,12 @@ void PresetBundle::setup_directories()
|
|||
}
|
||||
}
|
||||
|
||||
void PresetBundle::load_presets()
|
||||
void PresetBundle::load_presets(const AppConfig &config)
|
||||
{
|
||||
std::string errors_cummulative;
|
||||
const std::string dir_path = data_dir()
|
||||
// First load the vendor specific system presets.
|
||||
std::string errors_cummulative = this->load_system_presets();
|
||||
|
||||
const std::string dir_user_presets = data_dir()
|
||||
#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR
|
||||
// Store the print/filament/printer presets into a "presets" directory.
|
||||
+ "/presets"
|
||||
|
@ -119,17 +140,17 @@ void PresetBundle::load_presets()
|
|||
#endif
|
||||
;
|
||||
try {
|
||||
this->prints.load_presets(dir_path, "print");
|
||||
this->prints.load_presets(dir_user_presets, "print");
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
}
|
||||
try {
|
||||
this->filaments.load_presets(dir_path, "filament");
|
||||
this->filaments.load_presets(dir_user_presets, "filament");
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
}
|
||||
try {
|
||||
this->printers.load_presets(dir_path, "printer");
|
||||
this->printers.load_presets(dir_user_presets, "printer");
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
}
|
||||
|
@ -137,6 +158,31 @@ void PresetBundle::load_presets()
|
|||
this->update_compatible_with_printer(false);
|
||||
if (! errors_cummulative.empty())
|
||||
throw std::runtime_error(errors_cummulative);
|
||||
|
||||
this->load_selections(config);
|
||||
}
|
||||
|
||||
// Load system presets into this PresetBundle.
|
||||
// For each vendor, there will be a single PresetBundle loaded.
|
||||
std::string PresetBundle::load_system_presets()
|
||||
{
|
||||
// Here the vendor specific read only Config Bundles are stored.
|
||||
boost::filesystem::path dir = (boost::filesystem::path(data_dir()) / "vendor").make_preferred();
|
||||
std::string errors_cummulative;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
|
||||
if (boost::filesystem::is_regular_file(dir_entry.status()) && boost::algorithm::iends_with(dir_entry.path().filename().string(), ".ini")) {
|
||||
std::string name = dir_entry.path().filename().string();
|
||||
// Remove the .ini suffix.
|
||||
name.erase(name.size() - 4);
|
||||
try {
|
||||
// Load the config bundle, flatten it.
|
||||
this->load_configbundle(dir_entry.path().string(), LOAD_CFGBNDLE_SYSTEM);
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
}
|
||||
}
|
||||
return errors_cummulative;
|
||||
}
|
||||
|
||||
static inline std::string remove_ini_suffix(const std::string &name)
|
||||
|
@ -147,6 +193,14 @@ static inline std::string remove_ini_suffix(const std::string &name)
|
|||
return out;
|
||||
}
|
||||
|
||||
// Set the "enabled" flag for printer vendors, printer models and printer variants
|
||||
// based on the user configuration.
|
||||
// If the "vendor" section is missing, enable all models and variants of the particular vendor.
|
||||
void PresetBundle::load_installed_printers(const AppConfig &config)
|
||||
{
|
||||
// m_storage
|
||||
}
|
||||
|
||||
// Load selections (current print, current filaments, current printer) from config.ini
|
||||
// This is done just once on application start up.
|
||||
void PresetBundle::load_selections(const AppConfig &config)
|
||||
|
@ -200,10 +254,16 @@ bool PresetBundle::load_compatible_bitmaps()
|
|||
{
|
||||
const std::string path_bitmap_compatible = "flag-green-icon.png";
|
||||
const std::string path_bitmap_incompatible = "flag-red-icon.png";
|
||||
const std::string path_bitmap_lock = "lock.png";
|
||||
const std::string path_bitmap_lock_open = "lock_open.png";
|
||||
bool loaded_compatible = m_bitmapCompatible ->LoadFile(
|
||||
wxString::FromUTF8(Slic3r::var(path_bitmap_compatible).c_str()), wxBITMAP_TYPE_PNG);
|
||||
bool loaded_incompatible = m_bitmapIncompatible->LoadFile(
|
||||
wxString::FromUTF8(Slic3r::var(path_bitmap_incompatible).c_str()), wxBITMAP_TYPE_PNG);
|
||||
bool loaded_lock = m_bitmapLock->LoadFile(
|
||||
wxString::FromUTF8(Slic3r::var(path_bitmap_lock).c_str()), wxBITMAP_TYPE_PNG);
|
||||
bool loaded_lock_open = m_bitmapLockOpen->LoadFile(
|
||||
wxString::FromUTF8(Slic3r::var(path_bitmap_lock_open).c_str()), wxBITMAP_TYPE_PNG);
|
||||
if (loaded_compatible) {
|
||||
prints .set_bitmap_compatible(m_bitmapCompatible);
|
||||
filaments.set_bitmap_compatible(m_bitmapCompatible);
|
||||
|
@ -214,7 +274,17 @@ bool PresetBundle::load_compatible_bitmaps()
|
|||
filaments.set_bitmap_incompatible(m_bitmapIncompatible);
|
||||
// printers .set_bitmap_incompatible(m_bitmapIncompatible);
|
||||
}
|
||||
return loaded_compatible && loaded_incompatible;
|
||||
if (loaded_lock) {
|
||||
prints .set_bitmap_lock(m_bitmapLock);
|
||||
filaments.set_bitmap_lock(m_bitmapLock);
|
||||
printers .set_bitmap_lock(m_bitmapLock);
|
||||
}
|
||||
if (loaded_lock_open) {
|
||||
prints .set_bitmap_lock_open(m_bitmapLock);
|
||||
filaments.set_bitmap_lock_open(m_bitmapLock);
|
||||
printers .set_bitmap_lock_open(m_bitmapLock);
|
||||
}
|
||||
return loaded_compatible && loaded_incompatible && loaded_lock && loaded_lock_open;
|
||||
}
|
||||
|
||||
DynamicPrintConfig PresetBundle::full_config() const
|
||||
|
@ -594,11 +664,54 @@ static void flatten_configbundle_hierarchy(boost::property_tree::ptree &tree)
|
|||
flatten_configbundle_hierarchy(tree, "printer");
|
||||
}
|
||||
|
||||
static void load_vendor_profile(const boost::property_tree::ptree &tree, VendorProfile &vendor_profile)
|
||||
{
|
||||
const std::string printer_model_key = "printer_model:";
|
||||
for (auto §ion : tree)
|
||||
if (section.first == "vendor") {
|
||||
// Load the names of the active presets.
|
||||
for (auto &kvp : section.second) {
|
||||
if (kvp.first == "name")
|
||||
vendor_profile.name = kvp.second.data();
|
||||
else if (kvp.first == "id")
|
||||
vendor_profile.id = kvp.second.data();
|
||||
else if (kvp.first == "config_version")
|
||||
vendor_profile.config_version = kvp.second.data();
|
||||
else if (kvp.first == "config_update_url")
|
||||
vendor_profile.config_update_url = kvp.second.data();
|
||||
}
|
||||
} else if (boost::starts_with(section.first, printer_model_key)) {
|
||||
VendorProfile::PrinterModel model;
|
||||
model.name = section.first.substr(printer_model_key.size());
|
||||
section.second.get<std::string>("variants", "");
|
||||
std::vector<std::string> variants;
|
||||
if (Slic3r::unescape_strings_cstyle(section.second.get<std::string>("variants", ""), variants)) {
|
||||
for (const std::string &variant_name : variants) {
|
||||
if (model.variant(variant_name) == nullptr)
|
||||
model.variants.emplace_back(VendorProfile::PrinterVariant(variant_name));
|
||||
}
|
||||
} else {
|
||||
// Log error?
|
||||
}
|
||||
if (! model.name.empty() && ! model.variants.empty())
|
||||
vendor_profile.models.insert(model);
|
||||
}
|
||||
}
|
||||
|
||||
// Load a config bundle file, into presets and store the loaded presets into separate files
|
||||
// of the local configuration directory.
|
||||
void PresetBundle::install_vendor_configbundle(const std::string &src_path0)
|
||||
{
|
||||
boost::filesystem::path src_path(src_path0);
|
||||
boost::filesystem::copy_file(src_path, (boost::filesystem::path(data_dir()) / "vendor" / src_path.filename()).make_preferred(), boost::filesystem::copy_option::overwrite_if_exists);
|
||||
}
|
||||
|
||||
// Load a config bundle file, into presets and store the loaded presets into separate files
|
||||
// of the local configuration directory.
|
||||
size_t PresetBundle::load_configbundle(const std::string &path, unsigned int flags)
|
||||
{
|
||||
if (flags & LOAD_CFGBNDLE_RESET_USER_PROFILE)
|
||||
if (flags & (LOAD_CFGBNDLE_RESET_USER_PROFILE | LOAD_CFGBNDLE_SYSTEM))
|
||||
// Reset this bundle, delete user profile files if LOAD_CFGBNDLE_SAVE.
|
||||
this->reset(flags & LOAD_CFGBNDLE_SAVE);
|
||||
|
||||
// 1) Read the complete config file into a boost::property_tree.
|
||||
|
@ -609,6 +722,17 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
|
|||
// Flatten the config bundle by applying the inheritance rules. Internal profiles (with names starting with '*') are removed.
|
||||
flatten_configbundle_hierarchy(tree);
|
||||
|
||||
const VendorProfile *vendor_profile = nullptr;
|
||||
if (flags & LOAD_CFGBNDLE_SYSTEM) {
|
||||
VendorProfile vp;
|
||||
load_vendor_profile(tree, vp);
|
||||
if (vp.name.empty())
|
||||
throw std::runtime_error(std::string("Vendor Config Bundle is not valid: Missing vendor name key."));
|
||||
if (vp.num_variants() == 0)
|
||||
return 0;
|
||||
vendor_profile = &(*this->vendors.insert(vp).first);
|
||||
}
|
||||
|
||||
// 2) Parse the property_tree, extract the active preset names and the profiles, save them into local config files.
|
||||
std::vector<std::string> loaded_prints;
|
||||
std::vector<std::string> loaded_filaments;
|
||||
|
@ -622,15 +746,15 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
|
|||
std::vector<std::string> *loaded = nullptr;
|
||||
std::string preset_name;
|
||||
if (boost::starts_with(section.first, "print:")) {
|
||||
presets = &prints;
|
||||
presets = &this->prints;
|
||||
loaded = &loaded_prints;
|
||||
preset_name = section.first.substr(6);
|
||||
} else if (boost::starts_with(section.first, "filament:")) {
|
||||
presets = &filaments;
|
||||
presets = &this->filaments;
|
||||
loaded = &loaded_filaments;
|
||||
preset_name = section.first.substr(9);
|
||||
} else if (boost::starts_with(section.first, "printer:")) {
|
||||
presets = &printers;
|
||||
presets = &this->printers;
|
||||
loaded = &loaded_printers;
|
||||
preset_name = section.first.substr(8);
|
||||
} else if (section.first == "presets") {
|
||||
|
@ -664,6 +788,40 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
|
|||
for (auto &kvp : section.second)
|
||||
config.set_deserialize(kvp.first, kvp.second.data());
|
||||
Preset::normalize(config);
|
||||
if ((flags & LOAD_CFGBNDLE_SYSTEM) && presets == &printers) {
|
||||
// Filter out printer presets, which are not mentioned in the vendor profile.
|
||||
// These presets are considered not installed.
|
||||
auto printer_model = config.opt_string("printer_model");
|
||||
if (printer_model.empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||
section.first << "\" defines no printer model, it will be ignored.";
|
||||
continue;
|
||||
}
|
||||
auto printer_variant = config.opt_string("printer_variant");
|
||||
if (printer_variant.empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||
section.first << "\" defines no printer variant, it will be ignored.";
|
||||
continue;
|
||||
}
|
||||
auto it_model = vendor_profile->models.find(VendorProfile::PrinterModel(printer_model));
|
||||
if (it_model == vendor_profile->models.end()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||
section.first << "\" defines invalid printer model \"" << printer_model << "\", it will be ignored.";
|
||||
continue;
|
||||
}
|
||||
auto it_variant = it_model->variant(printer_variant);
|
||||
if (it_variant == nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||
section.first << "\" defines invalid printer variant \"" << printer_variant << "\", it will be ignored.";
|
||||
continue;
|
||||
}
|
||||
const Preset *preset_existing = presets->find_preset(section.first, false);
|
||||
if (preset_existing != nullptr) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a Vendor Config Bundle \"" << path << "\": The printer preset \"" <<
|
||||
section.first << "\" has already been loaded from another Confing Bundle.";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Decide a full path to this .ini file.
|
||||
auto file_name = boost::algorithm::iends_with(preset_name, ".ini") ? preset_name : preset_name + ".ini";
|
||||
auto file_path = (boost::filesystem::path(data_dir())
|
||||
|
@ -678,24 +836,29 @@ size_t PresetBundle::load_configbundle(const std::string &path, unsigned int fla
|
|||
Preset &loaded = presets->load_preset(file_path.string(), preset_name, std::move(config), false);
|
||||
if (flags & LOAD_CFGBNDLE_SAVE)
|
||||
loaded.save();
|
||||
if (flags & LOAD_CFGBNDLE_SYSTEM) {
|
||||
loaded.is_system = true;
|
||||
loaded.vendor = vendor_profile;
|
||||
}
|
||||
++ presets_loaded;
|
||||
}
|
||||
}
|
||||
|
||||
// 3) Activate the presets.
|
||||
if (! active_print.empty())
|
||||
prints.select_preset_by_name(active_print, true);
|
||||
if (! active_printer.empty())
|
||||
printers.select_preset_by_name(active_printer, true);
|
||||
// Activate the first filament preset.
|
||||
if (! active_filaments.empty() && ! active_filaments.front().empty())
|
||||
filaments.select_preset_by_name(active_filaments.front(), true);
|
||||
if ((flags & LOAD_CFGBNDLE_SYSTEM) == 0) {
|
||||
if (! active_print.empty())
|
||||
prints.select_preset_by_name(active_print, true);
|
||||
if (! active_printer.empty())
|
||||
printers.select_preset_by_name(active_printer, true);
|
||||
// Activate the first filament preset.
|
||||
if (! active_filaments.empty() && ! active_filaments.front().empty())
|
||||
filaments.select_preset_by_name(active_filaments.front(), true);
|
||||
this->update_multi_material_filament_presets();
|
||||
for (size_t i = 0; i < std::min(this->filament_presets.size(), active_filaments.size()); ++ i)
|
||||
this->filament_presets[i] = filaments.find_preset(active_filaments[i], true)->name;
|
||||
this->update_compatible_with_printer(false);
|
||||
}
|
||||
|
||||
this->update_multi_material_filament_presets();
|
||||
for (size_t i = 0; i < std::min(this->filament_presets.size(), active_filaments.size()); ++ i)
|
||||
this->filament_presets[i] = filaments.find_preset(active_filaments[i], true)->name;
|
||||
|
||||
this->update_compatible_with_printer(false);
|
||||
return presets_loaded;
|
||||
}
|
||||
|
||||
|
@ -836,49 +999,29 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, wxBitma
|
|||
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
|
||||
// to the filament color image.
|
||||
if (wide_icons)
|
||||
bitmap_key += preset.is_compatible ? "comp" : "notcomp";
|
||||
auto it = m_mapColorToBitmap.find(bitmap_key);
|
||||
wxBitmap *bitmap = (it == m_mapColorToBitmap.end()) ? nullptr : it->second;
|
||||
bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
|
||||
bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
|
||||
if (preset.is_dirty)
|
||||
bitmap_key += ",drty";
|
||||
wxBitmap *bitmap = m_bitmapCache->find(bitmap_key);
|
||||
if (bitmap == nullptr) {
|
||||
// Create the bitmap with color bars.
|
||||
bitmap = new wxBitmap((wide_icons ? 16 : 0) + 24, 16);
|
||||
#if defined(__APPLE__) || defined(_MSC_VER)
|
||||
bitmap->UseAlpha();
|
||||
#endif
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
if (wide_icons && ! preset.is_compatible)
|
||||
// Paint the red flag.
|
||||
memDC.DrawBitmap(*m_bitmapIncompatible, 0, 0, true);
|
||||
std::vector<wxBitmap> bmps;
|
||||
if (wide_icons)
|
||||
// Paint a red flag for incompatible presets.
|
||||
bmps.emplace_back(preset.is_compatible ? m_bitmapCache->mkclear(16, 16) : *m_bitmapIncompatible);
|
||||
// Paint the color bars.
|
||||
parse_color(filament_rgb, rgb);
|
||||
wxImage image(24, 16);
|
||||
image.InitAlpha();
|
||||
unsigned char* imgdata = image.GetData();
|
||||
unsigned char* imgalpha = image.GetAlpha();
|
||||
for (size_t i = 0; i < image.GetWidth() * image.GetHeight(); ++ i) {
|
||||
*imgdata ++ = rgb[0];
|
||||
*imgdata ++ = rgb[1];
|
||||
*imgdata ++ = rgb[2];
|
||||
*imgalpha ++ = wxALPHA_OPAQUE;
|
||||
}
|
||||
bmps.emplace_back(m_bitmapCache->mksolid(single_bar ? 24 : 16, 16, rgb));
|
||||
if (! single_bar) {
|
||||
parse_color(extruder_rgb, rgb);
|
||||
imgdata = image.GetData();
|
||||
for (size_t r = 0; r < 16; ++ r) {
|
||||
imgdata = image.GetData() + r * image.GetWidth() * 3;
|
||||
for (size_t c = 0; c < 16; ++ c) {
|
||||
*imgdata ++ = rgb[0];
|
||||
*imgdata ++ = rgb[1];
|
||||
*imgdata ++ = rgb[2];
|
||||
}
|
||||
}
|
||||
bmps.emplace_back(m_bitmapCache->mksolid(8, 16, rgb));
|
||||
}
|
||||
memDC.DrawBitmap(wxBitmap(image), wide_icons ? 16 : 0, 0, true);
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
m_mapColorToBitmap[bitmap_key] = bitmap;
|
||||
// Paint a lock at the system presets.
|
||||
bmps.emplace_back(m_bitmapCache->mkclear(4, 16));
|
||||
bmps.emplace_back((preset.is_system || preset.is_default) ?
|
||||
(preset.is_dirty ? *m_bitmapLockOpen : *m_bitmapLock) : m_bitmapCache->mkclear(16, 16));
|
||||
bitmap = m_bitmapCache->insert(bitmap_key, bmps);
|
||||
}
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), (bitmap == 0) ? wxNullBitmap : *bitmap);
|
||||
if (selected)
|
||||
|
|
|
@ -4,8 +4,14 @@
|
|||
#include "AppConfig.hpp"
|
||||
#include "Preset.hpp"
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace GUI {
|
||||
class BitmapCache;
|
||||
};
|
||||
|
||||
class PlaceholderParser;
|
||||
|
||||
// Bundle of Print + Filament + Printer presets.
|
||||
|
@ -22,11 +28,10 @@ public:
|
|||
void setup_directories();
|
||||
|
||||
// Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets.
|
||||
void load_presets();
|
||||
|
||||
// Load selections (current print, current filaments, current printer) from config.ini
|
||||
// This is done just once on application start up.
|
||||
void load_selections(const AppConfig &config);
|
||||
void load_presets(const AppConfig &config);
|
||||
|
||||
// Export selections (current print, current filaments, current printer) into config.ini
|
||||
void export_selections(AppConfig &config);
|
||||
// Export selections (current print, current filaments, current printer) into a placeholder parser.
|
||||
|
@ -39,6 +44,10 @@ public:
|
|||
// extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
|
||||
std::vector<std::string> filament_presets;
|
||||
|
||||
// There will be an entry for each system profile loaded,
|
||||
// and the system profiles will point to the VendorProfile instances owned by PresetBundle::vendors.
|
||||
std::set<VendorProfile> vendors;
|
||||
|
||||
bool has_defauls_only() const
|
||||
{ return prints.size() <= 1 && filaments.size() <= 1 && printers.size() <= 1; }
|
||||
|
||||
|
@ -69,11 +78,16 @@ public:
|
|||
// Save the profiles, which have been loaded.
|
||||
LOAD_CFGBNDLE_SAVE = 1,
|
||||
// Delete all old config profiles before loading.
|
||||
LOAD_CFGBNDLE_RESET_USER_PROFILE = 2
|
||||
LOAD_CFGBNDLE_RESET_USER_PROFILE = 2,
|
||||
// Load a system config bundle.
|
||||
LOAD_CFGBNDLE_SYSTEM = 4,
|
||||
};
|
||||
// Load the config bundle, store it to the user profile directory by default.
|
||||
size_t load_configbundle(const std::string &path, unsigned int flags = LOAD_CFGBNDLE_SAVE);
|
||||
|
||||
// Install the Vendor specific config bundle into user's directory.
|
||||
void install_vendor_configbundle(const std::string &src_path);
|
||||
|
||||
// Export a config bundle file containing all the presets and the names of the active presets.
|
||||
void export_configbundle(const std::string &path); // , const DynamicPrintConfig &settings);
|
||||
|
||||
|
@ -99,6 +113,17 @@ public:
|
|||
void update_compatible_with_printer(bool select_other_if_incompatible);
|
||||
|
||||
private:
|
||||
std::string load_system_presets();
|
||||
|
||||
// Set the "enabled" flag for printer vendors, printer models and printer variants
|
||||
// based on the user configuration.
|
||||
// If the "vendor" section is missing, enable all models and variants of the particular vendor.
|
||||
void load_installed_printers(const AppConfig &config);
|
||||
|
||||
// Load selections (current print, current filaments, current printer) from config.ini
|
||||
// This is done just once on application start up.
|
||||
void load_selections(const AppConfig &config);
|
||||
|
||||
// Load print, filament & printer presets from a config. If it is an external config, then the name is extracted from the external path.
|
||||
// and the external config is just referenced, not stored into user profile directory.
|
||||
// If it is not an external config, then the config will be stored into the user profile directory.
|
||||
|
@ -110,8 +135,12 @@ private:
|
|||
wxBitmap *m_bitmapCompatible;
|
||||
// Indicator, that the preset is NOT compatible with the selected printer.
|
||||
wxBitmap *m_bitmapIncompatible;
|
||||
// Caching color bitmaps for the
|
||||
std::map<std::string, wxBitmap*> m_mapColorToBitmap;
|
||||
// Indicator, that the preset is system and not modified.
|
||||
wxBitmap *m_bitmapLock;
|
||||
// Indicator, that the preset is system and user modified.
|
||||
wxBitmap *m_bitmapLockOpen;
|
||||
// Caching color bitmaps for the filament combo box.
|
||||
GUI::BitmapCache *m_bitmapCache;
|
||||
};
|
||||
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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() {}
|
||||
|
|
|
@ -41,4 +41,6 @@
|
|||
void update_skein_dir(char *dir);
|
||||
std::string get_last_output_dir(const char *alt = "");
|
||||
void update_last_output_dir(char *dir);
|
||||
|
||||
void reset_selections();
|
||||
};
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
bool default() %code%{ RETVAL = THIS->is_default; %};
|
||||
bool external() %code%{ RETVAL = THIS->is_external; %};
|
||||
bool system() %code%{ RETVAL = THIS->is_system; %};
|
||||
bool visible() %code%{ RETVAL = THIS->is_visible; %};
|
||||
bool dirty() %code%{ RETVAL = THIS->is_dirty; %};
|
||||
bool compatible() %code%{ RETVAL = THIS->is_compatible; %};
|
||||
|
@ -110,10 +111,10 @@ PresetCollection::arrayref()
|
|||
croak("Cannot create configuration directories:\n%s\n", e.what());
|
||||
}
|
||||
%};
|
||||
void load_presets()
|
||||
void load_presets(AppConfig *config)
|
||||
%code%{
|
||||
try {
|
||||
THIS->load_presets();
|
||||
THIS->load_presets(*config);
|
||||
} catch (std::exception& e) {
|
||||
croak("Loading of Slic3r presets from %s failed.\n\n%s\n",
|
||||
Slic3r::data_dir().c_str(), e.what());
|
||||
|
@ -143,6 +144,14 @@ PresetCollection::arrayref()
|
|||
croak("Loading of a config bundle %s failed:\n%s\n", path, e.what());
|
||||
}
|
||||
%};
|
||||
void install_vendor_configbundle(const char *path)
|
||||
%code%{
|
||||
try {
|
||||
THIS->install_vendor_configbundle(path);
|
||||
} catch (std::exception& e) {
|
||||
croak("Installing a vendor config bundle %s failed:\n%s\n", path, e.what());
|
||||
}
|
||||
%};
|
||||
void export_configbundle(char *path)
|
||||
%code%{
|
||||
try {
|
||||
|
@ -154,7 +163,6 @@ PresetCollection::arrayref()
|
|||
|
||||
void set_default_suppressed(bool default_suppressed);
|
||||
|
||||
void load_selections (AppConfig *config) %code%{ THIS->load_selections(*config); %};
|
||||
void export_selections(AppConfig *config) %code%{ THIS->export_selections(*config); %};
|
||||
void export_selections_pp(PlaceholderParser *pp) %code%{ THIS->export_selections(*pp); %};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue