Added "Notes" page to the filament configuration.
Added "filament_max_volumetric_speed", a cap on the maximum volumetric extrusion role, filament specific. This is very useful when mixing rigid filament with a soft filament. Extended the import / export of multi-string values into configuration values, including the test cases. Multi-line strings will be enclosed into quotes, quotes escaped using a C-style escape sequences. Single word strings could still be stored without quotes.
This commit is contained in:
parent
4e66ed81d2
commit
3d3654707b
@ -138,7 +138,10 @@ sub new {
|
|||||||
$self->_on_presets_changed;
|
$self->_on_presets_changed;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
# C++ instance DynamicPrintConfig
|
||||||
$self->{config} = Slic3r::Config->new;
|
$self->{config} = Slic3r::Config->new;
|
||||||
|
# Initialize the DynamicPrintConfig by default keys/values.
|
||||||
|
# Possible %params keys: no_controller
|
||||||
$self->build(%params);
|
$self->build(%params);
|
||||||
$self->update_tree;
|
$self->update_tree;
|
||||||
$self->_update;
|
$self->_update;
|
||||||
@ -910,7 +913,7 @@ sub build {
|
|||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
$self->init_config_options(qw(
|
$self->init_config_options(qw(
|
||||||
filament_colour filament_diameter extrusion_multiplier
|
filament_colour filament_diameter filament_notes filament_max_volumetric_speed extrusion_multiplier
|
||||||
temperature first_layer_temperature bed_temperature first_layer_bed_temperature
|
temperature first_layer_temperature bed_temperature first_layer_bed_temperature
|
||||||
fan_always_on cooling
|
fan_always_on cooling
|
||||||
min_fan_speed max_fan_speed bridge_fan_speed disable_fan_first_layers
|
min_fan_speed max_fan_speed bridge_fan_speed disable_fan_first_layers
|
||||||
@ -991,6 +994,27 @@ sub build {
|
|||||||
$optgroup->append_single_option_line('min_print_speed');
|
$optgroup->append_single_option_line('min_print_speed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $page = $self->add_options_page('Advanced', 'wrench.png');
|
||||||
|
{
|
||||||
|
my $optgroup = $page->new_optgroup('Print speed override');
|
||||||
|
$optgroup->append_single_option_line('filament_max_volumetric_speed', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $page = $self->add_options_page('Notes', 'note.png');
|
||||||
|
{
|
||||||
|
my $optgroup = $page->new_optgroup('Notes',
|
||||||
|
label_width => 0,
|
||||||
|
);
|
||||||
|
my $option = $optgroup->get_option('filament_notes', 0);
|
||||||
|
$option->full_width(1);
|
||||||
|
$option->height(250);
|
||||||
|
$optgroup->append_single_option_line($option);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _update {
|
sub _update {
|
||||||
|
@ -8,6 +8,159 @@
|
|||||||
|
|
||||||
namespace Slic3r {
|
namespace Slic3r {
|
||||||
|
|
||||||
|
std::string escape_string_cstyle(const std::string &str)
|
||||||
|
{
|
||||||
|
// Allocate a buffer twice the input string length,
|
||||||
|
// so the output will fit even if all input characters get escaped.
|
||||||
|
std::vector<char> out(str.size() * 2, 0);
|
||||||
|
char *outptr = out.data();
|
||||||
|
for (size_t i = 0; i < str.size(); ++ i) {
|
||||||
|
char c = str[i];
|
||||||
|
if (c == '\n' || c == '\r') {
|
||||||
|
(*outptr ++) = '\\';
|
||||||
|
(*outptr ++) = 'n';
|
||||||
|
} else
|
||||||
|
(*outptr ++) = c;
|
||||||
|
}
|
||||||
|
return std::string(out.data(), outptr - out.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string escape_strings_cstyle(const std::vector<std::string> &strs)
|
||||||
|
{
|
||||||
|
// 1) Estimate the output buffer size to avoid buffer reallocation.
|
||||||
|
size_t outbuflen = 0;
|
||||||
|
for (size_t i = 0; i < strs.size(); ++ i)
|
||||||
|
// Reserve space for every character escaped + quotes + semicolon.
|
||||||
|
outbuflen += strs[i].size() * 2 + 3;
|
||||||
|
// 2) Fill in the buffer.
|
||||||
|
std::vector<char> out(outbuflen, 0);
|
||||||
|
char *outptr = out.data();
|
||||||
|
for (size_t j = 0; j < strs.size(); ++ j) {
|
||||||
|
if (j > 0)
|
||||||
|
// Separate the strings.
|
||||||
|
(*outptr ++) = ';';
|
||||||
|
const std::string &str = strs[j];
|
||||||
|
// Is the string simple or complex? Complex string contains spaces, tabs, new lines and other
|
||||||
|
// escapable characters. Empty string shall be quoted as well, if it is the only string in strs.
|
||||||
|
bool should_quote = strs.size() == 1 && str.empty();
|
||||||
|
for (size_t i = 0; i < str.size(); ++ i) {
|
||||||
|
char c = str[i];
|
||||||
|
if (c == ' ' || c == '\t' || c == '\\' || c == '"' || c == '\r' || c == '\n') {
|
||||||
|
should_quote = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (should_quote) {
|
||||||
|
(*outptr ++) = '"';
|
||||||
|
for (size_t i = 0; i < str.size(); ++ i) {
|
||||||
|
char c = str[i];
|
||||||
|
if (c == '\\' || c == '"') {
|
||||||
|
(*outptr ++) = '\\';
|
||||||
|
(*outptr ++) = c;
|
||||||
|
} else if (c == '\n' || c == '\r') {
|
||||||
|
(*outptr ++) = '\\';
|
||||||
|
(*outptr ++) = 'n';
|
||||||
|
} else
|
||||||
|
(*outptr ++) = c;
|
||||||
|
}
|
||||||
|
(*outptr ++) = '"';
|
||||||
|
} else {
|
||||||
|
memcpy(outptr, str.data(), str.size());
|
||||||
|
outptr += str.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::string(out.data(), outptr - out.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unescape_string_cstyle(const std::string &str, std::string &str_out)
|
||||||
|
{
|
||||||
|
std::vector<char> out(str.size(), 0);
|
||||||
|
char *outptr = out.data();
|
||||||
|
for (size_t i = 0; i < str.size(); ++ i) {
|
||||||
|
char c = str[i];
|
||||||
|
if (c == '\\') {
|
||||||
|
if (++ i == str.size())
|
||||||
|
return false;
|
||||||
|
c = str[i];
|
||||||
|
if (c == 'n')
|
||||||
|
(*outptr ++) = '\n';
|
||||||
|
} else
|
||||||
|
(*outptr ++) = c;
|
||||||
|
}
|
||||||
|
str_out.assign(out.data(), outptr - out.data());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &out)
|
||||||
|
{
|
||||||
|
out.clear();
|
||||||
|
if (str.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
for (;;) {
|
||||||
|
// Skip white spaces.
|
||||||
|
char c = str[i];
|
||||||
|
while (c == ' ' || c == '\t') {
|
||||||
|
if (++ i == str.size())
|
||||||
|
return true;
|
||||||
|
c = str[i];
|
||||||
|
}
|
||||||
|
// Start of a word.
|
||||||
|
std::vector<char> buf;
|
||||||
|
buf.reserve(16);
|
||||||
|
// Is it enclosed in quotes?
|
||||||
|
c = str[i];
|
||||||
|
if (c == '"') {
|
||||||
|
// Complex case, string is enclosed in quotes.
|
||||||
|
for (++ i; i < str.size(); ++ i) {
|
||||||
|
c = str[i];
|
||||||
|
if (c == '"') {
|
||||||
|
// End of string.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (c == '\\') {
|
||||||
|
if (++ i == str.size())
|
||||||
|
return false;
|
||||||
|
c = str[i];
|
||||||
|
if (c == 'n')
|
||||||
|
c = '\n';
|
||||||
|
}
|
||||||
|
buf.push_back(c);
|
||||||
|
}
|
||||||
|
if (i == str.size())
|
||||||
|
return false;
|
||||||
|
++ i;
|
||||||
|
} else {
|
||||||
|
for (; i < str.size(); ++ i) {
|
||||||
|
c = str[i];
|
||||||
|
if (c == ';')
|
||||||
|
break;
|
||||||
|
buf.push_back(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Store the string into the output vector.
|
||||||
|
out.push_back(std::string(buf.data(), buf.size()));
|
||||||
|
if (i == str.size())
|
||||||
|
break;
|
||||||
|
// Skip white spaces.
|
||||||
|
c = str[i];
|
||||||
|
while (c == ' ' || c == '\t') {
|
||||||
|
if (++ i == str.size())
|
||||||
|
// End of string. This is correct.
|
||||||
|
return true;
|
||||||
|
c = str[i];
|
||||||
|
}
|
||||||
|
if (c != ';')
|
||||||
|
return false;
|
||||||
|
if (++ i == str.size()) {
|
||||||
|
// Emit one additional empty string.
|
||||||
|
out.push_back(std::string());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
operator== (const ConfigOption &a, const ConfigOption &b)
|
operator== (const ConfigOption &a, const ConfigOption &b)
|
||||||
{
|
{
|
||||||
@ -116,16 +269,16 @@ ConfigBase::set_deserialize(const t_config_option_key &opt_key, std::string str)
|
|||||||
// Return an absolute value of a possibly relative config variable.
|
// Return an absolute value of a possibly relative config variable.
|
||||||
// For example, return absolute infill extrusion width, either from an absolute value, or relative to the layer height.
|
// For example, return absolute infill extrusion width, either from an absolute value, or relative to the layer height.
|
||||||
double
|
double
|
||||||
ConfigBase::get_abs_value(const t_config_option_key &opt_key) {
|
ConfigBase::get_abs_value(const t_config_option_key &opt_key) const {
|
||||||
ConfigOption* opt = this->option(opt_key, false);
|
const ConfigOption* opt = this->option(opt_key);
|
||||||
if (ConfigOptionFloatOrPercent* optv = dynamic_cast<ConfigOptionFloatOrPercent*>(opt)) {
|
if (const ConfigOptionFloatOrPercent* optv = dynamic_cast<const ConfigOptionFloatOrPercent*>(opt)) {
|
||||||
// get option definition
|
// get option definition
|
||||||
const ConfigOptionDef* def = this->def->get(opt_key);
|
const ConfigOptionDef* def = this->def->get(opt_key);
|
||||||
assert(def != NULL);
|
assert(def != NULL);
|
||||||
|
|
||||||
// compute absolute value over the absolute value of the base option
|
// compute absolute value over the absolute value of the base option
|
||||||
return optv->get_abs_value(this->get_abs_value(def->ratio_over));
|
return optv->get_abs_value(this->get_abs_value(def->ratio_over));
|
||||||
} else if (ConfigOptionFloat* optv = dynamic_cast<ConfigOptionFloat*>(opt)) {
|
} else if (const ConfigOptionFloat* optv = dynamic_cast<const ConfigOptionFloat*>(opt)) {
|
||||||
return optv->value;
|
return optv->value;
|
||||||
} else {
|
} else {
|
||||||
throw "Not a valid option type for get_abs_value()";
|
throw "Not a valid option type for get_abs_value()";
|
||||||
@ -135,9 +288,9 @@ ConfigBase::get_abs_value(const t_config_option_key &opt_key) {
|
|||||||
// Return an absolute value of a possibly relative config variable.
|
// Return an absolute value of a possibly relative config variable.
|
||||||
// For example, return absolute infill extrusion width, either from an absolute value, or relative to a provided value.
|
// For example, return absolute infill extrusion width, either from an absolute value, or relative to a provided value.
|
||||||
double
|
double
|
||||||
ConfigBase::get_abs_value(const t_config_option_key &opt_key, double ratio_over) {
|
ConfigBase::get_abs_value(const t_config_option_key &opt_key, double ratio_over) const {
|
||||||
// get stored option value
|
// get stored option value
|
||||||
ConfigOptionFloatOrPercent* opt = dynamic_cast<ConfigOptionFloatOrPercent*>(this->option(opt_key));
|
const ConfigOptionFloatOrPercent* opt = dynamic_cast<const ConfigOptionFloatOrPercent*>(this->option(opt_key));
|
||||||
assert(opt != NULL);
|
assert(opt != NULL);
|
||||||
|
|
||||||
// compute absolute value
|
// compute absolute value
|
||||||
|
@ -18,6 +18,11 @@ namespace Slic3r {
|
|||||||
typedef std::string t_config_option_key;
|
typedef std::string t_config_option_key;
|
||||||
typedef std::vector<std::string> t_config_option_keys;
|
typedef std::vector<std::string> t_config_option_keys;
|
||||||
|
|
||||||
|
extern std::string escape_string_cstyle(const std::string &str);
|
||||||
|
extern std::string escape_strings_cstyle(const std::vector<std::string> &strs);
|
||||||
|
extern bool unescape_string_cstyle(const std::string &str, std::string &out);
|
||||||
|
extern bool unescape_strings_cstyle(const std::string &str, std::vector<std::string> &out);
|
||||||
|
|
||||||
// A generic value of a configuration option.
|
// A generic value of a configuration option.
|
||||||
class ConfigOption {
|
class ConfigOption {
|
||||||
public:
|
public:
|
||||||
@ -112,6 +117,7 @@ class ConfigOptionFloats : public ConfigOptionVector<double>
|
|||||||
|
|
||||||
std::vector<std::string> vserialize() const {
|
std::vector<std::string> vserialize() const {
|
||||||
std::vector<std::string> vv;
|
std::vector<std::string> vv;
|
||||||
|
vv.reserve(this->values.size());
|
||||||
for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
for (std::vector<double>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << *it;
|
ss << *it;
|
||||||
@ -171,6 +177,7 @@ class ConfigOptionInts : public ConfigOptionVector<int>
|
|||||||
|
|
||||||
std::vector<std::string> vserialize() const {
|
std::vector<std::string> vserialize() const {
|
||||||
std::vector<std::string> vv;
|
std::vector<std::string> vv;
|
||||||
|
vv.reserve(this->values.size());
|
||||||
for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
for (std::vector<int>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << *it;
|
ss << *it;
|
||||||
@ -200,28 +207,11 @@ class ConfigOptionString : public ConfigOptionSingle<std::string>
|
|||||||
ConfigOptionString(std::string _value) : ConfigOptionSingle<std::string>(_value) {};
|
ConfigOptionString(std::string _value) : ConfigOptionSingle<std::string>(_value) {};
|
||||||
|
|
||||||
std::string serialize() const {
|
std::string serialize() const {
|
||||||
std::string str = this->value;
|
return escape_string_cstyle(this->value);
|
||||||
|
|
||||||
// s/\R/\\n/g
|
|
||||||
size_t pos = 0;
|
|
||||||
while ((pos = str.find("\n", pos)) != std::string::npos || (pos = str.find("\r", pos)) != std::string::npos) {
|
|
||||||
str.replace(pos, 1, "\\n");
|
|
||||||
pos += 2; // length of "\\n"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool deserialize(std::string str) {
|
bool deserialize(std::string str) {
|
||||||
// s/\\n/\n/g
|
return unescape_string_cstyle(str, this->value);
|
||||||
size_t pos = 0;
|
|
||||||
while ((pos = str.find("\\n", pos)) != std::string::npos) {
|
|
||||||
str.replace(pos, 2, "\n");
|
|
||||||
pos += 1; // length of "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
this->value = str;
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -231,12 +221,7 @@ class ConfigOptionStrings : public ConfigOptionVector<std::string>
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
std::string serialize() const {
|
std::string serialize() const {
|
||||||
std::ostringstream ss;
|
return escape_strings_cstyle(this->values);
|
||||||
for (std::vector<std::string>::const_iterator it = this->values.begin(); it != this->values.end(); ++it) {
|
|
||||||
if (it - this->values.begin() != 0) ss << ";";
|
|
||||||
ss << *it;
|
|
||||||
}
|
|
||||||
return ss.str();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::string> vserialize() const {
|
std::vector<std::string> vserialize() const {
|
||||||
@ -244,13 +229,7 @@ class ConfigOptionStrings : public ConfigOptionVector<std::string>
|
|||||||
};
|
};
|
||||||
|
|
||||||
bool deserialize(std::string str) {
|
bool deserialize(std::string str) {
|
||||||
this->values.clear();
|
return unescape_strings_cstyle(str, this->values);
|
||||||
std::istringstream is(str);
|
|
||||||
std::string item_str;
|
|
||||||
while (std::getline(is, item_str, ';')) {
|
|
||||||
this->values.push_back(item_str);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -637,8 +616,8 @@ class ConfigBase
|
|||||||
std::string serialize(const t_config_option_key &opt_key) const;
|
std::string serialize(const t_config_option_key &opt_key) const;
|
||||||
bool set_deserialize(const t_config_option_key &opt_key, std::string str);
|
bool set_deserialize(const t_config_option_key &opt_key, std::string str);
|
||||||
|
|
||||||
double get_abs_value(const t_config_option_key &opt_key);
|
double get_abs_value(const t_config_option_key &opt_key) const;
|
||||||
double get_abs_value(const t_config_option_key &opt_key, double ratio_over);
|
double get_abs_value(const t_config_option_key &opt_key, double ratio_over) const;
|
||||||
void setenv_();
|
void setenv_();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -865,6 +865,13 @@ GCode::_extrude(ExtrusionPath path, std::string description, double speed)
|
|||||||
this->config.max_volumetric_speed.value / path.mm3_per_mm
|
this->config.max_volumetric_speed.value / path.mm3_per_mm
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (EXTRUDER_CONFIG(filament_max_volumetric_speed) > 0) {
|
||||||
|
// cap speed with max_volumetric_speed anyway (even if user is not using autospeed)
|
||||||
|
speed = std::min(
|
||||||
|
speed,
|
||||||
|
EXTRUDER_CONFIG(filament_max_volumetric_speed) / path.mm3_per_mm
|
||||||
|
);
|
||||||
|
}
|
||||||
double F = speed * 60; // convert mm/sec to mm/min
|
double F = speed * 60; // convert mm/sec to mm/min
|
||||||
|
|
||||||
// extrude arc or line
|
// extrude arc or line
|
||||||
|
@ -298,6 +298,31 @@ PrintConfigDef::PrintConfigDef()
|
|||||||
def->default_value = opt;
|
def->default_value = opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def = this->add("filament_notes", coStrings);
|
||||||
|
def->label = "Filament notes";
|
||||||
|
def->tooltip = "You can put your notes regarding the filament here.";
|
||||||
|
def->cli = "filament-notes=s@";
|
||||||
|
def->multiline = true;
|
||||||
|
def->full_width = true;
|
||||||
|
def->height = 130;
|
||||||
|
{
|
||||||
|
ConfigOptionStrings* opt = new ConfigOptionStrings();
|
||||||
|
opt->values.push_back("");
|
||||||
|
def->default_value = opt;
|
||||||
|
}
|
||||||
|
|
||||||
|
def = this->add("filament_max_volumetric_speed", coFloats);
|
||||||
|
def->label = "Max volumetric speed";
|
||||||
|
def->tooltip = "Maximum volumetric speed allowed for this filament. Limits the maximum volumetric speed of a print to the minimum of print and filament volumetric speed. Set to zero for no limit.";
|
||||||
|
def->sidetext = "mm³/s";
|
||||||
|
def->cli = "filament-max-volumetric-speed=f@";
|
||||||
|
def->min = 0;
|
||||||
|
{
|
||||||
|
ConfigOptionFloats* opt = new ConfigOptionFloats();
|
||||||
|
opt->values.push_back(0.f);
|
||||||
|
def->default_value = opt;
|
||||||
|
}
|
||||||
|
|
||||||
def = this->add("filament_diameter", coFloats);
|
def = this->add("filament_diameter", coFloats);
|
||||||
def->label = "Diameter";
|
def->label = "Diameter";
|
||||||
def->tooltip = "Enter your filament diameter here. Good precision is required, so use a caliper and do multiple measurements along the filament, then compute the average.";
|
def->tooltip = "Enter your filament diameter here. Good precision is required, so use a caliper and do multiple measurements along the filament, then compute the average.";
|
||||||
|
@ -292,6 +292,7 @@ class GCodeConfig : public virtual StaticPrintConfig
|
|||||||
ConfigOptionString extrusion_axis;
|
ConfigOptionString extrusion_axis;
|
||||||
ConfigOptionFloats extrusion_multiplier;
|
ConfigOptionFloats extrusion_multiplier;
|
||||||
ConfigOptionFloats filament_diameter;
|
ConfigOptionFloats filament_diameter;
|
||||||
|
ConfigOptionFloats filament_max_volumetric_speed;
|
||||||
ConfigOptionBool gcode_comments;
|
ConfigOptionBool gcode_comments;
|
||||||
ConfigOptionEnum<GCodeFlavor> gcode_flavor;
|
ConfigOptionEnum<GCodeFlavor> gcode_flavor;
|
||||||
ConfigOptionString layer_gcode;
|
ConfigOptionString layer_gcode;
|
||||||
@ -326,6 +327,7 @@ class GCodeConfig : public virtual StaticPrintConfig
|
|||||||
OPT_PTR(extrusion_axis);
|
OPT_PTR(extrusion_axis);
|
||||||
OPT_PTR(extrusion_multiplier);
|
OPT_PTR(extrusion_multiplier);
|
||||||
OPT_PTR(filament_diameter);
|
OPT_PTR(filament_diameter);
|
||||||
|
OPT_PTR(filament_max_volumetric_speed);
|
||||||
OPT_PTR(gcode_comments);
|
OPT_PTR(gcode_comments);
|
||||||
OPT_PTR(gcode_flavor);
|
OPT_PTR(gcode_flavor);
|
||||||
OPT_PTR(layer_gcode);
|
OPT_PTR(layer_gcode);
|
||||||
@ -385,6 +387,7 @@ class PrintConfig : public GCodeConfig
|
|||||||
ConfigOptionBool fan_always_on;
|
ConfigOptionBool fan_always_on;
|
||||||
ConfigOptionInt fan_below_layer_time;
|
ConfigOptionInt fan_below_layer_time;
|
||||||
ConfigOptionStrings filament_colour;
|
ConfigOptionStrings filament_colour;
|
||||||
|
ConfigOptionStrings filament_notes;
|
||||||
ConfigOptionFloat first_layer_acceleration;
|
ConfigOptionFloat first_layer_acceleration;
|
||||||
ConfigOptionInt first_layer_bed_temperature;
|
ConfigOptionInt first_layer_bed_temperature;
|
||||||
ConfigOptionFloatOrPercent first_layer_extrusion_width;
|
ConfigOptionFloatOrPercent first_layer_extrusion_width;
|
||||||
@ -441,6 +444,7 @@ class PrintConfig : public GCodeConfig
|
|||||||
OPT_PTR(fan_always_on);
|
OPT_PTR(fan_always_on);
|
||||||
OPT_PTR(fan_below_layer_time);
|
OPT_PTR(fan_below_layer_time);
|
||||||
OPT_PTR(filament_colour);
|
OPT_PTR(filament_colour);
|
||||||
|
OPT_PTR(filament_notes);
|
||||||
OPT_PTR(first_layer_acceleration);
|
OPT_PTR(first_layer_acceleration);
|
||||||
OPT_PTR(first_layer_bed_temperature);
|
OPT_PTR(first_layer_bed_temperature);
|
||||||
OPT_PTR(first_layer_extrusion_width);
|
OPT_PTR(first_layer_extrusion_width);
|
||||||
|
@ -4,7 +4,8 @@ use strict;
|
|||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Slic3r::XS;
|
use Slic3r::XS;
|
||||||
use Test::More tests => 110;
|
use Test::More tests => 146;
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintConfig) {
|
foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintConfig) {
|
||||||
$config->set('layer_height', 0.3);
|
$config->set('layer_height', 0.3);
|
||||||
@ -25,6 +26,47 @@ foreach my $config (Slic3r::Config->new, Slic3r::Config::Static::new_FullPrintCo
|
|||||||
$config->set_deserialize('notes', 'bar\nbaz');
|
$config->set_deserialize('notes', 'bar\nbaz');
|
||||||
is $config->get('notes'), "bar\nbaz", 'deserialize string with newline';
|
is $config->get('notes'), "bar\nbaz", 'deserialize string with newline';
|
||||||
|
|
||||||
|
foreach my $test_data (
|
||||||
|
{
|
||||||
|
name => 'empty',
|
||||||
|
values => [],
|
||||||
|
serialized => ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'single empty',
|
||||||
|
values => [''],
|
||||||
|
serialized => '""'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'single noempty, simple',
|
||||||
|
values => ['RGB'],
|
||||||
|
serialized => 'RGB'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'multiple noempty, simple',
|
||||||
|
values => ['ABC', 'DEF', '09182745@!#$*(&'],
|
||||||
|
serialized => 'ABC;DEF;09182745@!#$*(&'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'multiple, simple, some empty',
|
||||||
|
values => ['ABC', 'DEF', '', '09182745@!#$*(&', ''],
|
||||||
|
serialized => 'ABC;DEF;;09182745@!#$*(&;'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'complex',
|
||||||
|
values => ['some "quoted" notes', "yet\n some notes", "whatever \n notes", ''],
|
||||||
|
serialized => '"some \"quoted\" notes";"yet\n some notes";"whatever \n notes";'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$config->set('filament_notes', $test_data->{values});
|
||||||
|
is $config->serialize('filament_notes'), $test_data->{serialized}, 'serialize multi-string value ' . $test_data->{name};
|
||||||
|
$config->set_deserialize('filament_notes', '');
|
||||||
|
is_deeply $config->get('filament_notes'), [], 'deserialize multi-string value - empty ' . $test_data->{name};
|
||||||
|
$config->set_deserialize('filament_notes', $test_data->{serialized});
|
||||||
|
is_deeply $config->get('filament_notes'), $test_data->{values}, 'deserialize complex multi-string value ' . $test_data->{name};
|
||||||
|
}
|
||||||
|
|
||||||
$config->set('first_layer_height', 0.3);
|
$config->set('first_layer_height', 0.3);
|
||||||
ok abs($config->get('first_layer_height') - 0.3) < 1e-4, 'set/get absolute floatOrPercent';
|
ok abs($config->get('first_layer_height') - 0.3) < 1e-4, 'set/get absolute floatOrPercent';
|
||||||
is $config->serialize('first_layer_height'), '0.3', 'serialize absolute floatOrPercent';
|
is $config->serialize('first_layer_height'), '0.3', 'serialize absolute floatOrPercent';
|
||||||
|
Loading…
Reference in New Issue
Block a user