Physical Printers.
- save/load printers - consistency between selection on Tab and Plater
This commit is contained in:
parent
7c7dcab032
commit
02624689ce
@ -1339,108 +1339,178 @@ const Preset* PrinterPresetCollection::find_by_model_id(const std::string &model
|
||||
|
||||
return it != cend() ? &*it : nullptr;
|
||||
}
|
||||
/*
|
||||
PhysicalPrinter& PhysicalPrinterCollection::load_external_printer(
|
||||
// Path to the profile source file (a G-code, an AMF or 3MF file, a config file)
|
||||
const std::string& path,
|
||||
// Name of the profile, derived from the source file name.
|
||||
const std::string& name,
|
||||
// Original name of the profile, extracted from the loaded config. Empty, if the name has not been stored.
|
||||
const std::string& original_name,
|
||||
// Config to initialize the preset from.
|
||||
const DynamicPrintConfig& config,
|
||||
// Select the preset after loading?
|
||||
bool select)
|
||||
{
|
||||
// Load the preset over a default preset, so that the missing fields are filled in from the default preset.
|
||||
DynamicPrintConfig cfg(this->default_printer().config);
|
||||
cfg.apply_only(config, cfg.keys(), true);
|
||||
// Is there a preset already loaded with the name stored inside the config?
|
||||
std::deque<PhysicalPrinter>::iterator it = this->find_printer_internal(original_name);
|
||||
bool found = it != m_printers.end() && it->name == original_name;
|
||||
if (!found) {
|
||||
// Try to match the original_name against the "renamed_from" profile names of loaded system profiles.
|
||||
/ *
|
||||
it = this->find_preset_renamed(original_name);
|
||||
found = it != m_presets.end();
|
||||
* /
|
||||
}
|
||||
if (found) {
|
||||
if (profile_print_params_same(it->config, cfg)) {
|
||||
// The preset exists and it matches the values stored inside config.
|
||||
if (select)
|
||||
this->select_printer(it - m_printers.begin());
|
||||
return *it;
|
||||
}
|
||||
if (profile_host_params_same_or_anonymized(it->config, cfg) == ProfileHostParams::Anonymized) {
|
||||
// The project being loaded is anonymized. Replace the empty host keys of the loaded profile with the data from the original profile.
|
||||
// See "Octoprint Settings when Opening a .3MF file" GH issue #3244
|
||||
auto opt_update = [it, &cfg](const std::string& opt_key) {
|
||||
auto opt = it->config.option<ConfigOptionString>(opt_key);
|
||||
if (opt != nullptr)
|
||||
cfg.set_key_value(opt_key, opt->clone());
|
||||
};
|
||||
opt_update("print_host");
|
||||
opt_update("printhost_apikey");
|
||||
opt_update("printhost_cafile");
|
||||
}
|
||||
}
|
||||
// The external preset does not match an internal preset, load the external preset.
|
||||
std::string new_name;
|
||||
for (size_t idx = 0;; ++idx) {
|
||||
std::string suffix;
|
||||
if (original_name.empty()) {
|
||||
if (idx > 0)
|
||||
suffix = " (" + std::to_string(idx) + ")";
|
||||
}
|
||||
else {
|
||||
if (idx == 0)
|
||||
suffix = " (" + original_name + ")";
|
||||
else
|
||||
suffix = " (" + original_name + "-" + std::to_string(idx) + ")";
|
||||
}
|
||||
new_name = name + suffix;
|
||||
it = this->find_printer_internal(new_name);
|
||||
if (it == m_printers.end() || it->name != new_name)
|
||||
// Unique profile name. Insert a new profile.
|
||||
break;
|
||||
if (profile_print_params_same(it->config, cfg)) {
|
||||
// The preset exists and it matches the values stored inside config.
|
||||
if (select)
|
||||
this->select_printer(it - m_printers.begin());
|
||||
return *it;
|
||||
}
|
||||
// Form another profile name.
|
||||
}
|
||||
// Insert a new profile.
|
||||
PhysicalPrinter& printer = this->load_printer(path, new_name, std::move(cfg), select);
|
||||
|
||||
return printer;
|
||||
// -------------------------
|
||||
// *** PhysicalPrinter ***
|
||||
// -------------------------
|
||||
|
||||
const std::vector<std::string>& PhysicalPrinter::printer_options()
|
||||
{
|
||||
static std::vector<std::string> s_opts;
|
||||
if (s_opts.empty()) {
|
||||
s_opts = {
|
||||
"preset_name",
|
||||
"printer_technology",
|
||||
"host_type",
|
||||
"print_host",
|
||||
"printhost_apikey",
|
||||
"printhost_cafile",
|
||||
"login",
|
||||
"password"
|
||||
};
|
||||
}
|
||||
return s_opts;
|
||||
}
|
||||
|
||||
void PhysicalPrinterCollection::save_printer(const std::string& new_name)
|
||||
const std::string& PhysicalPrinter::get_preset_name()
|
||||
{
|
||||
return config.opt_string("preset_name");
|
||||
}
|
||||
|
||||
void PhysicalPrinter::update_from_preset(const Preset& preset)
|
||||
{
|
||||
config.apply_only(preset.config, printer_options(), false);
|
||||
// add preset name to the options list
|
||||
config.set_key_value("preset_name", new ConfigOptionString(preset.name));
|
||||
}
|
||||
|
||||
void PhysicalPrinter::update_from_config(const DynamicPrintConfig& new_config)
|
||||
{
|
||||
config.apply_only(new_config, printer_options(), false);
|
||||
}
|
||||
|
||||
PhysicalPrinter::PhysicalPrinter(const std::string& name, const Preset& preset) :
|
||||
name(name)
|
||||
{
|
||||
update_from_preset(preset);
|
||||
}
|
||||
|
||||
|
||||
// -----------------------------------
|
||||
// *** PhysicalPrinterCollection ***
|
||||
// -----------------------------------
|
||||
|
||||
PhysicalPrinterCollection::PhysicalPrinterCollection( const std::vector<std::string>& keys)
|
||||
{
|
||||
}
|
||||
|
||||
// Load all presets found in dir_path.
|
||||
// Throws an exception on error.
|
||||
void PhysicalPrinterCollection::load_printers(const std::string& dir_path, const std::string& subdir)
|
||||
{
|
||||
boost::filesystem::path dir = boost::filesystem::canonical(boost::filesystem::path(dir_path) / subdir).make_preferred();
|
||||
m_dir_path = dir.string();
|
||||
std::string errors_cummulative;
|
||||
// Store the loaded printers into a new vector, otherwise the binary search for already existing presets would be broken.
|
||||
std::deque<PhysicalPrinter> printers_loaded;
|
||||
for (auto& dir_entry : boost::filesystem::directory_iterator(dir))
|
||||
if (Slic3r::is_ini_file(dir_entry)) {
|
||||
std::string name = dir_entry.path().filename().string();
|
||||
// Remove the .ini suffix.
|
||||
name.erase(name.size() - 4);
|
||||
if (this->find_printer(name, false)) {
|
||||
// This happens when there's is a preset (most likely legacy one) with the same name as a system preset
|
||||
// that's already been loaded from a bundle.
|
||||
BOOST_LOG_TRIVIAL(warning) << "Preset already present, not loading: " << name;
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
PhysicalPrinter printer(name);
|
||||
printer.file = dir_entry.path().string();
|
||||
// Load the preset file, apply preset values on top of defaults.
|
||||
try {
|
||||
DynamicPrintConfig config;
|
||||
config.load_from_ini(printer.file);
|
||||
printer.update_from_config(config);
|
||||
printer.loaded = true;
|
||||
}
|
||||
catch (const std::ifstream::failure& err) {
|
||||
throw std::runtime_error(std::string("The selected preset cannot be loaded: ") + printer.file + "\n\tReason: " + err.what());
|
||||
}
|
||||
catch (const std::runtime_error& err) {
|
||||
throw std::runtime_error(std::string("Failed loading the preset file: ") + printer.file + "\n\tReason: " + err.what());
|
||||
}
|
||||
printers_loaded.emplace_back(printer);
|
||||
}
|
||||
catch (const std::runtime_error& err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
}
|
||||
}
|
||||
m_printers.insert(m_printers.end(), std::make_move_iterator(printers_loaded.begin()), std::make_move_iterator(printers_loaded.end()));
|
||||
std::sort(m_printers.begin(), m_printers.end());
|
||||
//! this->select_preset(first_visible_idx());
|
||||
if (!errors_cummulative.empty())
|
||||
throw std::runtime_error(errors_cummulative);
|
||||
}
|
||||
|
||||
PhysicalPrinter* PhysicalPrinterCollection::find_printer( const std::string& name, bool first_visible_if_not_found)
|
||||
{
|
||||
PhysicalPrinter key(name);
|
||||
auto it = this->find_printer_internal(name);
|
||||
// Ensure that a temporary copy is returned if the preset found is currently selected.
|
||||
return (it != m_printers.end() && it->name == key.name) ? &this->printer(it - m_printers.begin()) :
|
||||
first_visible_if_not_found ? &this->printer(0) : nullptr;
|
||||
}
|
||||
|
||||
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
|
||||
std::string PhysicalPrinterCollection::path_from_name(const std::string& new_name) const
|
||||
{
|
||||
std::string file_name = boost::iends_with(new_name, ".ini") ? new_name : (new_name + ".ini");
|
||||
return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string();
|
||||
}
|
||||
|
||||
void PhysicalPrinterCollection::save_printer(const PhysicalPrinter& edited_printer)
|
||||
{
|
||||
// 1) Find the printer with a new_name or create a new one,
|
||||
// initialize it with the edited config.
|
||||
auto it = this->find_printer_internal(new_name);
|
||||
if (it != m_printers.end() && it->name == new_name) {
|
||||
// Preset with the same name found.
|
||||
PhysicalPrinter& printer = *it;
|
||||
auto it = this->find_printer_internal(edited_printer.name);
|
||||
if (it != m_printers.end() && it->name == edited_printer.name) {
|
||||
// Printer with the same name found.
|
||||
// Overwriting an existing preset.
|
||||
printer.config = std::move(m_edited_printer.config);
|
||||
it->config = std::move(edited_printer.config);
|
||||
}
|
||||
else {
|
||||
// Creating a new printer.
|
||||
PhysicalPrinter& printer = *m_printers.insert(it, m_edited_printer);
|
||||
std::string old_name = printer.name;
|
||||
printer.name = new_name;
|
||||
it = m_printers.insert(it, edited_printer);
|
||||
}
|
||||
// 2) Activate the saved preset.
|
||||
this->select_printer_by_name(new_name, true);
|
||||
// 3) Store the active preset to disk.
|
||||
this->get_selected_preset().save();
|
||||
assert(it != m_printers.end());
|
||||
|
||||
// 2) Save printer
|
||||
PhysicalPrinter& printer = *it;
|
||||
if (printer.file.empty())
|
||||
printer.file = this->path_from_name(printer.name);
|
||||
printer.save();
|
||||
|
||||
// update idx_selected
|
||||
m_idx_selected = it - m_printers.begin();
|
||||
}
|
||||
*/
|
||||
|
||||
bool PhysicalPrinterCollection::delete_printer(const std::string& name)
|
||||
{
|
||||
auto it = this->find_printer_internal(name);
|
||||
|
||||
const PhysicalPrinter& printer = *it;
|
||||
if (it == m_printers.end())
|
||||
return false;
|
||||
|
||||
// Erase the preset file.
|
||||
boost::nowide::remove(printer.file.c_str());
|
||||
m_printers.erase(it);
|
||||
return true;
|
||||
}
|
||||
|
||||
PhysicalPrinter& PhysicalPrinterCollection::select_printer_by_name(const std::string& name)
|
||||
{
|
||||
auto it = this->find_printer_internal(name);
|
||||
assert(it != m_printers.end());
|
||||
|
||||
// update idx_selected
|
||||
m_idx_selected = it - m_printers.begin();
|
||||
return *it;
|
||||
}
|
||||
|
||||
|
||||
namespace PresetUtils {
|
||||
const VendorProfile::PrinterModel* system_printer_model(const Preset &preset)
|
||||
{
|
||||
|
@ -535,14 +535,14 @@ namespace PresetUtils {
|
||||
class PhysicalPrinter
|
||||
{
|
||||
public:
|
||||
PhysicalPrinter(const std::string& name) : name(name) {}
|
||||
PhysicalPrinter() {}
|
||||
PhysicalPrinter(const std::string& name) : name(name){}
|
||||
PhysicalPrinter(const std::string& name, const Preset& preset);
|
||||
|
||||
// Name of the Physical Printer, usually derived form the file name.
|
||||
std::string name;
|
||||
// File name of the Physical Printer.
|
||||
std::string file;
|
||||
// Name of the related Printer preset
|
||||
std::string preset_name;
|
||||
|
||||
// Has this profile been loaded?
|
||||
bool loaded = false;
|
||||
@ -550,7 +550,13 @@ public:
|
||||
// Configuration data, loaded from a file, or set from the defaults.
|
||||
DynamicPrintConfig config;
|
||||
|
||||
static const std::vector<std::string>& printer_options();
|
||||
const std::string& get_preset_name();
|
||||
|
||||
void save() { this->config.save(this->file); }
|
||||
void save_to(const std::string& file_name) const { this->config.save(file_name); }
|
||||
void update_from_preset(const Preset& preset);
|
||||
void update_from_config(const DynamicPrintConfig &new_config);
|
||||
|
||||
// Return a printer technology, return ptFFF if the printer technology is not set.
|
||||
static PrinterTechnology printer_technology(const DynamicPrintConfig& cfg) {
|
||||
@ -562,18 +568,22 @@ public:
|
||||
PrinterTechnology printer_technology() const { return printer_technology(this->config); }
|
||||
|
||||
// Sort lexicographically by a preset name. The preset name shall be unique across a single PresetCollection.
|
||||
bool operator<(const Preset& other) const { return this->name < other.name; }
|
||||
bool operator<(const PhysicalPrinter& other) const { return this->name < other.name; }
|
||||
|
||||
protected:
|
||||
friend class PhysicalPrinterCollection;
|
||||
};
|
||||
/*
|
||||
// Collections of presets of the same type (one of the Print, Filament or Printer type).
|
||||
|
||||
|
||||
// ---------------------------------
|
||||
// *** PhysicalPrinterCollection ***
|
||||
// ---------------------------------
|
||||
|
||||
// Collections of physical printers
|
||||
class PhysicalPrinterCollection
|
||||
{
|
||||
public:
|
||||
// Initialize the PresetCollection with the "- default -" preset.
|
||||
PhysicalPrinterCollection(const std::vector<std::string>& keys) : m_idx_selected(0) {}
|
||||
PhysicalPrinterCollection(const std::vector<std::string>& keys);
|
||||
~PhysicalPrinterCollection() {}
|
||||
|
||||
typedef std::deque<PhysicalPrinter>::iterator Iterator;
|
||||
@ -585,63 +595,39 @@ public:
|
||||
ConstIterator end() const { return m_printers.cend(); }
|
||||
ConstIterator cend() const { return m_printers.cend(); }
|
||||
|
||||
bool empty() const {return m_printers.empty(); }
|
||||
|
||||
void reset(bool delete_files) {};
|
||||
|
||||
const std::deque<PhysicalPrinter>& operator()() const { return m_printers; }
|
||||
|
||||
// Load ini files of the particular type from the provided directory path.
|
||||
void load_printers(const std::string& dir_path, const std::string& subdir){};
|
||||
|
||||
// Load a preset from an already parsed config file, insert it into the sorted sequence of presets
|
||||
// and select it, losing previous modifications.
|
||||
PhysicalPrinter& load_printer(const std::string& path, const std::string& name, const DynamicPrintConfig& config, bool select = true);
|
||||
PhysicalPrinter& load_printer(const std::string& path, const std::string& name, DynamicPrintConfig&& config, bool select = true);
|
||||
|
||||
PhysicalPrinter& load_external_printer(
|
||||
// Path to the profile source file (a G-code, an AMF or 3MF file, a config file)
|
||||
const std::string& path,
|
||||
// Name of the profile, derived from the source file name.
|
||||
const std::string& name,
|
||||
// Original name of the profile, extracted from the loaded config. Empty, if the name has not been stored.
|
||||
const std::string& original_name,
|
||||
// Config to initialize the preset from.
|
||||
const DynamicPrintConfig& config,
|
||||
// Select the preset after loading?
|
||||
bool select = true);
|
||||
void load_printers(const std::string& dir_path, const std::string& subdir);
|
||||
|
||||
// Save the printer under a new name. If the name is different from the old one,
|
||||
// a new printer is stored into the list of printers.
|
||||
// ? New printer is activated.
|
||||
void save_printer(const std::string& new_name);
|
||||
// New printer is activated.
|
||||
void save_printer(const PhysicalPrinter& printer);
|
||||
|
||||
// Delete the current preset, activate the first visible preset.
|
||||
// returns true if the preset was deleted successfully.
|
||||
bool delete_current_printer() {return true;}
|
||||
// Delete the current preset, activate the first visible preset.
|
||||
// returns true if the preset was deleted successfully.
|
||||
bool delete_printer(const std::string& name) { return true; }
|
||||
bool delete_printer(const std::string& name);
|
||||
|
||||
// Select a printer. If an invalid index is provided, the first visible printer is selected.
|
||||
PhysicalPrinter& select_printer(size_t idx);
|
||||
// Return the selected preset, without the user modifications applied.
|
||||
PhysicalPrinter& get_selected_preset() { return m_printers[m_idx_selected]; }
|
||||
const PhysicalPrinter& get_selected_preset() const { return m_printers[m_idx_selected]; }
|
||||
PhysicalPrinter& get_selected_printer() { return m_printers[m_idx_selected]; }
|
||||
const PhysicalPrinter& get_selected_printer() const { return m_printers[m_idx_selected]; }
|
||||
size_t get_selected_idx() const { return m_idx_selected; }
|
||||
// Returns the name of the selected preset, or an empty string if no preset is selected.
|
||||
std::string get_selected_preset_name() const { return (m_idx_selected == size_t(-1)) ? std::string() : this->get_selected_preset().name; }
|
||||
PhysicalPrinter& get_edited_preset() { return m_edited_printer; }
|
||||
const PhysicalPrinter& get_edited_preset() const { return m_edited_printer; }
|
||||
std::string get_selected_printer_name() const { return (m_idx_selected == size_t(-1)) ? std::string() : this->get_selected_printer().name; }
|
||||
DynamicPrintConfig* get_selected_printer_config() { return (m_idx_selected == size_t(-1)) ? nullptr : &(this->get_selected_printer().config); }
|
||||
|
||||
// Return a preset possibly with modifications.
|
||||
PhysicalPrinter& default_printer(size_t idx = 0) { return m_printers[idx]; }
|
||||
const PhysicalPrinter& default_printer(size_t idx = 0) const { return m_printers[idx]; }
|
||||
// select printer with name and return reference on it
|
||||
PhysicalPrinter& select_printer_by_name(const std::string& name);
|
||||
bool has_selection() const { return m_idx_selected != size_t(-1); }
|
||||
void unselect_printer() { m_idx_selected = size_t(-1); }
|
||||
|
||||
// used to update preset_choice from Tab
|
||||
const std::deque<PhysicalPrinter>& get_presets() const { return m_printers; }
|
||||
size_t get_idx_selected() { return m_idx_selected; }
|
||||
|
||||
// Return a preset by an index. If the preset is active, a temporary copy is returned.
|
||||
PhysicalPrinter& printer(size_t idx) { return (idx == m_idx_selected) ? m_edited_printer : m_printers[idx]; }
|
||||
// Return a printer by an index. If the printer is active, a temporary copy is returned.
|
||||
PhysicalPrinter& printer(size_t idx) { return m_printers[idx]; }
|
||||
const PhysicalPrinter& printer(size_t idx) const { return const_cast<PhysicalPrinterCollection*>(this)->printer(idx); }
|
||||
|
||||
// Return a preset by its name. If the preset is active, a temporary copy is returned.
|
||||
@ -652,20 +638,10 @@ public:
|
||||
return const_cast<PhysicalPrinterCollection*>(this)->find_printer(name, first_visible_if_not_found);
|
||||
}
|
||||
|
||||
// Return number of presets including the "- default -" preset.
|
||||
size_t size() const { return m_printers.size(); }
|
||||
|
||||
// Select a profile by its name. Return true if the selection changed.
|
||||
// Without force, the selection is only updated if the index changes.
|
||||
// With force, the changes are reverted if the new index is the same as the old index.
|
||||
bool select_printer_by_name(const std::string& name, bool force) {};
|
||||
|
||||
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
|
||||
std::string path_from_name(const std::string& new_name) const;
|
||||
|
||||
private:
|
||||
// PhysicalPrinterCollection();
|
||||
PhysicalPrinterCollection(const PhysicalPrinterCollection& other);
|
||||
PhysicalPrinterCollection& operator=(const PhysicalPrinterCollection& other);
|
||||
|
||||
// Find a preset position in the sorted list of presets.
|
||||
@ -674,8 +650,8 @@ private:
|
||||
// If a preset does not exist, an iterator is returned indicating where to insert a preset with the same name.
|
||||
std::deque<PhysicalPrinter>::iterator find_printer_internal(const std::string& name)
|
||||
{
|
||||
PhysicalPrinter key(name);
|
||||
auto it = std::lower_bound(m_printers.begin()+0, m_printers.end(), key);
|
||||
PhysicalPrinter printer(name);
|
||||
auto it = std::lower_bound(m_printers.begin(), m_printers.end(), printer);
|
||||
return it;
|
||||
}
|
||||
std::deque<PhysicalPrinter>::const_iterator find_printer_internal(const std::string& name) const
|
||||
@ -683,23 +659,18 @@ private:
|
||||
return const_cast<PhysicalPrinterCollection*>(this)->find_printer_internal(name);
|
||||
}
|
||||
|
||||
static std::vector<std::string> dirty_options(const Preset* edited, const Preset* reference, const bool is_printer_type = false);
|
||||
|
||||
// List of presets, starting with the "- default -" preset.
|
||||
// List of printers
|
||||
// Use deque to force the container to allocate an object per each entry,
|
||||
// so that the addresses of the presets don't change during resizing of the container.
|
||||
std::deque<PhysicalPrinter> m_printers;
|
||||
// Initially this printer contains a copy of the selected printer. Later on, this copy may be modified by the user.
|
||||
PhysicalPrinter m_edited_printer;
|
||||
// Selected preset.
|
||||
size_t m_idx_selected;
|
||||
|
||||
// Selected printer.
|
||||
size_t m_idx_selected = size_t(-1);
|
||||
|
||||
// Path to the directory to store the config files into.
|
||||
std::string m_dir_path;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
*/
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
|
@ -41,7 +41,8 @@ PresetBundle::PresetBundle() :
|
||||
filaments(Preset::TYPE_FILAMENT, Preset::filament_options(), static_cast<const HostConfig&>(FullPrintConfig::defaults())),
|
||||
sla_materials(Preset::TYPE_SLA_MATERIAL, Preset::sla_material_options(), static_cast<const SLAMaterialConfig&>(SLAFullPrintConfig::defaults())),
|
||||
sla_prints(Preset::TYPE_SLA_PRINT, Preset::sla_print_options(), static_cast<const SLAPrintObjectConfig&>(SLAFullPrintConfig::defaults())),
|
||||
printers(Preset::TYPE_PRINTER, Preset::printer_options(), static_cast<const HostConfig&>(FullPrintConfig::defaults()), "- default FFF -")
|
||||
printers(Preset::TYPE_PRINTER, Preset::printer_options(), static_cast<const HostConfig&>(FullPrintConfig::defaults()), "- default FFF -"),
|
||||
physical_printers(PhysicalPrinter::printer_options())
|
||||
{
|
||||
// The following keys are handled by the UI, they do not have a counterpart in any StaticPrintConfig derived classes,
|
||||
// therefore they need to be handled differently. As they have no counterpart in StaticPrintConfig, they are not being
|
||||
@ -139,14 +140,16 @@ void PresetBundle::setup_directories()
|
||||
data_dir / "presets" / "filament",
|
||||
data_dir / "presets" / "sla_print",
|
||||
data_dir / "presets" / "sla_material",
|
||||
data_dir / "presets" / "printer"
|
||||
data_dir / "presets" / "printer",
|
||||
data_dir / "presets" / "physical_printer"
|
||||
#else
|
||||
// Store the print/filament/printer presets at the same location as the upstream Slic3r.
|
||||
data_dir / "print",
|
||||
data_dir / "filament",
|
||||
data_dir / "sla_print",
|
||||
data_dir / "sla_material",
|
||||
data_dir / "printer"
|
||||
data_dir / "printer",
|
||||
data_dir / "physical_printer"
|
||||
#endif
|
||||
};
|
||||
for (const boost::filesystem::path &path : paths) {
|
||||
@ -196,6 +199,11 @@ void PresetBundle::load_presets(AppConfig &config, const std::string &preferred_
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
}
|
||||
try {
|
||||
this->physical_printers.load_printers(dir_user_presets, "physical_printer");
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
}
|
||||
this->update_multi_material_filament_presets();
|
||||
this->update_compatible(PresetSelectCompatibleType::Never);
|
||||
if (! errors_cummulative.empty())
|
||||
@ -422,6 +430,14 @@ void PresetBundle::load_selections(AppConfig &config, const std::string &preferr
|
||||
// exist.
|
||||
this->update_compatible(PresetSelectCompatibleType::Always);
|
||||
this->update_multi_material_filament_presets();
|
||||
|
||||
// Parse the initial physical printer name.
|
||||
std::string initial_physical_printer_name = remove_ini_suffix(config.get("extras", "physical_printer"));
|
||||
|
||||
// Activate physical printer from the config
|
||||
const PhysicalPrinter* initial_physical_printer = physical_printers.find_printer(initial_physical_printer_name);
|
||||
if (initial_physical_printer)
|
||||
physical_printers.select_printer_by_name(initial_physical_printer_name);
|
||||
}
|
||||
|
||||
// Export selections (current print, current filaments, current printer) into config.ini
|
||||
@ -441,6 +457,8 @@ void PresetBundle::export_selections(AppConfig &config)
|
||||
config.set("presets", "sla_print", sla_prints.get_selected_preset_name());
|
||||
config.set("presets", "sla_material", sla_materials.get_selected_preset_name());
|
||||
config.set("presets", "printer", printers.get_selected_preset_name());
|
||||
|
||||
config.set("extras", "physical_printer", physical_printers.get_selected_printer_name());
|
||||
}
|
||||
|
||||
DynamicPrintConfig PresetBundle::full_config() const
|
||||
|
@ -39,6 +39,7 @@ public:
|
||||
PresetCollection& materials(PrinterTechnology pt) { return pt == ptFFF ? this->filaments : this->sla_materials; }
|
||||
const PresetCollection& materials(PrinterTechnology pt) const { return pt == ptFFF ? this->filaments : this->sla_materials; }
|
||||
PrinterPresetCollection printers;
|
||||
PhysicalPrinterCollection physical_printers;
|
||||
// Filament preset names for a multi-extruder or multi-material print.
|
||||
// extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
|
||||
std::vector<std::string> filament_presets;
|
||||
|
@ -130,6 +130,26 @@ void PrintConfigDef::init_common_params()
|
||||
def->min = 0;
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionFloat(0.2));
|
||||
|
||||
// Options used by physical printers
|
||||
|
||||
def = this->add("login", coString);
|
||||
def->label = L("Login");
|
||||
// def->tooltip = L("");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
|
||||
def = this->add("password", coString);
|
||||
def->label = L("Password");
|
||||
// def->tooltip = L("");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
|
||||
def = this->add("preset_name", coString);
|
||||
def->label = L("Printer preset name");
|
||||
def->tooltip = L("Related printer preset name");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
}
|
||||
|
||||
void PrintConfigDef::init_fff_params()
|
||||
|
@ -942,8 +942,6 @@ void Sidebar::msw_rescale()
|
||||
|
||||
void Sidebar::sys_color_changed()
|
||||
{
|
||||
// Update preset comboboxes in respect to the system color ...
|
||||
// combo->msw_rescale() updates icon on button, so use it
|
||||
for (PlaterPresetComboBox* combo : std::vector<PlaterPresetComboBox*>{ p->combo_print,
|
||||
p->combo_sla_print,
|
||||
p->combo_sla_material,
|
||||
@ -952,12 +950,8 @@ void Sidebar::sys_color_changed()
|
||||
for (PlaterPresetComboBox* combo : p->combos_filament)
|
||||
combo->msw_rescale();
|
||||
|
||||
// ... then refill them and set min size to correct layout of the sidebar
|
||||
update_all_preset_comboboxes();
|
||||
|
||||
p->object_list->sys_color_changed();
|
||||
p->object_manipulation->sys_color_changed();
|
||||
// p->object_settings->msw_rescale();
|
||||
p->object_layers->sys_color_changed();
|
||||
|
||||
// btn...->msw_rescale() updates icon on button, so use it
|
||||
@ -3208,12 +3202,23 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
|
||||
//! instead of
|
||||
//! combo->GetStringSelection().ToUTF8().data());
|
||||
|
||||
const std::string preset_name = wxGetApp().preset_bundle->get_preset_name_by_alias(preset_type,
|
||||
std::string preset_name = wxGetApp().preset_bundle->get_preset_name_by_alias(preset_type,
|
||||
Preset::remove_suffix_modified(combo->GetString(selection).ToUTF8().data()));
|
||||
|
||||
if (preset_type == Preset::TYPE_FILAMENT) {
|
||||
wxGetApp().preset_bundle->set_filament_preset(idx, preset_name);
|
||||
}
|
||||
|
||||
if (preset_type == Preset::TYPE_PRINTER) {
|
||||
if(combo->is_selected_physical_printer()) {
|
||||
// Select related printer preset on the Printer Settings Tab
|
||||
const std::string printer_name = combo->GetString(selection).ToUTF8().data();
|
||||
PhysicalPrinter& printer = wxGetApp().preset_bundle->physical_printers.select_printer_by_name(printer_name);
|
||||
preset_name = wxGetApp().preset_bundle->get_preset_name_by_alias(preset_type, printer.get_preset_name());
|
||||
}
|
||||
else
|
||||
wxGetApp().preset_bundle->physical_printers.unselect_printer();
|
||||
}
|
||||
|
||||
// TODO: ?
|
||||
if (preset_type == Preset::TYPE_FILAMENT && sidebar->is_multifilament()) {
|
||||
@ -3974,7 +3979,12 @@ void Plater::priv::show_action_buttons(const bool ready_to_slice) const
|
||||
this->ready_to_slice = ready_to_slice;
|
||||
|
||||
wxWindowUpdateLocker noUpdater(sidebar);
|
||||
const auto prin_host_opt = config->option<ConfigOptionString>("print_host");
|
||||
|
||||
DynamicPrintConfig* selected_printer_config = wxGetApp().preset_bundle->physical_printers.get_selected_printer_config();
|
||||
if (!selected_printer_config)
|
||||
selected_printer_config = config;
|
||||
|
||||
const auto prin_host_opt = selected_printer_config->option<ConfigOptionString>("print_host");
|
||||
const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty();
|
||||
|
||||
// when a background processing is ON, export_btn and/or send_btn are showing
|
||||
@ -4893,7 +4903,9 @@ void Plater::send_gcode()
|
||||
{
|
||||
if (p->model.objects.empty()) { return; }
|
||||
|
||||
PrintHostJob upload_job(p->config);
|
||||
// if physical_printer is selected, send gcode for this printer
|
||||
DynamicPrintConfig* physical_printer_config = wxGetApp().preset_bundle->physical_printers.get_selected_printer_config();
|
||||
PrintHostJob upload_job(physical_printer_config ? physical_printer_config : p->config);
|
||||
if (upload_job.empty()) { return; }
|
||||
|
||||
// Obtain default output path
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
#include "RemovableDriveManager.hpp"
|
||||
#include "BitmapCache.hpp"
|
||||
#include "BonjourDialog.hpp"
|
||||
|
||||
using Slic3r::GUI::format_wxstr;
|
||||
|
||||
@ -241,8 +242,9 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset
|
||||
evt.StopPropagation();
|
||||
if (marker == LABEL_ITEM_PHYSICAL_PRINTERS)
|
||||
{
|
||||
PhysicalPrinterDialog dlg(_L("New Physical Printer"), this->m_last_selected);
|
||||
dlg.ShowModal();
|
||||
PhysicalPrinterDialog dlg(wxEmptyString);
|
||||
if (dlg.ShowModal() == wxID_OK)
|
||||
this->update();
|
||||
return;
|
||||
}
|
||||
if (marker >= LABEL_ITEM_WIZARD_PRINTERS) {
|
||||
@ -255,7 +257,7 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset
|
||||
}
|
||||
wxTheApp->CallAfter([sp]() { wxGetApp().run_wizard(ConfigWizard::RR_USER, sp); });
|
||||
}
|
||||
} else if ( this->m_last_selected != selected_item || m_collection->current_is_dirty() ) {
|
||||
} else if (marker == LABEL_ITEM_PHYSICAL_PRINTER || this->m_last_selected != selected_item || m_collection->current_is_dirty() ) {
|
||||
this->m_last_selected = selected_item;
|
||||
evt.SetInt(this->m_type);
|
||||
evt.Skip();
|
||||
@ -319,6 +321,16 @@ PlaterPresetComboBox::PlaterPresetComboBox(wxWindow *parent, Preset::Type preset
|
||||
|
||||
edit_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent)
|
||||
{
|
||||
// In a case of a physical printer, for its editing open PhysicalPrinterDialog
|
||||
if (m_type == Preset::TYPE_PRINTER && this->is_selected_physical_printer())
|
||||
{
|
||||
PhysicalPrinterDialog dlg(this->GetString(this->GetSelection()));
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
update();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Tab* tab = wxGetApp().get_tab(m_type);
|
||||
if (!tab)
|
||||
return;
|
||||
@ -355,6 +367,13 @@ PlaterPresetComboBox::~PlaterPresetComboBox()
|
||||
edit_btn->Destroy();
|
||||
}
|
||||
|
||||
bool PlaterPresetComboBox::is_selected_physical_printer()
|
||||
{
|
||||
auto selected_item = this->GetSelection();
|
||||
auto marker = reinterpret_cast<Marker>(this->GetClientData(selected_item));
|
||||
return marker == LABEL_ITEM_PHYSICAL_PRINTER;
|
||||
}
|
||||
|
||||
// Only the compatible presets are shown.
|
||||
// If an incompatible preset is selected, it is shown as well.
|
||||
void PlaterPresetComboBox::update()
|
||||
@ -388,7 +407,6 @@ void PlaterPresetComboBox::update()
|
||||
bool wide_icons = !selected_preset.is_compatible;
|
||||
|
||||
std::map<wxString, wxBitmap*> nonsys_presets;
|
||||
std::map<wxString, wxBitmap*> physical_printers;
|
||||
|
||||
wxString selected = "";
|
||||
wxString tooltip = "";
|
||||
@ -400,9 +418,11 @@ void PlaterPresetComboBox::update()
|
||||
for (size_t i = presets.front().is_visible ? 0 : m_collection->num_default_presets(); i < presets.size(); ++i)
|
||||
{
|
||||
const Preset& preset = presets[i];
|
||||
bool is_selected = m_type == Preset::TYPE_FILAMENT ?
|
||||
m_preset_bundle->filament_presets[m_extruder_idx] == preset.name :
|
||||
i == m_collection->get_selected_idx();
|
||||
bool is_selected = m_type == Preset::TYPE_FILAMENT ?
|
||||
m_preset_bundle->filament_presets[m_extruder_idx] == preset.name :
|
||||
// The case, when some physical printer is selected
|
||||
m_type == Preset::TYPE_PRINTER && m_preset_bundle->physical_printers.has_selection() ? false :
|
||||
i == m_collection->get_selected_idx();
|
||||
|
||||
if (!preset.is_visible || (!preset.is_compatible && !is_selected))
|
||||
continue;
|
||||
@ -495,17 +515,6 @@ void PlaterPresetComboBox::update()
|
||||
selected_preset_item = GetCount() - 1;
|
||||
}
|
||||
}
|
||||
if (!physical_printers.empty())
|
||||
{
|
||||
set_label_marker(Append(separator(L("Physical printers")), wxNullBitmap));
|
||||
for (std::map<wxString, wxBitmap*>::iterator it = physical_printers.begin(); it != physical_printers.end(); ++it) {
|
||||
Append(it->first, *it->second);
|
||||
if (it->first == selected ||
|
||||
// just in case: mark selected_preset_item as a first added element
|
||||
selected_preset_item == INT_MAX)
|
||||
selected_preset_item = GetCount() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_type == Preset::TYPE_PRINTER || m_type == Preset::TYPE_SLA_MATERIAL) {
|
||||
std::string bitmap_key = "";
|
||||
@ -536,8 +545,45 @@ void PlaterPresetComboBox::update()
|
||||
else
|
||||
set_label_marker(Append(separator(L("Add/Remove printers")), *bmp), LABEL_ITEM_WIZARD_PRINTERS);
|
||||
}
|
||||
if (m_type == Preset::TYPE_PRINTER) {
|
||||
std::string bitmap_key = "";
|
||||
|
||||
if (m_type == Preset::TYPE_PRINTER)
|
||||
{
|
||||
// add Physical printers, if any exists
|
||||
if (!m_preset_bundle->physical_printers.empty()) {
|
||||
set_label_marker(Append(separator(L("Physical printers")), wxNullBitmap));
|
||||
const PhysicalPrinterCollection& ph_printers = m_preset_bundle->physical_printers;
|
||||
|
||||
for (PhysicalPrinterCollection::ConstIterator it = ph_printers.begin(); it != ph_printers.end(); ++it) {
|
||||
std::string bitmap_key = it->printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name;
|
||||
if (wide_icons)
|
||||
bitmap_key += "wide,";
|
||||
bitmap_key += "-h" + std::to_string(icon_height);
|
||||
|
||||
wxBitmap* bmp = m_bitmap_cache->find(bitmap_key);
|
||||
if (bmp == nullptr) {
|
||||
// Create the bitmap with color bars.
|
||||
std::vector<wxBitmap> bmps;
|
||||
if (wide_icons)
|
||||
// Paint a red flag for incompatible presets.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(norm_icon_width, icon_height));
|
||||
// Paint the color bars.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(thin_space_icon_width, icon_height));
|
||||
bmps.emplace_back(create_scaled_bitmap(it->printer_technology() == ptSLA ? "sla_printer" : m_main_bitmap_name));
|
||||
// Paint a lock at the system presets.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(wide_space_icon_width+norm_icon_width, icon_height));
|
||||
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
|
||||
}
|
||||
|
||||
set_label_marker(Append(wxString::FromUTF8((it->name).c_str()), *bmp), LABEL_ITEM_PHYSICAL_PRINTER);
|
||||
if (ph_printers.has_selection() && it->name == ph_printers.get_selected_printer_name() ||
|
||||
// just in case: mark selected_preset_item as a first added element
|
||||
selected_preset_item == INT_MAX)
|
||||
selected_preset_item = GetCount() - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// add LABEL_ITEM_PHYSICAL_PRINTERS
|
||||
std::string bitmap_key;
|
||||
if (wide_icons)
|
||||
bitmap_key += "wide,";
|
||||
bitmap_key += "edit_preset_list";
|
||||
@ -589,10 +635,10 @@ void PlaterPresetComboBox::msw_rescale()
|
||||
// *** TabPresetComboBox ***
|
||||
// ---------------------------------
|
||||
|
||||
TabPresetComboBox::TabPresetComboBox(wxWindow* parent, Preset::Type preset_type, bool is_from_physical_printer/* = false*/) :
|
||||
TabPresetComboBox::TabPresetComboBox(wxWindow* parent, Preset::Type preset_type) :
|
||||
PresetComboBox(parent, preset_type, wxSize(35 * wxGetApp().em_unit(), -1))
|
||||
{
|
||||
Bind(wxEVT_COMBOBOX, [this, is_from_physical_printer](wxCommandEvent& evt) {
|
||||
Bind(wxEVT_COMBOBOX, [this](wxCommandEvent& evt) {
|
||||
// see https://github.com/prusa3d/PrusaSlicer/issues/3889
|
||||
// Under OSX: in case of use of a same names written in different case (like "ENDER" and "Ender")
|
||||
// m_presets_choice->GetSelection() will return first item, because search in PopupListCtrl is case-insensitive.
|
||||
@ -603,21 +649,17 @@ TabPresetComboBox::TabPresetComboBox(wxWindow* parent, Preset::Type preset_type,
|
||||
if (marker >= LABEL_ITEM_MARKER && marker < LABEL_ITEM_MAX) {
|
||||
this->SetSelection(this->m_last_selected);
|
||||
if (marker == LABEL_ITEM_WIZARD_PRINTERS)
|
||||
wxTheApp->CallAfter([this, is_from_physical_printer]() {
|
||||
wxTheApp->CallAfter([this]() {
|
||||
wxGetApp().run_wizard(ConfigWizard::RR_USER, ConfigWizard::SP_PRINTERS);
|
||||
if (is_from_physical_printer)
|
||||
|
||||
// update combobox if its parent is a PhysicalPrinterDialog
|
||||
PhysicalPrinterDialog* parent = dynamic_cast<PhysicalPrinterDialog*>(this->GetParent());
|
||||
if (parent != nullptr)
|
||||
update();
|
||||
});
|
||||
}
|
||||
else if ( is_from_physical_printer) {
|
||||
// do nothing
|
||||
}
|
||||
else if (m_last_selected != selected_item || m_collection->current_is_dirty() ) {
|
||||
std::string selected_string = this->GetString(selected_item).ToUTF8().data();
|
||||
Tab* tab = wxGetApp().get_tab(this->m_type);
|
||||
assert (tab);
|
||||
tab->select_preset(selected_string);
|
||||
}
|
||||
else if (on_selection_changed && (m_last_selected != selected_item || m_collection->current_is_dirty()) )
|
||||
on_selection_changed(selected_item);
|
||||
|
||||
evt.StopPropagation();
|
||||
});
|
||||
@ -760,35 +802,212 @@ void TabPresetComboBox::update_dirty()
|
||||
//------------------------------------------
|
||||
|
||||
|
||||
PhysicalPrinterDialog::PhysicalPrinterDialog(const wxString& printer_name, int last_selected_preset)
|
||||
PhysicalPrinterDialog::PhysicalPrinterDialog(wxString printer_name)
|
||||
: DPIDialog(NULL, wxID_ANY, _L("PhysicalPrinter"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
{
|
||||
SetFont(wxGetApp().normal_font());
|
||||
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
|
||||
int border = 10;
|
||||
int em = em_unit();
|
||||
|
||||
printer_text = new wxTextCtrl(this, wxID_ANY, printer_name, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
|
||||
printer_presets = new TabPresetComboBox(this, Preset::TYPE_PRINTER, true);
|
||||
printer_presets->update();
|
||||
m_printer_presets = new TabPresetComboBox(this, Preset::TYPE_PRINTER);
|
||||
m_printer_presets->set_selection_changed_function([this](int selection) {
|
||||
std::string selected_string = Preset::remove_suffix_modified(m_printer_presets->GetString(selection).ToUTF8().data());
|
||||
Preset* preset = wxGetApp().preset_bundle->printers.find_preset(selected_string);
|
||||
assert(preset);
|
||||
Preset& edited_preset = wxGetApp().preset_bundle->printers.get_edited_preset();
|
||||
if (preset->name == edited_preset.name)
|
||||
preset = &edited_preset;
|
||||
m_printer.update_from_preset(*preset);
|
||||
|
||||
// update values
|
||||
m_optgroup->reload_config();
|
||||
update_octoprint_visible();
|
||||
});
|
||||
m_printer_presets->update();
|
||||
|
||||
wxString preset_name = m_printer_presets->GetString(m_printer_presets->GetSelection());
|
||||
|
||||
if (printer_name.IsEmpty())
|
||||
printer_name = preset_name + " - "+_L("Physical Printer");
|
||||
m_printer_name = new wxTextCtrl(this, wxID_ANY, printer_name, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER);
|
||||
|
||||
PhysicalPrinterCollection& printers = wxGetApp().preset_bundle->physical_printers;
|
||||
PhysicalPrinter* printer = printers.find_printer(into_u8(printer_name));
|
||||
if (!printer) {
|
||||
const Preset& preset = wxGetApp().preset_bundle->printers.get_edited_preset();
|
||||
printer = new PhysicalPrinter(into_u8(printer_name), preset);
|
||||
}
|
||||
assert(printer);
|
||||
m_printer = *printer;
|
||||
|
||||
m_config = &m_printer.config;
|
||||
|
||||
m_optgroup = new ConfigOptionsGroup(this, _L("Print Host upload"), m_config);
|
||||
build_printhost_settings(m_optgroup);
|
||||
m_optgroup->reload_config();
|
||||
|
||||
wxStdDialogButtonSizer* btns = this->CreateStdDialogButtonSizer(wxOK | wxCANCEL);
|
||||
wxButton* btnOK = static_cast<wxButton*>(this->FindWindowById(wxID_OK, this));
|
||||
btnOK->Bind(wxEVT_BUTTON, &PhysicalPrinterDialog::OnOK, this);
|
||||
|
||||
wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
topSizer->Add(printer_text , 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
|
||||
topSizer->Add(printer_presets , 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
|
||||
topSizer->Add(btns , 0, wxEXPAND | wxALL, border);
|
||||
topSizer->Add(m_printer_name , 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
|
||||
topSizer->Add(m_printer_presets , 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
|
||||
topSizer->Add(m_optgroup->sizer , 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
|
||||
topSizer->Add(btns , 0, wxEXPAND | wxALL, border);
|
||||
|
||||
SetSizer(topSizer);
|
||||
topSizer->SetSizeHints(this);
|
||||
}
|
||||
|
||||
void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgroup)
|
||||
{
|
||||
m_optgroup->append_single_option_line("host_type");
|
||||
|
||||
auto create_sizer_with_btn = [this](wxWindow* parent, ScalableButton** btn, const std::string& icon_name, const wxString& label) {
|
||||
*btn = new ScalableButton(parent, wxID_ANY, icon_name, label, wxDefaultSize, wxDefaultPosition, wxBU_LEFT | wxBU_EXACTFIT);
|
||||
(*btn)->SetFont(wxGetApp().normal_font());
|
||||
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(*btn);
|
||||
return sizer;
|
||||
};
|
||||
|
||||
auto printhost_browse = [=](wxWindow* parent)
|
||||
{
|
||||
auto sizer = create_sizer_with_btn(parent, &m_printhost_browse_btn, "browse", _L("Browse") + " " + dots);
|
||||
m_printhost_browse_btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent& e) {
|
||||
BonjourDialog dialog(this, Preset::printer_technology(m_printer.config));
|
||||
if (dialog.show_and_lookup()) {
|
||||
m_optgroup->set_value("print_host", std::move(dialog.get_selected()), true);
|
||||
m_optgroup->get_field("print_host")->field_changed();
|
||||
}
|
||||
});
|
||||
|
||||
return sizer;
|
||||
};
|
||||
|
||||
auto print_host_test = [=](wxWindow* parent) {
|
||||
auto sizer = create_sizer_with_btn(parent, &m_printhost_test_btn, "test", _L("Test"));
|
||||
|
||||
m_printhost_test_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& e) {
|
||||
std::unique_ptr<PrintHost> host(PrintHost::get_print_host(m_config));
|
||||
if (!host) {
|
||||
const wxString text = _L("Could not get a valid Printer Host reference");
|
||||
show_error(this, text);
|
||||
return;
|
||||
}
|
||||
wxString msg;
|
||||
if (host->test(msg)) {
|
||||
show_info(this, host->get_test_ok_msg(), _L("Success!"));
|
||||
}
|
||||
else {
|
||||
show_error(this, host->get_test_failed_msg(msg));
|
||||
}
|
||||
});
|
||||
|
||||
return sizer;
|
||||
};
|
||||
|
||||
// Set a wider width for a better alignment
|
||||
Option option = m_optgroup->get_option("print_host");
|
||||
option.opt.width = Field::def_width_wider();
|
||||
Line host_line = m_optgroup->create_single_option_line(option);
|
||||
host_line.append_widget(printhost_browse);
|
||||
host_line.append_widget(print_host_test);
|
||||
m_optgroup->append_line(host_line);
|
||||
option = m_optgroup->get_option("printhost_apikey");
|
||||
option.opt.width = Field::def_width_wider();
|
||||
m_optgroup->append_single_option_line(option);
|
||||
|
||||
const auto ca_file_hint = _u8L("HTTPS CA file is optional. It is only needed if you use HTTPS with a self-signed certificate.");
|
||||
|
||||
if (Http::ca_file_supported()) {
|
||||
option = m_optgroup->get_option("printhost_cafile");
|
||||
option.opt.width = Field::def_width_wider();
|
||||
Line cafile_line = m_optgroup->create_single_option_line(option);
|
||||
|
||||
auto printhost_cafile_browse = [=](wxWindow* parent) {
|
||||
auto sizer = create_sizer_with_btn(parent, &m_printhost_cafile_browse_btn, "browse", _L("Browse") + " " + dots);
|
||||
m_printhost_cafile_browse_btn->Bind(wxEVT_BUTTON, [this, m_optgroup](wxCommandEvent e) {
|
||||
static const auto filemasks = _L("Certificate files (*.crt, *.pem)|*.crt;*.pem|All files|*.*");
|
||||
wxFileDialog openFileDialog(this, _L("Open CA certificate file"), "", "", filemasks, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
if (openFileDialog.ShowModal() != wxID_CANCEL) {
|
||||
m_optgroup->set_value("printhost_cafile", std::move(openFileDialog.GetPath()), true);
|
||||
m_optgroup->get_field("printhost_cafile")->field_changed();
|
||||
}
|
||||
});
|
||||
|
||||
return sizer;
|
||||
};
|
||||
|
||||
cafile_line.append_widget(printhost_cafile_browse);
|
||||
m_optgroup->append_line(cafile_line);
|
||||
|
||||
Line cafile_hint{ "", "" };
|
||||
cafile_hint.full_width = 1;
|
||||
cafile_hint.widget = [this, ca_file_hint](wxWindow* parent) {
|
||||
auto txt = new wxStaticText(parent, wxID_ANY, ca_file_hint);
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(txt);
|
||||
return sizer;
|
||||
};
|
||||
m_optgroup->append_line(cafile_hint);
|
||||
}
|
||||
else {
|
||||
Line line{ "", "" };
|
||||
line.full_width = 1;
|
||||
|
||||
line.widget = [ca_file_hint](wxWindow* parent) {
|
||||
std::string info = _u8L("HTTPS CA File") + ":\n\t" +
|
||||
(boost::format(_u8L("On this system, %s uses HTTPS certificates from the system Certificate Store or Keychain.")) % SLIC3R_APP_NAME).str() +
|
||||
"\n\t" + _u8L("To use a custom CA file, please import your CA file into Certificate Store / Keychain.");
|
||||
|
||||
auto txt = new wxStaticText(parent, wxID_ANY, from_u8((boost::format("%1%\n\n\t%2%") % info % ca_file_hint).str()));
|
||||
txt->SetFont(wxGetApp().normal_font());
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(txt, 1, wxEXPAND);
|
||||
return sizer;
|
||||
};
|
||||
|
||||
m_optgroup->append_line(line);
|
||||
}
|
||||
|
||||
for (const std::string& opt_key : std::vector<std::string>{ "login", "password" }) {
|
||||
option = m_optgroup->get_option(opt_key);
|
||||
option.opt.width = Field::def_width_wider();
|
||||
m_optgroup->append_single_option_line(option);
|
||||
}
|
||||
|
||||
update_octoprint_visible();
|
||||
}
|
||||
|
||||
void PhysicalPrinterDialog::update_octoprint_visible()
|
||||
{
|
||||
const PrinterTechnology tech = Preset::printer_technology(m_printer.config);
|
||||
// Only offer the host type selection for FFF, for SLA it's always the SL1 printer (at the moment)
|
||||
Field* host_type = m_optgroup->get_field("host_type");
|
||||
if (tech == ptFFF)
|
||||
host_type->enable();
|
||||
else {
|
||||
host_type->set_value(int(PrintHostType::htOctoPrint), false);
|
||||
host_type->disable();
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalPrinterDialog::on_dpi_changed(const wxRect& suggested_rect)
|
||||
{
|
||||
const int& em = em_unit();
|
||||
|
||||
m_printhost_browse_btn->msw_rescale();
|
||||
m_printhost_test_btn->msw_rescale();
|
||||
if (m_printhost_cafile_browse_btn)
|
||||
m_printhost_cafile_browse_btn->msw_rescale();
|
||||
|
||||
m_optgroup->msw_rescale();
|
||||
|
||||
msw_buttons_rescale(this, em, { wxID_OK, wxID_CANCEL });
|
||||
|
||||
const wxSize& size = wxSize(40 * em, 30 * em);
|
||||
@ -798,5 +1017,46 @@ void PhysicalPrinterDialog::on_dpi_changed(const wxRect& suggested_rect)
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void PhysicalPrinterDialog::OnOK(wxEvent& event)
|
||||
{
|
||||
wxString printer_name = m_printer_name->GetValue();
|
||||
if (printer_name.IsEmpty()) {
|
||||
show_error(this, _L("The supplied name is empty. It can't be saved."));
|
||||
return;
|
||||
}
|
||||
|
||||
PhysicalPrinterCollection& printers = wxGetApp().preset_bundle->physical_printers;
|
||||
const PhysicalPrinter* existing = printers.find_printer(into_u8(printer_name));
|
||||
if (existing && into_u8(printer_name) != printers.get_selected_printer_name())
|
||||
{
|
||||
wxString msg_text = from_u8((boost::format(_u8L("Printer with name \"%1%\" already exists.")) % printer_name).str());
|
||||
msg_text += "\n" + _L("Replace?");
|
||||
wxMessageDialog dialog(nullptr, msg_text, _L("Warning"), wxICON_WARNING | wxYES | wxNO);
|
||||
|
||||
if (dialog.ShowModal() == wxID_NO)
|
||||
return;
|
||||
|
||||
// Remove the printer from the list.
|
||||
printers.delete_printer(into_u8(printer_name));
|
||||
}
|
||||
|
||||
//upadte printer name, if it was changed
|
||||
m_printer.name = into_u8(printer_name);
|
||||
|
||||
// save new physical printer
|
||||
printers.save_printer(m_printer);
|
||||
|
||||
// update selection on the tab only when it was changed
|
||||
if (m_printer.get_preset_name() != wxGetApp().preset_bundle->printers.get_selected_preset_name()) {
|
||||
Tab* tab = wxGetApp().get_tab(Preset::TYPE_PRINTER);
|
||||
if (tab) {
|
||||
wxString preset_name = m_printer_presets->GetString(m_printer_presets->GetSelection());
|
||||
tab->select_preset(into_u8(preset_name));
|
||||
}
|
||||
}
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
class wxString;
|
||||
class wxTextCtrl;
|
||||
class ScalableButton;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@ -33,7 +34,8 @@ public:
|
||||
~PresetComboBox();
|
||||
|
||||
enum LabelItemType {
|
||||
LABEL_ITEM_MARKER = 0xffffff01,
|
||||
LABEL_ITEM_PHYSICAL_PRINTER = 0xffffff01,
|
||||
LABEL_ITEM_MARKER,
|
||||
LABEL_ITEM_PHYSICAL_PRINTERS,
|
||||
LABEL_ITEM_WIZARD_PRINTERS,
|
||||
LABEL_ITEM_WIZARD_FILAMENTS,
|
||||
@ -121,11 +123,13 @@ public:
|
||||
void set_extruder_idx(const int extr_idx) { m_extruder_idx = extr_idx; }
|
||||
int get_extruder_idx() const { return m_extruder_idx; }
|
||||
|
||||
bool is_selected_physical_printer();
|
||||
|
||||
void update() override;
|
||||
void msw_rescale() override;
|
||||
|
||||
private:
|
||||
int m_extruder_idx = -1;
|
||||
int m_extruder_idx = -1;
|
||||
};
|
||||
|
||||
|
||||
@ -135,8 +139,11 @@ private:
|
||||
|
||||
class TabPresetComboBox : public PresetComboBox
|
||||
{
|
||||
bool show_incompatible {false};
|
||||
std::function<void(int)> on_selection_changed { nullptr };
|
||||
|
||||
public:
|
||||
TabPresetComboBox(wxWindow *parent, Preset::Type preset_type, bool is_from_physical_printer = false);
|
||||
TabPresetComboBox(wxWindow *parent, Preset::Type preset_type);
|
||||
~TabPresetComboBox() {}
|
||||
void set_show_incompatible_presets(bool show_incompatible_presets) {
|
||||
show_incompatible = show_incompatible_presets;
|
||||
@ -146,25 +153,33 @@ public:
|
||||
void update_dirty();
|
||||
void msw_rescale() override;
|
||||
|
||||
private:
|
||||
bool show_incompatible{false};
|
||||
void set_selection_changed_function(std::function<void(int)> sel_changed) { on_selection_changed = sel_changed; }
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------
|
||||
// PhysicalPrinterDialog
|
||||
//------------------------------------------
|
||||
|
||||
class ConfigOptionsGroup;
|
||||
class PhysicalPrinterDialog : public DPIDialog
|
||||
{
|
||||
std::string printer_name;
|
||||
std::string preset_name;
|
||||
PhysicalPrinter m_printer;
|
||||
DynamicPrintConfig* m_config { nullptr };
|
||||
|
||||
wxTextCtrl* printer_text { nullptr };
|
||||
PresetComboBox* printer_presets;
|
||||
wxTextCtrl* m_printer_name { nullptr };
|
||||
TabPresetComboBox* m_printer_presets { nullptr };
|
||||
ConfigOptionsGroup* m_optgroup { nullptr };
|
||||
|
||||
ScalableButton* m_printhost_browse_btn;
|
||||
ScalableButton* m_printhost_test_btn;
|
||||
ScalableButton* m_printhost_cafile_browse_btn {nullptr};
|
||||
|
||||
void build_printhost_settings(ConfigOptionsGroup* optgroup);
|
||||
void update_octoprint_visible();
|
||||
void OnOK(wxEvent& event);
|
||||
|
||||
public:
|
||||
PhysicalPrinterDialog(const wxString& printer_name, int last_selected_preset);
|
||||
PhysicalPrinterDialog(wxString printer_name);
|
||||
~PhysicalPrinterDialog() {}
|
||||
|
||||
protected:
|
||||
|
@ -161,6 +161,13 @@ void Tab::create_preset_tab()
|
||||
|
||||
// preset chooser
|
||||
m_presets_choice = new TabPresetComboBox(panel, m_type);
|
||||
m_presets_choice->set_selection_changed_function([this](int selection) {
|
||||
// unselect pthysical printer, if it was selected
|
||||
m_preset_bundle->physical_printers.unselect_printer();
|
||||
// select preset
|
||||
std::string selected_string = m_presets_choice->GetString(selection).ToUTF8().data();
|
||||
select_preset(selected_string);
|
||||
});
|
||||
|
||||
auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
||||
|
||||
@ -3022,6 +3029,9 @@ void Tab::select_preset(std::string preset_name, bool delete_current)
|
||||
|
||||
if (canceled) {
|
||||
update_tab_ui();
|
||||
// unselect physical printer selection to the correct synchronization of the printer presets between Tab and Plater
|
||||
if (m_type == Preset::TYPE_PRINTER)
|
||||
m_preset_bundle->physical_printers.unselect_printer();
|
||||
// Trigger the on_presets_changed event so that we also restore the previous value in the plater selector,
|
||||
// if this action was initiated from the plater.
|
||||
on_presets_changed();
|
||||
|
Loading…
Reference in New Issue
Block a user