Merge branch 'master' of https://github.com/prusa3d/Slic3r into scene_manipulators
This commit is contained in:
commit
b4efff1d95
27
My Settings
Normal file
27
My Settings
Normal file
@ -0,0 +1,27 @@
|
||||
# generated by Slic3r Prusa Edition 1.38.4 on 2017-12-20 at 11:02:03
|
||||
bed_temperature = 0
|
||||
bridge_fan_speed = 100
|
||||
compatible_printers =
|
||||
compatible_printers_condition =
|
||||
cooling = 1
|
||||
disable_fan_first_layers = 3
|
||||
end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n"
|
||||
extrusion_multiplier = 1
|
||||
fan_always_on = 0
|
||||
fan_below_layer_time = 60
|
||||
filament_colour = #29b2b2
|
||||
filament_cost = 0
|
||||
filament_density = 0
|
||||
filament_diameter = 3
|
||||
filament_max_volumetric_speed = 0
|
||||
filament_notes = ""
|
||||
filament_soluble = 0
|
||||
filament_type = PLA
|
||||
first_layer_bed_temperature = 0
|
||||
first_layer_temperature = 205
|
||||
max_fan_speed = 100
|
||||
min_fan_speed = 35
|
||||
min_print_speed = 10
|
||||
slowdown_below_layer_time = 5
|
||||
start_filament_gcode = "; Filament gcode\n"
|
||||
temperature = 200
|
@ -106,12 +106,11 @@ sub OnInit {
|
||||
|
||||
# Suppress the '- default -' presets.
|
||||
$self->{preset_bundle}->set_default_suppressed($self->{app_config}->get('no_defaults') ? 1 : 0);
|
||||
eval { $self->{preset_bundle}->load_presets };
|
||||
eval { $self->{preset_bundle}->load_presets($self->{app_config}); };
|
||||
if ($@) {
|
||||
warn $@ . "\n";
|
||||
show_error(undef, $@);
|
||||
}
|
||||
eval { $self->{preset_bundle}->load_selections($self->{app_config}) };
|
||||
$run_wizard = 1 if $self->{preset_bundle}->has_defauls_only;
|
||||
|
||||
Slic3r::GUI::set_preset_bundle($self->{preset_bundle});
|
||||
|
@ -666,7 +666,13 @@ sub config_wizard {
|
||||
wxTheApp->{preset_bundle}->load_config('My Settings', $result->{config});
|
||||
} else {
|
||||
# Wizard returned a name of a preset bundle bundled with the installation. Unpack it.
|
||||
wxTheApp->{preset_bundle}->load_configbundle($directory . '/' . $result->{preset_name} . '.ini');
|
||||
wxTheApp->{preset_bundle}->install_vendor_configbundle($directory . '/' . $result->{preset_name} . '.ini');
|
||||
# Reset the print / filament / printer selections, so that following line will select some sensible defaults.
|
||||
if ($fresh_start) {
|
||||
wxTheApp->{app_config}->reset_selections;
|
||||
}
|
||||
# Reload all presets after the vendor config bundle has been installed.
|
||||
wxTheApp->{preset_bundle}->load_presets(wxTheApp->{app_config});
|
||||
}
|
||||
};
|
||||
Slic3r::GUI::catch_error($self) and return;
|
||||
|
BIN
resources/icons/lock.png
Normal file
BIN
resources/icons/lock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 749 B |
BIN
resources/icons/lock_open.png
Normal file
BIN
resources/icons/lock_open.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 727 B |
BIN
resources/icons/sys_lock.png
Normal file
BIN
resources/icons/sys_lock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 448 B |
BIN
resources/icons/sys_unlock.png
Normal file
BIN
resources/icons/sys_unlock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 454 B |
Binary file not shown.
@ -3,7 +3,7 @@ msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2018-02-28 13:53+0100\n"
|
||||
"PO-Revision-Date: 2018-02-28 14:04+0100\n"
|
||||
"PO-Revision-Date: 2018-03-21 16:01+0100\n"
|
||||
"Last-Translator: Oleksandra Iushchenko <yusanka@gmail.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -3330,7 +3330,7 @@ msgstr ""
|
||||
|
||||
#: c:\src\Slic3r\xs\src\libslic3r\GCode\PreviewData.cpp:137
|
||||
msgid "None"
|
||||
msgstr "Жадне"
|
||||
msgstr "Жодне"
|
||||
|
||||
#: c:\src\Slic3r\xs\src\libslic3r\GCode\PreviewData.cpp:138
|
||||
#: c:\src\Slic3r\lib\Slic3r\GUI\Plater\3DPreview.pm:80
|
||||
@ -3718,11 +3718,11 @@ msgstr "Файл"
|
||||
|
||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:419
|
||||
msgid "&Plater"
|
||||
msgstr "Платер"
|
||||
msgstr "&Платер"
|
||||
|
||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:420
|
||||
msgid "&Object"
|
||||
msgstr "Об'єкт"
|
||||
msgstr "&Об'єкт"
|
||||
|
||||
#: c:\src\Slic3r\lib\Slic3r\GUI\MainFrame.pm:421
|
||||
msgid "&Window"
|
||||
|
@ -909,10 +909,10 @@ use_volumetric_e = 0
|
||||
variable_layer_height = 1
|
||||
wipe = 1
|
||||
z_offset = 0
|
||||
#printer_model = MK2S
|
||||
#printer_variant = 0.4
|
||||
#default_print_profile = 0.15mm OPTIMAL
|
||||
#default_filament_profile = Prusa PLA
|
||||
printer_model = MK2S
|
||||
printer_variant = 0.4
|
||||
default_print_profile = 0.15mm OPTIMAL
|
||||
default_filament_profile = Prusa PLA
|
||||
|
||||
[printer:*multimaterial*]
|
||||
inherits = *common*
|
||||
@ -928,7 +928,7 @@ retract_restart_extra = 0
|
||||
retract_restart_extra_toolchange = 0
|
||||
retract_speed = 80
|
||||
single_extruder_multi_material = 1
|
||||
#printer_model = MK2SMM
|
||||
printer_model = MK2SMM
|
||||
|
||||
[printer:*mm-single*]
|
||||
inherits = *multimaterial*
|
||||
@ -956,15 +956,15 @@ nozzle_diameter = 0.25
|
||||
retract_length = 1
|
||||
retract_speed = 50
|
||||
variable_layer_height = 0
|
||||
#printer_variant = 0.25
|
||||
#default_print_profile = 0.10mm DETAIL 0.25 nozzle
|
||||
printer_variant = 0.25
|
||||
default_print_profile = 0.10mm DETAIL 0.25 nozzle
|
||||
|
||||
[printer:Original Prusa i3 MK2 0.6 nozzle]
|
||||
inherits = *common*
|
||||
max_layer_height = 0.35
|
||||
min_layer_height = 0.1
|
||||
nozzle_diameter = 0.6
|
||||
#printer_variant = 0.6
|
||||
printer_variant = 0.6
|
||||
|
||||
[printer:Original Prusa i3 MK2 MM Single Mode]
|
||||
inherits = *mm-single*
|
||||
@ -972,7 +972,7 @@ inherits = *mm-single*
|
||||
[printer:Original Prusa i3 MK2 MM Single Mode 0.6 nozzle]
|
||||
inherits = *mm-single*
|
||||
nozzle_diameter = 0.6
|
||||
#printer_variant = 0.6
|
||||
printer_variant = 0.6
|
||||
|
||||
[printer:Original Prusa i3 MK2 MultiMaterial]
|
||||
inherits = *mm-multi*
|
||||
@ -981,7 +981,7 @@ nozzle_diameter = 0.4,0.4,0.4,0.4
|
||||
[printer:Original Prusa i3 MK2 MultiMaterial 0.6 nozzle]
|
||||
inherits = *mm-multi*
|
||||
nozzle_diameter = 0.6,0.6,0.6,0.6
|
||||
#printer_variant = 0.6
|
||||
printer_variant = 0.6
|
||||
|
||||
[printer:Original Prusa i3 MK3]
|
||||
inherits = *common*
|
||||
@ -989,8 +989,8 @@ end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
|
||||
retract_lift_below = 209
|
||||
start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
|
||||
#printer_model = MK3
|
||||
#default_print_profile = 0.15mm OPTIMAL MK3
|
||||
printer_model = MK3
|
||||
default_print_profile = 0.15mm OPTIMAL MK3
|
||||
|
||||
[printer:Original Prusa i3 MK3 0.25 nozzle]
|
||||
inherits = *common*
|
||||
@ -999,8 +999,8 @@ end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
|
||||
retract_lift_below = 209
|
||||
start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
|
||||
#printer_model = MK3
|
||||
#default_print_profile = 0.10mm DETAIL MK3
|
||||
printer_model = MK3
|
||||
default_print_profile = 0.10mm DETAIL MK3
|
||||
|
||||
[printer:Original Prusa i3 MK3 0.6 nozzle]
|
||||
inherits = *common*
|
||||
@ -1009,8 +1009,8 @@ end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n
|
||||
retract_lift_below = 209
|
||||
start_gcode = M115 U3.1.1-RC5 ; tell printer latest fw version\nM201 X1000 Y1000 Z200 E5000 ; sets maximum accelerations, mm/sec^2\nM203 X200 Y200 Z12 E120 ; sets maximum feedrates, mm/sec\nM204 S1250 T1250 ; sets acceleration (S) and retract acceleration (T)\nM205 X10 Y10 Z0.4 E2.5 ; sets the jerk limits, mm/sec\nM205 S0 T0 ; sets the minimum extruding and travel feed rate, mm/sec\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0\nM221 S{if layer_height==0.05}100{else}95{endif}
|
||||
#printer_model = MK3
|
||||
#default_print_profile = 0.15mm OPTIMAL MK3
|
||||
printer_model = MK3
|
||||
default_print_profile = 0.15mm OPTIMAL MK3
|
||||
|
||||
[presets]
|
||||
print = 0.15mm OPTIMAL MK3
|
||||
|
@ -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
|
||||
@ -299,6 +301,11 @@ add_library(Shiny STATIC
|
||||
${LIBDIR}/Shiny/ShinyZone.h
|
||||
)
|
||||
|
||||
add_library(semver STATIC
|
||||
${LIBDIR}/semver/semver.h
|
||||
${LIBDIR}/semver/semver.c
|
||||
)
|
||||
|
||||
# Generate the Slic3r Perl module (XS) typemap file.
|
||||
set(MyTypemap ${CMAKE_CURRENT_BINARY_DIR}/typemap)
|
||||
add_custom_command(
|
||||
|
@ -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) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ static inline Polyline make_wave_horizontal(
|
||||
polyline.points.emplace_back(Point(0, coord_t(clamp(0., height, y0) * scaleFactor)));
|
||||
double phase_offset_sin = (z_sin < 0 ? M_PI : 0) + (flip ? 0 : M_PI);
|
||||
double phase_offset_cos = z_sin < 0 ? M_PI : 0.;
|
||||
for (double x=0.; x < width + segmentSize; x += segmentSize) {
|
||||
for (double x = 0.; x < width + segmentSize; x += segmentSize) {
|
||||
x = std::min(x, width);
|
||||
double a = cos(x + phase_offset_cos);
|
||||
double b = - z_sin;
|
||||
@ -55,10 +55,10 @@ static inline Polyline make_wave_horizontal(
|
||||
return polyline;
|
||||
}
|
||||
|
||||
static Polylines make_gyroid_waves(double gridZ, double density, double layer_width, double width, double height)
|
||||
static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double line_spacing, double width, double height)
|
||||
{
|
||||
double scaleFactor = scale_(layer_width) / density;
|
||||
double segmentSize = 0.5 * density;
|
||||
double scaleFactor = scale_(line_spacing) / density_adjusted;
|
||||
double segmentSize = 0.5 * density_adjusted;
|
||||
//scale factor for 5% : 8 712 388
|
||||
// 1z = 10^-6 mm ?
|
||||
double z = gridZ / scaleFactor;
|
||||
@ -74,7 +74,7 @@ static Polylines make_gyroid_waves(double gridZ, double density, double layer_wi
|
||||
} else {
|
||||
// Horizontal wave
|
||||
bool flip = true;
|
||||
for (double y0 = 0.; y0 < width; y0 += M_PI, flip = !flip)
|
||||
for (double y0 = 0.; y0 < height; y0 += M_PI, flip = !flip)
|
||||
result.emplace_back(make_wave_horizontal(width, height, y0, segmentSize, scaleFactor, z_cos, z_sin, flip));
|
||||
}
|
||||
return result;
|
||||
@ -87,17 +87,20 @@ void FillGyroid::_fill_surface_single(
|
||||
ExPolygon &expolygon,
|
||||
Polylines &polylines_out)
|
||||
{
|
||||
// no rotation is supported for this infill pattern
|
||||
// no rotation is supported for this infill pattern (yet)
|
||||
BoundingBox bb = expolygon.contour.bounding_box();
|
||||
coord_t distance = coord_t(scale_(this->spacing) / (params.density*this->scaling));
|
||||
// Density adjusted to have a good %of weight.
|
||||
double density_adjusted = params.density * 1.75;
|
||||
// Distance between the gyroid waves in scaled coordinates.
|
||||
coord_t distance = coord_t(scale_(this->spacing) / density_adjusted);
|
||||
|
||||
// align bounding box to a multiple of our grid module
|
||||
bb.merge(_align_to_grid(bb.min, Point(2*M_PI*distance, 2*M_PI*distance)));
|
||||
bb.merge(_align_to_grid(bb.min, Point(2.*M_PI*distance, 2.*M_PI*distance)));
|
||||
|
||||
// generate pattern
|
||||
Polylines polylines = make_gyroid_waves(
|
||||
scale_(this->z),
|
||||
params.density*this->scaling,
|
||||
density_adjusted,
|
||||
this->spacing,
|
||||
ceil(bb.size().x / distance) + 1.,
|
||||
ceil(bb.size().y / distance) + 1.);
|
||||
|
@ -17,10 +17,6 @@ public:
|
||||
virtual bool use_bridge_flow() const { return true; }
|
||||
|
||||
protected:
|
||||
|
||||
// mult of density, to have a good %of weight for each density parameter
|
||||
float scaling = 1.75;
|
||||
|
||||
virtual void _fill_surface_single(
|
||||
const FillParams ¶ms,
|
||||
unsigned int thickness_layers,
|
||||
|
@ -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("");
|
||||
|
||||
|
617
xs/src/semver/semver.c
Normal file
617
xs/src/semver/semver.c
Normal file
@ -0,0 +1,617 @@
|
||||
/*
|
||||
* semver.c
|
||||
*
|
||||
* Copyright (c) 2015-2017 Tomas Aparicio
|
||||
* MIT licensed
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "semver.h"
|
||||
|
||||
#define SLICE_SIZE 50
|
||||
#define DELIMITER "."
|
||||
#define PR_DELIMITER "-"
|
||||
#define MT_DELIMITER "+"
|
||||
#define NUMBERS "0123456789"
|
||||
#define ALPHA "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
#define DELIMITERS DELIMITER PR_DELIMITER MT_DELIMITER
|
||||
#define VALID_CHARS NUMBERS ALPHA DELIMITERS
|
||||
|
||||
static const size_t MAX_SIZE = sizeof(char) * 255;
|
||||
static const int MAX_SAFE_INT = (unsigned int) -1 >> 1;
|
||||
|
||||
/**
|
||||
* Define comparison operators, storing the
|
||||
* ASCII code per each symbol in hexadecimal notation.
|
||||
*/
|
||||
|
||||
enum operators {
|
||||
SYMBOL_GT = 0x3e,
|
||||
SYMBOL_LT = 0x3c,
|
||||
SYMBOL_EQ = 0x3d,
|
||||
SYMBOL_TF = 0x7e,
|
||||
SYMBOL_CF = 0x5e
|
||||
};
|
||||
|
||||
/**
|
||||
* Private helpers
|
||||
*/
|
||||
|
||||
/*
|
||||
* Remove [begin:len-begin] from str by moving len data from begin+len to begin.
|
||||
* If len is negative cut out to the end of the string.
|
||||
*/
|
||||
static int
|
||||
strcut (char *str, int begin, int len) {
|
||||
size_t l;
|
||||
l = strlen(str);
|
||||
|
||||
if((int)l < 0 || (int)l > MAX_SAFE_INT) return -1;
|
||||
|
||||
if (len < 0) len = l - begin + 1;
|
||||
if (begin + len > (int)l) len = l - begin;
|
||||
memmove(str + begin, str + begin + len, l - len + 1 - begin);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int
|
||||
contains (const char c, const char *matrix, size_t len) {
|
||||
size_t x;
|
||||
for (x = 0; x < len; x++)
|
||||
if ((char) matrix[x] == c) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
has_valid_chars (const char *str, const char *matrix) {
|
||||
size_t i, len, mlen;
|
||||
len = strlen(str);
|
||||
mlen = strlen(matrix);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (contains(str[i], matrix, mlen) == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
binary_comparison (int x, int y) {
|
||||
if (x == y) return 0;
|
||||
if (x > y) return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_int (const char *s) {
|
||||
int valid, num;
|
||||
valid = has_valid_chars(s, NUMBERS);
|
||||
if (valid == 0) return -1;
|
||||
|
||||
num = strtol(s, NULL, 10);
|
||||
if (num > MAX_SAFE_INT) return -1;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a string allocated on the heap with the content from sep to end and
|
||||
* terminate buf at sep.
|
||||
*/
|
||||
static char *
|
||||
parse_slice (char *buf, char sep) {
|
||||
char *pr, *part;
|
||||
int plen;
|
||||
|
||||
/* Find separator in buf */
|
||||
pr = strchr(buf, sep);
|
||||
if (pr == NULL) return NULL;
|
||||
/* Length from separator to end of buf */
|
||||
plen = strlen(pr);
|
||||
|
||||
/* Copy from buf into new string */
|
||||
part = calloc(plen + 1, sizeof(*part));
|
||||
if (part == NULL) return NULL;
|
||||
memcpy(part, pr + 1, plen);
|
||||
/* Null terminate new string */
|
||||
part[plen] = '\0';
|
||||
|
||||
/* Terminate buf where separator was */
|
||||
*pr = '\0';
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string as semver expression.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - Parsed successfully
|
||||
* `-1` - In case of error
|
||||
*/
|
||||
|
||||
int
|
||||
semver_parse (const char *str, semver_t *ver) {
|
||||
int valid, res;
|
||||
size_t len;
|
||||
char *buf;
|
||||
valid = semver_is_valid(str);
|
||||
if (!valid) return -1;
|
||||
|
||||
len = strlen(str);
|
||||
buf = calloc(len + 1, sizeof(*buf));
|
||||
if (buf == NULL) return -1;
|
||||
strcpy(buf, str);
|
||||
|
||||
ver->metadata = parse_slice(buf, MT_DELIMITER[0]);
|
||||
ver->prerelease = parse_slice(buf, PR_DELIMITER[0]);
|
||||
|
||||
res = semver_parse_version(buf, ver);
|
||||
free(buf);
|
||||
#if DEBUG > 0
|
||||
printf("[debug] semver.c %s = %d.%d.%d, %s %s\n", str, ver->major, ver->minor, ver->patch, ver->prerelease, ver->metadata);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a given string as semver expression.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - Parsed successfully
|
||||
* `-1` - Parse error or invalid
|
||||
*/
|
||||
|
||||
int
|
||||
semver_parse_version (const char *str, semver_t *ver) {
|
||||
size_t len;
|
||||
int index, value;
|
||||
char *slice, *next, *endptr;
|
||||
slice = (char *) str;
|
||||
index = 0;
|
||||
|
||||
while (slice != NULL && index++ < 4) {
|
||||
next = strchr(slice, DELIMITER[0]);
|
||||
if (next == NULL)
|
||||
len = strlen(slice);
|
||||
else
|
||||
len = next - slice;
|
||||
if (len > SLICE_SIZE) return -1;
|
||||
|
||||
/* Cast to integer and store */
|
||||
value = strtol(slice, &endptr, 10);
|
||||
if (endptr != next && *endptr != '\0') return -1;
|
||||
|
||||
switch (index) {
|
||||
case 1: ver->major = value; break;
|
||||
case 2: ver->minor = value; break;
|
||||
case 3: ver->patch = value; break;
|
||||
}
|
||||
|
||||
/* Continue with the next slice */
|
||||
if (next == NULL)
|
||||
slice = NULL;
|
||||
else
|
||||
slice = next + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
compare_prerelease (char *x, char *y) {
|
||||
char *lastx, *lasty, *xptr, *yptr, *endptr;
|
||||
int xlen, ylen, xisnum, yisnum, xnum, ynum;
|
||||
int xn, yn, min, res;
|
||||
if (x == NULL && y == NULL) return 0;
|
||||
if (y == NULL && x) return -1;
|
||||
if (x == NULL && y) return 1;
|
||||
|
||||
lastx = x;
|
||||
lasty = y;
|
||||
xlen = strlen(x);
|
||||
ylen = strlen(y);
|
||||
|
||||
while (1) {
|
||||
if ((xptr = strchr(lastx, DELIMITER[0])) == NULL)
|
||||
xptr = x + xlen;
|
||||
if ((yptr = strchr(lasty, DELIMITER[0])) == NULL)
|
||||
yptr = y + ylen;
|
||||
|
||||
xnum = strtol(lastx, &endptr, 10);
|
||||
xisnum = endptr == xptr ? 1 : 0;
|
||||
ynum = strtol(lasty, &endptr, 10);
|
||||
yisnum = endptr == yptr ? 1 : 0;
|
||||
|
||||
if (xisnum && !yisnum) return -1;
|
||||
if (!xisnum && yisnum) return 1;
|
||||
|
||||
if (xisnum && yisnum) {
|
||||
/* Numerical comparison */
|
||||
if (xnum != ynum) return xnum < ynum ? -1 : 1;
|
||||
} else {
|
||||
/* String comparison */
|
||||
xn = xptr - lastx;
|
||||
yn = yptr - lasty;
|
||||
min = xn < yn ? xn : yn;
|
||||
if ((res = strncmp(lastx, lasty, min))) return res < 0 ? -1 : 1;
|
||||
if (xn != yn) return xn < yn ? -1 : 1;
|
||||
}
|
||||
|
||||
lastx = xptr + 1;
|
||||
lasty = yptr + 1;
|
||||
if (lastx == x + xlen + 1 && lasty == y + ylen + 1) break;
|
||||
if (lastx == x + xlen + 1) return -1;
|
||||
if (lasty == y + ylen + 1) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
semver_compare_prerelease (semver_t x, semver_t y) {
|
||||
return compare_prerelease(x.prerelease, y.prerelease);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a major, minor and patch binary comparison (x, y).
|
||||
* This function is mostly used internally
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - If versiona are equal
|
||||
* `1` - If x is higher than y
|
||||
* `-1` - If x is lower than y
|
||||
*/
|
||||
|
||||
int
|
||||
semver_compare_version (semver_t x, semver_t y) {
|
||||
int res;
|
||||
|
||||
if ((res = binary_comparison(x.major, y.major)) == 0) {
|
||||
if ((res = binary_comparison(x.minor, y.minor)) == 0) {
|
||||
return binary_comparison(x.patch, y.patch);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two semantic versions (x, y).
|
||||
*
|
||||
* Returns:
|
||||
* - `1` if x is higher than y
|
||||
* - `0` if x is equal to y
|
||||
* - `-1` if x is lower than y
|
||||
*/
|
||||
|
||||
int
|
||||
semver_compare (semver_t x, semver_t y) {
|
||||
int res;
|
||||
|
||||
if ((res = semver_compare_version(x, y)) == 0) {
|
||||
return semver_compare_prerelease(x, y);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `greater than` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_gt (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `lower than` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_lt (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) == -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `equality` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_eq (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `non equal to` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_neq (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `greater than or equal` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_gte (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a `lower than or equal` comparison
|
||||
*/
|
||||
|
||||
int
|
||||
semver_lte (semver_t x, semver_t y) {
|
||||
return semver_compare(x, y) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if version `x` can be satisfied by `y`
|
||||
* performing a comparison with caret operator.
|
||||
*
|
||||
* See: https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Can be satisfied
|
||||
* `0` - Cannot be satisfied
|
||||
*/
|
||||
|
||||
int
|
||||
semver_satisfies_caret (semver_t x, semver_t y) {
|
||||
if (x.major == y.major) {
|
||||
if (x.major == 0) {
|
||||
return x.minor >= y.minor;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if version `x` can be satisfied by `y`
|
||||
* performing a comparison with tilde operator.
|
||||
*
|
||||
* See: https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Can be satisfied
|
||||
* `0` - Cannot be satisfied
|
||||
*/
|
||||
|
||||
int
|
||||
semver_satisfies_patch (semver_t x, semver_t y) {
|
||||
return x.major == y.major
|
||||
&& x.minor == y.minor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if both versions can be satisfied
|
||||
* based on the given comparison operator.
|
||||
*
|
||||
* Allowed operators:
|
||||
*
|
||||
* - `=` - Equality
|
||||
* - `>=` - Higher or equal to
|
||||
* - `<=` - Lower or equal to
|
||||
* - `<` - Lower than
|
||||
* - `>` - Higher than
|
||||
* - `^` - Caret comparison (see https://docs.npmjs.com/misc/semver#caret-ranges-1-2-3-0-2-5-0-0-4)
|
||||
* - `~` - Tilde comparison (see https://docs.npmjs.com/misc/semver#tilde-ranges-1-2-3-1-2-1)
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Can be satisfied
|
||||
* `0` - Cannot be satisfied
|
||||
*/
|
||||
|
||||
int
|
||||
semver_satisfies (semver_t x, semver_t y, const char *op) {
|
||||
int first, second;
|
||||
/* Extract the comparison operator */
|
||||
first = op[0];
|
||||
second = op[1];
|
||||
|
||||
/* Caret operator */
|
||||
if (first == SYMBOL_CF)
|
||||
return semver_satisfies_caret(x, y);
|
||||
|
||||
/* Tilde operator */
|
||||
if (first == SYMBOL_TF)
|
||||
return semver_satisfies_patch(x, y);
|
||||
|
||||
/* Strict equality */
|
||||
if (first == SYMBOL_EQ)
|
||||
return semver_eq(x, y);
|
||||
|
||||
/* Greater than or equal comparison */
|
||||
if (first == SYMBOL_GT) {
|
||||
if (second == SYMBOL_EQ) {
|
||||
return semver_gte(x, y);
|
||||
}
|
||||
return semver_gt(x, y);
|
||||
}
|
||||
|
||||
/* Lower than or equal comparison */
|
||||
if (first == SYMBOL_LT) {
|
||||
if (second == SYMBOL_EQ) {
|
||||
return semver_lte(x, y);
|
||||
}
|
||||
return semver_lt(x, y);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free heep allocated memory of a given semver.
|
||||
* This is just a convenient function that you
|
||||
* should call when you're done.
|
||||
*/
|
||||
|
||||
void
|
||||
semver_free (semver_t *x) {
|
||||
if (x->metadata) {
|
||||
free(x->metadata);
|
||||
x->metadata = NULL;
|
||||
}
|
||||
if (x->prerelease) {
|
||||
free(x->prerelease);
|
||||
x->prerelease = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders
|
||||
*/
|
||||
|
||||
static void
|
||||
concat_num (char * str, int x, char * sep) {
|
||||
char buf[SLICE_SIZE] = {0};
|
||||
if (sep == NULL) sprintf(buf, "%d", x);
|
||||
else sprintf(buf, "%s%d", sep, x);
|
||||
strcat(str, buf);
|
||||
}
|
||||
|
||||
static void
|
||||
concat_char (char * str, char * x, char * sep) {
|
||||
char buf[SLICE_SIZE] = {0};
|
||||
sprintf(buf, "%s%s", sep, x);
|
||||
strcat(str, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a given semver as string
|
||||
*/
|
||||
|
||||
void
|
||||
semver_render (semver_t *x, char *dest) {
|
||||
if (x->major) concat_num(dest, x->major, NULL);
|
||||
if (x->minor) concat_num(dest, x->minor, DELIMITER);
|
||||
if (x->patch) concat_num(dest, x->patch, DELIMITER);
|
||||
if (x->prerelease) concat_char(dest, x->prerelease, PR_DELIMITER);
|
||||
if (x->metadata) concat_char(dest, x->metadata, MT_DELIMITER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Version bump helpers
|
||||
*/
|
||||
|
||||
void
|
||||
semver_bump (semver_t *x) {
|
||||
x->major++;
|
||||
}
|
||||
|
||||
void
|
||||
semver_bump_minor (semver_t *x) {
|
||||
x->minor++;
|
||||
}
|
||||
|
||||
void
|
||||
semver_bump_patch (semver_t *x) {
|
||||
x->patch++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helpers
|
||||
*/
|
||||
|
||||
static int
|
||||
has_valid_length (const char *s) {
|
||||
return strlen(s) <= MAX_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given semver string is valid
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `1` - Valid expression
|
||||
* `0` - Invalid
|
||||
*/
|
||||
|
||||
int
|
||||
semver_is_valid (const char *s) {
|
||||
return has_valid_length(s)
|
||||
&& has_valid_chars(s, VALID_CHARS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes non-valid characters in the given string.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
* `0` - Valid
|
||||
* `-1` - Invalid input
|
||||
*/
|
||||
|
||||
int
|
||||
semver_clean (char *s) {
|
||||
size_t i, len, mlen;
|
||||
int res;
|
||||
if (has_valid_length(s) == 0) return -1;
|
||||
|
||||
len = strlen(s);
|
||||
mlen = strlen(VALID_CHARS);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (contains(s[i], VALID_CHARS, mlen) == 0) {
|
||||
res = strcut(s, i, 1);
|
||||
if(res == -1) return -1;
|
||||
--len; --i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
char_to_int (const char * str) {
|
||||
int buf;
|
||||
size_t i,len, mlen;
|
||||
buf = 0;
|
||||
len = strlen(str);
|
||||
mlen = strlen(VALID_CHARS);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
if (contains(str[i], VALID_CHARS, mlen))
|
||||
buf += (int) str[i];
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a given semver as numeric value.
|
||||
* Useful for ordering and filtering.
|
||||
*/
|
||||
|
||||
int
|
||||
semver_numeric (semver_t *x) {
|
||||
int num;
|
||||
char buf[SLICE_SIZE * 3];
|
||||
memset(&buf, 0, SLICE_SIZE * 3);
|
||||
|
||||
if (x->major) concat_num(buf, x->major, NULL);
|
||||
if (x->minor) concat_num(buf, x->minor, NULL);
|
||||
if (x->patch) concat_num(buf, x->patch, NULL);
|
||||
|
||||
num = parse_int(buf);
|
||||
if(num == -1) return -1;
|
||||
|
||||
if (x->prerelease) num += char_to_int(x->prerelease);
|
||||
if (x->metadata) num += char_to_int(x->metadata);
|
||||
|
||||
return num;
|
||||
}
|
105
xs/src/semver/semver.h
Normal file
105
xs/src/semver/semver.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* semver.h
|
||||
*
|
||||
* Copyright (c) 2015-2017 Tomas Aparicio
|
||||
* MIT licensed
|
||||
*/
|
||||
|
||||
#ifndef __SEMVER_H
|
||||
#define __SEMVER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef SEMVER_VERSION
|
||||
#define SEMVER_VERSION "0.2.0"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* semver_t struct
|
||||
*/
|
||||
|
||||
typedef struct semver_version_s {
|
||||
int major;
|
||||
int minor;
|
||||
int patch;
|
||||
char * metadata;
|
||||
char * prerelease;
|
||||
} semver_t;
|
||||
|
||||
/**
|
||||
* Set prototypes
|
||||
*/
|
||||
|
||||
int
|
||||
semver_satisfies (semver_t x, semver_t y, const char *op);
|
||||
|
||||
int
|
||||
semver_satisfies_caret (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_satisfies_patch (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_compare (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_compare_version (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_compare_prerelease (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_gt (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_gte (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_lt (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_lte (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_eq (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_neq (semver_t x, semver_t y);
|
||||
|
||||
int
|
||||
semver_parse (const char *str, semver_t *ver);
|
||||
|
||||
int
|
||||
semver_parse_version (const char *str, semver_t *ver);
|
||||
|
||||
void
|
||||
semver_render (semver_t *x, char *dest);
|
||||
|
||||
int
|
||||
semver_numeric (semver_t *x);
|
||||
|
||||
void
|
||||
semver_bump (semver_t *x);
|
||||
|
||||
void
|
||||
semver_bump_minor (semver_t *x);
|
||||
|
||||
void
|
||||
semver_bump_patch (semver_t *x);
|
||||
|
||||
void
|
||||
semver_free (semver_t *x);
|
||||
|
||||
int
|
||||
semver_is_valid (const char *s);
|
||||
|
||||
int
|
||||
semver_clean (char *s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
@ -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();
|
||||
|
||||
|
@ -184,6 +184,7 @@ void BedShapePanel::set_shape(ConfigOptionPoints* points)
|
||||
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> PresetCollection::dirty_options(const Preset *edited, const Preset *reference)
|
||||
{
|
||||
std::vector<std::string> changed = this->get_selected_preset().config.diff(this->get_edited_preset().config);
|
||||
// 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> 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)
|
||||
@ -85,6 +103,7 @@ 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 / "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);
|
||||
|
||||
@ -101,6 +115,17 @@ public:
|
||||
static bool parse_color(const std::string &scolor, unsigned char *rgb_out);
|
||||
|
||||
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.
|
||||
@ -112,8 +137,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,6 +159,13 @@ 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);
|
||||
|
||||
@ -154,6 +173,7 @@ public:
|
||||
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() {}
|
||||
|
90
xs/src/slic3r/Utils/Semver.hpp
Normal file
90
xs/src/slic3r/Utils/Semver.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef slic3r_Semver_hpp_
|
||||
#define slic3r_Semver_hpp_
|
||||
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include "semver/semver.h"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
class Semver
|
||||
{
|
||||
public:
|
||||
struct Major { const int i; Major(int i) : i(i) {} };
|
||||
struct Minor { const int i; Minor(int i) : i(i) {} };
|
||||
struct Patch { const int i; Patch(int i) : i(i) {} };
|
||||
|
||||
static boost::optional<Semver> parse(const std::string &str)
|
||||
{
|
||||
semver_t ver;
|
||||
if (::semver_parse(str.c_str(), &ver) == 0) {
|
||||
return Semver(ver);
|
||||
} else {
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
Semver(Semver &&other) { *this = std::move(other); }
|
||||
Semver(const Semver &other) { *this = other; }
|
||||
|
||||
Semver &operator=(Semver &&other)
|
||||
{
|
||||
ver = other.ver;
|
||||
other.ver.major = other.ver.minor = other.ver.patch = 0;
|
||||
other.ver.metadata = other.ver.prerelease = nullptr;
|
||||
}
|
||||
|
||||
Semver &operator=(const Semver &other)
|
||||
{
|
||||
ver = other.ver;
|
||||
if (other.ver.metadata != nullptr) { std::strcpy(ver.metadata, other.ver.metadata); }
|
||||
if (other.ver.prerelease != nullptr) { std::strcpy(ver.prerelease, other.ver.prerelease); }
|
||||
}
|
||||
|
||||
~Semver() { ::semver_free(&ver); }
|
||||
|
||||
// Comparison
|
||||
bool operator<(const Semver &b) const { return ::semver_compare(ver, b.ver) == -1; }
|
||||
bool operator<=(const Semver &b) const { return ::semver_compare(ver, b.ver) <= 0; }
|
||||
bool operator==(const Semver &b) const { return ::semver_compare(ver, b.ver) == 0; }
|
||||
bool operator!=(const Semver &b) const { return ::semver_compare(ver, b.ver) != 0; }
|
||||
bool operator>=(const Semver &b) const { return ::semver_compare(ver, b.ver) >= 0; }
|
||||
bool operator>(const Semver &b) const { return ::semver_compare(ver, b.ver) == 1; }
|
||||
// We're using '&' instead of the '~' operator here as '~' is unary-only:
|
||||
bool operator&(const Semver &b) const { return ::semver_satisfies_patch(ver, b.ver); }
|
||||
bool operator^(const Semver &b) const { return ::semver_satisfies_caret(ver, b.ver); }
|
||||
|
||||
// Conversion
|
||||
std::string to_string() const {
|
||||
auto res = (boost::format("%1%.%2%.%3%") % ver.major % ver.minor % ver.patch).str();
|
||||
if (ver.prerelease != nullptr) { res += '-'; res += ver.prerelease; }
|
||||
if (ver.metadata != nullptr) { res += '+'; res += ver.metadata; }
|
||||
return res;
|
||||
}
|
||||
|
||||
// Arithmetics
|
||||
Semver& operator+=(const Major &b) { ver.major += b.i; return *this; }
|
||||
Semver& operator+=(const Minor &b) { ver.minor += b.i; return *this; }
|
||||
Semver& operator+=(const Patch &b) { ver.patch += b.i; return *this; }
|
||||
Semver& operator-=(const Major &b) { ver.major -= b.i; return *this; }
|
||||
Semver& operator-=(const Minor &b) { ver.minor -= b.i; return *this; }
|
||||
Semver& operator-=(const Patch &b) { ver.patch -= b.i; return *this; }
|
||||
Semver operator+(const Major &b) const { Semver res(*this); return res += b; }
|
||||
Semver operator+(const Minor &b) const { Semver res(*this); return res += b; }
|
||||
Semver operator+(const Patch &b) const { Semver res(*this); return res += b; }
|
||||
Semver operator-(const Major &b) const { Semver res(*this); return res -= b; }
|
||||
Semver operator-(const Minor &b) const { Semver res(*this); return res -= b; }
|
||||
Semver operator-(const Patch &b) const { Semver res(*this); return res -= b; }
|
||||
private:
|
||||
semver_t ver;
|
||||
|
||||
Semver(semver_t ver) : ver(ver) {}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
#endif
|
@ -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…
Reference in New Issue
Block a user