From 221f9bcc14a38b5cf4e104c95dd605bdc4404376 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 27 Dec 2023 01:18:40 +0100 Subject: [PATCH 01/19] revert de70415af12e9577fb17b0c23b6f0700d6ee63a3 --- resources/ui_layout/default/filament.ui | 140 +-- resources/ui_layout/default/print.ui | 1 - resources/ui_layout/example/filament.ui | 138 +-- src/PrusaSlicer.cpp | 4 +- src/libslic3r/Config.cpp | 10 +- src/libslic3r/Config.hpp | 352 +++----- src/libslic3r/Extruder.cpp | 36 +- src/libslic3r/Extruder.hpp | 2 +- src/libslic3r/Fill/Fill.cpp | 4 +- src/libslic3r/Format/3mf.cpp | 16 +- src/libslic3r/Format/CWS.cpp | 2 +- src/libslic3r/Format/SL1.cpp | 4 +- src/libslic3r/Format/SLAArchive.cpp | 16 +- src/libslic3r/GCodeWriter.cpp | 22 +- src/libslic3r/GCodeWriter.hpp | 2 +- src/libslic3r/Model.cpp | 4 +- src/libslic3r/MultiMaterialSegmentation.cpp | 2 +- src/libslic3r/PlaceholderParser.cpp | 20 +- src/libslic3r/PrintApply.cpp | 2 +- src/libslic3r/PrintBase.cpp | 3 +- src/libslic3r/PrintConfig.cpp | 67 +- src/libslic3r/PrintObject.cpp | 8 +- src/libslic3r/SLA/Rotfinder.cpp | 4 +- src/libslic3r/SLAPrint.cpp | 86 +- src/libslic3r/SLAPrintSteps.cpp | 52 +- src/libslic3r/Slicing.cpp | 2 +- src/slic3r/GUI/BedShapeDialog.cpp | 12 +- src/slic3r/GUI/CalibrationBridgeDialog.cpp | 2 +- src/slic3r/GUI/CalibrationFlowDialog.cpp | 2 +- .../GUI/CalibrationOverBridgeDialog.cpp | 7 +- .../GUI/CalibrationRetractionDialog.cpp | 9 +- src/slic3r/GUI/ConfigManipulation.cpp | 32 +- src/slic3r/GUI/Field.cpp | 808 ++++++------------ src/slic3r/GUI/Field.hpp | 76 +- src/slic3r/GUI/GLCanvas3D.cpp | 4 +- src/slic3r/GUI/GUI.cpp | 139 ++- src/slic3r/GUI/GUI.hpp | 2 +- src/slic3r/GUI/GUI_ObjectLayers.cpp | 2 +- src/slic3r/GUI/GUI_Preview.cpp | 10 +- src/slic3r/GUI/Jobs/ArrangeJob.cpp | 6 +- src/slic3r/GUI/OptionsGroup.cpp | 189 +++- src/slic3r/GUI/OptionsGroup.hpp | 5 +- src/slic3r/GUI/PhysicalPrinterDialog.cpp | 6 +- src/slic3r/GUI/Plater.cpp | 8 +- src/slic3r/GUI/ScriptExecutor.cpp | 122 ++- src/slic3r/GUI/Tab.cpp | 19 +- src/slic3r/GUI/Tab.hpp | 2 +- src/slic3r/GUI/UnsavedChangesDialog.cpp | 4 +- 48 files changed, 1124 insertions(+), 1341 deletions(-) diff --git a/resources/ui_layout/default/filament.ui b/resources/ui_layout/default/filament.ui index eeaa1973a75..845f5e3773b 100644 --- a/resources/ui_layout/default/filament.ui +++ b/resources/ui_layout/default/filament.ui @@ -1,97 +1,97 @@ -#note: all settings are id$0 as the slicer consider there is only one value in the arrays in the gui. + page:Filament:spool group:filament_spool_weight_event:Filament - setting:id$0:filament_colour - setting:id$0:filament_diameter - setting:id$0:extrusion_multiplier - setting:id$0:filament_density - setting:id$0:filament_cost - setting:id$0:filament_spool_weight + setting:filament_colour + setting:filament_diameter + setting:extrusion_multiplier + setting:filament_density + setting:filament_cost + setting:filament_spool_weight group:Temperature °C line:Extruder - setting:id$0:first_layer_temperature - setting:id$0:temperature + setting:first_layer_temperature + setting:temperature end_line line:Bed - setting:id$0:first_layer_bed_temperature - setting:id$0:label:Other layers:bed_temperature + setting:first_layer_bed_temperature + setting:label:Other layers:bed_temperature end_line - setting:id$0:chamber_temperature + setting:chamber_temperature group:Filament properties - setting:id$0:width$7:filament_type - setting:id$0:filament_soluble - setting:id$0:filament_shrink - setting:id$0:filament_max_overlap + setting:width$7:filament_type + setting:filament_soluble + setting:filament_shrink + setting:filament_max_overlap group:Print speed override - setting:id$0:filament_max_speed - setting:id$0:filament_max_volumetric_speed + setting:filament_max_speed + setting:filament_max_volumetric_speed volumetric_speed_description page:Cooling:time group:Fan speed - default - setting:id$0:label$Run the fan at default speed when possible:fan_always_on + setting:label$Run the fan at default speed when possible:fan_always_on line:Disable fan for the first - setting:id$0:width$5:label$_:sidetext_width$7:disable_fan_first_layers - setting:id$0:width$5:label_width$12:full_fan_speed_layer + setting:width$5:label$_:sidetext_width$7:disable_fan_first_layers + setting:width$5:label_width$12:full_fan_speed_layer end_line - setting:id$0:min_fan_speed + setting:min_fan_speed line:Perimeter fan speed - setting:id$0:label_width$12:label$Internal:perimeter_fan_speed - setting:id$0:label_width$12:label$External:external_perimeter_fan_speed + setting:label_width$12:label$Internal:perimeter_fan_speed + setting:label_width$12:label$External:external_perimeter_fan_speed line:Internal Infill fan speed - setting:id$0:label_width$12:label$Sparse:infill_fan_speed + setting:label_width$12:label$Sparse:infill_fan_speed line:Solid Infill fan speed - setting:id$0:label_width$12:label$Solid:solid_infill_fan_speed - setting:id$0:label_width$12:label$Top solid:top_fan_speed + setting:label_width$12:label$Solid:solid_infill_fan_speed + setting:label_width$12:label$Top solid:top_fan_speed line:Support Material fan speed - setting:id$0:label_width$12:label$Default:support_material_fan_speed - setting:id$0:label_width$12:label$Interface:support_material_interface_fan_speed + setting:label_width$12:label$Default:support_material_fan_speed + setting:label_width$12:label$Interface:support_material_interface_fan_speed line:Bridges fan speed - setting:id$0:label_width$12:label$Bridges:bridge_fan_speed - setting:id$0:label_width$12:label$Internal bridges:bridge_internal_fan_speed + setting:label_width$12:label$Bridges:bridge_fan_speed + setting:label_width$12:label$Internal bridges:bridge_internal_fan_speed line:Overhangs Perimeter fan speed - setting:id$0:label_width$12:label$Overhangs:overhangs_fan_speed + setting:label_width$12:label$Overhangs:overhangs_fan_speed line:Gap fill fan speed - setting:id$0:label_width$12:label$Gap fill:gap_fill_fan_speed + setting:label_width$12:label$Gap fill:gap_fill_fan_speed group:Short layer time - began to increase base fan speed - setting:id$0:fan_below_layer_time - setting:id$0:label$Max fan speed:max_fan_speed + setting:fan_below_layer_time + setting:label$Max fan speed:max_fan_speed group:Very short layer time - began to decrease extrusion rate - setting:id$0:label$Layer time goal:slowdown_below_layer_time - setting:id$0:width$4:max_speed_reduction - setting:id$0:width$4:min_print_speed + setting:label$Layer time goal:slowdown_below_layer_time + setting:width$4:max_speed_reduction + setting:width$4:min_print_speed group:Behavior cooling_description page:Multimaterial:funnel group:Multimaterial toolchange temperature - setting:id$0:filament_enable_toolchange_temp - setting:id$0:filament_toolchange_temp - setting:id$0:filament_use_fast_skinnydip - setting:id$0:filament_enable_toolchange_part_fan - setting:id$0:filament_toolchange_part_fan_speed + setting:filament_enable_toolchange_temp + setting:filament_toolchange_temp + setting:filament_use_fast_skinnydip + setting:filament_enable_toolchange_part_fan + setting:filament_toolchange_part_fan_speed group:Multimaterial toolchange string reduction - setting:id$0:filament_use_skinnydip - setting:id$0:filament_skinnydip_distance - setting:id$0:filament_melt_zone_pause - setting:id$0:filament_cooling_zone_pause - setting:id$0:filament_dip_insertion_speed - setting:id$0:filament_dip_extraction_speed + setting:filament_use_skinnydip + setting:filament_skinnydip_distance + setting:filament_melt_zone_pause + setting:filament_cooling_zone_pause + setting:filament_dip_insertion_speed + setting:filament_dip_extraction_speed group:Wipe tower parameters - setting:id$0:filament_minimal_purge_on_wipe_tower - setting:id$0:filament_max_wipe_tower_speed + setting:filament_minimal_purge_on_wipe_tower + setting:filament_max_wipe_tower_speed group:Toolchange parameters with single extruder MM printers - setting:id$0:filament_loading_speed_start - setting:id$0:filament_loading_speed - setting:id$0:filament_unloading_speed_start - setting:id$0:filament_unloading_speed - setting:id$0:filament_load_time - setting:id$0:filament_unload_time - setting:id$0:filament_toolchange_delay - setting:id$0:filament_cooling_moves - setting:id$0:filament_cooling_initial_speed - setting:id$0:filament_cooling_final_speed - setting:id$0:filament_wipe_advanced_pigment + setting:filament_loading_speed_start + setting:filament_loading_speed + setting:filament_unloading_speed_start + setting:filament_unloading_speed + setting:filament_load_time + setting:filament_unload_time + setting:filament_toolchange_delay + setting:filament_cooling_moves + setting:filament_cooling_initial_speed + setting:filament_cooling_final_speed + setting:filament_wipe_advanced_pigment filament_ramming_parameters @@ -99,20 +99,20 @@ filament_overrides_page page:Custom G-code:cog group:no_title:validate_gcode:Start G-code - setting:id$0:full_width:height$35:start_filament_gcode + setting:full_width:height$35:start_filament_gcode group:no_title:validate_gcode:End G-code - setting:id$0:full_width:height$35:end_filament_gcode + setting:full_width:height$35:end_filament_gcode page:Notes:note.png group:label_width$0:Notes - setting:id$0:full_width:height$25:filament_notes + setting:full_width:height$25:filament_notes group:label_width$0:Custom variables - setting:id$0:full_width:height$15:filament_custom_variables + setting:full_width:height$15:filament_custom_variables page:Dependencies:wrench.png group:Profile dependencies - setting:id$0:compatible_printers - setting:id$0:full_width:color:compatible_printers_condition - setting:id$0:compatible_prints - setting:id$0:full_width:color:compatible_prints_condition + setting:compatible_printers + setting:full_width:color:compatible_printers_condition + setting:compatible_prints + setting:full_width:color:compatible_prints_condition parent_preset_description diff --git a/resources/ui_layout/default/print.ui b/resources/ui_layout/default/print.ui index a1b54e6b2b7..196981ae37f 100644 --- a/resources/ui_layout/default/print.ui +++ b/resources/ui_layout/default/print.ui @@ -202,7 +202,6 @@ group:sidetext_width$5:Infill angle setting:label_width$6:width$5:label$increment:fill_angle_increment setting:label_width$6:width$5:label$increment:fill_angle_cross vector_line:fill_angle_template -# setting:fill_angle_template group:sidetext_width$5:Advanced setting:solid_infill_every_layers setting:solid_infill_below_area diff --git a/resources/ui_layout/example/filament.ui b/resources/ui_layout/example/filament.ui index 7aefcd3fbd8..845f5e3773b 100644 --- a/resources/ui_layout/example/filament.ui +++ b/resources/ui_layout/example/filament.ui @@ -1,97 +1,97 @@ page:Filament:spool group:filament_spool_weight_event:Filament - setting:id$0:filament_colour - setting:id$0:filament_diameter - setting:id$0:extrusion_multiplier - setting:id$0:filament_density - setting:id$0:filament_cost - setting:id$0:filament_spool_weight + setting:filament_colour + setting:filament_diameter + setting:extrusion_multiplier + setting:filament_density + setting:filament_cost + setting:filament_spool_weight group:Temperature °C line:Extruder - setting:id$0:first_layer_temperature - setting:id$0:temperature + setting:first_layer_temperature + setting:temperature end_line line:Bed - setting:id$0:first_layer_bed_temperature - setting:id$0:label:Other layers:bed_temperature + setting:first_layer_bed_temperature + setting:label:Other layers:bed_temperature end_line - setting:id$0:chamber_temperature + setting:chamber_temperature group:Filament properties - setting:id$0:width$7:filament_type - setting:id$0:filament_soluble - setting:id$0:filament_shrink - setting:id$0:filament_max_overlap + setting:width$7:filament_type + setting:filament_soluble + setting:filament_shrink + setting:filament_max_overlap group:Print speed override - setting:id$0:filament_max_speed - setting:id$0:filament_max_volumetric_speed + setting:filament_max_speed + setting:filament_max_volumetric_speed volumetric_speed_description page:Cooling:time group:Fan speed - default - setting:id$0:label$Run the fan at default speed when possible:fan_always_on + setting:label$Run the fan at default speed when possible:fan_always_on line:Disable fan for the first - setting:id$0:width$5:label$_:sidetext_width$7:disable_fan_first_layers - setting:id$0:width$5:label_width$12:full_fan_speed_layer + setting:width$5:label$_:sidetext_width$7:disable_fan_first_layers + setting:width$5:label_width$12:full_fan_speed_layer end_line - setting:id$0:min_fan_speed + setting:min_fan_speed line:Perimeter fan speed - setting:id$0:label_width$12:label$Internal:perimeter_fan_speed - setting:id$0:label_width$12:label$External:external_perimeter_fan_speed + setting:label_width$12:label$Internal:perimeter_fan_speed + setting:label_width$12:label$External:external_perimeter_fan_speed line:Internal Infill fan speed - setting:id$0:label_width$12:label$Sparse:infill_fan_speed + setting:label_width$12:label$Sparse:infill_fan_speed line:Solid Infill fan speed - setting:id$0:label_width$12:label$Solid:solid_infill_fan_speed - setting:id$0:label_width$12:label$Top solid:top_fan_speed + setting:label_width$12:label$Solid:solid_infill_fan_speed + setting:label_width$12:label$Top solid:top_fan_speed line:Support Material fan speed - setting:id$0:label_width$12:label$Default:support_material_fan_speed - setting:id$0:label_width$12:label$Interface:support_material_interface_fan_speed + setting:label_width$12:label$Default:support_material_fan_speed + setting:label_width$12:label$Interface:support_material_interface_fan_speed line:Bridges fan speed - setting:id$0:label_width$12:label$Bridges:bridge_fan_speed - setting:id$0:label_width$12:label$Internal bridges:bridge_internal_fan_speed + setting:label_width$12:label$Bridges:bridge_fan_speed + setting:label_width$12:label$Internal bridges:bridge_internal_fan_speed line:Overhangs Perimeter fan speed - setting:id$0:label_width$12:label$Overhangs:overhangs_fan_speed + setting:label_width$12:label$Overhangs:overhangs_fan_speed line:Gap fill fan speed - setting:id$0:label_width$12:label$Gap fill:gap_fill_fan_speed + setting:label_width$12:label$Gap fill:gap_fill_fan_speed group:Short layer time - began to increase base fan speed - setting:id$0:fan_below_layer_time - setting:id$0:label$Max fan speed:max_fan_speed + setting:fan_below_layer_time + setting:label$Max fan speed:max_fan_speed group:Very short layer time - began to decrease extrusion rate - setting:id$0:label$Layer time goal:slowdown_below_layer_time - setting:id$0:width$4:max_speed_reduction - setting:id$0:width$4:min_print_speed + setting:label$Layer time goal:slowdown_below_layer_time + setting:width$4:max_speed_reduction + setting:width$4:min_print_speed group:Behavior cooling_description page:Multimaterial:funnel group:Multimaterial toolchange temperature - setting:id$0:filament_enable_toolchange_temp - setting:id$0:filament_toolchange_temp - setting:id$0:filament_use_fast_skinnydip - setting:id$0:filament_enable_toolchange_part_fan - setting:id$0:filament_toolchange_part_fan_speed + setting:filament_enable_toolchange_temp + setting:filament_toolchange_temp + setting:filament_use_fast_skinnydip + setting:filament_enable_toolchange_part_fan + setting:filament_toolchange_part_fan_speed group:Multimaterial toolchange string reduction - setting:id$0:filament_use_skinnydip - setting:id$0:filament_skinnydip_distance - setting:id$0:filament_melt_zone_pause - setting:id$0:filament_cooling_zone_pause - setting:id$0:filament_dip_insertion_speed - setting:id$0:filament_dip_extraction_speed + setting:filament_use_skinnydip + setting:filament_skinnydip_distance + setting:filament_melt_zone_pause + setting:filament_cooling_zone_pause + setting:filament_dip_insertion_speed + setting:filament_dip_extraction_speed group:Wipe tower parameters - setting:id$0:filament_minimal_purge_on_wipe_tower - setting:id$0:filament_max_wipe_tower_speed + setting:filament_minimal_purge_on_wipe_tower + setting:filament_max_wipe_tower_speed group:Toolchange parameters with single extruder MM printers - setting:id$0:filament_loading_speed_start - setting:id$0:filament_loading_speed - setting:id$0:filament_unloading_speed_start - setting:id$0:filament_unloading_speed - setting:id$0:filament_load_time - setting:id$0:filament_unload_time - setting:id$0:filament_toolchange_delay - setting:id$0:filament_cooling_moves - setting:id$0:filament_cooling_initial_speed - setting:id$0:filament_cooling_final_speed - setting:id$0:filament_wipe_advanced_pigment + setting:filament_loading_speed_start + setting:filament_loading_speed + setting:filament_unloading_speed_start + setting:filament_unloading_speed + setting:filament_load_time + setting:filament_unload_time + setting:filament_toolchange_delay + setting:filament_cooling_moves + setting:filament_cooling_initial_speed + setting:filament_cooling_final_speed + setting:filament_wipe_advanced_pigment filament_ramming_parameters @@ -99,20 +99,20 @@ filament_overrides_page page:Custom G-code:cog group:no_title:validate_gcode:Start G-code - setting:id$0:full_width:height$35:start_filament_gcode + setting:full_width:height$35:start_filament_gcode group:no_title:validate_gcode:End G-code - setting:id$0:full_width:height$35:end_filament_gcode + setting:full_width:height$35:end_filament_gcode page:Notes:note.png group:label_width$0:Notes - setting:id$0:full_width:height$25:filament_notes + setting:full_width:height$25:filament_notes group:label_width$0:Custom variables - setting:id$0:full_width:height$15:filament_custom_variables + setting:full_width:height$15:filament_custom_variables page:Dependencies:wrench.png group:Profile dependencies - setting:id$0:compatible_printers - setting:id$0:full_width:color:compatible_printers_condition - setting:id$0:compatible_prints - setting:id$0:full_width:color:compatible_prints_condition + setting:compatible_printers + setting:full_width:color:compatible_printers_condition + setting:compatible_prints + setting:full_width:color:compatible_prints_condition parent_preset_description diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 7eedfd923dd..5b875bbc751 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -237,8 +237,8 @@ int CLI::run(int argc, char **argv) // The default bed shape should reflect the default display parameters // and not the fff defaults. - double w = sla_print_config.display_width.get_float(); - double h = sla_print_config.display_height.get_float(); + double w = sla_print_config.display_width.getFloat(); + double h = sla_print_config.display_height.getFloat(); sla_print_config.bed_shape.values = { Vec2d(0, 0), Vec2d(w, 0), Vec2d(w, h), Vec2d(0, h) }; sla_print_config.apply(m_print_config, true); diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 19ed3c2001c..c603e316a1e 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -320,7 +320,7 @@ ConfigOption* ConfigOptionDef::create_default_option() const if (this->default_value) return (this->default_value->type() == coEnum) ? // Special case: For a DynamicConfig, convert a templated enum to a generic enum. - new ConfigOptionEnumGeneric(this->enum_keys_map, this->default_value->get_int()) : + new ConfigOptionEnumGeneric(this->enum_keys_map, this->default_value->getInt()) : this->default_value->clone(); return this->create_empty_option(); } @@ -781,12 +781,12 @@ double ConfigBase::get_computed_value(const t_config_option_key &opt_key, int ex if (extruder_id < 0) { const ConfigOption* opt_extruder_id = nullptr; if ((opt_extruder_id = this->option("extruder")) == nullptr) - if ((opt_extruder_id = this->option("current_extruder")) == nullptr || - opt_extruder_id->get_int() < 0 || opt_extruder_id->get_int() >= vector_opt->size()) { + if ((opt_extruder_id = this->option("current_extruder")) == nullptr + || opt_extruder_id->getInt() < 0 || opt_extruder_id->getInt() >= vector_opt->size()) { std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " need to has the extuder id to get the right value, but it's not available"; throw ConfigurationError(ss.str()); } - extruder_id = opt_extruder_id->get_int(); + extruder_id = opt_extruder_id->getInt(); idx = extruder_id; } } else { @@ -797,7 +797,7 @@ double ConfigBase::get_computed_value(const t_config_option_key &opt_key, int ex } if (idx >= 0) { if (raw_opt->type() == coFloats || raw_opt->type() == coInts || raw_opt->type() == coBools) - return vector_opt->get_float(idx); + return vector_opt->getFloat(idx); if (raw_opt->type() == coFloatsOrPercents) { const ConfigOptionFloatsOrPercents* opt_fl_per = static_cast(raw_opt); if (!opt_fl_per->values[idx].percent) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index e4e79328778..e046e49cfe2 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -81,7 +81,6 @@ extern bool unescape_strings_cstyle(const std::string &str, std::vector< extern std::string escape_ampersand(const std::string& str); -constexpr char NIL_STR_VALUE[] = "nil"; enum class OptionCategory : int { @@ -396,12 +395,11 @@ class ConfigOption { virtual ConfigOption* clone() const = 0; // Set a value from a ConfigOption. The two options should be compatible. virtual void set(const ConfigOption *option) = 0; - virtual int32_t get_int(int idx = 0) const { throw BadOptionTypeException("Calling ConfigOption::get_int on a non-int ConfigOption"); } - virtual double get_float(int idx = 0) const { throw BadOptionTypeException("Calling ConfigOption::get_float on a non-float ConfigOption"); } - virtual bool get_bool(int idx = 0) const { throw BadOptionTypeException("Calling ConfigOption::get_bool on a non-boolean ConfigOption"); } - virtual void set_enum_int(int32_t /* val */) { throw BadOptionTypeException("Calling ConfigOption::set_enum_int on a non-enum ConfigOption"); } - virtual boost::any get_any(int idx = 0) const { throw BadOptionTypeException("Calling ConfigOption::get_any on a raw ConfigOption"); } - virtual void set_any(boost::any, int idx = -1) { throw BadOptionTypeException("Calling ConfigOption::set_any on a raw ConfigOption"); } + virtual int32_t getInt() const { throw BadOptionTypeException("Calling ConfigOption::getInt on a non-int ConfigOption"); } + virtual double getFloat() const { throw BadOptionTypeException("Calling ConfigOption::getFloat on a non-float ConfigOption"); } + virtual bool getBool() const { throw BadOptionTypeException("Calling ConfigOption::getBool on a non-boolean ConfigOption"); } + virtual void setInt(int32_t /* val */) { throw BadOptionTypeException("Calling ConfigOption::setInt on a non-int ConfigOption"); } + virtual boost::any getAny() const { throw BadOptionTypeException("Calling ConfigOption::getBool on a non-boolean ConfigOption"); } virtual bool operator==(const ConfigOption &rhs) const = 0; bool operator!=(const ConfigOption &rhs) const { return ! (*this == rhs); } virtual size_t hash() const throw() = 0; @@ -409,8 +407,8 @@ class ConfigOption { bool is_vector() const { return ! this->is_scalar(); } // If this option is nullable, then it may have its value or values set to nil. virtual bool nullable() const { return false; } - // A scalar is nil, or all values of a vector are nil if idx < 0. - virtual bool is_nil(int idx = -1) const { return false; } + // A scalar is nil, or all values of a vector are nil. + virtual bool is_nil() const { return false; } bool is_phony() const { return (flags & FCO_PHONY) != 0; } void set_phony(bool phony) { if (phony) this->flags |= FCO_PHONY; else this->flags &= uint8_t(0xFF ^ FCO_PHONY); } // Is this option overridden by another option? @@ -442,8 +440,7 @@ class ConfigOptionSingle : public ConfigOption { explicit ConfigOptionSingle(T value) : value(value) {} explicit ConfigOptionSingle(T value, bool phony) : ConfigOption(phony), value(value) {} operator T() const { return this->value; } - boost::any get_any(int idx = 0) const override { return boost::any(value); } - void set_any(boost::any anyval, int idx = -1) override { value = boost::any_cast(anyval); } + virtual boost::any getAny() const { return boost::any(value); } void set(const ConfigOption *rhs) override { @@ -490,25 +487,25 @@ class ConfigOptionVectorBase : public ConfigOption { virtual void resize(size_t n, const ConfigOption *opt_default = nullptr) = 0; // Clear the values vector. virtual void clear() = 0; - // get the stored default value for filling empty vector. - // If you use it, double check if you shouldn't instead use the ConfigOptionDef.defaultvalue, which is the default value of a setting. - // currently, it's used to try to have a meaningful value for a Field if the default value is Nil (and to avoid cloning the option, clear it, asking for an item) - virtual boost::any get_default_value() const = 0; // Get size of this vector. virtual size_t size() const = 0; // Is this vector empty? virtual bool empty() const = 0; + // Is the value nil? That should only be possible if this->nullable(). + virtual bool is_nil(size_t idx) const = 0; // Get if the size of this vector is/should be the same as nozzle_diameter bool is_extruder_size() const { return (flags & FCO_EXTRUDER_ARRAY) != 0; } ConfigOptionVectorBase* set_is_extruder_size(bool is_extruder_size) { if (is_extruder_size) this->flags |= FCO_EXTRUDER_ARRAY; else this->flags &= uint8_t(0xFF ^ FCO_EXTRUDER_ARRAY); return this; } + virtual double getFloat(int idx) const { throw BadOptionTypeException("Calling ConfigOption::getFloat(idx) on a non-numeric arrray ConfigOptionVectorBase"); } // We just overloaded and hid two base class virtual methods. // Let's show it was intentional (warnings). using ConfigOption::set; + using ConfigOption::is_nil; protected: @@ -517,28 +514,18 @@ class ConfigOptionVectorBase : public ConfigOption { }; // Value of a vector valued option (bools, ints, floats, strings, points), template -template class ConfigOptionVector : public ConfigOptionVectorBase +template +class ConfigOptionVector : public ConfigOptionVectorBase { -private: - void set_default_from_values() { - assert(!values.empty()); - if (!values.empty()) - default_value = values.front(); - } - -protected: - // this default is used to fill this vector when resized. It's not the default of a setting, for it please use the - // ConfigOptionDef. - T default_value; public: - std::vector values; - ConfigOptionVector() {} explicit ConfigOptionVector(const T& default_val) : default_value(default_val) {} - explicit ConfigOptionVector(size_t n, const T &value) : values(n, value), default_value(value) {} - explicit ConfigOptionVector(std::initializer_list il) : values(std::move(il)) { set_default_from_values(); } - explicit ConfigOptionVector(const std::vector &values) : values(values) { set_default_from_values(); } - explicit ConfigOptionVector(std::vector &&values) : values(std::move(values)) { set_default_from_values(); } + explicit ConfigOptionVector(size_t n, const T& value) : values(n, value) {} + explicit ConfigOptionVector(std::initializer_list il) : values(std::move(il)) {} + explicit ConfigOptionVector(const std::vector &values) : values(values) {} + explicit ConfigOptionVector(std::vector &&values) : values(std::move(values)) {} + std::vector values; + T default_value; void set(const ConfigOption *rhs) override { @@ -574,10 +561,12 @@ template class ConfigOptionVector : public ConfigOptionVectorBase // This function is useful to split values from multiple extrder / filament settings into separate configurations. void set_at(const ConfigOption *rhs, size_t i, size_t j) override { - // Fill with default value up to the needed position + // It is expected that the vector value has at least one value, which is the default, if not overwritten. + assert(! this->values.empty()); if (this->values.size() <= i) { // Resize this vector, fill in the new vector fields with the copy of the first field. - this->values.resize(i + 1, this->default_value); + T v = this->values.front(); + this->values.resize(i + 1, v); } if (rhs->type() == this->type()) { // Assign the first value of the rhs vector. @@ -592,10 +581,12 @@ template class ConfigOptionVector : public ConfigOptionVectorBase } void set_at(T val, size_t i) { - // Fill with default value up to the needed position + // It is expected that the vector value has at least one value, which is the default, if not overwritten. + assert(!this->values.empty()); if (this->values.size() <= i) { // Resize this vector, fill in the new vector fields with the copy of the first field. - this->values.resize(i + 1, this->default_value); + T v = this->values.front(); + this->values.resize(i + 1, v); } this->values[i] = val; } @@ -607,22 +598,15 @@ template class ConfigOptionVector : public ConfigOptionVectorBase } T& get_at(size_t i) { return const_cast(std::as_const(*this).get_at(i)); } - boost::any get_any(int idx) const override { return idx < 0 ? boost::any(values) : boost::any(get_at(idx)); } - void set_any(boost::any anyval, int idx = -1) override - { - if (idx < 0) - values = boost::any_cast>(anyval); - else - set_at(boost::any_cast(anyval), idx); - } + virtual boost::any getAny() const { return boost::any(values); } - // Resize this vector by duplicating the /*last*/first or default value. + // Resize this vector by duplicating the /*last*/first value. // If the current vector is empty, the default value is used instead. void resize(size_t n, const ConfigOption *opt_default = nullptr) override { assert(opt_default == nullptr || opt_default->is_vector()); // assert(opt_default == nullptr || dynamic_cast>(opt_default)); - // assert(! this->values.empty() || opt_default != nullptr); + assert(! this->values.empty() || opt_default != nullptr); if (n == 0) this->values.clear(); else if (n < this->values.size()) @@ -633,12 +617,12 @@ template class ConfigOptionVector : public ConfigOptionVectorBase this->values.resize(n, this->default_value); if (opt_default->type() != this->type()) throw ConfigurationError("ConfigOptionVector::resize(): Extending with an incompatible type."); - if(auto other = static_cast*>(opt_default); other->values.empty()) - this->values.resize(n, other->default_value); + if(static_cast*>(opt_default)->values.empty()) + this->values.resize(n, this->default_value); else - this->values.resize(n, other->values.front()); + this->values.resize(n, static_cast*>(opt_default)->values.front()); } else { - // Resize by duplicating the /*last*/first value. + // Resize by duplicating the last value. this->values.resize(n, this->values./*back*/front()); } } @@ -648,10 +632,6 @@ template class ConfigOptionVector : public ConfigOptionVectorBase void clear() override { this->values.clear(); } size_t size() const override { return this->values.size(); } bool empty() const override { return this->values.empty(); } - // get the stored default value for filling empty vector. - // If you use it, double check if you shouldn't instead use the ConfigOptionDef.defaultvalue, which is the default value of a setting. - // currently, it's used to try to have a meaningful value for a Field if the default value is Nil - boost::any get_default_value() const override { return boost::any(default_value); } bool operator==(const ConfigOption &rhs) const override { @@ -718,7 +698,10 @@ template class ConfigOptionVector : public ConfigOptionVectorBase } for (; i < rhs_vec->size(); ++ i) if (! rhs_vec->is_nil(i)) { - this->values.resize(i + 1, this->default_value); + if (this->values.empty()) + this->values.resize(i + 1); + else + this->values.resize(i + 1, this->values.front()); this->values[i] = rhs_vec->values[i]; modified = true; } @@ -739,7 +722,7 @@ class ConfigOptionFloat : public ConfigOptionSingle static ConfigOptionType static_type() { return coFloat; } ConfigOptionType type() const override { return static_type(); } - double get_float(int idx = 0) const override { return this->value; } + double getFloat() const override { return this->value; } ConfigOption* clone() const override { return new ConfigOptionFloat(*this); } bool operator==(const ConfigOptionFloat &rhs) const throw() { return this->value == rhs.value; } bool operator< (const ConfigOptionFloat &rhs) const throw() { return this->value < rhs.value; } @@ -794,38 +777,19 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector } // Could a special "nil" value be stored inside the vector, indicating undefined value? bool nullable() const override { return NULLABLE; } - double get_float(int idx = 0) const override { return get_at(idx); } - - bool is_nil(int idx = 0) const override - { - if (idx < 0) { - for (double v : this->values) - if (!std::isnan(v) && v != NIL_VALUE()) - return false; - return true; - } else { - return idx < values.size() ? (std::isnan(this->values[idx]) || NIL_VALUE() == this->values[idx]) : - values.empty() ? (std::isnan(this->default_value) || NIL_VALUE() == this->default_value) : - (std::isnan(this->values.front()) || NIL_VALUE() == this->values.front()); - } - } - - static inline bool is_nil(const boost::any &to_check) - { - return std::isnan(boost::any_cast(to_check)) || boost::any_cast(to_check) == NIL_VALUE(); - } - // don't use it to compare, use is_nil() to check. - static inline boost::any create_nil() - { - return boost::any(NIL_VALUE()); - } + // Special "nil" value to be stored into the vector if this->supports_nil(). + static double nil_value() { return std::numeric_limits::quiet_NaN(); } + // A scalar is nil, or all values of a vector are nil. + bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; } + bool is_nil(size_t idx) const override { return idx < values.size() ? std::isnan(this->values[idx]) : values.empty() ? std::isnan(this->default_value) : std::isnan(this->values.front()); } + virtual double getFloat(int idx) const override { return values[idx]; } std::string serialize() const override { std::ostringstream ss; for (const double &v : this->values) { if (&v != &this->values.front()) - ss << ","; + ss << ","; serialize_single_value(ss, v); } return ss.str(); @@ -851,9 +815,9 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector std::string item_str; while (std::getline(is, item_str, ',')) { boost::trim(item_str); - if (item_str == NIL_STR_VALUE) { + if (item_str == "nil") { if (NULLABLE) - this->values.push_back(NIL_VALUE()); + this->values.push_back(nil_value()); else throw ConfigurationError("Deserializing nil into a non-nullable object"); } else { @@ -873,16 +837,12 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector } protected: - // Special "nil" value to be stored into the vector if this->supports_nil(). - // try to not use nan. It's a weird value, and other types don't use it. - static double NIL_VALUE() { return std::numeric_limits::quiet_NaN(); } // std::numeric_limits::max(); } - void serialize_single_value(std::ostringstream &ss, const double v) const { if (std::isfinite(v)) ss << v; - else if (std::isnan(v) || v == NIL_VALUE()) { + else if (std::isnan(v)) { if (NULLABLE) - ss << NIL_STR_VALUE; + ss << "nil"; else throw ConfigurationError("Serializing NaN"); } else @@ -893,8 +853,7 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector if (v1.size() != v2.size()) return false; for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++ it1, ++ it2) - if (!(((std::isnan(*it1) || *it1 == NIL_VALUE()) && (std::isnan(*it2) || *it2 == NIL_VALUE())) || - *it1 == *it2)) + if (! ((std::isnan(*it1) && std::isnan(*it2)) || *it1 == *it2)) return false; return true; } else @@ -904,8 +863,8 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector static bool vectors_lower(const std::vector &v1, const std::vector &v2) { if (NULLABLE) { for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++ it1, ++ it2) { - auto null1 = int(std::isnan(*it1) || *it1 == NIL_VALUE()); - auto null2 = int(std::isnan(*it2) || *it2 == NIL_VALUE()); + auto null1 = int(std::isnan(*it1)); + auto null2 = int(std::isnan(*it2)); return (null1 < null2) || (null1 == null2 && *it1 < *it2); } return v1.size() < v2.size(); @@ -931,8 +890,8 @@ class ConfigOptionInt : public ConfigOptionSingle static ConfigOptionType static_type() { return coInt; } ConfigOptionType type() const override { return static_type(); } - int32_t get_int(int idx = 0) const override { return this->value; } - double get_float(int idx = 0) const override { return this->value; } + int32_t getInt() const override { return this->value; } + void setInt(int32_t val) override { this->value = val; } ConfigOption* clone() const override { return new ConfigOptionInt(*this); } bool operator==(const ConfigOptionInt &rhs) const throw() { return this->value == rhs.value; } @@ -980,25 +939,13 @@ class ConfigOptionIntsTempl : public ConfigOptionVector bool operator==(const ConfigOptionIntsTempl &rhs) const throw() { return this->values == rhs.values; } bool operator< (const ConfigOptionIntsTempl &rhs) const throw() { return this->values < rhs.values; } // Could a special "nil" value be stored inside the vector, indicating undefined value? - bool nullable() const override { return NULLABLE; } + bool nullable() const override { return NULLABLE; } // Special "nil" value to be stored into the vector if this->supports_nil(). - static int32_t NIL_VALUE() { return std::numeric_limits::max(); } - int32_t get_int(int idx= 0) const override { return get_at(idx); } - double get_float(int idx = 0) const override { return get_at(idx); } - - bool is_nil(int idx = 0) const override - { - if (idx < 0) { - for (int32_t v : this->values) - if (v != NIL_VALUE()) - return false; - return true; - } else { - return idx < values.size() ? NIL_VALUE() == this->values[idx] : - values.empty() ? NIL_VALUE() == this->default_value : - NIL_VALUE() == this->values.front(); - } - } + static int32_t nil_value() { return std::numeric_limits::max(); } + // A scalar is nil, or all values of a vector are nil. + bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } + bool is_nil(size_t idx) const override { return idx < values.size() ? this->values[idx] == nil_value() : values.empty() ? this->default_value == nil_value() : this->values.front() == nil_value(); } + virtual double getFloat(int idx) const override { return values[idx]; } std::string serialize() const override { @@ -1031,9 +978,9 @@ class ConfigOptionIntsTempl : public ConfigOptionVector std::string item_str; while (std::getline(is, item_str, ',')) { boost::trim(item_str); - if (item_str == NIL_STR_VALUE) { + if (item_str == "nil") { if (NULLABLE) - this->values.push_back(NIL_VALUE()); + this->values.push_back(nil_value()); else throw ConfigurationError("Deserializing nil into a non-nullable object"); } else { @@ -1048,9 +995,9 @@ class ConfigOptionIntsTempl : public ConfigOptionVector private: void serialize_single_value(std::ostringstream &ss, const int32_t v) const { - if (v == NIL_VALUE()) { + if (v == nil_value()) { if (NULLABLE) - ss << NIL_STR_VALUE; + ss << "nil"; else throw ConfigurationError("Serializing NaN"); } else @@ -1111,7 +1058,7 @@ class ConfigOptionStrings : public ConfigOptionVector ConfigOptionStrings& operator=(const ConfigOption *opt) { this->set(opt); return *this; } bool operator==(const ConfigOptionStrings &rhs) const throw() { return this->values == rhs.values; } bool operator< (const ConfigOptionStrings &rhs) const throw() { return this->values < rhs.values; } - bool is_nil(int) const override { return false; } + bool is_nil(size_t) const override { return false; } std::string serialize() const override { @@ -1200,7 +1147,7 @@ class ConfigOptionPercentsTempl : public ConfigOptionFloatsTempl if (&v != &this->values.front()) ss << ","; this->serialize_single_value(ss, v); - if (! (std::isnan(v) || v == NIL_VALUE())) + if (! std::isnan(v)) ss << "%"; } std::string str = ss.str(); @@ -1214,7 +1161,7 @@ class ConfigOptionPercentsTempl : public ConfigOptionFloatsTempl for (const double v : this->values) { std::ostringstream ss; this->serialize_single_value(ss, v); - if (! (std::isnan(v) || v == NIL_VALUE())) + if (! std::isnan(v)) ss << "%"; vv.push_back(ss.str()); } @@ -1244,39 +1191,22 @@ class ConfigOptionFloatOrPercent : public ConfigOptionPercent ConfigOptionType type() const override { return static_type(); } ConfigOption* clone() const override { return new ConfigOptionFloatOrPercent(*this); } ConfigOptionFloatOrPercent& operator=(const ConfigOption* opt) { this->set(opt); return *this; } - bool operator==(const ConfigOption &rhs) const override + bool operator==(const ConfigOption &rhs) const override { if (rhs.type() != this->type()) throw ConfigurationError("ConfigOptionFloatOrPercent: Comparing incompatible types"); - assert(dynamic_cast(&rhs)); - return *this == *static_cast(&rhs); - } - bool operator==(const ConfigOptionFloatOrPercent &rhs) const throw() - { - return this->value == rhs.value && this->percent == rhs.percent; - } - size_t hash() const throw() override - { - size_t seed = std::hash{}(this->value); - return this->percent ? seed ^ 0x9e3779b9 : seed; - } - bool operator<(const ConfigOptionFloatOrPercent &rhs) const throw() - { - return this->value < rhs.value || (this->value == rhs.value && int(this->percent) < int(rhs.percent)); + assert(dynamic_cast(&rhs)); + return *this == *static_cast(&rhs); } + bool operator==(const ConfigOptionFloatOrPercent &rhs) const throw() + { return this->value == rhs.value && this->percent == rhs.percent; } + size_t hash() const throw() override + { size_t seed = std::hash{}(this->value); return this->percent ? seed ^ 0x9e3779b9 : seed; } + bool operator< (const ConfigOptionFloatOrPercent &rhs) const throw() + { return this->value < rhs.value || (this->value == rhs.value && int(this->percent) < int(rhs.percent)); } - double get_abs_value(double ratio_over) const - { - return this->percent ? (ratio_over * this->value / 100) : this->value; - } - // special case for get/set any: use a FloatOrPercent like for FloatsOrPercents, to have the is_percent - boost::any get_any(int idx = 0) const override { return boost::any(FloatOrPercent{value, percent}); } - void set_any(boost::any anyval, int idx = -1) override - { - auto fl_or_per = boost::any_cast(anyval); - this->value = fl_or_per.value; - this->percent = fl_or_per.percent; - } + double get_abs_value(double ratio_over) const + { return this->percent ? (ratio_over * this->value / 100) : this->value; } void set(const ConfigOption *rhs) override { if (rhs->type() != this->type()) @@ -1334,7 +1264,10 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVectorsupports_nil(). - static FloatOrPercent NIL_VALUE() { return FloatOrPercent{ std::numeric_limits::max(), false }; } + static FloatOrPercent nil_value() { return { std::numeric_limits::quiet_NaN(), false }; } + // A scalar is nil, or all values of a vector are nil. + bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v.value)) return false; return true; } + bool is_nil(size_t idx) const override { return idx < values.size() ? std::isnan(this->values[idx].value) : values.empty() ? std::isnan(this->default_value.value) : std::isnan(this->values.front().value); } double get_abs_value(size_t i, double ratio_over) const { if (this->is_nil(i)) return 0; const FloatOrPercent& data = this->get_at(i); @@ -1342,20 +1275,6 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVectorvalues) - if (v != NIL_VALUE()) - return false; - return true; - } else { - return idx < values.size() ? NIL_VALUE() == this->values[idx] : - values.empty() ? NIL_VALUE() == this->default_value : - NIL_VALUE() == this->values.front(); - } - } - std::string serialize() const override { std::ostringstream ss; @@ -1387,9 +1306,9 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVectorvalues.push_back(NIL_VALUE()); + this->values.push_back(nil_value()); else throw ConfigurationError("Deserializing nil into a non-nullable object"); } else { @@ -1415,9 +1334,9 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVectorvalue) || it1->value == NIL_VALUE().value) && - (std::isnan(it2->value) || it2->value == NIL_VALUE().value)) || - *it1 == *it2)) + if (! ((std::isnan(it1->value) && std::isnan(it2->value)) || *it1 == *it2)) return false; return true; } else @@ -1440,8 +1357,8 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector &v1, const std::vector &v2) { if (NULLABLE) { for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++ it1, ++ it2) { - auto null1 = int(std::isnan(it1->value) || it1->value == NIL_VALUE().value); - auto null2 = int(std::isnan(it2->value) || it2->value == NIL_VALUE().value); + auto null1 = int(std::isnan(it1->value)); + auto null2 = int(std::isnan(it2->value)); return (null1 < null2) || (null1 == null2 && *it1 < *it2); } return v1.size() < v2.size(); @@ -1523,7 +1440,7 @@ class ConfigOptionPoints : public ConfigOptionVector bool operator==(const ConfigOptionPoints &rhs) const throw() { return this->values == rhs.values; } bool operator< (const ConfigOptionPoints &rhs) const throw() { return std::lexicographical_compare(this->values.begin(), this->values.end(), rhs.values.begin(), rhs.values.end(), [](const auto &l, const auto &r){ return l < r; }); } - bool is_nil(int) const override { return false; } + bool is_nil(size_t) const override { return false; } std::string serialize() const override { @@ -1632,9 +1549,7 @@ class ConfigOptionBool : public ConfigOptionSingle static ConfigOptionType static_type() { return coBool; } ConfigOptionType type() const override { return static_type(); } - bool get_bool(int idx = 0) const override { return this->value; } - int32_t get_int(int idx = 0) const override { return this->value?1:0; } - double get_float(int idx = 0) const override { return this->value?1.:0.; } + bool getBool() const override { return this->value; } ConfigOption* clone() const override { return new ConfigOptionBool(*this); } ConfigOptionBool& operator=(const ConfigOption *opt) { this->set(opt); return *this; } bool operator==(const ConfigOptionBool &rhs) const throw() { return this->value == rhs.value; } @@ -1669,7 +1584,6 @@ class ConfigOptionBoolsTempl : public ConfigOptionVector { public: ConfigOptionBoolsTempl() : ConfigOptionVector() {} - explicit ConfigOptionBoolsTempl(bool default_value) : ConfigOptionVector(default_value) {} explicit ConfigOptionBoolsTempl(size_t n, bool value) : ConfigOptionVector(n, (unsigned char)value) {} explicit ConfigOptionBoolsTempl(std::initializer_list il) { values.reserve(il.size()); for (bool b : il) values.emplace_back((unsigned char)b); } explicit ConfigOptionBoolsTempl(std::initializer_list il) { values.reserve(il.size()); for (unsigned char b : il) values.emplace_back(b); } @@ -1685,41 +1599,20 @@ class ConfigOptionBoolsTempl : public ConfigOptionVector // Could a special "nil" value be stored inside the vector, indicating undefined value? bool nullable() const override { return NULLABLE; } // Special "nil" value to be stored into the vector if this->supports_nil(). - static unsigned char NIL_VALUE() { return std::numeric_limits::max(); } - bool get_bool(int idx = 0) const override { return ConfigOptionVector::get_at(idx) != 0; } - int32_t get_int(int idx = 0) const override { return ConfigOptionVector::get_at(idx) != 0 ? 1 : 0; } - double get_float(int idx = 0) const override { return ConfigOptionVector::get_at(idx) != 0 ? 1. : 0.; } - - // I commented it, it shouldn't do anything wrong, as if(uint) == if(uint!=0) - //bool& get_at(size_t i) { - // assert(! this->values.empty()); - // if (this->values.empty()) { - // values.push_back(default_value); - // } - // return *reinterpret_cast(&((i < this->values.size()) ? this->values[i] : this->values.front())); - //} - - //FIXME this smells, the parent class has the method declared returning (unsigned char&). - // I commented it, it shouldn't do anything wrong, as if(uint) == if(uint!=0) - // Please use get_bool(i) - //bool get_at(size_t i) const { - // return ((i < this->values.size()) ? this->values[i] : (this->values.empty() ? default_value != 0 : this->values.front() != 0)); - //} + static unsigned char nil_value() { return std::numeric_limits::max(); } + // A scalar is nil, or all values of a vector are nil. + bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } + bool is_nil(size_t idx) const override { return idx < values.size() ? this->values[idx] == nil_value() : values.empty() ? this->default_value == nil_value() : this->values.front() == nil_value(); } + virtual double getFloat(int idx) const override { return values[idx] ? 1 : 0; } - bool is_nil(int idx = 0) const override - { - if (idx < 0) { - for (uint8_t v : this->values) - if (v != NIL_VALUE()) - return false; - return true; - } else { - return idx < values.size() ? NIL_VALUE() == this->values[idx] : - values.empty() ? NIL_VALUE() == this->default_value : - NIL_VALUE() == this->values.front(); - } + bool& get_at(size_t i) { + assert(! this->values.empty()); + return *reinterpret_cast(&((i < this->values.size()) ? this->values[i] : this->values.front())); } + //FIXME this smells, the parent class has the method declared returning (unsigned char&). + bool get_at(size_t i) const { return ((i < this->values.size()) ? this->values[i] : this->values.front()) != 0; } + std::string serialize() const override { std::ostringstream ss; @@ -1752,9 +1645,9 @@ class ConfigOptionBoolsTempl : public ConfigOptionVector while (std::getline(is, item_str, ',')) { boost::trim(item_str); unsigned char new_value = 0; - if (item_str == NIL_STR_VALUE) { + if (item_str == "nil") { if (NULLABLE) - new_value = NIL_VALUE(); + new_value = nil_value(); else throw ConfigurationError("Deserializing nil into a non-nullable object"); } else if (item_str == "1") { @@ -1778,9 +1671,9 @@ class ConfigOptionBoolsTempl : public ConfigOptionVector protected: void serialize_single_value(std::ostringstream &ss, const unsigned char v) const { - if (v == NIL_VALUE()) { + if (v == nil_value()) { if (NULLABLE) - ss << NIL_STR_VALUE; + ss << "nil"; else throw ConfigurationError("Serializing NaN"); } else @@ -1814,25 +1707,22 @@ class ConfigOptionEnum : public ConfigOptionSingle ConfigOptionEnum& operator=(const ConfigOption *opt) { this->set(opt); return *this; } bool operator==(const ConfigOptionEnum &rhs) const throw() { return this->value == rhs.value; } bool operator< (const ConfigOptionEnum &rhs) const throw() { return int(this->value) < int(rhs.value); } - int32_t get_int(int idx = 0) const override { return (int32_t)this->value; } - void set_enum_int(int32_t val) override { this->value = T(val); } - // special case for get/set any: use a int like for ConfigOptionEnumGeneric, to simplify - boost::any get_any(int idx = 0) const override { return boost::any(get_int(idx)); } - void set_any(boost::any anyval, int idx = -1) override { set_enum_int(boost::any_cast(anyval)); } + int32_t getInt() const override { return (int32_t)this->value; } + void setInt(int val) override { this->value = T(val); } bool operator==(const ConfigOption &rhs) const override { if (rhs.type() != this->type()) throw ConfigurationError("ConfigOptionEnum: Comparing incompatible types"); // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - return this->value == (T)rhs.get_int(); + return this->value == (T)rhs.getInt(); } void set(const ConfigOption *rhs) override { if (rhs->type() != this->type()) throw ConfigurationError("ConfigOptionEnum: Assigning an incompatible type"); // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - this->value = (T)rhs->get_int(); + this->value = (T)rhs->getInt(); this->flags = rhs->flags; } @@ -1896,15 +1786,14 @@ class ConfigOptionEnumGeneric : public ConfigOptionInt if (rhs.type() != this->type()) throw ConfigurationError("ConfigOptionEnumGeneric: Comparing incompatible types"); // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - return this->value == rhs.get_int(); + return this->value == rhs.getInt(); } - void set_enum_int(int32_t val) override { this->value = val; } void set(const ConfigOption *rhs) override { if (rhs->type() != this->type()) throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type"); // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - this->value = rhs->get_int(); + this->value = rhs->getInt(); this->flags = rhs->flags; } @@ -1950,7 +1839,7 @@ class ConfigOptionDef // Static text legend, // Vector value, but edited as a single string. - // one_string, // it's now the default for vector without any idx. If you want to edit the first value, set the idx to 0 + one_string, }; // Identifier of this option. It is stored here so that it is accessible through the by_serialization_key_ordinal map. @@ -2502,7 +2391,6 @@ class DynamicConfig : public virtual ConfigBase // Be careful, as this method does not test the existence of opt_key in this->def(). bool set_key_value(const std::string &opt_key, ConfigOption *opt) { - assert(opt != nullptr); auto it = this->options.find(opt_key); if (it == this->options.end()) { this->options[opt_key].reset(opt); @@ -2535,15 +2423,10 @@ class DynamicConfig : public virtual ConfigBase int32_t& opt_int(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } int32_t opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } - // no dynamic_cast - bool get_bool(const t_config_option_key &opt_key, size_t idx = 0) const {return this->option(opt_key)->get_bool(idx);} - int32_t get_int(const t_config_option_key &opt_key, size_t idx = 0) const {return this->option(opt_key)->get_int(idx);} - double get_float(const t_config_option_key &opt_key, size_t idx = 0) const {return this->option(opt_key)->get_float(idx);} - // In ConfigManipulation::toggle_print_fff_options, it is called on option with type ConfigOptionEnumGeneric* and also ConfigOptionEnum*. - // Thus the virtual method get_int() is used to retrieve the enum value. + // Thus the virtual method getInt() is used to retrieve the enum value. template - ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast(this->option(opt_key)->get_int()); } + ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast(this->option(opt_key)->getInt()); } bool opt_bool(const t_config_option_key &opt_key) const { return this->option(opt_key)->value != 0; } bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option(opt_key)->get_at(idx) != 0; } @@ -2581,5 +2464,4 @@ class StaticConfig : public virtual ConfigBase } - #endif diff --git a/src/libslic3r/Extruder.cpp b/src/libslic3r/Extruder.cpp index ca156d5b8f5..76b624e4334 100644 --- a/src/libslic3r/Extruder.cpp +++ b/src/libslic3r/Extruder.cpp @@ -31,8 +31,6 @@ Mill::Mill(uint16_t mill_id, GCodeConfig* config) : double Tool::extrude(double dE) { - assert(dE < std::numeric_limits::max()); - assert(dE > -std::numeric_limits::max()); // in case of relative E distances we always reset to 0 before any output if (m_config->use_relative_e_distances) m_E = 0.; @@ -50,14 +48,8 @@ double Tool::extrude(double dE) The restart_extra argument sets the extra length to be used for unretraction. If we're actually performing a retraction, any restart_extra value supplied will overwrite the previous one if any. */ -double Tool::retract(double length, std::optional restart_extra, std::optional restart_extra_toolchange) -{ - assert(length < std::numeric_limits::max()); - assert(length > 0); - assert(!restart_extra || *restart_extra < std::numeric_limits::max()); - assert(!restart_extra || *restart_extra > -std::numeric_limits::max()); - assert(!restart_extra_toolchange || *restart_extra_toolchange < std::numeric_limits::max()); - assert(!restart_extra_toolchange || *restart_extra_toolchange > -std::numeric_limits::max()); +double Tool::retract(double length, double restart_extra, double restart_extra_toolchange) +{ // in case of relative E distances we always reset to 0 before any output if (m_config->use_relative_e_distances) m_E = 0.; @@ -66,11 +58,11 @@ double Tool::retract(double length, std::optional restart_extra, std::op m_E -= to_retract; m_absolute_E -= to_retract; m_retracted += to_retract; - if(restart_extra) - m_restart_extra = *restart_extra; + if(!std::isnan(restart_extra)) + m_restart_extra = restart_extra; } - if (restart_extra_toolchange) - m_restart_extra_toolchange = *restart_extra_toolchange; + if (!std::isnan(restart_extra_toolchange)) + m_restart_extra_toolchange = restart_extra_toolchange; return to_retract; } @@ -212,19 +204,11 @@ double Extruder::retract_before_wipe() const double Extruder::retract_length() const { - assert(!m_config->retract_length.is_nil()); - assert(m_config->retract_length.get_at(m_id) < std::numeric_limits::max()); - assert(m_config->retract_length.get_at(m_id) > -std::numeric_limits::max()); - assert(m_config->retract_length.values.size() > m_id); return m_config->retract_length.get_at(m_id); } double Extruder::retract_lift() const { - assert(!m_config->retract_lift.is_nil()); - assert(m_config->retract_lift.get_at(m_id) < std::numeric_limits::max()); - assert(m_config->retract_lift.get_at(m_id) > -std::numeric_limits::max()); - assert(m_config->retract_lift.values.size() > m_id); return m_config->retract_lift.get_at(m_id); } @@ -241,10 +225,6 @@ int Extruder::deretract_speed() const double Extruder::retract_restart_extra() const { - assert(!m_config->retract_restart_extra.is_nil()); - assert(m_config->retract_restart_extra.get_at(m_id) < std::numeric_limits::max()); - assert(m_config->retract_restart_extra.get_at(m_id) > -std::numeric_limits::max()); - assert(m_config->retract_restart_extra.values.size() > m_id); return m_config->retract_restart_extra.get_at(m_id); } @@ -255,10 +235,6 @@ double Extruder::retract_length_toolchange() const double Extruder::retract_restart_extra_toolchange() const { - assert(!m_config->retract_restart_extra_toolchange.is_nil()); - assert(m_config->retract_restart_extra_toolchange.get_at(m_id) < std::numeric_limits::max()); - assert(m_config->retract_restart_extra_toolchange.get_at(m_id) > -std::numeric_limits::max()); - assert(m_config->retract_restart_extra_toolchange.values.size() > m_id); return m_config->retract_restart_extra_toolchange.get_at(m_id); } diff --git a/src/libslic3r/Extruder.hpp b/src/libslic3r/Extruder.hpp index e4e16d2639e..5e665f856d7 100644 --- a/src/libslic3r/Extruder.hpp +++ b/src/libslic3r/Extruder.hpp @@ -25,7 +25,7 @@ class Tool uint16_t id() const { return m_id; } virtual double extrude(double dE); - virtual double retract(double length, std::optional restart_extra, std::optional restart_extra_from_toolchange); + virtual double retract(double length, double restart_extra, double restart_extra_from_toolchange); virtual double need_unretract(); virtual double unretract(); virtual void reset_retract(); diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 63de0d2d51b..697fcb566a0 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -170,7 +170,7 @@ std::vector group_fills(const Layer &layer) params.pattern = region_config.bridge_fill_pattern.value; params.connection = region_config.infill_connection_bridge.value; } - if (region_config.infill_dense.get_bool() + if (region_config.infill_dense.getBool() && region_config.fill_density < 40 && surface.maxNbSolidLayersOnTop == 1) { params.density = 0.42f; @@ -203,7 +203,7 @@ std::vector group_fills(const Layer &layer) params.role = erSolidInfill; } } - params.fill_exactly = region_config.enforce_full_fill_volume.get_bool(); + params.fill_exactly = region_config.enforce_full_fill_volume.getBool(); params.bridge_angle = float(surface.bridge_angle); params.angle = (is_denser) ? 0 : compute_fill_angle(region_config, layerm.layer()->id()); params.can_angle_cross = region_config.fill_angle_cross; diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index aa9e27e37ab..dcc5464c0a6 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -2945,7 +2945,7 @@ namespace Slic3r { log << "\n"; } if (config.option(opt_key) != nullptr && config.option(opt_key)->type() == ConfigOptionType::coEnum) { - log << "enum : " << config.option(opt_key)->get_int(); + log << "enum : " << config.option(opt_key)->getInt(); log << "\n"; const ConfigOptionDef* def = nullptr; try { @@ -2960,7 +2960,7 @@ namespace Slic3r { } } if (config.option(opt_key) != nullptr && config.option(opt_key)->type() == ConfigOptionType::coInt) { - log << "int : " << config.option(opt_key)->get_int(); + log << "int : " << config.option(opt_key)->getInt(); log << "\n"; } log.close(); @@ -3171,9 +3171,9 @@ namespace Slic3r { } if (obj->config.option(key) != nullptr && obj->config.option(key)->type() == ConfigOptionType::coEnum) { try{ - log << "raw_int_value : " << obj->config.option(key)->get_int() << "\n"; + log << "raw_int_value : " << obj->config.option(key)->getInt() << "\n"; } catch (std::exception ex) {} - log << "enum : " << obj->config.option(key)->get_int(); + log << "enum : " << obj->config.option(key)->getInt(); log << "\n"; const ConfigOptionDef* def = nullptr; try { @@ -3188,7 +3188,7 @@ namespace Slic3r { } } if (obj->config.option(key) != nullptr && obj->config.option(key)->type() == ConfigOptionType::coInt) { - log << "int : " << obj->config.option(key)->get_int(); + log << "int : " << obj->config.option(key)->getInt(); log << "\n"; } log.close(); @@ -3279,9 +3279,9 @@ namespace Slic3r { } if (volume->config.option(key) != nullptr && volume->config.option(key)->type() == ConfigOptionType::coEnum) { try{ - log << "raw_int_value : " << volume->config.option(key)->get_int() << "\n"; + log << "raw_int_value : " << volume->config.option(key)->getInt() << "\n"; } catch (std::exception ex) {} - log << "enum : " << volume->config.option(key)->get_int(); + log << "enum : " << volume->config.option(key)->getInt(); log << "\n"; const ConfigOptionDef* def = nullptr; try { @@ -3296,7 +3296,7 @@ namespace Slic3r { } } if (volume->config.option(key) != nullptr && volume->config.option(key)->type() == ConfigOptionType::coInt) { - log << "int : " << volume->config.option(key)->get_int(); + log << "int : " << volume->config.option(key)->getInt(); log << "\n"; } log.close(); diff --git a/src/libslic3r/Format/CWS.cpp b/src/libslic3r/Format/CWS.cpp index 229bd64fa07..395be504402 100644 --- a/src/libslic3r/Format/CWS.cpp +++ b/src/libslic3r/Format/CWS.cpp @@ -60,7 +60,7 @@ void fill_iniconf(ConfMap &m, const SLAPrint &print) double used_material = (stats.objects_used_material + stats.support_used_material) / 1000; - int num_fade = print.default_object_config().faded_layers.get_int(); + int num_fade = print.default_object_config().faded_layers.getInt(); num_fade = num_fade >= 0 ? num_fade : 0; m["usedMaterial"] = std::to_string(used_material); diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp index deb70b25585..1f6b1aa90f0 100644 --- a/src/libslic3r/Format/SL1.cpp +++ b/src/libslic3r/Format/SL1.cpp @@ -232,7 +232,7 @@ SliceParams get_slice_params(const DynamicPrintConfig &cfg) if (!opt_layerh || !opt_init_layerh) throw MissingProfileError("Invalid SL1 / SL1S file"); - return SliceParams{opt_layerh->get_float(), opt_init_layerh->get_float()}; + return SliceParams{opt_layerh->getFloat(), opt_init_layerh->getFloat()}; } std::vector extract_slices_from_sla_archive( @@ -400,7 +400,7 @@ void fill_iniconf(ConfMap &m, const SLAPrint &print) double used_material = (stats.objects_used_material + stats.support_used_material) / 1000; - int num_fade = print.default_object_config().faded_layers.get_int(); + int num_fade = print.default_object_config().faded_layers.getInt(); num_fade = num_fade >= 0 ? num_fade : 0; m["usedMaterial"] = std::to_string(used_material); diff --git a/src/libslic3r/Format/SLAArchive.cpp b/src/libslic3r/Format/SLAArchive.cpp index 337c7f26158..d6b77c41628 100644 --- a/src/libslic3r/Format/SLAArchive.cpp +++ b/src/libslic3r/Format/SLAArchive.cpp @@ -25,15 +25,15 @@ std::unique_ptr SLAAbstractArchive::create_raster() const sla::RasterBase::PixelDim pxdim; std::array mirror; - double w = this->config().display_width.get_float(); - double h = this->config().display_height.get_float(); - auto pw = size_t(this->config().display_pixels_x.get_int()); - auto ph = size_t(this->config().display_pixels_y.get_int()); + double w = this->config().display_width.getFloat(); + double h = this->config().display_height.getFloat(); + auto pw = size_t(this->config().display_pixels_x.getInt()); + auto ph = size_t(this->config().display_pixels_y.getInt()); - mirror[X] = this->config().display_mirror_x.get_bool(); - mirror[Y] = this->config().display_mirror_y.get_bool(); + mirror[X] = this->config().display_mirror_x.getBool(); + mirror[Y] = this->config().display_mirror_y.getBool(); - auto ro = this->config().display_orientation.get_int(); + auto ro = this->config().display_orientation.getInt(); sla::RasterBase::Orientation orientation = ro == sla::RasterBase::roPortrait ? sla::RasterBase::roPortrait : sla::RasterBase::roLandscape; @@ -47,7 +47,7 @@ std::unique_ptr SLAAbstractArchive::create_raster() const pxdim = sla::RasterBase::PixelDim{w / pw, h / ph}; sla::RasterBase::Trafo tr{orientation, mirror}; - double gamma = this->config().gamma_correction.get_float(); + double gamma = this->config().gamma_correction.getFloat(); return sla::create_raster_grayscale_aa(res, pxdim, gamma, tr); } diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index c204563dd9b..dd3fc8909c0 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -637,16 +637,14 @@ std::string GCodeWriter::retract(bool before_wipe) return this->_retract( factor * config_region->print_retract_length, factor * m_tool->retract_restart_extra(), - std::nullopt, + NAN, "retract" ); } - auto rect_length = m_tool->retract_length(); - auto rect_length2 = m_tool->retract_restart_extra(); return this->_retract( factor * m_tool->retract_length(), factor * m_tool->retract_restart_extra(), - std::nullopt, + NAN, "retract" ); } @@ -657,13 +655,13 @@ std::string GCodeWriter::retract_for_toolchange(bool before_wipe) assert(factor >= 0. && factor <= 1. + EPSILON); return this->_retract( factor * m_tool->retract_length_toolchange(), - std::nullopt, + NAN, factor * m_tool->retract_restart_extra_toolchange(), "retract for toolchange" ); } -std::string GCodeWriter::_retract(double length, std::optional restart_extra, std::optional restart_extra_toolchange, const std::string &comment) +std::string GCodeWriter::_retract(double length, double restart_extra, double restart_extra_toolchange, const std::string &comment) { std::ostringstream gcode; @@ -677,17 +675,9 @@ std::string GCodeWriter::_retract(double length, std::optional restart_e if (this->config.use_volumetric_e) { double d = m_tool->filament_diameter(); double area = d * d * PI/4; - assert(length * area < std::numeric_limits::max()); - assert(length * area > 0); - assert(!restart_extra || *restart_extra * area < std::numeric_limits::max()); - assert(!restart_extra || *restart_extra * area > -std::numeric_limits::max()); - assert(!restart_extra_toolchange || *restart_extra_toolchange * area < std::numeric_limits::max()); - assert(!restart_extra_toolchange || *restart_extra_toolchange * area > -std::numeric_limits::max()); length = length * area; - if(restart_extra) - restart_extra = *restart_extra * area; - if(restart_extra_toolchange) - restart_extra_toolchange = *restart_extra_toolchange * area; + restart_extra = restart_extra * area; + restart_extra_toolchange = restart_extra_toolchange * area; } double dE = m_tool->retract(length, restart_extra, restart_extra_toolchange); diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index a4f8d525c2c..7d46974a7e1 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -115,7 +115,7 @@ class GCodeWriter { Vec3d m_pos = Vec3d::Zero(); std::string _travel_to_z(double z, const std::string &comment); - std::string _retract(double length, std::optional restart_extra, std::optional restart_extra_toolchange, const std::string &comment); + std::string _retract(double length, double restart_extra, double restart_extra_toolchange, const std::string &comment); }; diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 798b1710bc7..fd2078787ca 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1752,9 +1752,9 @@ int ModelVolume::extruder_id() const int extruder_id = -1; if (this->is_model_part()) { const ConfigOption *opt = this->config.option("extruder"); - if ((opt == nullptr) || (opt->get_int() == 0)) + if ((opt == nullptr) || (opt->getInt() == 0)) opt = this->object->config.option("extruder"); - extruder_id = (opt == nullptr) ? 0 : opt->get_int(); + extruder_id = (opt == nullptr) ? 0 : opt->getInt(); } return extruder_id; } diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index dc1448cb808..f6a380d1a41 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1691,7 +1691,7 @@ std::vector> multi_material_segmentation_by_painting(con std::vector edge_grids(num_layers); const ConstLayerPtrsAdaptor layers = print_object.layers(); std::vector input_expolygons(num_layers); - coord_t resolution = scale_t(print_object.config().option("resolution")->get_float()); + coord_t resolution = scale_t(print_object.config().option("resolution")->getFloat()); throw_on_cancel_callback(); diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 92c25b503e0..b13d689dba8 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -770,7 +770,7 @@ namespace client if (vector_opt->is_extruder_size()) { if (raw_opt->type() == coFloats || raw_opt->type() == coInts || raw_opt->type() == coBools) - return vector_opt->get_float(int(current_extruder_id)); + return vector_opt->getFloat(int(current_extruder_id)); if (raw_opt->type() == coFloatsOrPercents) { const ConfigOptionFloatsOrPercents* opt_fl_per = static_cast(raw_opt); if (!opt_fl_per->values[current_extruder_id].percent) @@ -869,7 +869,7 @@ namespace client ctx->throw_exception("Variable does not exist", opt_key); if (opt_index->type() != coInt) ctx->throw_exception("Indexing variable has to be integer", opt_key); - int idx = opt_index->get_int(); + int idx = opt_index->getInt(); if (idx < 0) ctx->throw_exception("Negative vector index", opt_key); output = vec->vserialize()[(idx >= (int)vec->size()) ? 0 : idx]; @@ -936,12 +936,12 @@ namespace client } const ConfigOptionDef* opt_def; switch (opt.opt->type()) { - case coFloat: output.set_d(opt.opt->get_float()); break; - case coInt: output.set_i(opt.opt->get_int()); break; + case coFloat: output.set_d(opt.opt->getFloat()); break; + case coInt: output.set_i(opt.opt->getInt()); break; case coString: output.set_s(static_cast(opt.opt)->value); break; - case coPercent: output.set_d(opt.opt->get_float()); break; + case coPercent: output.set_d(opt.opt->getFloat()); break; case coPoint: output.set_s(opt.opt->serialize()); break; - case coBool: output.set_b(opt.opt->get_bool()); break; + case coBool: output.set_b(opt.opt->getBool()); break; case coFloatOrPercent: { if (boost::ends_with(opt_key, "extrusion_width")) { @@ -949,12 +949,12 @@ namespace client output.set_d(Flow::extrusion_width(opt_key, *ctx, static_cast(ctx->current_extruder_id))); } else if (! static_cast(opt.opt)->percent) { // Not a percent, just return the value. - output.set_d(opt.opt->get_float()); + output.set_d(opt.opt->getFloat()); } else { // Resolve dependencies using the "ratio_over" link to a parent value. opt_def = print_config_def.get(opt_key); assert(opt_def != nullptr); - double v = opt.opt->get_float() * 0.01; // percent to ratio + double v = opt.opt->getFloat() * 0.01; // percent to ratio for (;;) { const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over); if (opt_parent == nullptr) @@ -985,7 +985,7 @@ namespace client case coInts: opt_def = print_config_def.get(opt_key); if (opt_def->is_vector_extruder) { - output.set_i(int(((ConfigOptionVectorBase *) opt.opt)->get_float(int(ctx->current_extruder_id)))); + output.set_i(int(((ConfigOptionVectorBase*)opt.opt)->getFloat(int(ctx->current_extruder_id)))); break; } else ctx->throw_exception("Unknown scalar variable type", opt.it_range); @@ -993,7 +993,7 @@ namespace client case coPercents: vector_opt = static_cast(opt.opt); if (vector_opt->is_extruder_size()) { - output.set_d(((ConfigOptionVectorBase *) opt.opt)->get_float(int(ctx->current_extruder_id))); + output.set_d(((ConfigOptionVectorBase*)opt.opt)->getFloat(int(ctx->current_extruder_id))); break; } else ctx->throw_exception("Unknown scalar variable type", opt.it_range); diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 7d577f64f0a..1c62773d053 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -159,7 +159,7 @@ static bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_ const auto &kvp2 = *it2 ++; if (std::abs(kvp1.first.first - kvp2.first.first ) > EPSILON || std::abs(kvp1.first.second - kvp2.first.second) > EPSILON || - (check_layer_height && std::abs(kvp1.second.option("layer_height")->get_float() - kvp2.second.option("layer_height")->get_float()) > EPSILON)) + (check_layer_height && std::abs(kvp1.second.option("layer_height")->getFloat() - kvp2.second.option("layer_height")->getFloat()) > EPSILON)) return false; } return true; diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index 035fc3334a2..e5f299b22ff 100644 --- a/src/libslic3r/PrintBase.cpp +++ b/src/libslic3r/PrintBase.cpp @@ -76,8 +76,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str cfg.set_key_value("input_filename_base", new ConfigOptionString(filename_base)); } try { - uint16_t extruder_initial = config_override->option("initial_extruder") != nullptr && - config_override->option("initial_extruder")->type() == coInt ? config_override->option("initial_extruder")->get_int() : 0; + uint16_t extruder_initial = config_override->option("initial_extruder") != nullptr && config_override->option("initial_extruder")->type() == coInt ? config_override->option("initial_extruder")->getInt() : 0; boost::filesystem::path filepath = format.empty() ? cfg.opt_string("input_filename_base") + default_ext : this->placeholder_parser().process(format, extruder_initial, &cfg); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index d5bbbf7f7fd..4aada338432 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -376,6 +376,7 @@ void PrintConfigDef::init_common_params() def->mode = comExpert | comPrusa; def->min = 0; def->max = 2048; + //def->gui_type = ConfigOptionDef::GUIType::one_string; // i prefer two boxes def->set_default_value(new ConfigOptionPoints{ std::initializer_list{ Vec2d(0,0), Vec2d(0,0) } }); def = this->add("thumbnails_color", coString); @@ -2293,7 +2294,7 @@ void PrintConfigDef::init_fff_params() def->max = 360; def->full_width = true; def->mode = comExpert | comSuSi; - def->set_default_value(new ConfigOptionFloats(0.)); + def->set_default_value(new ConfigOptionFloats{}); def = this->add("fill_density", coPercent); def->gui_type = ConfigOptionDef::GUIType::f_enum_open; @@ -4216,6 +4217,7 @@ void PrintConfigDef::init_fff_params() "and they can access the Slic3r config settings by reading environment variables." "\nThe script, if passed as a relative path, will also be searched from the slic3r directory, " "the slic3r configuration directory and the user directory."); + def->gui_flags = "serialized"; def->multiline = true; def->full_width = true; def->height = 6; @@ -6419,35 +6421,12 @@ void PrintConfigDef::init_fff_params() def->full_label = it_opt->second.full_label; def->tooltip = it_opt->second.tooltip; def->sidetext = it_opt->second.sidetext; - def->mode = it_opt->second.mode; - // create default value with the default value is taken from the default value of the config. - // put a nil value as first entry. + def->mode = it_opt->second.mode; switch (def->type) { - case coBools: { - ConfigOptionBoolsNullable* opt = new ConfigOptionBoolsNullable(it_opt->second.default_value.get()->get_bool()); - opt->values.push_back(ConfigOptionBoolsNullable::NIL_VALUE()); - def->set_default_value(opt); - break; - } - case coFloats: { - ConfigOptionFloatsNullable *opt = new ConfigOptionFloatsNullable(it_opt->second.default_value.get()->get_float()); - opt->values.push_back(ConfigOptionFloatsNullable::NIL_VALUE()); - def->set_default_value(opt); - break; - } - case coPercents: { - ConfigOptionPercentsNullable *opt = new ConfigOptionPercentsNullable(it_opt->second.default_value.get()->get_float()); - opt->values.push_back(ConfigOptionPercentsNullable::NIL_VALUE()); - def->set_default_value(opt); - break; - } - case coFloatsOrPercents: { - ConfigOptionFloatsOrPercentsNullable*opt = new ConfigOptionFloatsOrPercentsNullable( - static_cast(it_opt->second.default_value.get())->get_at(0)); - opt->values.push_back(ConfigOptionFloatsOrPercentsNullable::NIL_VALUE()); - def->set_default_value(opt); - break; - } + case coFloats : def->set_default_value(new ConfigOptionFloatsNullable (static_cast(it_opt->second.default_value.get())->values)); break; + case coPercents : def->set_default_value(new ConfigOptionPercentsNullable(static_cast(it_opt->second.default_value.get())->values)); break; + case coFloatsOrPercents : def->set_default_value(new ConfigOptionFloatsOrPercentsNullable(static_cast(it_opt->second.default_value.get())->values)); break; + case coBools : def->set_default_value(new ConfigOptionBoolsNullable (static_cast(it_opt->second.default_value.get())->values)); break; default: assert(false); } } @@ -7984,7 +7963,7 @@ std::map PrintConfigDef::to_prusa(t_config_option_key& } else if ("monotonicgapfill" == value) { value = "monotonic"; } - if (all_conf.has("fill_angle_increment") && ((int(all_conf.option("fill_angle_increment")->get_float())-90)%180) == 0 && "rectilinear" == value + if (all_conf.has("fill_angle_increment") && ((int(all_conf.option("fill_angle_increment")->getFloat())-90)%180) == 0 && "rectilinear" == value && ("fill_pattern" == opt_key || "top_fill_pattern" == opt_key)) { value = "alignedrectilinear"; } @@ -8147,10 +8126,10 @@ PrinterTechnology printer_technology(const ConfigBase& cfg) if (opt) return opt->value; const ConfigOptionBool* export_opt = cfg.option("export_sla"); - if (export_opt && export_opt->get_bool()) return ptSLA; + if (export_opt && export_opt->getBool()) return ptSLA; export_opt = cfg.option("export_gcode"); - if (export_opt && export_opt->get_bool()) return ptFFF; + if (export_opt && export_opt->getBool()) return ptFFF; return ptUnknown; } @@ -8206,7 +8185,7 @@ double min_object_distance(const ConfigBase *config, double ref_height /* = 0*/) double base_dist = 0; //std::cout << "START min_object_distance =>" << base_dist << "\n"; const ConfigOptionBool* co_opt = config->option("complete_objects"); - if (config->option("parallel_objects_step")->get_float() > 0 || co_opt && co_opt->value) { + if (config->option("parallel_objects_step")->getFloat() > 0 || co_opt && co_opt->value) { double skirt_dist = 0; try { std::vector vals = dynamic_cast(config->option("nozzle_diameter"))->values; @@ -8216,7 +8195,7 @@ double min_object_distance(const ConfigBase *config, double ref_height /* = 0*/) // min object distance is max(duplicate_distance, clearance_radius) // /2 becasue we only count the grawing for the current object //add 1 as safety offset. - double extruder_clearance_radius = config->option("extruder_clearance_radius")->get_float() / 2; + double extruder_clearance_radius = config->option("extruder_clearance_radius")->getFloat() / 2; if (extruder_clearance_radius > base_dist) { base_dist = extruder_clearance_radius; } @@ -8225,15 +8204,15 @@ double min_object_distance(const ConfigBase *config, double ref_height /* = 0*/) //ideally, we should use print::first_layer_height() const double first_layer_height = dynamic_cast(config->option("first_layer_height"))->get_abs_value(max_nozzle_diam); //add the skirt - int skirts = config->option("skirts")->get_int(); + int skirts = config->option("skirts")->getInt(); if (skirts > 0 && ref_height == 0) - skirts += config->option("skirt_brim")->get_int(); - if (skirts > 0 && config->option("skirt_height")->get_int() >= 1 && !config->option("complete_objects_one_skirt")->get_bool()) { + skirts += config->option("skirt_brim")->getInt(); + if (skirts > 0 && config->option("skirt_height")->getInt() >= 1 && !config->option("complete_objects_one_skirt")->getBool()) { float overlap_ratio = 1; //can't know the extruder, so we settle on the worst: 100% //if (config->option("filament_max_overlap")) overlap_ratio = config->get_computed_value("filament_max_overlap"); if (ref_height == 0) { - skirt_dist = config->option("skirt_distance")->get_float(); + skirt_dist = config->option("skirt_distance")->getFloat(); Flow skirt_flow = Flow::new_from_config_width( frPerimeter, *Flow::extrusion_width_option("skirt", *config), @@ -8248,9 +8227,9 @@ double min_object_distance(const ConfigBase *config, double ref_height /* = 0*/) //set to 0 becasue it's incorporated into the base_dist, so we don't want to be added in to it again. skirt_dist = 0; } else { - double skirt_height = ((double)config->option("skirt_height")->get_int() - 1) * config->get_computed_value("layer_height") + first_layer_height; + double skirt_height = ((double)config->option("skirt_height")->getInt() - 1) * config->get_computed_value("layer_height") + first_layer_height; if (ref_height <= skirt_height) { - skirt_dist = config->option("skirt_distance")->get_float(); + skirt_dist = config->option("skirt_distance")->getFloat(); Flow skirt_flow = Flow::new_from_config_width( frPerimeter, *Flow::extrusion_width_option("skirt", *config), @@ -8276,13 +8255,13 @@ double min_object_distance(const ConfigBase *config, double ref_height /* = 0*/) void DynamicPrintConfig::normalize_fdm() { if (this->has("extruder")) { - int extruder = this->option("extruder")->get_int(); + int extruder = this->option("extruder")->getInt(); this->erase("extruder"); if (extruder != 0) { if (!this->has("infill_extruder")) - this->option("infill_extruder", true)->value = (extruder); + this->option("infill_extruder", true)->setInt(extruder); if (!this->has("perimeter_extruder")) - this->option("perimeter_extruder", true)->value = (extruder); + this->option("perimeter_extruder", true)->setInt(extruder); // Don't propagate the current extruder to support. // For non-soluble supports, the default "0" extruder means to use the active extruder, // for soluble supports one certainly does not want to set the extruder to non-soluble. @@ -8296,7 +8275,7 @@ void DynamicPrintConfig::normalize_fdm() this->erase("first_layer_extruder"); if (!this->has("solid_infill_extruder") && this->has("infill_extruder")) - this->option("solid_infill_extruder", true)->value = (this->option("infill_extruder")->get_int()); + this->option("solid_infill_extruder", true)->setInt(this->option("infill_extruder")->getInt()); if (this->has("spiral_vase") && this->opt("spiral_vase", true)->value) { { diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index da8375dd980..4c9e9be0eda 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1297,7 +1297,7 @@ bool PrintObject::invalidate_state_by_config_options( for (const PrintRegion* region : this->m_print->print_regions_mutable()) { //count how many surface there are on each one - if (region->config().infill_dense.get_bool() && region->config().fill_density < 40) { + if (region->config().infill_dense.getBool() && region->config().fill_density < 40) { std::vector layeridx2lregion; std::vector new_surfaces; //surface store, as you can't modify them when working in // // store the LayerRegion on which we are working @@ -2541,12 +2541,12 @@ static constexpr const std::initializer_list keys_extrud // 2) Copy the rest of the values. for (auto it = in.cbegin(); it != in.cend(); ++it) if (it->first != key_extruder) - if (ConfigOptionInt *my_opt = out.option(it->first, false); my_opt != nullptr) { + if (ConfigOption* my_opt = out.option(it->first, false); my_opt != nullptr) { if (one_of(it->first, keys_extruders)) { // Ignore "default" extruders. - int extruder = it->second->get_int(); + int extruder = static_cast(it->second.get())->value; if (extruder > 0) - my_opt->value = (extruder); + my_opt->setInt(extruder); } else my_opt->set(it->second.get()); } diff --git a/src/libslic3r/SLA/Rotfinder.cpp b/src/libslic3r/SLA/Rotfinder.cpp index 042c0fab346..196646dc9ee 100644 --- a/src/libslic3r/SLA/Rotfinder.cpp +++ b/src/libslic3r/SLA/Rotfinder.cpp @@ -195,8 +195,8 @@ XYRotation from_transform3f(const Transform3f &tr) inline bool is_on_floor(const SLAPrintObjectConfig &cfg) { - auto opt_elevation = cfg.support_object_elevation.get_float(); - auto opt_padaround = cfg.pad_around_object.get_bool(); + auto opt_elevation = cfg.support_object_elevation.getFloat(); + auto opt_padaround = cfg.pad_around_object.getBool(); return opt_elevation < EPSILON || opt_padaround; } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index d7b53a4325e..69b80fbf62d 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -30,7 +30,7 @@ namespace Slic3r { bool is_zero_elevation(const SLAPrintObjectConfig &c) { - return c.pad_enable.get_bool() && c.pad_around_object.get_bool(); + return c.pad_enable.getBool() && c.pad_around_object.getBool(); } // Compile the argument for support creation from the static print config. @@ -38,20 +38,20 @@ sla::SupportTreeConfig make_support_cfg(const SLAPrintObjectConfig& c) { sla::SupportTreeConfig scfg; - scfg.enabled = c.supports_enable.get_bool(); - scfg.head_front_radius_mm = 0.5*c.support_head_front_diameter.get_float(); - double pillar_r = 0.5 * c.support_pillar_diameter.get_float(); + scfg.enabled = c.supports_enable.getBool(); + scfg.head_front_radius_mm = 0.5*c.support_head_front_diameter.getFloat(); + double pillar_r = 0.5 * c.support_pillar_diameter.getFloat(); scfg.head_back_radius_mm = pillar_r; scfg.head_fallback_radius_mm = - 0.01 * c.support_small_pillar_diameter_percent.get_float() * pillar_r; - scfg.head_penetration_mm = c.support_head_penetration.get_float(); - scfg.head_width_mm = c.support_head_width.get_float(); + 0.01 * c.support_small_pillar_diameter_percent.getFloat() * pillar_r; + scfg.head_penetration_mm = c.support_head_penetration.getFloat(); + scfg.head_width_mm = c.support_head_width.getFloat(); scfg.object_elevation_mm = is_zero_elevation(c) ? - 0. : c.support_object_elevation.get_float(); - scfg.bridge_slope = c.support_critical_angle.get_float() * PI / 180.0 ; - scfg.max_bridge_length_mm = c.support_max_bridge_length.get_float(); - scfg.max_pillar_link_distance_mm = c.support_max_pillar_link_distance.get_float(); - switch(c.support_pillar_connection_mode.get_int()) { + 0. : c.support_object_elevation.getFloat(); + scfg.bridge_slope = c.support_critical_angle.getFloat() * PI / 180.0 ; + scfg.max_bridge_length_mm = c.support_max_bridge_length.getFloat(); + scfg.max_pillar_link_distance_mm = c.support_max_pillar_link_distance.getFloat(); + switch(c.support_pillar_connection_mode.getInt()) { case slapcmZigZag: scfg.pillar_connection_mode = sla::PillarConnectionMode::zigzag; break; case slapcmCross: @@ -59,15 +59,15 @@ sla::SupportTreeConfig make_support_cfg(const SLAPrintObjectConfig& c) case slapcmDynamic: scfg.pillar_connection_mode = sla::PillarConnectionMode::dynamic; break; } - scfg.ground_facing_only = c.support_buildplate_only.get_bool(); - scfg.pillar_widening_factor = c.support_pillar_widening_factor.get_float(); - scfg.base_radius_mm = 0.5*c.support_base_diameter.get_float(); - scfg.base_height_mm = c.support_base_height.get_float(); + scfg.ground_facing_only = c.support_buildplate_only.getBool(); + scfg.pillar_widening_factor = c.support_pillar_widening_factor.getFloat(); + scfg.base_radius_mm = 0.5*c.support_base_diameter.getFloat(); + scfg.base_height_mm = c.support_base_height.getFloat(); scfg.pillar_base_safety_distance_mm = - c.support_base_safety_distance.get_float() < EPSILON ? - scfg.safety_distance_mm : c.support_base_safety_distance.get_float(); + c.support_base_safety_distance.getFloat() < EPSILON ? + scfg.safety_distance_mm : c.support_base_safety_distance.getFloat(); - scfg.max_bridges_on_pillar = unsigned(c.support_max_bridges_on_pillar.get_int()); + scfg.max_bridges_on_pillar = unsigned(c.support_max_bridges_on_pillar.getInt()); return scfg; } @@ -79,12 +79,12 @@ sla::PadConfig::EmbedObject builtin_pad_cfg(const SLAPrintObjectConfig& c) ret.enabled = is_zero_elevation(c); if(ret.enabled) { - ret.everywhere = c.pad_around_object_everywhere.get_bool(); - ret.object_gap_mm = c.pad_object_gap.get_float(); - ret.stick_width_mm = c.pad_object_connector_width.get_float(); - ret.stick_stride_mm = c.pad_object_connector_stride.get_float(); + ret.everywhere = c.pad_around_object_everywhere.getBool(); + ret.object_gap_mm = c.pad_object_gap.getFloat(); + ret.stick_width_mm = c.pad_object_connector_width.getFloat(); + ret.stick_stride_mm = c.pad_object_connector_stride.getFloat(); ret.stick_penetration_mm = c.pad_object_connector_penetration - .get_float(); + .getFloat(); } return ret; @@ -94,12 +94,12 @@ sla::PadConfig make_pad_cfg(const SLAPrintObjectConfig& c) { sla::PadConfig pcfg; - pcfg.wall_thickness_mm = c.pad_wall_thickness.get_float(); - pcfg.wall_slope = c.pad_wall_slope.get_float() * PI / 180.0; + pcfg.wall_thickness_mm = c.pad_wall_thickness.getFloat(); + pcfg.wall_slope = c.pad_wall_slope.getFloat() * PI / 180.0; - pcfg.max_merge_dist_mm = c.pad_max_merge_distance.get_float(); - pcfg.wall_height_mm = c.pad_wall_height.get_float(); - pcfg.brim_size_mm = c.pad_brim_size.get_float(); + pcfg.max_merge_dist_mm = c.pad_max_merge_distance.getFloat(); + pcfg.wall_height_mm = c.pad_wall_height.getFloat(); + pcfg.brim_size_mm = c.pad_brim_size.getFloat(); // set builtin pad implicitly ON pcfg.embed_object = builtin_pad_cfg(c); @@ -620,7 +620,7 @@ std::pair SLAPrint::validate(std:: for(SLAPrintObject * po : m_objects) { const ModelObject *mo = po->model_object(); - bool supports_en = po->config().supports_enable.get_bool(); + bool supports_en = po->config().supports_enable.getBool(); if(supports_en && mo->sla_points_status == sla::PointsStatus::UserModified && @@ -653,16 +653,16 @@ std::pair SLAPrint::validate(std:: if (!pval.empty()) return { PrintBase::PrintValidationError::pveWrongSettings, pval }; } - double expt_max = m_printer_config.max_exposure_time.get_float(); - double expt_min = m_printer_config.min_exposure_time.get_float(); - double expt_cur = m_material_config.exposure_time.get_float(); + double expt_max = m_printer_config.max_exposure_time.getFloat(); + double expt_min = m_printer_config.min_exposure_time.getFloat(); + double expt_cur = m_material_config.exposure_time.getFloat(); if (expt_cur < expt_min || expt_cur > expt_max) return { PrintBase::PrintValidationError::pveWrongSettings, L("Exposition time is out of printer profile bounds.") }; - double iexpt_max = m_printer_config.max_initial_exposure_time.get_float(); - double iexpt_min = m_printer_config.min_initial_exposure_time.get_float(); - double iexpt_cur = m_material_config.initial_exposure_time.get_float(); + double iexpt_max = m_printer_config.max_initial_exposure_time.getFloat(); + double iexpt_min = m_printer_config.min_initial_exposure_time.getFloat(); + double iexpt_cur = m_material_config.initial_exposure_time.getFloat(); if (iexpt_cur < iexpt_min || iexpt_cur > iexpt_max) return { PrintBase::PrintValidationError::pveWrongSettings, L("Initial exposition time is out of printer profile bounds.") }; @@ -1031,11 +1031,11 @@ bool SLAPrintObject::invalidate_all_steps() double SLAPrintObject::get_elevation() const { if (is_zero_elevation(m_config)) return 0.; - bool en = m_config.supports_enable.get_bool(); + bool en = m_config.supports_enable.getBool(); - double ret = en ? m_config.support_object_elevation.get_float() : 0.; + double ret = en ? m_config.support_object_elevation.getFloat() : 0.; - if(m_config.pad_enable.get_bool()) { + if(m_config.pad_enable.getBool()) { // Normally the elevation for the pad itself would be the thickness of // its walls but currently it is half of its thickness. Whatever it // will be in the future, we provide the config to the get_pad_elevation @@ -1057,7 +1057,7 @@ double SLAPrintObject::get_current_elevation() const if(!has_supports && !has_pad) return 0; else if(has_supports && !has_pad) { - return m_config.support_object_elevation.get_float(); + return m_config.support_object_elevation.getFloat(); } return get_elevation(); @@ -1148,7 +1148,7 @@ TriangleMesh SLAPrintObject::get_mesh(SLAPrintObjectStep step) const const TriangleMesh& SLAPrintObject::support_mesh() const { - if(m_config.supports_enable.get_bool() && m_supportdata) + if(m_config.supports_enable.getBool() && m_supportdata) return m_supportdata->tree_mesh; return EMPTY_MESH; @@ -1156,7 +1156,7 @@ const TriangleMesh& SLAPrintObject::support_mesh() const const TriangleMesh& SLAPrintObject::pad_mesh() const { - if(m_config.pad_enable.get_bool() && m_supportdata) + if(m_config.pad_enable.getBool() && m_supportdata) return m_supportdata->pad_mesh; return EMPTY_MESH; @@ -1165,7 +1165,7 @@ const TriangleMesh& SLAPrintObject::pad_mesh() const const indexed_triangle_set &SLAPrintObject::hollowed_interior_mesh() const { if (m_hollowing_data && m_hollowing_data->interior && - m_config.hollowing_enable.get_bool()) + m_config.hollowing_enable.getBool()) return sla::get_mesh(*m_hollowing_data->interior); return EMPTY_TRIANGLE_SET; diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index 261d74894dc..0a0b5015c5f 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -78,7 +78,7 @@ SLAPrint::Steps::Steps(SLAPrint *print) : m_print{print} , m_rng{std::random_device{}()} , objcount{m_print->m_objects.size()} - , ilhd{m_print->m_material_config.initial_layer_height.get_float()} + , ilhd{m_print->m_material_config.initial_layer_height.getFloat()} , ilh{float(ilhd)} , ilhs{scaled(ilhd)} , objectstep_scale{(max_objstatus - min_objstatus) / (objcount * 100.0)} @@ -88,11 +88,11 @@ void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin { if (o == soSupport && !po.m_supportdata) return; - auto faded_lyrs = size_t(po.m_config.faded_layers.get_int()); - double min_w = m_print->m_printer_config.elephant_foot_min_width.get_float() / 2.; - double start_efc = m_print->m_printer_config.first_layer_size_compensation.get_float(); + auto faded_lyrs = size_t(po.m_config.faded_layers.getInt()); + double min_w = m_print->m_printer_config.elephant_foot_min_width.getFloat() / 2.; + double start_efc = m_print->m_printer_config.first_layer_size_compensation.getFloat(); - double doffs = m_print->m_printer_config.absolute_correction.get_float(); + double doffs = m_print->m_printer_config.absolute_correction.getFloat(); coord_t clpr_offs = scaled(doffs); faded_lyrs = std::min(po.m_slice_index.size(), faded_lyrs); @@ -123,16 +123,16 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po) { po.m_hollowing_data.reset(); - if (! po.m_config.hollowing_enable.get_bool()) { + if (! po.m_config.hollowing_enable.getBool()) { BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!"; return; } BOOST_LOG_TRIVIAL(info) << "Performing hollowing step!"; - double thickness = po.m_config.hollowing_min_thickness.get_float(); - double quality = po.m_config.hollowing_quality.get_float(); - double closing_d = po.m_config.hollowing_closing_distance.get_float(); + double thickness = po.m_config.hollowing_min_thickness.getFloat(); + double quality = po.m_config.hollowing_quality.getFloat(); + double closing_d = po.m_config.hollowing_closing_distance.getFloat(); sla::HollowingConfig hlwcfg{thickness, quality, closing_d}; sla::InteriorPtr interior = generate_interior(po.transformed_mesh(), hlwcfg); @@ -490,7 +490,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po) // We need to prepare the slice index... - double lhd = m_print->m_objects.front()->m_config.layer_height.get_float(); + double lhd = m_print->m_objects.front()->m_config.layer_height.getFloat(); float lh = float(lhd); coord_t lhs = scaled(lhd); auto && bb3d = mesh.bounding_box(); @@ -567,7 +567,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po) // We apply the printer correction offset here. apply_printer_corrections(po, soModel); - if(po.m_config.supports_enable.get_bool() || po.m_config.pad_enable.get_bool()) + if(po.m_config.supports_enable.getBool() || po.m_config.pad_enable.getBool()) { po.m_supportdata.reset(new SLAPrintObject::SupportData(po.get_mesh_to_print())); } @@ -578,7 +578,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po) void SLAPrint::Steps::support_points(SLAPrintObject &po) { // If supports are disabled, we can skip the model scan. - if(!po.m_config.supports_enable.get_bool()) return; + if(!po.m_config.supports_enable.getBool()) return; if (!po.m_supportdata) po.m_supportdata.reset(new SLAPrintObject::SupportData(po.get_mesh_to_print())); @@ -681,7 +681,7 @@ void SLAPrint::Steps::support_tree(SLAPrintObject &po) po.m_supportdata->create_support_tree(ctl); - if (!po.m_config.supports_enable.get_bool()) return; + if (!po.m_config.supports_enable.getBool()) return; throw_if_canceled(); @@ -706,7 +706,7 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) { // and before the supports had been sliced. (or the slicing has to be // repeated) - if(po.m_config.pad_enable.get_bool()) { + if(po.m_config.pad_enable.getBool()) { // Get the distilled pad configuration from the config sla::PadConfig pcfg = make_pad_cfg(po.m_config); @@ -714,13 +714,13 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) { double pad_h = pcfg.full_height(); const TriangleMesh &trmesh = po.transformed_mesh(); - if (!po.m_config.supports_enable.get_bool() || pcfg.embed_object) { + if (!po.m_config.supports_enable.getBool() || pcfg.embed_object) { // No support (thus no elevation) or zero elevation mode // we sometimes call it "builtin pad" is enabled so we will // get a sample from the bottom of the mesh and use it for pad // creation. sla::pad_blueprint(trmesh.its, bp, float(pad_h), - float(po.m_config.layer_height.get_float()), + float(po.m_config.layer_height.getFloat()), [this](){ throw_if_canceled(); }); } @@ -748,7 +748,7 @@ void SLAPrint::Steps::slice_supports(SLAPrintObject &po) { if(sd) sd->support_slices.clear(); // Don't bother if no supports and no pad is present. - if (!po.m_config.supports_enable.get_bool() && !po.m_config.pad_enable.get_bool()) + if (!po.m_config.supports_enable.getBool() && !po.m_config.pad_enable.getBool()) return; if(sd && sd->support_tree_ptr) { @@ -887,18 +887,18 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() { print_statistics.clear(); - const double area_fill = printer_config.area_fill.get_float()*0.01;// 0.5 (50%); - const double fast_tilt = printer_config.fast_tilt_time.get_float();// 5.0; - const double slow_tilt = printer_config.slow_tilt_time.get_float();// 8.0; - const double hv_tilt = printer_config.high_viscosity_tilt_time.get_float();// 10.0; + const double area_fill = printer_config.area_fill.getFloat()*0.01;// 0.5 (50%); + const double fast_tilt = printer_config.fast_tilt_time.getFloat();// 5.0; + const double slow_tilt = printer_config.slow_tilt_time.getFloat();// 8.0; + const double hv_tilt = printer_config.high_viscosity_tilt_time.getFloat();// 10.0; - const double init_exp_time = material_config.initial_exposure_time.get_float(); - const double exp_time = material_config.exposure_time.get_float(); + const double init_exp_time = material_config.initial_exposure_time.getFloat(); + const double exp_time = material_config.exposure_time.getFloat(); - const int fade_layers_cnt = m_print->m_default_object_config.faded_layers.get_int();// 10 // [3;20] + const int fade_layers_cnt = m_print->m_default_object_config.faded_layers.getInt();// 10 // [3;20] - const auto width = scaled(printer_config.display_width.get_float()); - const auto height = scaled(printer_config.display_height.get_float()); + const auto width = scaled(printer_config.display_width.getFloat()); + const auto height = scaled(printer_config.display_height.getFloat()); const double display_area = width*height; double supports_volume(0.0); diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 844d40bb8b1..9e84279e6fa 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -315,7 +315,7 @@ std::vector layer_height_profile_from_ranges( for (t_layer_config_ranges::const_iterator it_range = layer_config_ranges.begin(); it_range != layer_config_ranges.end(); ++ it_range) { coordf_t lo = it_range->first.first; coordf_t hi = std::min(it_range->first.second, slicing_params.object_print_z_height()); - coordf_t height = it_range->second.option("layer_height")->get_float(); + coordf_t height = it_range->second.option("layer_height")->getFloat(); if (! ranges_non_overlapping.empty()) // Trim current low with the last high. lo = std::max(lo, ranges_non_overlapping.back().first.second); diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index ec877bd4c14..2cf116e3118 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -42,7 +42,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para t_config_option_key key; switch (param) { case Parameter::RectSize: - def.type = coPoint; + def.type = coPoints; def.set_default_value(new ConfigOptionPoints{ Vec2d(200, 200) }); def.min = 0; def.max = 100000; @@ -51,7 +51,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para key = "rect_size"; break; case Parameter::RectOrigin: - def.type = coPoint; + def.type = coPoints; def.set_default_value(new ConfigOptionPoints{ Vec2d(0, 0) }); def.min = -100000; def.max = 100000; @@ -120,14 +120,12 @@ void BedShape::apply_optgroup_values(ConfigOptionsGroupShp optgroup) { switch (m_build_volume.type()) { case BuildVolume::Type::Circle: - optgroup->set_value("diameter", 2. * unscaled(m_build_volume.circle().radius)); + optgroup->set_value("diameter", double_to_string(2. * unscaled(m_build_volume.circle().radius))); break; default: // rectangle, convex, concave... - optgroup->set_value("rect_size", Vec2d(m_build_volume.bounding_volume().size().x(), - m_build_volume.bounding_volume().size().y())); - optgroup->set_value("rect_origin", Vec2d(-m_build_volume.bounding_volume().min.x(), - -m_build_volume.bounding_volume().min.y())); + optgroup->set_value("rect_size" , new ConfigOptionPoints{ to_2d(m_build_volume.bounding_volume().size()) }); + optgroup->set_value("rect_origin" , new ConfigOptionPoints{ - to_2d(m_build_volume.bounding_volume().min) }); } } diff --git a/src/slic3r/GUI/CalibrationBridgeDialog.cpp b/src/slic3r/GUI/CalibrationBridgeDialog.cpp index 0d703d42915..476b78bdb58 100644 --- a/src/slic3r/GUI/CalibrationBridgeDialog.cpp +++ b/src/slic3r/GUI/CalibrationBridgeDialog.cpp @@ -133,7 +133,7 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool DynamicPrintConfig new_print_config = *print_config; //make a copy new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true)); //if skirt, use only one - if (print_config->option("skirts")->get_int() > 0 && print_config->option("skirt_height")->get_int() > 0) { + if (print_config->option("skirts")->getInt() > 0 && print_config->option("skirt_height")->getInt() > 0) { new_print_config.set_key_value("complete_objects_one_skirt", new ConfigOptionBool(true)); } diff --git a/src/slic3r/GUI/CalibrationFlowDialog.cpp b/src/slic3r/GUI/CalibrationFlowDialog.cpp index d697aad6f20..040c7a79cee 100644 --- a/src/slic3r/GUI/CalibrationFlowDialog.cpp +++ b/src/slic3r/GUI/CalibrationFlowDialog.cpp @@ -132,7 +132,7 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) { DynamicPrintConfig new_print_config = *print_config; //make a copy new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true)); //if skirt, use only one - if (print_config->option("skirts")->get_int() > 0 && print_config->option("skirt_height")->get_int() > 0) { + if (print_config->option("skirts")->getInt() > 0 && print_config->option("skirt_height")->getInt() > 0) { new_print_config.set_key_value("complete_objects_one_skirt", new ConfigOptionBool(true)); } diff --git a/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp b/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp index 699f1e861c5..344be6ba129 100644 --- a/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp +++ b/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp @@ -93,8 +93,8 @@ void CalibrationOverBridgeDialog::create_geometry(bool over_bridge) { bool has_to_arrange = false; const ConfigOptionFloat* extruder_clearance_radius = print_config->option("extruder_clearance_radius"); const ConfigOptionPoints* bed_shape = printer_config->option("bed_shape"); - const float brim_width = print_config->option("brim_width")->get_float(); - const float skirt_width = print_config->option("skirts")->get_int() == 0 ? 0 : print_config->option("skirt_distance")->get_float() + print_config->option("skirts")->get_int() * nozzle_diameter * 2; + const float brim_width = print_config->option("brim_width")->getFloat(); + const float skirt_width = print_config->option("skirts")->getInt() == 0 ? 0 : print_config->option("skirt_distance")->getFloat() + print_config->option("skirts")->getInt() * nozzle_diameter * 2; Vec2d bed_size = BoundingBoxf(bed_shape->values).size(); Vec2d bed_min = BoundingBoxf(bed_shape->values).min; float offsetx = 3 + 30 * xyz_scale + extruder_clearance_radius->value + brim_width + (brim_width > extruder_clearance_radius->value ? brim_width - extruder_clearance_radius->value : 0); @@ -114,8 +114,7 @@ void CalibrationOverBridgeDialog::create_geometry(bool over_bridge) { DynamicPrintConfig new_print_config = *print_config; //make a copy new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true)); //if skirt, use only one - if (print_config->option("skirts")->get_int() > 0 && - print_config->option("skirt_height")->get_int() > 0) { + if (print_config->option("skirts")->getInt() > 0 && print_config->option("skirt_height")->getInt() > 0) { new_print_config.set_key_value("complete_objects_one_skirt", new ConfigOptionBool(true)); } diff --git a/src/slic3r/GUI/CalibrationRetractionDialog.cpp b/src/slic3r/GUI/CalibrationRetractionDialog.cpp index 3f9dd45eae4..5604513cfe2 100644 --- a/src/slic3r/GUI/CalibrationRetractionDialog.cpp +++ b/src/slic3r/GUI/CalibrationRetractionDialog.cpp @@ -81,13 +81,14 @@ void CalibrationRetractionDialog::remove_slowdown(wxCommandEvent& event_args) { DynamicPrintConfig new_filament_config = *filament_config; //make a copy const ConfigOptionFloats *fil_conf = filament_config->option("slowdown_below_layer_time"); - ConfigOptionFloats *new_fil_conf = new ConfigOptionFloats(5); + ConfigOptionFloats *new_fil_conf = new ConfigOptionFloats(); + new_fil_conf->default_value = 5; new_fil_conf->values = fil_conf->values; new_fil_conf->values[0] = 0; new_filament_config.set_key_value("slowdown_below_layer_time", new_fil_conf); - fil_conf = filament_config->option("fan_below_layer_time"); - new_fil_conf = new ConfigOptionFloats(60); + fil_conf = filament_config->option("fan_below_layer_time"); new_fil_conf = new ConfigOptionFloats(); + new_fil_conf->default_value = 60; new_fil_conf->values = fil_conf->values; new_fil_conf->values[0] = 0; new_filament_config.set_key_value("fan_below_layer_time", new_fil_conf); @@ -252,7 +253,7 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) { DynamicPrintConfig new_print_config = *print_config; //make a copy new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true)); //if skirt, use only one - if (print_config->option("skirts")->get_int() > 0 && print_config->option("skirt_height")->get_int() > 0) { + if (print_config->option("skirts")->getInt() > 0 && print_config->option("skirt_height")->getInt() > 0) { new_print_config.set_key_value("complete_objects_one_skirt", new ConfigOptionBool(true)); } this->gui_app->get_tab(Preset::TYPE_FFF_PRINT)->load_config(new_print_config); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 4e7b0e51838..a1a5c876230 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -86,9 +86,9 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con && config->opt_bool("overhangs_reverse") == false && config->opt_bool("gap_fill_last") == false && config->opt_int("solid_over_perimeters") == 0 - && config->option("seam_notch_all")->get_float() == 0 - && config->option("seam_notch_inner")->get_float() == 0 - && config->option("seam_notch_outer")->get_float() == 0 + && config->option("seam_notch_all")->getFloat() == 0 + && config->option("seam_notch_inner")->getFloat() == 0 + && config->option("seam_notch_outer")->getFloat() == 0 )) { wxString msg_text = _(L("The Spiral Vase mode requires:\n" "- no top solid layers\n" @@ -363,7 +363,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("overhangs_reverse_threshold", have_perimeters && config->opt_bool("overhangs_reverse")); toggle_field("overhangs_speed_enforce", have_perimeters && !config->opt_bool("perimeter_loop")); toggle_field("min_width_top_surface", have_perimeters && config->opt_bool("only_one_perimeter_top") && !have_arachne); - toggle_field("thin_perimeters_all", have_perimeters && config->option("thin_perimeters")->get_float() != 0 && !have_arachne); + toggle_field("thin_perimeters_all", have_perimeters && config->option("thin_perimeters")->getFloat() != 0 && !have_arachne); bool have_thin_wall = !have_arachne && have_perimeters; toggle_field("thin_walls", have_thin_wall); for (auto el : { "thin_walls_min_width", "thin_walls_overlap", "thin_walls_merge" }) @@ -374,9 +374,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("perimeter_loop_seam", config->opt_bool("perimeter_loop")); - bool have_notch = have_perimeters && (config->option("seam_notch_all")->get_float() != 0 || - config->option("seam_notch_inner")->get_float() != 0 || - config->option("seam_notch_outer")->get_float() != 0); + bool have_notch = have_perimeters && (config->option("seam_notch_all")->getFloat() != 0 || + config->option("seam_notch_inner")->getFloat() != 0 || + config->option("seam_notch_outer")->getFloat() != 0); toggle_field("seam_notch_angle", have_notch); bool have_gap_fill = !have_arachne; @@ -434,7 +434,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) //speed for (auto el : { "small_perimeter_min_length", "small_perimeter_max_length" }) - toggle_field(el, config->option("small_perimeter_speed")->get_float() > 0); + toggle_field(el, config->option("small_perimeter_speed")->getFloat() > 0); bool has_ironing_pattern = config->opt_enum("top_fill_pattern") == InfillPattern::ipSmooth || config->opt_enum("bottom_fill_pattern") == InfillPattern::ipSmooth @@ -511,14 +511,14 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field(el, have_raft); //for default_extrusion_width/spacing, you need to ahve at least an extrusion_width with 0 - bool have_default_width = config->option("first_layer_extrusion_width")->get_float() == 0 || - (config->option("perimeter_extrusion_width")->get_float() == 0 && (have_perimeters || have_brim)) || - (config->option("external_perimeter_extrusion_width")->get_float() == 0 && have_perimeters) || - (config->option("infill_extrusion_width")->get_float() == 0 && (have_infill || has_solid_infill)) || - (config->option("solid_infill_extrusion_width")->get_float() == 0 && has_solid_infill) || - (config->option("top_infill_extrusion_width")->get_float() == 0 && has_top_solid_infill) || - (config->option("support_material_extrusion_width")->get_float() == 0 && have_support_material) || - (config->option("skirt_extrusion_width")->get_float() == 0 && have_skirt); + bool have_default_width = config->option("first_layer_extrusion_width")->getFloat() == 0 || + (config->option("perimeter_extrusion_width")->getFloat() == 0 && (have_perimeters || have_brim)) || + (config->option("external_perimeter_extrusion_width")->getFloat() == 0 && have_perimeters) || + (config->option("infill_extrusion_width")->getFloat() == 0 && (have_infill || has_solid_infill)) || + (config->option("solid_infill_extrusion_width")->getFloat() == 0 && has_solid_infill) || + (config->option("top_infill_extrusion_width")->getFloat() == 0 && has_top_solid_infill) || + (config->option("support_material_extrusion_width")->getFloat() == 0 && have_support_material) || + (config->option("skirt_extrusion_width")->getFloat() == 0 && have_skirt); toggle_field("extrusion_width", have_default_width); toggle_field("extrusion_spacing", have_default_width); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index e8af859eeb3..ecd9cc819f9 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -76,35 +76,6 @@ wxString get_points_string(const std::vector& values) return ret_str; } -std::pair get_strings_points(const wxString &str, double min, double max, std::vector &out_values) -{ - bool invalid_val = false; - bool out_of_range_val = false; - wxStringTokenizer points(str, ","); - while (points.HasMoreTokens()) { - wxString token = points.GetNextToken(); - double x, y; - wxStringTokenizer point(token, "x"); - if (point.HasMoreTokens()) { - wxString x_str = point.GetNextToken(); - if (x_str.ToDouble(&x) && point.HasMoreTokens()) { - wxString y_str = point.GetNextToken(); - if (y_str.ToDouble(&y) && !point.HasMoreTokens()) { - if (min <= x && x <= max && min <= y && y <= max) { - out_values.push_back(Vec2d(x, y)); - continue; - } - out_of_range_val = true; - break; - } - } - } - invalid_val = true; - break; - } - return {invalid_val, out_of_range_val}; -} - Field::~Field() { @@ -139,8 +110,6 @@ void Field::PostInitialize() auto tag_pos = m_opt_id.find("#"); if (tag_pos != std::string::npos) m_opt_idx = stoi(m_opt_id.substr(tag_pos + 1, m_opt_id.size())); - else - m_opt_idx = -1; // no index, ie full vector in serialized form break; } default: @@ -357,327 +326,122 @@ void RichTooltipTimer::Notify() { } } -bool Field::is_matched(const std::string &string, const std::string &pattern) +bool Field::is_matched(const std::string& string, const std::string& pattern) { std::regex regex_pattern(pattern, std::regex_constants::icase); // use ::icase to make the matching case insensitive like /i in perl return std::regex_match(string, regex_pattern); } -static wxString na_value() { return _L("N/A"); } - -// return the string to set, and bool if there is a nil value -std::pair any_to_wxstring(const boost::any &value, const ConfigOptionDef &opt, const int opt_idx) -{ - wxString text_value; - bool has_nil = false; - auto deserialize = [&text_value, &value, &opt, &has_nil](ConfigOptionVectorBase &&writer, bool check_nil = true) { - writer.set_any(value, -1); - text_value = writer.serialize(); - if (check_nil && opt.nullable) - has_nil = (text_value.Replace(NIL_STR_VALUE, na_value()) > 0); - //replace ',' by ';' - text_value.Replace(",", ";"); - if (!is_decimal_separator_point()) { - // adjust to locale: '.' -> ',' - //',' are the decimal separator, transform from '.' from serialization (which happens in C locale) - text_value.Replace(".", ","); - } - }; - // first, easy convert-to one-string - switch (opt.type) { - case coFloats: - if (opt_idx < 0) { - deserialize(ConfigOptionFloats{}); - break; - } - case coPercents: - if (opt_idx < 0) { - deserialize(ConfigOptionPercents{}); - break; - } - if (opt.nullable && ConfigOptionFloatsNullable::is_nil(value)) { - text_value = na_value(); - has_nil = true; - break; - } - case coFloat: - case coPercent: text_value = double_to_string(boost::any_cast(value), opt.precision); break; - case coStrings: - if (opt_idx < 0) { - //custom for strings, as we don't need the serialized form, the normal one with ';' in-between is enough - ConfigOptionStrings reader; - reader.set_any(value, opt_idx); - std::string good_str; - for (std::string s : reader.values) good_str += s + ";"; - if(!good_str.empty()) - good_str.pop_back(); - text_value = good_str; - break; - } - // can't be nullable - case coString: text_value = boost::any_cast(value); break; - case coFloatsOrPercents: - if (opt_idx < 0) { - deserialize(ConfigOptionFloatsOrPercents{}); - break; - } - if (opt.nullable && - boost::any_cast(value) == ConfigOptionFloatsOrPercentsNullable::NIL_VALUE()) { - text_value = na_value(); - has_nil = true; - break; - } - case coFloatOrPercent: - FloatOrPercent fl_or_per = boost::any_cast(value); - text_value = double_to_string(fl_or_per.value); - if (fl_or_per.percent) - text_value.append("%"); - break; - case coBools: - if (opt_idx < 0) { - deserialize(ConfigOptionBools{}); - } else { - if (opt.nullable && boost::any_cast(value) == ConfigOptionBoolsNullable::NIL_VALUE()) { - text_value = na_value(); - has_nil = true; - break; - } - text_value = boost::any_cast(value) != 0 ? "true" : "false"; - } - break; - case coBool: - if (opt.is_script) - text_value = boost::any_cast(value) != 0 ? "true" : "false"; - else - text_value = boost::any_cast(value) ? "true" : "false"; - case coInts: - if (opt_idx < 0) { - deserialize(ConfigOptionInts{}); - break; - } - if (opt.nullable && boost::any_cast(value) == ConfigOptionIntsNullable::NIL_VALUE()) { - text_value = na_value(); - has_nil = true; - break; - } - case coInt: text_value = wxString::Format(_T("%i"), int(boost::any_cast(value))); break; - case coPoints: - if (opt_idx < 0) { - deserialize(ConfigOptionPoints{}); - assert(text_value == get_points_string(boost::any_cast>(value))); - break; - } - case coPoint: text_value = get_points_string({boost::any_cast(value)}); - } - return {text_value, has_nil}; -} - -// return true if the field isn't the same as before -bool TextField::get_vector_value(const wxString &str, ConfigOptionVectorBase &reader) -{ - std::string vector_str = str.ToStdString(); - if (str.size() > 2 && str.at(0) == '[' && str.at(str.size() - 1) == ']') { - // validate data inside - // first, remove all spaces - vector_str = str.SubString(1, str.size() - 1).ToStdString(); - } - // FIXME: also remove other unwanted chars only "[0-9].-,;" should remain - boost::erase_all(vector_str, " "); - bool is_decimal_sep_point = is_decimal_separator_point(); - if (!is_decimal_sep_point) { - //',' are the decimal separator, transform to '.' for deserialization (which happens in C locale) - boost::replace_all(vector_str, ",", "."); - } - boost::replace_all(vector_str, ";", ","); - try { - reader.deserialize(vector_str); - } catch (std::exception) {} - std::string good_str = reader.serialize(); - // replace ',' by ';' - boost::replace_all(good_str, ",", ";"); - if (!is_decimal_sep_point) { - // adjust to locale: '.' -> ',' - //',' are the decimal separator, transform from '.' from serialization (which happens in C locale) - boost::replace_all(good_str, ".", ","); - } - return (str.ToStdString() != good_str); -} +static wxString na_value() { return _(L("N/A")); } -//TODO move value verification on another methods that won't be called at each value.get() -void TextField::get_value_by_opt_type(wxString &str, const bool check_value /* = true*/) +//TODO move value verification on another methos that won't be called at each value.get() +void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true*/) { - bool need_update = false; - // convert nil values to serializable ones - if (m_opt.nullable && (m_opt.type != coString && m_opt.type != coStrings)) { - need_update = str.Replace(na_value(), NIL_STR_VALUE); - } - - // val is needed at the end of this function, for "max_volumetric_speed" || "gap_fill_speed" (bad practice) double val = 0; - switch (m_opt.type) { - case coInts: // not used yet - if (m_opt_idx < 0) { - ConfigOptionInts reader; - need_update = get_vector_value(str, reader); - m_value = reader.values; - break; - } // else: one int on m_opt_idx, done below - case coInt: { - m_value = wxAtoi(str); - val = wxAtoi(str); - break; - } - case coBools: // not used - if (m_opt_idx < 0) { - ConfigOptionBools reader; - need_update = get_vector_value(str, reader); - m_value = reader.values; - break; - } // else: one bool on m_opt_idx, done below - case coBool: { - wxString lower = str; - lower.LowerCase(); - if (m_opt.is_script || m_opt.type == coBools) { - m_value = (lower == "true" || lower == "1") ? uint8_t(1) : uint8_t(0); - } else { - m_value = lower == "true" || lower == "1"; - } - break; - } - case coPercents: //% are optional & copercents uses cofloats deserialize anyway - case coFloats: - if (m_opt_idx < 0) { - ConfigOptionFloats reader; - need_update = get_vector_value(str, reader); - m_value = reader.values; - break; - } - case coPercent: - case coFloat: { - if (m_opt.type == coPercent && !str.IsEmpty() && str.Last() == '%') - str.RemoveLast(); - else if (!str.IsEmpty() && str.Last() == '%') { + switch (m_opt.type) { + case coInt: + m_value = wxAtoi(str); + val = wxAtoi(str); + break; + case coPercent: + case coPercents: + case coFloats: + case coFloat:{ + if (m_opt.type == coPercent && !str.IsEmpty() && str.Last() == '%') + str.RemoveLast(); + else if (!str.IsEmpty() && str.Last() == '%') + { if (!check_value) { m_value.clear(); break; } - wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label); + wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label); show_error(m_parent, from_u8((boost::format(_utf8(L("%s doesn't support percentage"))) % label).str())); - set_text_value(double_to_string(m_opt.min, m_opt.precision).ToStdString(), true); - m_value = double(m_opt.min); - break; - } + set_value(double_to_string(m_opt.min, m_opt.precision), true); + m_value = double(m_opt.min); + break; + } - bool is_na_value = m_opt.nullable && str == NIL_STR_VALUE; + bool is_na_value = m_opt.nullable && str == na_value(); - const char dec_sep = is_decimal_separator_point() ? '.' : ','; + const char dec_sep = is_decimal_separator_point() ? '.' : ','; const char dec_sep_alt = dec_sep == '.' ? ',' : '.'; - // Replace the first incorrect separator in decimal number, + // Replace the first incorrect separator in decimal number, // if this value doesn't "N/A" value in some language // see https://github.com/prusa3d/PrusaSlicer/issues/6921 if (!is_na_value && str.Replace(dec_sep_alt, dec_sep, false) != 0) - set_text_value(str.ToStdString(), false); + set_value(str, false); if (str == dec_sep) val = 0.0; - else { - if (is_na_value) { - val = NAN; - m_value = ConfigOptionFloatsNullable::create_nil(); - break; - } else if (!str.ToDouble(&val)) { + else + { + if (is_na_value) + val = ConfigOptionFloatsNullable::nil_value(); + else if (!str.ToDouble(&val)) + { if (!check_value) { m_value.clear(); break; } - val = m_opt.min == INT_MIN ? std::max(0., m_opt.max) : m_opt.min; show_error(m_parent, _(L("Invalid numeric input."))); - set_text_value(double_to_string(val, m_opt.precision).ToStdString(), true); + set_value(double_to_string(val, m_opt.precision), true); } - if (m_opt.min > val || val > m_opt.max) { + if (m_opt.min > val || val > m_opt.max) + { if (!check_value) { m_value.clear(); break; } if (m_opt_id == "extrusion_multiplier") { if (m_value.empty() || boost::any_cast(m_value) != val) { - wxString msg_text = - format_wxstr(_L("Input value is out of range\n" - "Are you sure that %s is a correct value and that you want to continue?"), - str); - // wxMessageDialog dialog(m_parent, msg_text, _L("Parameter - // validation") + ": " + m_opt_id, wxICON_WARNING | wxYES | wxNO); - WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, - wxYES | wxNO); + wxString msg_text = format_wxstr(_L("Input value is out of range\n" + "Are you sure that %s is a correct value and that you want to continue?"), str); +// wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxICON_WARNING | wxYES | wxNO); + WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxYES | wxNO); if (dialog.ShowModal() == wxID_NO) { if (m_value.empty()) { - if (m_opt.min > val) - val = m_opt.min; - if (val > m_opt.max) - val = m_opt.max; - } else + if (m_opt.min > val) val = m_opt.min; + if (val > m_opt.max) val = m_opt.max; + } + else val = boost::any_cast(m_value); - set_text_value(double_to_string(val, m_opt.precision).ToStdString(), true); + set_value(double_to_string(val, m_opt.precision), true); } } - } else { + } + else { show_error(m_parent, _L("Input value is out of range")); - if (m_opt.min > val) - val = m_opt.min; - if (val > m_opt.max) - val = m_opt.max; - set_text_value(double_to_string(val, m_opt.precision).ToStdString(), true); + if (m_opt.min > val) val = m_opt.min; + if (val > m_opt.max) val = m_opt.max; + set_value(double_to_string(val, m_opt.precision), true); } } } m_value = val; + break; } + case coString: + case coStrings: + m_value = std::string(str.ToUTF8().data()); break; - } - case coStrings: - if (m_opt_idx < 0) { - ConfigOptionStrings reader; - //don't remove spaces and things like that - try { - reader.deserialize(str.ToStdString()); - } catch (std::exception) {} - std::string good_str; - for (std::string s : reader.values) good_str += s + ";"; - if (!good_str.empty()) - good_str.pop_back(); - need_update = (str.ToStdString() != good_str); - m_value = reader.values; - break; - } - case coString: m_value = std::string(str.ToUTF8().data()); break; case coFloatsOrPercents: - if (m_opt_idx < 0) { // not used yet - ConfigOptionFloatsOrPercents reader; - need_update = get_vector_value(str, reader); - m_value = reader.values; - break; - } case coFloatOrPercent: { - bool is_percent = false; if (!str.IsEmpty()) { if ("infill_overlap" == m_opt_id && m_last_validated_value != str) { bool bad = false; if (str.Last() != '%') { - is_percent = false; if (str.ToDouble(&val)) { - const DynamicPrintConfig &printer_config = - wxGetApp().preset_bundle->printers.get_edited_preset().config; - const std::vector &nozzle_diameters = - printer_config.option("nozzle_diameter")->values; - double nozzle_diameter = 0; - for (double diameter : nozzle_diameters) - nozzle_diameter = std::max(nozzle_diameter, diameter); + const DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; + const std::vector& nozzle_diameters = printer_config.option("nozzle_diameter")->values; + double nozzle_diameter = 0; + for (double diameter : nozzle_diameters) + nozzle_diameter = std::max(nozzle_diameter, diameter); if (val > nozzle_diameter / 2) { bad = true; } } } else { - is_percent = true; if (str.substr(0, str.size() - 1).ToCDouble(&val)) { if (val >= 50) { bad = true; @@ -685,76 +449,65 @@ void TextField::get_value_by_opt_type(wxString &str, const bool check_value /* = } } if (bad && check_value) { - const wxString msg_text = from_u8( - _u8L("The infill / perimeter encroachment can't be higher than half of the perimeter width.\n" - "Are you sure to use this value?")); - wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, - wxICON_WARNING | wxYES | wxNO); - auto ret = dialog.ShowModal(); + const wxString msg_text = from_u8(_u8L("The infill / perimeter encroachment can't be higher than half of the perimeter width.\n" + "Are you sure to use this value?")); + wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxICON_WARNING | wxYES | wxNO); + auto ret = dialog.ShowModal(); if (ret == wxID_NO) { - str = from_u8("49%"); + str = from_u8("49%"); m_last_validated_value = str; - set_text_value(str.ToStdString(), false); + set_value(str, false); str = m_last_validated_value; } m_last_validated_value = str; } - } else if (str.Last() != '%') { - is_percent = false; - const char dec_sep = is_decimal_separator_point() ? '.' : ','; + } + else if (str.Last() != '%') { + const char dec_sep = is_decimal_separator_point() ? '.' : ','; const char dec_sep_alt = dec_sep == '.' ? ',' : '.'; // Replace the first incorrect separator in decimal number. if (str.Replace(dec_sep_alt, dec_sep, false) != 0) - set_text_value(str.ToStdString(), false); + set_value(str, false); // remove space and "mm" substring, if any exists str.Replace(" ", "", true); str.Replace("m", "", true); - if (m_opt.nullable && str == NIL_STR_VALUE) { - m_value = ConfigOptionFloatsOrPercentsNullable::NIL_VALUE(); - break; + if (m_opt.nullable && str == na_value()) { + val = ConfigOptionFloatsNullable::nil_value(); + str = "nan"; } else if (!str.ToDouble(&val)) { if (!check_value) { m_value.clear(); break; } show_error(m_parent, _(L("Invalid numeric input."))); - set_value(FloatOrPercent{val, is_percent}, true); + set_value(double_to_string(val, m_opt.precision), true); } else { - //convert m_value into str to compare - FloatOrPercent val_from_m_value = m_value.empty() ? FloatOrPercent{0, false} : - boost::any_cast(m_value); - wxString str_from_m_value = double_to_string(val_from_m_value.value, m_opt.precision); - if (val_from_m_value.percent) - str_from_m_value += '%'; - - // at least check min, as we can want a 0 min - if (m_opt.min > val) { + + //at least check min, as we can want a 0 min + if (m_opt.min > val) + { if (!check_value) { m_value.clear(); break; } show_error(m_parent, _(L("Input value is out of range"))); - if (m_opt.min > val) - val = m_opt.min; - set_value(FloatOrPercent{val, is_percent}, true); - } else if (m_value.empty() || str != str_from_m_value) { - // empty of not equal -> need check + if (m_opt.min > val) val = m_opt.min; + set_value(double_to_string(val, m_opt.precision), true); + } else if (m_value.empty() || into_u8(str) != boost::any_cast(m_value)) { bool not_ok = (m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max); if (!not_ok && m_opt.max_literal.value != 0 && val != 0) { if (m_opt.max_literal.percent) { - const DynamicPrintConfig &printer_config = - wxGetApp().preset_bundle->printers.get_edited_preset().config; - const std::vector &nozzle_diameters = - printer_config.option("nozzle_diameter")->values; + const DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; + const std::vector& nozzle_diameters = printer_config.option("nozzle_diameter")->values; double nozzle_diameter = 0; for (double diameter : nozzle_diameters) nozzle_diameter = std::max(nozzle_diameter, diameter); if (m_opt.max_literal.value > 0) not_ok = val > nozzle_diameter * m_opt.max_literal.value; else - not_ok = val < nozzle_diameter * (-m_opt.max_literal.value); + not_ok = val < nozzle_diameter* (-m_opt.max_literal.value); } else { if (m_opt.max_literal.value > 0) not_ok = val > m_opt.max_literal.value; @@ -768,99 +521,102 @@ void TextField::get_value_by_opt_type(wxString &str, const bool check_value /* = break; } - bool infill_anchors = m_opt.opt_key == "infill_anchor" || - m_opt.opt_key == "infill_anchor_max"; - - const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : - "mm"; - const wxString stVal = double_to_string(val, m_opt.precision); - const wxString msg_text = from_u8( - (boost::format(_u8L("Do you mean %s%% instead of %s %s?\n" - "Select YES if you want to change this value to %s%%, \n" - "or NO if you are sure that %s %s is a correct value.")) % - stVal % stVal % sidetext % stVal % stVal % sidetext) - .str()); - WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, - wxYES | wxNO); + bool infill_anchors = m_opt.opt_key == "infill_anchor" || m_opt.opt_key == "infill_anchor_max"; + + const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm"; + const wxString stVal = double_to_string(val, m_opt.precision); + const wxString msg_text = from_u8((boost::format(_u8L("Do you mean %s%% instead of %s %s?\n" + "Select YES if you want to change this value to %s%%, \n" + "or NO if you are sure that %s %s is a correct value.")) % stVal % stVal % sidetext % stVal % stVal % sidetext).str()); + WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxYES | wxNO); if ((!infill_anchors || val > 100) && dialog.ShowModal() == wxID_YES) { str += "%"; - is_percent = true; m_last_validated_value = str; - set_value(FloatOrPercent{val, is_percent}, false /*true*/); + set_value(str, false/*true*/); str = m_last_validated_value; } else - set_value(FloatOrPercent{val, is_percent}, false); // it's no needed but can be helpful, when inputted value - // contained "," instead of "." + set_value(stVal, false); // it's no needed but can be helpful, when inputted value contained "," instead of "." m_last_validated_value = str; } } } } else { str.ToDouble(&val); - is_percent = true; } } - m_value = FloatOrPercent{val, is_percent}; + m_value = into_u8(str); break; } case coPoints: { std::vector out_values; str.Replace(" ", wxEmptyString, true); if (!str.IsEmpty()) { - auto [/*bool*/ invalid_val, /*bool*/ out_of_range_val] = get_strings_points(str, m_opt.min, m_opt.max, - out_values); + bool invalid_val = false; + bool out_of_range_val = false; + wxStringTokenizer points(str, ","); + while (points.HasMoreTokens()) { + wxString token = points.GetNextToken(); + double x, y; + wxStringTokenizer point(token, "x"); + if (point.HasMoreTokens()) { + wxString x_str = point.GetNextToken(); + if (x_str.ToDouble(&x) && point.HasMoreTokens()) { + wxString y_str = point.GetNextToken(); + if (y_str.ToDouble(&y) && !point.HasMoreTokens()) { + if (m_opt.min <= x && x <= m_opt.max && m_opt.min <= y && y <= m_opt.max) { + out_values.push_back(Vec2d(x, y)); + continue; + } + out_of_range_val = true; + break; + } + } + } + invalid_val = true; + break; + } if (out_of_range_val) { wxString text_value; if (!m_value.empty()) text_value = get_points_string(boost::any_cast>(m_value)); - set_text_value(text_value.ToStdString(), true); + set_value(text_value, true); show_error(m_parent, _L("Input value is out of range")); - } else if (invalid_val) { + } + else if (invalid_val) { wxString text_value; if (!m_value.empty()) text_value = get_points_string(boost::any_cast>(m_value)); - set_text_value(text_value.ToStdString(), true); - show_error(m_parent, format_wxstr(_L("Invalid input format. Expected vector of dimensions in the " - "following format: \"%1%\""), - "XxY, XxY, ...")); + set_value(text_value, true); + show_error(m_parent, format_wxstr(_L("Invalid input format. Expected vector of dimensions in the following format: \"%1%\""),"XxY, XxY, ..." )); } } m_value = out_values; - break; - } + break; } - default: break; - } + default: + break; + } if (!Field::warn_zero_gapfillspeed && ("max_volumetric_speed" == m_opt_id || "gap_fill_speed" == m_opt_id)) { - bool show_warning = false; - const DynamicPrintConfig &print_config = wxGetApp().preset_bundle->fff_prints.get_edited_preset().config; + bool show_warning = false; + const DynamicPrintConfig& print_config = wxGetApp().preset_bundle->fff_prints.get_edited_preset().config; if ("max_volumetric_speed" == m_opt_id && val > 0) show_warning = print_config.option("gap_fill_speed")->value == 0; if ("gap_fill_speed" == m_opt_id && val == 0) show_warning = true; if (show_warning) { - const wxString msg_text = from_u8( - _u8L("Auto Speed will try to maintain a constant flow rate accross all print moves." - "\nIt is not recommended to include gap moves to the Auto Speed calculation(by setting this " - "value to 0)." - "\nVery thin gap extrusions will often not max out the flow rate of your printer." - "\nAs a result, this will cause Auto Speed to lower the speeds of all other print moves to " - "match the low flow rate of these thin gaps.")); - wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, - wxICON_WARNING | wxOK); + const wxString msg_text = from_u8(_u8L("Auto Speed will try to maintain a constant flow rate accross all print moves." + "\nIt is not recommended to include gap moves to the Auto Speed calculation(by setting this value to 0)." + "\nVery thin gap extrusions will often not max out the flow rate of your printer." + "\nAs a result, this will cause Auto Speed to lower the speeds of all other print moves to match the low flow rate of these thin gaps.")); + wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxICON_WARNING | wxOK); dialog.ShowModal(); Field::warn_zero_gapfillspeed = true; } } - - if (need_update) { - wxString new_str = any_to_wxstring(m_value, m_opt, m_opt_idx).first; - set_text_value(new_str.ToStdString()); - } } void Field::msw_rescale() @@ -892,16 +648,60 @@ void TextCtrl::BUILD() { wxString text_value = wxString(""); - boost::any anyval = m_opt.default_value->get_any(m_opt_idx); - text_value = any_to_wxstring(m_opt.default_value->get_any(m_opt_idx), m_opt, m_opt_idx).first; - if (text_value == na_value()) { - // current value is nil, get the not-nil default value of the default option. - assert(m_opt.default_value->is_vector()); - m_last_meaningful_value = any_to_wxstring(static_cast(m_opt.default_value.get())->get_default_value(), m_opt, m_opt_idx).first; - } else { - m_last_meaningful_value = text_value; + switch (m_opt.type) { + case coFloatOrPercent: + { + text_value = double_to_string(m_opt.default_value->getFloat(), m_opt.precision); + if (m_opt.get_default_value()->percent) + text_value += "%"; + break; + } + case coPercent: + { + text_value = double_to_string(m_opt.default_value->getFloat(), m_opt.precision); + text_value += "%"; + break; + } + case coPercents: + case coFloats: + case coFloat: + { + double val = m_opt.type == coFloats ? + m_opt.get_default_value()->get_at(m_opt_idx) : + m_opt.type == coFloat ? + m_opt.default_value->getFloat() : + m_opt.get_default_value()->get_at(m_opt_idx); + text_value = double_to_string(val, m_opt.precision); + break; + } + case coFloatsOrPercents: + { + const ConfigOptionFloatsOrPercents* cofop = m_opt.get_default_value(); + text_value = double_to_string(cofop->get_at(m_opt_idx).value, m_opt.precision); + if (cofop->get_at(m_opt_idx).percent) + text_value += "%"; + break; } - assert(m_last_meaningful_value != na_value()); + case coString: + text_value = m_opt.get_default_value()->value; + break; + case coStrings: + { + const ConfigOptionStrings *vec = m_opt.get_default_value(); + if (vec == nullptr || vec->empty()) break; //for the case of empty default value + text_value = vec->get_at(m_opt_idx); + break; + } + case coPoint: + text_value = get_points_string({ m_opt.get_default_value()->value }); + break; + case coPoints: + text_value = get_points_string(m_opt.get_default_value()->values); + break; + default: + break; + } + m_last_meaningful_value = text_value; long style = m_opt.multiline ? wxTE_MULTILINE : wxTE_PROCESS_ENTER; #ifdef _WIN32 @@ -970,15 +770,7 @@ void TextCtrl::BUILD() { window = dynamic_cast(temp); this->set_tooltip(text_value); -} - - -void TextCtrl::set_text_value(const std::string &value, bool change_event) -{ - m_disable_change_event = !change_event; - dynamic_cast(window)->SetValue(value); - m_disable_change_event = false; -} +} bool TextCtrl::value_was_changed() { @@ -992,78 +784,22 @@ bool TextCtrl::value_was_changed() get_value_by_opt_type(ret_str); switch (m_opt.type) { - case coInts: - if (m_opt_idx < 0) { - return boost::any_cast>(m_value) != boost::any_cast>(val); - } - if (m_opt.nullable) { - uint8_t new_val = boost::any_cast(m_value); - uint8_t old_val = boost::any_cast(val); - if (new_val == ConfigOptionInts::NIL_VALUE() && old_val == ConfigOptionInts::NIL_VALUE()) - return false; - } case coInt: return boost::any_cast(m_value) != boost::any_cast(val); + case coPercent: case coPercents: case coFloats: - if (m_opt_idx < 0) { - return boost::any_cast>(m_value) != boost::any_cast>(val); - } - if (m_opt.nullable) { - double new_val = boost::any_cast(m_value); - double old_val = boost::any_cast(val); - if ((std::isnan(new_val) || ConfigOptionFloats::is_nil(m_value)) && - (std::isnan(old_val) || ConfigOptionFloats::is_nil(val))) - return false; - } - case coPercent: case coFloat: { + if (m_opt.nullable && std::isnan(boost::any_cast(m_value)) && + std::isnan(boost::any_cast(val))) + return false; return boost::any_cast(m_value) != boost::any_cast(val); } - case coStrings: - if (m_opt_idx < 0) { - return boost::any_cast>(m_value) != - boost::any_cast>(val); - } case coString: - return boost::any_cast(m_value) != boost::any_cast(val); - case coFloatsOrPercents: - if (m_opt_idx < 0) { - return boost::any_cast>(m_value) != - boost::any_cast>(val); - } - if (m_opt.nullable) { - FloatOrPercent new_val = boost::any_cast(m_value); - FloatOrPercent old_val = boost::any_cast(val); - if ((std::isnan(new_val.value) || new_val == ConfigOptionFloatsOrPercents::NIL_VALUE()) && - (std::isnan(old_val.value) || old_val == ConfigOptionFloatsOrPercents::NIL_VALUE())) - return false; - } + case coStrings: case coFloatOrPercent: - return boost::any_cast(m_value) != boost::any_cast(val); - case coPoints: - if (m_opt_idx < 0) { - return boost::any_cast>(m_value) != boost::any_cast>(val); - } - case coPoint: - return boost::any_cast(m_value) != boost::any_cast(val); - case coBools: - if (m_opt_idx < 0) { - return boost::any_cast>(m_value) != boost::any_cast>(val); - } else { - if (m_opt.nullable) { - uint8_t new_val = boost::any_cast(m_value); - uint8_t old_val = boost::any_cast(val); - if (new_val == ConfigOptionBools::NIL_VALUE() && old_val == ConfigOptionBools::NIL_VALUE()) - return false; - } - return boost::any_cast(m_value) != boost::any_cast(val); - } - case coBool: - if(m_opt.is_script) - return boost::any_cast(m_value) != boost::any_cast(val); - else - return boost::any_cast(m_value) != boost::any_cast(val); + case coFloatsOrPercents: + return boost::any_cast(m_value) != boost::any_cast(val); default: return true; } @@ -1077,29 +813,18 @@ void TextCtrl::propagate_value() on_kill_focus(); else if (value_was_changed()) on_change_field(); - //update m_last_meaningful_value ? - if (!m_value.empty() && dynamic_cast(window)->GetValue() != na_value()) - m_last_meaningful_value = dynamic_cast(window)->GetValue(); } void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) { - //can be: - //case coFloat: - //case coFloats: - //case coPercent: - //case coPercents: - //case coFloatOrPercent: - //case coFloatsOrPercents: - //case coString: - //case coStrings: - // coBools (if all) - // coInts (if all) - // coPoints (if all) - auto [/*wxString*/text_value, /*bool*/ has_nil] = any_to_wxstring(value, m_opt, m_opt_idx); - if (!has_nil) - m_last_meaningful_value = text_value; m_disable_change_event = !change_event; - dynamic_cast(window)->SetValue(text_value); + if (m_opt.nullable) { + const bool m_is_na_val = boost::any_cast(value) == na_value(); + if (!m_is_na_val) + m_last_meaningful_value = value; + dynamic_cast(window)->SetValue(m_is_na_val ? na_value() : boost::any_cast(value)); + } + else + dynamic_cast(window)->SetValue(boost::any_cast(value)); m_disable_change_event = false; if (!change_event) { @@ -1114,7 +839,7 @@ void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) void TextCtrl::set_last_meaningful_value() { - dynamic_cast(window)->SetValue(m_last_meaningful_value); + dynamic_cast(window)->SetValue(boost::any_cast(m_last_meaningful_value)); propagate_value(); } @@ -1172,10 +897,12 @@ void CheckBox::BUILD() { if (m_opt.height >= 0) size.SetHeight(m_opt.height * m_em_unit); if (m_opt.width >= 0) size.SetWidth(m_opt.width * m_em_unit); - bool check_value = m_opt.type == coBool || m_opt.type == coBools ? m_opt.default_value->get_bool(m_opt_idx) : - false; + bool check_value = m_opt.type == coBool ? + m_opt.default_value->getBool() : m_opt.type == coBools ? + m_opt.get_default_value()->get_at(m_opt_idx) : + false; - m_last_meaningful_value = static_cast(check_value); + m_last_meaningful_value = static_cast(check_value); #ifdef __WXGTK2__ //gtk2 can't resize checkboxes, so we are using togglable buttons instead @@ -1241,15 +968,13 @@ void CheckBox::set_widget_value(bool new_val) #endif } -void CheckBox::set_value(const boost::any &value, bool change_event) +void CheckBox::set_value(const boost::any& value, bool change_event) { - //can be coBool and coBools (with idx) m_disable_change_event = !change_event; - assert(m_opt.type == coBool || (m_opt.type == coBools && m_opt_idx >= 0)); - if (m_opt.type == coBools && m_opt.nullable) { - m_is_na_val = boost::any_cast(value) == ConfigOptionBoolsNullable::NIL_VALUE(); + if (m_opt.nullable) { + m_is_na_val = boost::any_cast(value) == ConfigOptionBoolsNullable::nil_value(); if (!m_is_na_val) - m_last_meaningful_value = boost::any_cast(value); + m_last_meaningful_value = value; set_widget_value(m_is_na_val ? false : boost::any_cast(value) != 0); } else if (m_opt.is_script) { uint8_t val = boost::any_cast(value); @@ -1257,12 +982,8 @@ void CheckBox::set_value(const boost::any &value, bool change_event) dynamic_cast(window)->Set3StateValue(wxCheckBoxState::wxCHK_UNDETERMINED); else set_widget_value(val != 0); - } else if (m_opt.type == coBools) { - set_widget_value(boost::any_cast(value) != 0); - } else { - assert(m_opt.type == coBool); + } else set_widget_value(boost::any_cast(value)); - } m_disable_change_event = false; } @@ -1270,7 +991,7 @@ void CheckBox::set_last_meaningful_value() { if (m_opt.nullable) { m_is_na_val = false; - set_widget_value(m_last_meaningful_value != 0); + set_widget_value(boost::any_cast(m_last_meaningful_value) != 0); on_change_field(); } } @@ -1302,7 +1023,7 @@ boost::any& CheckBox::get_value() if (m_opt.type == coBool) m_value = static_cast(value); else - m_value = m_is_na_val ? ConfigOptionBoolsNullable::NIL_VALUE() : static_cast(value); + m_value = m_is_na_val ? ConfigOptionBoolsNullable::nil_value() : static_cast(value); return m_value; } @@ -1334,7 +1055,7 @@ void SpinCtrl::BUILD() { switch (m_opt.type) { case coInt: - default_value = m_opt.default_value->get_int(); + default_value = m_opt.default_value->getInt(); text_value = wxString::Format(_T("%i"), default_value); break; case coInts: @@ -1636,17 +1357,17 @@ void Choice::set_selection() choice_ctrl* field = dynamic_cast(window); switch (m_opt.type) { case coEnum:{ - field->SetSelection(m_opt.default_value->get_int()); + field->SetSelection(m_opt.default_value->getInt()); break; } case coFloat: case coPercent: { - double val = m_opt.default_value->get_float(); + double val = m_opt.default_value->getFloat(); text_value = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 1); break; } case coInt:{ - text_value = wxString::Format(_T("%i"), int(m_opt.default_value->get_int())); + text_value = wxString::Format(_T("%i"), int(m_opt.default_value->getInt())); break; } case coStrings:{ @@ -1654,7 +1375,7 @@ void Choice::set_selection() break; } case coFloatOrPercent: { - text_value = double_to_string(m_opt.default_value->get_float(), m_opt.precision); + text_value = double_to_string(m_opt.default_value->getFloat(), m_opt.precision); if (m_opt.get_default_value()->percent) text_value += "%"; break; @@ -1673,7 +1394,7 @@ void Choice::set_selection() } } -void Choice::set_text_value(const std::string &value, bool change_event) //! Redundant? +void Choice::set_value(const std::string& value, bool change_event) //! Redundant? { m_disable_change_event = !change_event; @@ -1718,16 +1439,8 @@ int32_t Choice::idx_from_enum_value(int32_t val) { return 0; } -void Choice::set_value(const boost::any &value, bool change_event) +void Choice::set_value(const boost::any& value, bool change_event) { - // can be - // GUIType::select_open - // GUIType::f_enum_open: - // GUIType::i_enum_open: - // coEnum - assert(m_opt.type == coEnum || m_opt.gui_type == ConfigOptionDef::GUIType::select_open || - m_opt.gui_type == ConfigOptionDef::GUIType::f_enum_open || - m_opt.gui_type == ConfigOptionDef::GUIType::i_enum_open); m_disable_change_event = !change_event; choice_ctrl* field = dynamic_cast(window); @@ -1738,9 +1451,12 @@ void Choice::set_value(const boost::any &value, bool change_event) case coPercent: case coFloatOrPercent: case coString: - case coStrings: { - auto [/*wxString*/ text_value, /*bool*/ has_nil] = any_to_wxstring(value, m_opt, m_opt_idx); - + case coStrings: { + wxString text_value; + if (m_opt.type == coInt) + text_value = wxString::Format(_T("%i"), int(boost::any_cast(value))); + else + text_value = boost::any_cast(value); size_t idx = 0; const std::vector& enums = m_opt.enum_values.empty() ? m_opt.enum_labels : m_opt.enum_values; for (auto el : enums) @@ -1758,7 +1474,6 @@ void Choice::set_value(const boost::any &value, bool change_event) else field->SetSelection(idx); - // merill note: i don't like hacks like that. makes the code spagetti if (!m_value.empty() && m_opt.opt_key == "fill_density") { // If m_value was changed before, then update m_value here too to avoid case // when control's value is already changed from the ConfigManipulation::update_print_fff_config(), @@ -1814,7 +1529,7 @@ void Choice::convert_to_enum_value(int32_t ret_enum) { m_value = value; } else - m_value = m_opt.default_value->get_int(); + m_value = m_opt.default_value.get()->getInt(); } //Please don't use that on Enum fields it will just break everything @@ -1989,11 +1704,10 @@ void ColourPicker::set_undef_value(wxColourPickerCtrl* field) btn->SetBitmapLabel(bmp); } -void ColourPicker::set_value(const boost::any &value, bool change_event) +void ColourPicker::set_value(const boost::any& value, bool change_event) { - // can be ConfigOptionDef::GUIType::color m_disable_change_event = !change_event; - const wxString clr_str(boost::any_cast(value)); + const wxString clr_str(boost::any_cast(value)); auto field = dynamic_cast(window); wxColour clr(clr_str); @@ -2053,10 +1767,10 @@ void PointCtrl::BUILD() const wxSize field_size(4 * m_em_unit, -1); Vec2d default_pt; - if (m_opt.type == coPoint) + if(m_opt.type==coPoint) default_pt = m_opt.get_default_value()->value; else // coPoints - default_pt = m_opt.get_default_value()->get_at(0); + default_pt = m_opt.get_default_value()->values.at(0); double val = default_pt(0); wxString X = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None); val = default_pt(1); @@ -2152,7 +1866,7 @@ void PointCtrl::propagate_value(wxTextCtrl* win) on_change_field(); } -void PointCtrl::set_vec2d_value(const Vec2d& value, bool change_event) +void PointCtrl::set_value(const Vec2d& value, bool change_event) { m_disable_change_event = !change_event; @@ -2164,12 +1878,22 @@ void PointCtrl::set_vec2d_value(const Vec2d& value, bool change_event) m_disable_change_event = false; } -void PointCtrl::set_value(const boost::any &value, bool change_event) +void PointCtrl::set_value(const boost::any& value, bool change_event) { - // can be coPoint and coPoints (with idx) - assert(m_opt.type == coPoint || (m_opt.type == coPoints && m_opt_idx >= 0)); - Vec2d pt = boost::any_cast(value); - set_vec2d_value(pt, change_event); + Vec2d pt(Vec2d::Zero()); + const Vec2d *ptf = boost::any_cast(&value); + if (!ptf) + { + if (m_opt.type == coPoint) { + pt = boost::any_cast(value)->value; + } else { // coPoints + ConfigOptionPoints* pts = boost::any_cast(value); + pt = pts->values.at(0); + } + } + else + pt = *ptf; + set_value(pt, change_event); } boost::any& PointCtrl::get_value() @@ -2178,7 +1902,7 @@ boost::any& PointCtrl::get_value() if (!x_textctrl->GetValue().ToDouble(&x) || !y_textctrl->GetValue().ToDouble(&y)) { - set_value(m_value.empty() ? Vec2d(0.0, 0.0) : m_value, true); + set_value(m_value.empty() ? Vec2d(0.0, 0.0) : m_value, true); show_error(m_parent, _L("Invalid numeric input.")); } else @@ -2189,7 +1913,7 @@ boost::any& PointCtrl::get_value() if (x > m_opt.max) x = m_opt.max; if (m_opt.min > y) y = m_opt.min; if (y > m_opt.max) y = m_opt.max; - set_vec2d_value(Vec2d(x, y), true); + set_value(Vec2d(x, y), true); show_error(m_parent, _L("Input value is out of range")); } @@ -2281,34 +2005,24 @@ void SliderCtrl::BUILD() m_sizer = dynamic_cast(temp); } -void SliderCtrl::set_value(const boost::any &value, bool change_event) +void SliderCtrl::set_value(const boost::any& value, bool change_event) { - // only with ConfigOptionDef::GUIType::slider: & coFloat or coInt - assert(m_opt.gui_type == ConfigOptionDef::GUIType::slider && (m_opt.type == coFloat || m_opt.type == coInt)); m_disable_change_event = !change_event; - if (m_opt.type == coFloat) { - m_slider->SetValue(boost::any_cast(value) * m_scale); - double val = boost::any_cast(get_value()); - m_textctrl->SetLabel(wxString::Format("%d", val)); - } else if (m_opt.type == coInt) { - m_slider->SetValue(boost::any_cast(value) * m_scale); - int32_t val = boost::any_cast(get_value()); - m_textctrl->SetLabel(wxString::Format("%d", val)); - } + + m_slider->SetValue(boost::any_cast(value)*m_scale); + int val = boost::any_cast(get_value()); + m_textctrl->SetLabel(wxString::Format("%d", val)); m_disable_change_event = false; } -boost::any &SliderCtrl::get_value() +boost::any& SliderCtrl::get_value() { - // int ret_val; - // x_textctrl->GetValue().ToDouble(&val); - if (m_opt.type == coFloat) { - return m_value = double(m_slider->GetValue() / m_scale); - } else if (m_opt.type == coInt) { - return m_value = int32_t(m_slider->GetValue() / m_scale); - } +// int ret_val; +// x_textctrl->GetValue().ToDouble(&val); + return m_value = int(m_slider->GetValue()/m_scale); } + } // GUI } // Slic3r diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 574cda881e2..a567b5d67a5 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -38,8 +38,6 @@ using t_back_to_init = std::function; wxString double_to_string(double const value, const int max_precision = 6); wxString get_points_string(const std::vector& values); -// return {invalid_val, out_of_range_val} -std::pair get_strings_points(const wxString &str, double min, double max, std::vector &out_values); class Field; class RichTooltipTimer : public wxTimer @@ -109,7 +107,7 @@ class Field { /// Copy of ConfigOption for deduction purposes const ConfigOptionDef m_opt {ConfigOptionDef()}; const t_config_option_key m_opt_id;//! {""}; - int m_opt_idx = -1; + int m_opt_idx = 0; // for saving state bool m_is_enable{true}; @@ -120,7 +118,7 @@ class Field { /// Sets a value for this control. /// subclasses should overload with a specific version /// Postcondition: Method does not fire the on_change event. - virtual void set_value(const boost::any &value, bool change_event) = 0; + virtual void set_value(const boost::any& value, bool change_event) = 0; virtual void set_last_meaningful_value() {} virtual void set_na_value() {} @@ -155,7 +153,8 @@ class Field { virtual wxSizer* getSizer() { return nullptr; } virtual wxWindow* getWindow() { return nullptr; } - bool is_matched(const std::string &string, const std::string &pattern); + bool is_matched(const std::string& string, const std::string& pattern); + void get_value_by_opt_type(wxString& str, const bool check_value = true); /// Factory method for generating new derived classes. template @@ -242,6 +241,8 @@ class Field { // current value boost::any m_value; + // last meaningful value + boost::any m_last_meaningful_value; // last validated value wxString m_last_validated_value; @@ -254,23 +255,6 @@ class Field { friend class OptionsGroup; }; -class TextField : public Field -{ - using Field::Field; -protected: - TextField(const ConfigOptionDef &opt, const t_config_option_key &id) : Field(opt, id) {} - TextField(wxWindow *parent, const ConfigOptionDef &opt, const t_config_option_key &id) : Field(parent, opt, id) - {} - ~TextField() {} - - void get_value_by_opt_type(wxString &str, const bool check_value = true); - bool get_vector_value(const wxString &str, ConfigOptionVectorBase &reader); - virtual void set_text_value(const std::string &str, bool change_event = false) = 0; - - // last meaningful value (can be whatever the child class want it to be) - wxString m_last_meaningful_value; -}; - /// Convenience function, accepts a const reference to t_field and checks to see whether /// or not both wx pointers are null. inline bool is_bad_field(const t_field& obj) { return obj->getSizer() == nullptr && obj->getWindow() == nullptr; } @@ -281,16 +265,16 @@ inline bool is_window_field(const t_field& obj) { return !is_bad_field(obj) && o /// Covenience function to determine whether this field is a valid sizer field. inline bool is_sizer_field(const t_field& obj) { return !is_bad_field(obj) && obj->getSizer() != nullptr; } -class TextCtrl : public TextField { - using TextField::TextField; +class TextCtrl : public Field { + using Field::Field; #ifdef __WXGTK__ bool bChangedValueEvent = true; void change_field_value(wxEvent& event); #endif //__WXGTK__ public: - TextCtrl(const ConfigOptionDef &opt, const t_config_option_key &id) : TextField(opt, id) {} - TextCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : TextField(parent, opt, id) {} + TextCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} + TextCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} ~TextCtrl() {} void BUILD() override; @@ -299,7 +283,11 @@ class TextCtrl : public TextField { void propagate_value(); wxWindow* window {nullptr}; - void set_text_value(const std::string &value, bool change_event = false) override; + void set_value(const std::string& value, bool change_event = false) { + m_disable_change_event = !change_event; + dynamic_cast(window)->SetValue(wxString(value)); + m_disable_change_event = false; + } void set_value(const boost::any& value, bool change_event = false) override; void set_last_meaningful_value() override; void set_na_value() override; @@ -316,8 +304,6 @@ class TextCtrl : public TextField { class CheckBox : public Field { using Field::Field; bool m_is_na_val {false}; - // last meaningful value (can be whatever the child class want it to be) - uint8_t m_last_meaningful_value; void set_widget_value(bool new_val); public: @@ -328,12 +314,12 @@ class CheckBox : public Field { wxWindow* window{ nullptr }; void BUILD() override; - void set_bool_value(const bool value, bool change_event = false) { + void set_value(const bool value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetValue(value); m_disable_change_event = false; } - void set_value(const boost::any &value, bool change_event = false) override; + void set_value(const boost::any& value, bool change_event = false) override; void set_last_meaningful_value() override; void set_na_value() override; boost::any& get_value() override; @@ -362,7 +348,7 @@ class SpinCtrl : public Field { /// Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER void propagate_value() ; - void set_text_value(const std::string& value, bool change_event = false) { + void set_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetValue(value); m_disable_change_event = false; @@ -387,18 +373,16 @@ class SpinCtrl : public Field { wxWindow* getWindow() override { return window; } }; -class Choice : public TextField -{ - using TextField::TextField; +class Choice : public Field { + using Field::Field; protected: //used by get_value when it's an enum //convert the value from the select to the enum value. store it in m_value void convert_to_enum_value(int32_t idx_val); int32_t idx_from_enum_value(int32_t enum_val); public: - Choice(const ConfigOptionDef &opt, const t_config_option_key &id) : TextField(opt, id) {} - Choice(wxWindow *parent, const ConfigOptionDef &opt, const t_config_option_key &id) : TextField(parent, opt, id) - {} + Choice(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} + Choice(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} ~Choice() {} wxWindow* window{ nullptr }; @@ -415,8 +399,8 @@ class Choice : public TextField int m_last_selected { wxNOT_FOUND }; void set_selection(); - void set_text_value(const std::string &value, bool change_event = false); - void set_value(const boost::any &value, bool change_event = false) override; + void set_value(const std::string& value, bool change_event = false); + void set_value(const boost::any& value, bool change_event = false) override; void set_values(const std::vector &values); void set_values(const wxArrayString &values); boost::any& get_value() override; @@ -442,12 +426,12 @@ class ColourPicker : public Field { wxWindow* window{ nullptr }; void BUILD() override; - void set_text_value(const std::string& value, bool change_event = false) { + void set_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetColour(value); m_disable_change_event = false; } - void set_value(const boost::any &value, bool change_event = false) override; + void set_value(const boost::any& value, bool change_event = false) override; boost::any& get_value() override; void msw_rescale() override; void sys_color_changed() override; @@ -472,8 +456,8 @@ class PointCtrl : public Field { bool value_was_changed(wxTextCtrl* win); // Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER void propagate_value(wxTextCtrl* win); - void set_vec2d_value(const Vec2d& value, bool change_event = false); - void set_value(const boost::any &value, bool change_event = false) override; + void set_value(const Vec2d& value, bool change_event = false); + void set_value(const boost::any& value, bool change_event = false) override; boost::any& get_value() override; void msw_rescale() override; @@ -500,7 +484,7 @@ class StaticText : public Field { wxWindow* window{ nullptr }; void BUILD() override; - void set_text_value(const std::string& value, bool change_event = false) { + void set_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetLabel(wxString::FromUTF8(value.data())); m_disable_change_event = false; @@ -535,7 +519,7 @@ class SliderCtrl : public Field { void BUILD() override; - void set_int_value(const int value, bool change_event = false); + void set_value(const int value, bool change_event = false); void set_value(const boost::any& value, bool change_event = false) override; boost::any& get_value() override; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 2ba8dc8d53e..2263616296f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -279,8 +279,8 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const assert(extruders_min_height->values.size() == extruders_max_height->values.size()); assert(extruders_min_height->values.size() == nozzle_diameter->values.size()); for (size_t idx_extruder = 0; idx_extruder < extruders_min_height->values.size(); ++idx_extruder) { - min_height = std::min(min_height, float(extruders_min_height->get_abs_value(idx_extruder, nozzle_diameter->get_float(idx_extruder)))); - max_height = std::max(max_height, float(extruders_max_height->get_abs_value(idx_extruder, nozzle_diameter->get_float(idx_extruder)))); + min_height = std::min(min_height, float(extruders_min_height->get_abs_value(idx_extruder, nozzle_diameter->getFloat(idx_extruder)))); + max_height = std::max(max_height, float(extruders_max_height->get_abs_value(idx_extruder, nozzle_diameter->getFloat(idx_extruder)))); } min_height = check_z_step(min_height, z_step); max_height = check_z_step(max_height, z_step); diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index f785487ce54..ccd3cc08306 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -99,6 +99,139 @@ const std::string& shortkey_alt_prefix() return str; } +// opt_index = 0, by the reason of zero-index in ConfigOptionVector by default (in case only one element) +void change_opt_value(DynamicConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/) +{ + try{ + + if (config.def()->get(opt_key)->type == coBools && config.def()->get(opt_key)->nullable) { + ConfigOptionBoolsNullable* vec_new = new ConfigOptionBoolsNullable{ boost::any_cast(value) }; + config.option(opt_key)->set_at(vec_new, opt_index, 0); + return; + } + + const ConfigOptionDef *opt_def = config.def()->get(opt_key); + switch (opt_def->type) { + case coFloatOrPercent:{ + std::string str = boost::any_cast(value); + bool percent = false; + if (str.back() == '%') { + str.pop_back(); + percent = true; + } + double val = std::stod(str); // locale-dependent (on purpose - the input is the actual content of the field) + config.set_key_value(opt_key, new ConfigOptionFloatOrPercent(val, percent)); + break;} + case coFloatsOrPercents: { + std::string str = boost::any_cast(value); + bool percent = false; + if (str.back() == '%') { + str.pop_back(); + percent = true; + } + double val = stod(str); + ConfigOptionFloatsOrPercents* vec_new = new ConfigOptionFloatsOrPercents{ boost::any_cast(FloatOrPercent{val, percent}) }; + config.option(opt_key)->set_at(vec_new, opt_index, opt_index); + break; } + case coPercent: + config.set_key_value(opt_key, new ConfigOptionPercent(boost::any_cast(value))); + break; + case coFloat:{ + //config.set_key_value(opt_key, new ConfigOptionFloat(boost::any_cast(value))); + double& val_dbl = config.opt_float(opt_key); + val_dbl = boost::any_cast(value); + break; + } + case coPoint: { + config.set_key_value(opt_key, new ConfigOptionPoint(boost::any_cast(value))); + break; + } + case coPercents:{ + ConfigOptionPercents* vec_new = new ConfigOptionPercents{ boost::any_cast(value) }; + config.option(opt_key)->set_at(vec_new, opt_index, opt_index); + break; + } + case coFloats:{ + ConfigOptionFloats* vec_new = new ConfigOptionFloats{ boost::any_cast(value) }; + config.option(opt_key)->set_at(vec_new, opt_index, opt_index); + break; + } + case coString: { + //config.set_key_value(opt_key, new ConfigOptionString(boost::any_cast(value))); + std::string& val_str = config.opt_string(opt_key); + val_str = boost::any_cast(value); + break; + } + case coStrings:{ + if (opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "gcode_substitutions") { + config.option(opt_key)->values = + boost::any_cast>(value); + } + else if (config.def()->get(opt_key)->gui_flags.compare("serialized") == 0) { + std::string str = boost::any_cast(value); + std::vector values {}; + if (!str.empty()) { + if (str.back() == ';') str.pop_back(); + // Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values. + // Currently used for the post_process config value only. + boost::split(values, str, boost::is_any_of(";")); + if (values.size() == 1 && values[0] == "") + values.resize(0); + } + config.option(opt_key)->values = values; + } + else{ + ConfigOptionStrings* vec_new = new ConfigOptionStrings{ boost::any_cast(value) }; + config.option(opt_key)->set_at(vec_new, opt_index, 0); + } + } + break; + case coBool: + config.set_key_value(opt_key, new ConfigOptionBool(boost::any_cast(value))); + break; + case coBools:{ + ConfigOptionBools* vec_new = new ConfigOptionBools{ boost::any_cast(value) != 0 }; + config.option(opt_key)->set_at(vec_new, opt_index, 0); + break;} + case coInt:{ + //config.set_key_value(opt_key, new ConfigOptionInt(boost::any_cast(value))); + int& val_int = config.opt_int(opt_key); + val_int = boost::any_cast(value); + } + break; + case coInts:{ + ConfigOptionInts* vec_new = new ConfigOptionInts{ boost::any_cast(value) }; + config.option(opt_key)->set_at(vec_new, opt_index, 0); + } + break; + case coEnum:{ + ConfigOption* opt = opt_def->default_value.get()->clone(); + opt->setInt(boost::any_cast(value)); // we transport an int convertion of the enum in the boost anycast. + BOOST_LOG_TRIVIAL(debug) << "Set enum "<< opt_key << " as int " << boost::any_cast(value) << " into enum " << opt->serialize(); + config.set_key_value(opt_key, opt); + } + break; + case coPoints:{ + if (opt_key == "bed_shape") { + config.option(opt_key)->values = boost::any_cast>(value); + break; + } + ConfigOptionPoints* vec_new = new ConfigOptionPoints{ boost::any_cast(value) }; + config.option(opt_key)->set_at(vec_new, opt_index, 0); + } + break; + case coNone: + break; + default: + break; + } + } + catch (const std::exception &e) + { + wxLogError(format_wxstr("Internal error when changing value for %1%: %2%", opt_key, e.what())); + } +} + void show_error(wxWindow* parent, const wxString& message, bool monospaced_font) { ErrorDialog msg(parent, message, monospaced_font); @@ -160,7 +293,7 @@ static void add_config_substitutions(const ConfigSubstitutions& conf_substitutio { const std::vector& labels = def->enum_labels; const std::vector& values = def->enum_values; - int val = conf_substitution.new_value->get_int(); + int val = conf_substitution.new_value->getInt(); bool is_infill = def->opt_key == "top_fill_pattern" || def->opt_key == "bottom_fill_pattern" || @@ -188,12 +321,12 @@ static void add_config_substitutions(const ConfigSubstitutions& conf_substitutio break; } case coBool: - new_val = conf_substitution.new_value->get_bool() ? "true" : "false"; + new_val = conf_substitution.new_value->getBool() ? "true" : "false"; break; case coBools: if (conf_substitution.new_value->nullable()) for (const char v : static_cast(conf_substitution.new_value.get())->values) - new_val += std::string(v == ConfigOptionBoolsNullable::NIL_VALUE() ? "nil" : v ? "true" : "false") + ", "; + new_val += std::string(v == ConfigOptionBoolsNullable::nil_value() ? "nil" : v ? "true" : "false") + ", "; else for (const char v : static_cast(conf_substitution.new_value.get())->values) new_val += std::string(v ? "true" : "false") + ", "; diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index 62ba9ab8a37..21fb5c204a7 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -37,7 +37,7 @@ extern AppConfig* get_app_config(); extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_language_change); // Change option value in config -//void change_opt_value(DynamicConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); +void change_opt_value(DynamicConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); // If monospaced_font is true, the error message is displayed using html
tags, // so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser. diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp index 99a66d335d7..55fba0e332c 100644 --- a/src/slic3r/GUI/GUI_ObjectLayers.cpp +++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp @@ -131,7 +131,7 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinus // Add control for the "Layer height" - editor = new LayerRangeEditor(this, double_to_string(m_object->layer_config_ranges[range].option("layer_height")->get_float()), etLayerHeight, set_focus_data, + editor = new LayerRangeEditor(this, double_to_string(m_object->layer_config_ranges[range].option("layer_height")->getFloat()), etLayerHeight, set_focus_data, [range](coordf_t layer_height, bool, bool) { return wxGetApp().obj_list()->edit_layer_range(range, layer_height); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 2bd179abeea..bcdf8d594e6 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -844,26 +844,26 @@ void Preview::update_layers_slider_mode() if (!objects.empty()) { const int extruder = objects[0]->config.has("extruder") ? - objects[0]->config.option("extruder")->get_int() : 0; + objects[0]->config.option("extruder")->getInt() : 0; auto is_one_extruder_printed_model = [objects, extruder]() { for (ModelObject* object : objects) { if (object->config.has("extruder") && - object->config.option("extruder")->get_int() != extruder) + object->config.option("extruder")->getInt() != extruder) return false; for (ModelVolume* volume : object->volumes) if ((volume->config.has("extruder") && - volume->config.option("extruder")->get_int() != 0 && // extruder isn't default - volume->config.option("extruder")->get_int() != extruder) || + volume->config.option("extruder")->getInt() != 0 && // extruder isn't default + volume->config.option("extruder")->getInt() != extruder) || !volume->mmu_segmentation_facets.empty()) return false; for (const auto& range : object->layer_config_ranges) if (range.second.has("extruder") && - range.second.option("extruder")->get_int() != extruder) + range.second.option("extruder")->getInt() != extruder) return false; } return true; diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index e41c1271f7a..3181b99b2d0 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -80,12 +80,12 @@ void ArrangeJob::clear_input() void add_brim(arrangement::ArrangePolygon &ap, const ModelConfigObject &config, const Plater* plater) { - if (plater->config()->option("brim_per_object")->get_bool()) { + if (plater->config()->option("brim_per_object")->getBool()) { // object-brim increase the size of the object // Should be using the "inflation" field but it's non-functional right now. - coord_t diff = scale_(plater->config()->option("brim_width")->get_float() - plater->config()->option("extruder_clearance_radius")->get_float() / 2); + coord_t diff = scale_(plater->config()->option("brim_width")->getFloat() - plater->config()->option("extruder_clearance_radius")->getFloat() / 2); if (config.option("brim_width")) - diff = scale_(config.option("brim_width")->get_float() - plater->config()->option("extruder_clearance_radius")->get_float() / 2); + diff = scale_(config.option("brim_width")->getFloat() - plater->config()->option("extruder_clearance_radius")->getFloat() / 2); if (diff > 0) { ExPolygons brimmed = offset_ex(ap.poly, diff); assert(brimmed.size() == 1); diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 51dd05d57ed..7ad55dd2765 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -49,6 +49,9 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co case ConfigOptionDef::GUIType::legend: // StaticText m_fields.emplace(id, StaticText::Create(this->ctrl_parent(), opt, id)); break; + case ConfigOptionDef::GUIType::one_string: + m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); + break; default: switch (opt.type) { case coFloatOrPercent: @@ -61,22 +64,12 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co case coStrings: m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); break; - case coBools: - if (id.find('#') == std::string::npos) { - // string field with vector serialization - m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); - break; - } case coBool: + case coBools: m_fields.emplace(id, CheckBox::Create(this->ctrl_parent(), opt, id)); break; - case coInts: - if (id.find('#') == std::string::npos) { - // string field with vector serialization - m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); - break; - } case coInt: + case coInts: m_fields.emplace(id, SpinCtrl::Create(this->ctrl_parent(), opt, id)); break; case coEnum: @@ -665,7 +658,7 @@ void ConfigOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const b const std::string &opt_key = itOption.first; int opt_index = itOption.second; - this->change_opt_value(opt_key, value, opt_index); + this->change_opt_value(opt_key, value, opt_index == -1 ? 0 : opt_index); } OptionsGroup::on_change_OG(opt_id, value); @@ -733,8 +726,8 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, if (initial_conf.has(dep_key) && edited_conf.has(dep_key)) { ConfigOption* conf_opt = initial_conf.option(dep_key)->clone(); // update the field - tab->set_value(dep_key, initial_conf.option(dep_key)->get_any()); - tab->on_value_change(dep_key, conf_opt->get_any()); + tab->set_value(dep_key, get_config_value(initial_conf, dep_key)); + tab->on_value_change(dep_key, conf_opt->getAny()); } } } @@ -747,14 +740,14 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, } else if (it_opt_map == m_opt_map.end() || // This option doesn't have corresponded field is_option_without_field(opt_key) ) { - value = config.option(opt_key)->get_any(); + value = get_config_value(config, opt_key); this->change_opt_value(opt_key, value); return; } else { auto opt_id = it_opt_map->first; std::string opt_short_key = m_opt_map.at(opt_id).first; int opt_index = m_opt_map.at(opt_id).second; - value = config.option(opt_short_key)->get_any(opt_index); + value = get_config_value(config, opt_short_key, opt_index); } if(set_value(opt_key, value)) @@ -779,7 +772,7 @@ void ConfigOptionsGroup::reload_config() // index in the vector option, zero for scalars int opt_index = kvp.second.second; const ConfigOptionDef &option = m_options.at(opt_id).opt; - this->set_value(opt_id, m_config->option(opt_key)->get_any(opt_index)); + this->set_value(opt_id, config_value(opt_key, opt_index, option.gui_flags == "serialized")); } update_script_presets(); } @@ -971,6 +964,163 @@ void ConfigOptionsGroup::refresh() custom_ctrl->Refresh(); } +boost::any ConfigOptionsGroup::config_value(const std::string& opt_key, int opt_index, bool deserialize) { + + if (deserialize) { + // Want to edit a vector value(currently only multi - strings) in a single edit box. + // Aggregate the strings the old way. + // Currently used for the post_process config value only. + if (opt_index != -1) + throw Slic3r::OutOfRange("Can't deserialize option indexed value"); +// return join(';', m_config->get(opt_key)}); + return get_config_value(*m_config, opt_key); + } + else { +// return opt_index == -1 ? m_config->get(opt_key) : m_config->get_at(opt_key, opt_index); + return get_config_value(*m_config, opt_key, opt_index); + } +} + +boost::any ConfigOptionsGroup::get_config_value(const DynamicConfig& config, const std::string& opt_key, int opt_index /*= -1*/) +{ + size_t idx = opt_index == -1 ? 0 : opt_index; + + boost::any ret; + wxString text_value = wxString(""); + const ConfigOptionDef* opt = config.def()->get(opt_key); + + if (opt->nullable) + { + switch (opt->type) + { + case coPercents: + case coFloats: { + if (config.option(opt_key)->is_nil()) + ret = _(L("N/A")); + else { + double val = opt->type == coFloats ? + config.option(opt_key)->get_at(idx) : + config.option(opt_key)->get_at(idx); + ret = double_to_string(val, opt->precision); } + } + break; + case coFloatsOrPercents: { + if (config.option(opt_key)->is_nil()) + ret = _(L("N/A")); + else { + FloatOrPercent float_percent = config.option(opt_key)->get_at(idx); + text_value = double_to_string(float_percent.value, opt->precision); + if (float_percent.percent) + text_value += "%"; + ret = text_value; + } + } + break; + case coBools: + ret = config.option(opt_key)->values[idx]; + break; + case coInts: + ret = config.option(opt_key)->get_at(idx); + break; + case coPoints: + default: + break; + } + return ret; + } + + switch (opt->type) { + case coFloatOrPercent:{ + const auto &value = *config.option(opt_key); + + text_value = double_to_string(value.value, opt->precision); + if (value.percent) + text_value += "%"; + + ret = text_value; + break; + } + case coFloatsOrPercents:{ + const ConfigOptionFloatsOrPercents &value = *config.option(opt_key); + + text_value = double_to_string(value.get_at(idx).value, opt->precision); + if (value.get_at(idx).percent) + text_value += "%"; + + ret = text_value; + break; + } + case coPercent:{ + double val = config.option(opt_key)->value; + text_value = double_to_string(val, opt->precision); + ret = text_value; + } + break; + case coPercents: + case coFloats: + case coFloat:{ + double val = opt->type == coFloats ? + config.opt_float(opt_key, idx) : + opt->type == coFloat ? config.opt_float(opt_key) : + config.option(opt_key)->get_at(idx); + ret = double_to_string(val, opt->precision); + } + break; + case coString: + ret = from_u8(config.opt_string(opt_key)); + break; + case coStrings: + if (opt_key == "compatible_printers" || opt_key == "compatible_prints" || opt_key == "gcode_substitutions") { + ret = config.option(opt_key)->values; + break; + } + if (opt_key == "filament_ramming_parameters") { + ret = config.opt_string(opt_key, static_cast(idx)); + break; + } + if (config.option(opt_key)->values.empty()) + ret = text_value; + else if (opt->gui_flags == "serialized") { + std::vector values = config.option(opt_key)->values; + if (!values.empty() && !values[0].empty()) + for (auto el : values) + text_value += el + ";"; + ret = text_value; + } + else + ret = from_u8(config.opt_string(opt_key, static_cast(idx))); + break; + case coBool: + ret = config.opt_bool(opt_key); + break; + case coBools: + ret = config.opt_bool(opt_key, idx); + break; + case coInt: + ret = config.opt_int(opt_key); + break; + case coInts: + ret = config.opt_int(opt_key, idx); + break; + case coEnum: + ret = config.option(opt_key)->getInt(); + break; + case coPoint: + ret = config.option(opt_key)->value; + break; + case coPoints: + if (opt_key == "bed_shape") + ret = config.option(opt_key)->values; + else + ret = config.option(opt_key)->get_at(idx); + break; + case coNone: + default: + break; + } + return ret; +} + Field* ConfigOptionsGroup::get_fieldc(const t_config_option_key& opt_key, int opt_index) { Field* field = get_field(opt_key); @@ -1005,8 +1155,7 @@ std::pair ConfigOptionsGroup::get_custom_ctrl_with_blinki void ConfigOptionsGroup::change_opt_value(const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/) { - //Slic3r::GUI::change_opt_value(const_cast(*m_config), opt_key, value, opt_index); - const_cast(*m_config).option(opt_key)->set_any(value, opt_index); + Slic3r::GUI::change_opt_value(const_cast(*m_config), opt_key, value, opt_index); if (m_modelconfig) m_modelconfig->touch(); } diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index da388b6867a..7eca3b9231e 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -309,10 +309,9 @@ class ConfigOptionsGroup: public OptionsGroup { void msw_rescale(); void sys_color_changed(); void refresh(); - //call optionconfig->get_any() - //boost::any config_value(const std::string& opt_key, int opt_index, bool deserialize); + boost::any config_value(const std::string& opt_key, int opt_index, bool deserialize); // return option value from config - //boost::any get_config_value(const DynamicConfig& config, const std::string& opt_key, int opt_index = -1); + boost::any get_config_value(const DynamicConfig& config, const std::string& opt_key, int opt_index = -1); Field* get_fieldc(const t_config_option_key& opt_key, int opt_index); std::pair get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index/* = -1*/); diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index 9a4105017c6..328df639204 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -307,7 +307,7 @@ void PhysicalPrinterDialog::update_printers() boost::any any_string_type = std::string(""); auto value_idx = std::find(slugs.begin(), slugs.end(), m_config->opt("printhost_port")->value); if ((val.empty() || (any_string_type.type() == val.type() && boost::any_cast(val) == "")) && !slugs.empty() && value_idx == slugs.end()) { - m_config->option("printhost_port")->set_any(slugs[0]); // change_opt_value(*m_config, "printhost_port", slugs[0]); + change_opt_value(*m_config, "printhost_port", slugs[0]); choice->set_value(slugs[0], false); } else if (value_idx != slugs.end()) { choice->set_value(m_config->option("printhost_port")->value, false); @@ -325,7 +325,7 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr if(opt_key == "printhost_client_cert_enabled") this->m_show_cert_fields = boost::any_cast(value); if (!this->m_show_cert_fields && !m_config->opt_string("printhost_client_cert").empty()) { - m_config->option("printhost_client_cert")->set_any(std::string("")); //change_opt_value(*m_config, "printhost_client_cert", std::string("")); + change_opt_value(*m_config, "printhost_client_cert", std::string("")); //change_opt_value(*m_config, "printhost_client_cert_password", ""); m_config->set_deserialize_strict("printhost_client_cert_password", ""); } @@ -691,7 +691,7 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change) else if ((printer_change && !all_presets_are_from_mk3_family) || (!all_presets_are_from_mk3_family && m_config->option>("host_type")->value == htPrusaLink)) set_to_choice_and_config(htOctoPrint); else - choice->set_value(m_config->option("host_type")->get_int()); + choice->set_value(m_config->option("host_type")->getInt()); had_all_mk3 = all_presets_are_from_mk3_family; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index c07651e9219..9d09ffb23f9 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1281,11 +1281,11 @@ void Sidebar::update_sliced_info_sizer() wxString str_total_cost = "N/A"; DynamicPrintConfig* cfg = wxGetApp().get_tab(Preset::TYPE_SLA_MATERIAL)->get_config(); - if (cfg->option("bottle_cost")->get_float() > 0.0 && - cfg->option("bottle_volume")->get_float() > 0.0) + if (cfg->option("bottle_cost")->getFloat() > 0.0 && + cfg->option("bottle_volume")->getFloat() > 0.0) { - double material_cost = cfg->option("bottle_cost")->get_float() / - cfg->option("bottle_volume")->get_float(); + double material_cost = cfg->option("bottle_cost")->getFloat() / + cfg->option("bottle_volume")->getFloat(); str_total_cost = wxString::Format("%.3f", material_cost*(ps.objects_used_material + ps.support_used_material) / 1000); } p->sliced_info->SetTextAndShow(siCost, str_total_cost, "Cost"); diff --git a/src/slic3r/GUI/ScriptExecutor.cpp b/src/slic3r/GUI/ScriptExecutor.cpp index 728691a8b71..a84ac04ca60 100644 --- a/src/slic3r/GUI/ScriptExecutor.cpp +++ b/src/slic3r/GUI/ScriptExecutor.cpp @@ -86,9 +86,9 @@ bool as_get_bool(std::string& key) throw NoDefinitionException("error, can't find bool option " + key); if (opt->is_vector()) { const ConfigOptionVectorBase* vector = static_cast(opt); - return vector->get_float(0) != 0; + return vector->getFloat(0) != 0; } else { - return opt->get_bool(); + return opt->getBool(); } } void as_set_bool(std::string& key, bool b) @@ -113,9 +113,9 @@ int32_t as_get_int(std::string& key) throw NoDefinitionException("error, can't find int option " + key); if (opt->is_vector()) { const ConfigOptionVectorBase* vector = static_cast(opt); - return (int32_t)vector->get_float(0); + return (int32_t)vector->getFloat(0); } else { - return (int32_t)(opt->get_int()); + return (int32_t)(opt->getInt()); } } void as_set_int(std::string& key, int val) @@ -149,7 +149,7 @@ void as_set_int(std::string& key, int val) // } // if (value >= 0 && value < def->enum_values.size()) { ConfigOption* copy = result.second->clone(); - copy->set_enum_int(val); + copy->setInt(val); conf.set_key_value(key, copy); // return; // } @@ -164,9 +164,9 @@ float as_get_float(std::string& key) throw NoDefinitionException("error, can't find float option " + key); if (opt->is_vector()) { const ConfigOptionVectorBase* vector = static_cast(opt); - return (float)vector->get_float(0); + return (float)vector->getFloat(0); } else { - return (float)(opt->get_float()); + return (float)(opt->getFloat()); } } @@ -187,7 +187,7 @@ void as_set_float(std::string& key, float f_val) DynamicPrintConfig& conf = current_script->to_update()[result.first->type()]; if (result.second->type() == ConfigOptionType::coFloat) { - double old_value = result.second->get_float(); + double old_value = result.second->getFloat(); double new_val = round(f_val); // only update if difference is significant if (std::abs(old_value - new_val) / std::abs(old_value) < 0.0000001) @@ -207,7 +207,7 @@ void as_set_float(std::string& key, float f_val) } else if (result.second->type() == ConfigOptionType::coPercent) { double percent_f = floor(f_val * 100000. + 0.5) / 1000.; // only update if difference is significant - double old_value = result.second->get_float(); + double old_value = result.second->getFloat(); if (std::abs(old_value - percent_f) / std::abs(old_value) < 0.0000001) percent_f = old_value; conf.set_key_value(key, new ConfigOptionPercent(percent_f)); @@ -226,7 +226,7 @@ void as_set_float(std::string& key, float f_val) double new_val = round(f_val); if (!static_cast(result.second)->percent) { // only update if difference is significant - double old_value = result.second->get_float(); + double old_value = result.second->getFloat(); if (std::abs(old_value - new_val) / std::abs(old_value) < 0.0000001) new_val = old_value; } @@ -263,7 +263,7 @@ void as_set_percent(std::string& key, float f_val) DynamicPrintConfig& conf = current_script->to_update()[result.first->type()]; if (result.second->type() == ConfigOptionType::coFloat) { // only update if difference is significant - double old_value = result.second->get_float() * 100; + double old_value = result.second->getFloat() * 100; if (std::abs(old_value - percent_f) / std::abs(old_value) < 0.0000001) percent_f = old_value; // don't return int these check, as it can escpae a refresh of the scripted widget conf.set_key_value(key, new ConfigOptionFloat(percent_f / 100.)); @@ -279,7 +279,7 @@ void as_set_percent(std::string& key, float f_val) conf.set_key_value(key, new_opt); } else if (result.second->type() == ConfigOptionType::coPercent) { // only update if difference is significant - double old_value = get_coll(key).second->get_float(); + double old_value = get_coll(key).second->getFloat(); if (std::abs(old_value - percent_f) / std::abs(old_value) < 0.0000001) percent_f = old_value; conf.set_key_value(key, new ConfigOptionPercent(percent_f)); @@ -296,7 +296,7 @@ void as_set_percent(std::string& key, float f_val) } else if (result.second->type() == ConfigOptionType::coFloatOrPercent) { if (static_cast(result.second)->percent) { // only update if difference is significant - double old_value = result.second->get_float(); + double old_value = result.second->getFloat(); if (std::abs(old_value - percent_f) / std::abs(old_value) < 0.0000001) percent_f = old_value; } @@ -346,7 +346,7 @@ void as_set_string(std::string& key, std::string& val) for (; idx < def->enum_values.size() && def->enum_values[idx] != val; idx++) {} if (idx >= 0 && idx < def->enum_values.size()) { ConfigOption* copy = result.second->clone(); - copy->set_enum_int(idx); + copy->setInt(idx); conf.set_key_value(key, copy); } } @@ -788,35 +788,33 @@ void ScriptContainer::call_script_function_set(const ConfigOptionDef& def, const ctx->Prepare(func); std::string str_arg; switch (def.type) { - case coBools: ctx->SetArgByte(0, boost::any_cast(value)); break; - case coBool: ctx->SetArgByte(0, boost::any_cast(value)); break; + case coBool: + case coBools: ctx->SetArgByte(0, boost::any_cast(value)); break; case coInt: - case coInts: ctx->SetArgDWord(0, boost::any_cast(value)); break; + case coInts: ctx->SetArgDWord(0, boost::any_cast(value)); break; case coPercent: case coPercents: case coFloat: case coFloats: ctx->SetArgFloat(0, (float)boost::any_cast(value)); break; case coFloatOrPercent: case coFloatsOrPercents: { - FloatOrPercent fl_percent = boost::any_cast(value); - ctx->SetArgDWord(0, boost::any_cast((float) fl_percent.value)); - ctx->SetArgByte(1, boost::any_cast(fl_percent.percent)); + std::string flOrPercent = boost::any_cast(value); + float val = 0; + bool is_percent = false; + if (flOrPercent[flOrPercent.size() - 1] == '%') { + flOrPercent = flOrPercent.substr(0, flOrPercent.size() - 1); + val = std::stof(flOrPercent); + is_percent = true; + } else { + val = std::stof(flOrPercent); + } + ctx->SetArgDWord(0, boost::any_cast((float)val)); + ctx->SetArgByte(1, boost::any_cast(is_percent)); break; } case coPoint: - case coPoints: { - Vec2d vec = boost::any_cast(value); - ctx->SetArgFloat(0, (float) vec.x()); - ctx->SetArgFloat(1, (float) vec.y()); - break; - } - case coPoint3: { - Vec3d vec = boost::any_cast(value); - ctx->SetArgFloat(0, (float) vec.x()); - ctx->SetArgFloat(1, (float) vec.y()); - ctx->SetArgFloat(2, (float) vec.z()); - break; - } + case coPoints: { ctx->SetArgFloat(0, (float)boost::any_cast(value)); ctx->SetArgFloat(1, (float)boost::any_cast(value)); break; } //FIXME + case coPoint3: { ctx->SetArgFloat(0, (float)boost::any_cast(value)); ctx->SetArgFloat(1, (float)boost::any_cast(value)); ctx->SetArgFloat(2, (float)boost::any_cast(value)); break; } case coString: case coStrings: { str_arg = boost::any_cast(value); @@ -870,7 +868,7 @@ void ScriptContainer::call_script_function_set(const ConfigOptionDef& def, const for (const auto& data : to_update) { Tab* tab = wxGetApp().get_tab(data.first); for (auto opt_key : data.second.keys()) { - tab->on_value_change(opt_key, data.second.option(opt_key)->get_any()); + tab->on_value_change(opt_key, data.second.option(opt_key)->getAny()); } } // refresh the field if needed @@ -925,7 +923,7 @@ bool ScriptContainer::call_script_function_reset(const ConfigOptionDef& def) for (const auto& data : to_update) { Tab* tab = wxGetApp().get_tab(data.first); for (auto opt_key : data.second.keys()) { - tab->on_value_change(opt_key, data.second.option(opt_key)->get_any()); + tab->on_value_change(opt_key, data.second.option(opt_key)->getAny()); } } // refresh the field if needed @@ -1030,71 +1028,55 @@ boost::any ScriptContainer::call_script_function_get_value(const ConfigOptionDef int res = ctx->Execute(); int32_t ret_int; float ret_float; + boost::any field_val; boost::any opt_val; switch (def.type) { case coBool: - case coBools: { - ret_int = ctx->GetReturnDWord(); - opt_val = uint8_t(ret_int < 0 ? 2 : ret_int); - break; - } + case coBools: { ret_int = ctx->GetReturnDWord(); field_val = uint8_t(ret_int < 0 ? 2 : ret_int); opt_val = uint8_t((ret_int > 0)?1:0); break; } //CheckBox case coInt: - case coInts: { - ret_int = ctx->GetReturnDWord(); - opt_val = int32_t(ret_int); - break; - } // SpinCtrl + case coInts: { ret_int = ctx->GetReturnDWord(); field_val = int32_t(ret_int); opt_val = int(ret_int); break; } //SpinCtrl case coString: - case coStrings: { - opt_val = ret_str; - break; - } // TextCtrl + case coStrings: { field_val = from_u8(ret_str); opt_val = ret_str; break; } //TextCtrl case coPercent: - case coPercents: + case coPercents: ret_percent = true; case coFloat: - case coFloats: { - opt_val = double(ctx->GetReturnFloat()); - break; - } + case coFloats: opt_val = double(ctx->GetReturnFloat()); case coFloatOrPercent: case coFloatsOrPercents: { ret_float = ctx->GetReturnFloat(); - opt_val = FloatOrPercent{ret_float, ret_percent}; + wxString ret_wstring = double_to_string(ret_float); + if (ret_percent) + ret_wstring += '%'; + field_val = ret_wstring; //TextCtrl + if (opt_val.empty()) { opt_val = ret_wstring.ToStdString(); } break; } case coPoint: - case coPoints: { - double pt_x = ctx->GetReturnFloat(); - opt_val = Vec2d{pt_x, pt_x}; // FIXME - break; - } // FIXME PointCtrl - case coPoint3: { - double pt_x = ctx->GetReturnFloat(); - opt_val = Vec3d{pt_x, pt_x, pt_x}; - break; - } + case coPoints: { ret_float = ctx->GetReturnFloat(); field_val = Vec2d{ ret_float, ret_float }; opt_val = double(ctx->GetReturnFloat()); break; } //FIXME PointCtrl + case coPoint3: { ret_float = ctx->GetReturnFloat(); field_val = Vec3d{ ret_float, ret_float, ret_float }; opt_val = double(ctx->GetReturnFloat()); break; } case coEnum: { ret_int = ctx->GetReturnDWord(); if (ret_int >= 0 && ret_int < def.enum_values.size()) { - opt_val = int32_t(ret_int); + field_val = int32_t(ret_int); } else { - opt_val = int32_t(0); + field_val = int32_t(0); for (size_t i = 0; i < def.enum_values.size(); i++) { if (ret_str == def.enum_values[i]) - opt_val = int32_t(i); + field_val = int32_t(i); } } + opt_val = field_val; break; //Choice } } if (m_need_refresh) { refresh(def, opt_val); } - if (opt_val.empty()) { + if (field_val.empty()) { std::cout << "Error nullptr for script\n"; } - return opt_val; + return field_val; } void ScriptContainer::refresh(const ConfigOptionDef& def, boost::any value) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 4a07e187cb9..f20beba2736 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -820,7 +820,7 @@ void Tab::init_options_list() template void add_correct_opts_to_options_list(const std::string &opt_key, std::map& map, Tab *tab, const int& value) { - T *opt_cur = static_cast(tab->get_config()->option(opt_key)); + T *opt_cur = static_cast(tab->m_config->option(opt_key)); for (size_t i = 0; i < opt_cur->values.size(); i++) map.emplace(opt_key + "#" + std::to_string(i), value); } @@ -1253,8 +1253,7 @@ void Tab::toggle_option(const std::string& opt_key, bool toggle, int opt_index/* // and value can be some random value because in this case it will not been used void Tab::load_key_value(const std::string& opt_key, const boost::any& value, bool saved_value /*= false*/) { - if (!saved_value) - m_config->option(opt_key)->set_any(value, -1); // change_opt_value(*m_config, opt_key, value); + if (!saved_value) change_opt_value(*m_config, opt_key, value); // Mark the print & filament enabled if they are compatible with the currently selected preset. if (opt_key == "compatible_printers" || opt_key == "compatible_prints") { // Don't select another profile if this profile happens to become incompatible. @@ -1329,7 +1328,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) // update unscripted freq params Field* field = og_freq_chng_params->get_field(opt_key); if (field) { - boost::any val = m_config->option(opt_key)->get_any(field->m_opt_idx); + boost::any val = og_freq_chng_params->get_config_value(*m_config, opt_key); field->set_value(val, false); } @@ -1886,15 +1885,15 @@ std::vector Tab::create_pages(std::string setting_type_nam DynamicPrintConfig new_conf = *m_config; if (opt_key == "bottle_volume") { - double new_bottle_weight = boost::any_cast(value) / (new_conf.option("material_density")->get_float() * 1000); + double new_bottle_weight = boost::any_cast(value) / (new_conf.option("material_density")->getFloat() * 1000); new_conf.set_key_value("bottle_weight", new ConfigOptionFloat(new_bottle_weight)); } if (opt_key == "bottle_weight") { - double new_bottle_volume = boost::any_cast(value)*(new_conf.option("material_density")->get_float() * 1000); + double new_bottle_volume = boost::any_cast(value)*(new_conf.option("material_density")->getFloat() * 1000); new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume)); } if (opt_key == "material_density") { - double new_bottle_volume = new_conf.option("bottle_weight")->get_float() * boost::any_cast(value) * 1000; + double new_bottle_volume = new_conf.option("bottle_weight")->getFloat() * boost::any_cast(value) * 1000; new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume)); } @@ -2733,7 +2732,7 @@ void TabPrint::update() { const Preset& selected_preset = m_preset_bundle->fff_prints.get_selected_preset(); bool is_user_and_saved_preset = !selected_preset.is_system && !selected_preset.is_dirty; - bool support_material_overhangs_queried = m_config->opt_bool("support_material") && m_config->option("overhangs_width_speed")->get_float() == 0; + bool support_material_overhangs_queried = m_config->opt_bool("support_material") && m_config->option("overhangs_width_speed")->getFloat() == 0; m_config_manipulation.initialize_support_material_overhangs_queried(is_user_and_saved_preset && support_material_overhangs_queried); } @@ -2801,11 +2800,11 @@ PageShp TabFilament::create_filament_overrides_page() { Line line {"",""}; if (opt_key == "filament_retract_lift_above" || opt_key == "filament_retract_lift_below") { - Option opt = optgroup->get_option_and_register(opt_key, 0); + Option opt = optgroup->get_option_and_register(opt_key); opt.opt.label = opt.opt.get_full_label(); line = optgroup->create_single_option_line(opt); } else { - line = optgroup->create_single_option_line(optgroup->get_option_and_register(opt_key, 0)); + line = optgroup->create_single_option_line(optgroup->get_option_and_register(opt_key)); } line.near_label_widget = [this, optgroup, opt_key, opt_index](wxWindow* parent) { diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 739c31f02dc..b3a941af049 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -359,11 +359,11 @@ class Tab: public wxPanel bool m_page_switch_running = false; bool m_page_switch_planned = false; - DynamicPrintConfig* m_config; public: PresetBundle* m_preset_bundle; bool m_show_btn_incompatible_presets = false; PresetCollection* m_presets = nullptr; + DynamicPrintConfig* m_config; ogStaticText* m_parent_preset_description_line = nullptr; ScalableButton* m_detach_preset_btn = nullptr; diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index 96725c07d30..cb0736e4e3c 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -1039,7 +1039,7 @@ wxString get_string_from_enum(const std::string& opt_key, const DynamicPrintConf { const ConfigOptionDef& def = config.def()->options.at(opt_key); const std::vector& names = def.enum_labels.empty() ? def.enum_values : def.enum_labels; - int val = config.option(opt_key)->get_int(); + int val = config.option(opt_key)->getInt(); // if it doesn't use all list declared in PrintConfig.hpp. // So we should "convert" val to the correct one @@ -1119,7 +1119,7 @@ static wxString get_string_value(std::string opt_key, const DynamicPrintConfig& return _L("Undef"); } case coPercent: - return from_u8((boost::format("%1%%%") % int(config.optptr(opt_key)->get_float())).str()); + return from_u8((boost::format("%1%%%") % int(config.optptr(opt_key)->getFloat())).str()); case coPercents: { if (is_nullable) { auto values = config.opt(opt_key); From b03fb65527d4a612d6548c7f9d8d5c263fc7f302 Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 19 Dec 2023 01:35:17 +0100 Subject: [PATCH 02/19] config: change getXxx() to get_xxx() in config remove setInt for not-enum config --- src/PrusaSlicer.cpp | 4 +- src/libslic3r/Config.cpp | 8 +- src/libslic3r/Config.hpp | 47 +++++----- src/libslic3r/Fill/Fill.cpp | 4 +- src/libslic3r/Format/3mf.cpp | 16 ++-- src/libslic3r/Format/CWS.cpp | 2 +- src/libslic3r/Format/SL1.cpp | 4 +- src/libslic3r/Format/SLAArchive.cpp | 16 ++-- src/libslic3r/Model.cpp | 4 +- src/libslic3r/MultiMaterialSegmentation.cpp | 2 +- src/libslic3r/PlaceholderParser.cpp | 22 ++--- src/libslic3r/PrintApply.cpp | 4 +- src/libslic3r/PrintBase.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 30 +++---- src/libslic3r/PrintObject.cpp | 5 +- src/libslic3r/SLA/Rotfinder.cpp | 4 +- src/libslic3r/SLAPrint.cpp | 86 +++++++++---------- src/libslic3r/SLAPrintSteps.cpp | 52 +++++------ src/libslic3r/Slicing.cpp | 2 +- src/slic3r/GUI/CalibrationBridgeDialog.cpp | 2 +- src/slic3r/GUI/CalibrationFlowDialog.cpp | 2 +- .../GUI/CalibrationOverBridgeDialog.cpp | 6 +- .../GUI/CalibrationRetractionDialog.cpp | 2 +- src/slic3r/GUI/ConfigManipulation.cpp | 32 +++---- src/slic3r/GUI/Field.cpp | 20 ++--- src/slic3r/GUI/GLCanvas3D.cpp | 4 +- src/slic3r/GUI/GUI.cpp | 6 +- src/slic3r/GUI/GUI_ObjectLayers.cpp | 2 +- src/slic3r/GUI/GUI_Preview.cpp | 10 +-- src/slic3r/GUI/Jobs/ArrangeJob.cpp | 6 +- src/slic3r/GUI/OptionsGroup.cpp | 4 +- src/slic3r/GUI/PhysicalPrinterDialog.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 8 +- src/slic3r/GUI/ScriptExecutor.cpp | 32 +++---- src/slic3r/GUI/Tab.cpp | 8 +- src/slic3r/GUI/UnsavedChangesDialog.cpp | 4 +- 36 files changed, 233 insertions(+), 231 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index 5b875bbc751..129baabd8fb 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -237,8 +237,8 @@ int CLI::run(int argc, char **argv) // The default bed shape should reflect the default display parameters // and not the fff defaults. - double w = sla_print_config.display_width.getFloat(); - double h = sla_print_config.display_height.getFloat(); + double w = sla_print_config.display_width.get_float(); + double h = sla_print_config.display_height.get_float(); sla_print_config.bed_shape.values = { Vec2d(0, 0), Vec2d(w, 0), Vec2d(w, h), Vec2d(0, h) }; sla_print_config.apply(m_print_config, true); diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index c603e316a1e..ea0d1216448 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -320,7 +320,7 @@ ConfigOption* ConfigOptionDef::create_default_option() const if (this->default_value) return (this->default_value->type() == coEnum) ? // Special case: For a DynamicConfig, convert a templated enum to a generic enum. - new ConfigOptionEnumGeneric(this->enum_keys_map, this->default_value->getInt()) : + new ConfigOptionEnumGeneric(this->enum_keys_map, this->default_value->get_int()) : this->default_value->clone(); return this->create_empty_option(); } @@ -782,11 +782,11 @@ double ConfigBase::get_computed_value(const t_config_option_key &opt_key, int ex const ConfigOption* opt_extruder_id = nullptr; if ((opt_extruder_id = this->option("extruder")) == nullptr) if ((opt_extruder_id = this->option("current_extruder")) == nullptr - || opt_extruder_id->getInt() < 0 || opt_extruder_id->getInt() >= vector_opt->size()) { + || opt_extruder_id->get_int() < 0 || opt_extruder_id->get_int() >= vector_opt->size()) { std::stringstream ss; ss << "ConfigBase::get_abs_value(): " << opt_key << " need to has the extuder id to get the right value, but it's not available"; throw ConfigurationError(ss.str()); } - extruder_id = opt_extruder_id->getInt(); + extruder_id = opt_extruder_id->get_int(); idx = extruder_id; } } else { @@ -797,7 +797,7 @@ double ConfigBase::get_computed_value(const t_config_option_key &opt_key, int ex } if (idx >= 0) { if (raw_opt->type() == coFloats || raw_opt->type() == coInts || raw_opt->type() == coBools) - return vector_opt->getFloat(idx); + return vector_opt->get_float(idx); if (raw_opt->type() == coFloatsOrPercents) { const ConfigOptionFloatsOrPercents* opt_fl_per = static_cast(raw_opt); if (!opt_fl_per->values[idx].percent) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index e046e49cfe2..1c0a128fe27 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -395,11 +395,11 @@ class ConfigOption { virtual ConfigOption* clone() const = 0; // Set a value from a ConfigOption. The two options should be compatible. virtual void set(const ConfigOption *option) = 0; - virtual int32_t getInt() const { throw BadOptionTypeException("Calling ConfigOption::getInt on a non-int ConfigOption"); } - virtual double getFloat() const { throw BadOptionTypeException("Calling ConfigOption::getFloat on a non-float ConfigOption"); } - virtual bool getBool() const { throw BadOptionTypeException("Calling ConfigOption::getBool on a non-boolean ConfigOption"); } - virtual void setInt(int32_t /* val */) { throw BadOptionTypeException("Calling ConfigOption::setInt on a non-int ConfigOption"); } - virtual boost::any getAny() const { throw BadOptionTypeException("Calling ConfigOption::getBool on a non-boolean ConfigOption"); } + virtual int32_t get_int() const { throw BadOptionTypeException("Calling ConfigOption::get_int on a non-int ConfigOption"); } + virtual double get_float() const { throw BadOptionTypeException("Calling ConfigOption::get_float on a non-float ConfigOption"); } + virtual bool get_bool() const { throw BadOptionTypeException("Calling ConfigOption::get_bool on a non-boolean ConfigOption"); } + virtual void set_enum_int(int32_t /* val */) { throw BadOptionTypeException("Calling ConfigOption::set_enum_int on a non-enum ConfigOption"); } + virtual boost::any get_any() const { throw BadOptionTypeException("Calling ConfigOption::get_any on a raw ConfigOption"); } virtual bool operator==(const ConfigOption &rhs) const = 0; bool operator!=(const ConfigOption &rhs) const { return ! (*this == rhs); } virtual size_t hash() const throw() = 0; @@ -440,7 +440,7 @@ class ConfigOptionSingle : public ConfigOption { explicit ConfigOptionSingle(T value) : value(value) {} explicit ConfigOptionSingle(T value, bool phony) : ConfigOption(phony), value(value) {} operator T() const { return this->value; } - virtual boost::any getAny() const { return boost::any(value); } + boost::any get_any() const override { return boost::any(value); } void set(const ConfigOption *rhs) override { @@ -500,7 +500,7 @@ class ConfigOptionVectorBase : public ConfigOption { if (is_extruder_size) this->flags |= FCO_EXTRUDER_ARRAY; else this->flags &= uint8_t(0xFF ^ FCO_EXTRUDER_ARRAY); return this; } - virtual double getFloat(int idx) const { throw BadOptionTypeException("Calling ConfigOption::getFloat(idx) on a non-numeric arrray ConfigOptionVectorBase"); } + virtual double get_float(int idx) const { throw BadOptionTypeException("Calling ConfigOption::getFloat(idx) on a non-numeric arrray ConfigOptionVectorBase"); } // We just overloaded and hid two base class virtual methods. // Let's show it was intentional (warnings). @@ -598,7 +598,7 @@ class ConfigOptionVector : public ConfigOptionVectorBase } T& get_at(size_t i) { return const_cast(std::as_const(*this).get_at(i)); } - virtual boost::any getAny() const { return boost::any(values); } + virtual boost::any get_any() const { return boost::any(values); } // Resize this vector by duplicating the /*last*/first value. // If the current vector is empty, the default value is used instead. @@ -722,7 +722,7 @@ class ConfigOptionFloat : public ConfigOptionSingle static ConfigOptionType static_type() { return coFloat; } ConfigOptionType type() const override { return static_type(); } - double getFloat() const override { return this->value; } + double get_float() const override { return this->value; } ConfigOption* clone() const override { return new ConfigOptionFloat(*this); } bool operator==(const ConfigOptionFloat &rhs) const throw() { return this->value == rhs.value; } bool operator< (const ConfigOptionFloat &rhs) const throw() { return this->value < rhs.value; } @@ -782,7 +782,7 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector // A scalar is nil, or all values of a vector are nil. bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; } bool is_nil(size_t idx) const override { return idx < values.size() ? std::isnan(this->values[idx]) : values.empty() ? std::isnan(this->default_value) : std::isnan(this->values.front()); } - virtual double getFloat(int idx) const override { return values[idx]; } + double get_float(int idx) const override { return values[idx]; } std::string serialize() const override { @@ -890,8 +890,7 @@ class ConfigOptionInt : public ConfigOptionSingle static ConfigOptionType static_type() { return coInt; } ConfigOptionType type() const override { return static_type(); } - int32_t getInt() const override { return this->value; } - void setInt(int32_t val) override { this->value = val; } + int32_t get_int() const override { return this->value; } ConfigOption* clone() const override { return new ConfigOptionInt(*this); } bool operator==(const ConfigOptionInt &rhs) const throw() { return this->value == rhs.value; } @@ -945,7 +944,7 @@ class ConfigOptionIntsTempl : public ConfigOptionVector // A scalar is nil, or all values of a vector are nil. bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } bool is_nil(size_t idx) const override { return idx < values.size() ? this->values[idx] == nil_value() : values.empty() ? this->default_value == nil_value() : this->values.front() == nil_value(); } - virtual double getFloat(int idx) const override { return values[idx]; } + double get_float(int idx) const override { return values[idx]; } std::string serialize() const override { @@ -1549,7 +1548,7 @@ class ConfigOptionBool : public ConfigOptionSingle static ConfigOptionType static_type() { return coBool; } ConfigOptionType type() const override { return static_type(); } - bool getBool() const override { return this->value; } + bool get_bool() const override { return this->value; } ConfigOption* clone() const override { return new ConfigOptionBool(*this); } ConfigOptionBool& operator=(const ConfigOption *opt) { this->set(opt); return *this; } bool operator==(const ConfigOptionBool &rhs) const throw() { return this->value == rhs.value; } @@ -1603,7 +1602,7 @@ class ConfigOptionBoolsTempl : public ConfigOptionVector // A scalar is nil, or all values of a vector are nil. bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } bool is_nil(size_t idx) const override { return idx < values.size() ? this->values[idx] == nil_value() : values.empty() ? this->default_value == nil_value() : this->values.front() == nil_value(); } - virtual double getFloat(int idx) const override { return values[idx] ? 1 : 0; } + double get_float(int idx) const override { return values[idx] ? 1 : 0; } bool& get_at(size_t i) { assert(! this->values.empty()); @@ -1707,22 +1706,22 @@ class ConfigOptionEnum : public ConfigOptionSingle ConfigOptionEnum& operator=(const ConfigOption *opt) { this->set(opt); return *this; } bool operator==(const ConfigOptionEnum &rhs) const throw() { return this->value == rhs.value; } bool operator< (const ConfigOptionEnum &rhs) const throw() { return int(this->value) < int(rhs.value); } - int32_t getInt() const override { return (int32_t)this->value; } - void setInt(int val) override { this->value = T(val); } + int32_t get_int() const override { return (int32_t)this->value; } + void set_enum_int(int32_t val) override { this->value = T(val); } bool operator==(const ConfigOption &rhs) const override { if (rhs.type() != this->type()) throw ConfigurationError("ConfigOptionEnum: Comparing incompatible types"); // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - return this->value == (T)rhs.getInt(); + return this->value == (T)rhs.get_int(); } void set(const ConfigOption *rhs) override { if (rhs->type() != this->type()) throw ConfigurationError("ConfigOptionEnum: Assigning an incompatible type"); // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - this->value = (T)rhs->getInt(); + this->value = (T)rhs->get_int(); this->flags = rhs->flags; } @@ -1786,14 +1785,15 @@ class ConfigOptionEnumGeneric : public ConfigOptionInt if (rhs.type() != this->type()) throw ConfigurationError("ConfigOptionEnumGeneric: Comparing incompatible types"); // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - return this->value == rhs.getInt(); + return this->value == rhs.get_int(); } + void set_enum_int(int32_t val) override { this->value = val; } void set(const ConfigOption *rhs) override { if (rhs->type() != this->type()) throw ConfigurationError("ConfigOptionEnumGeneric: Assigning an incompatible type"); // rhs could be of the following type: ConfigOptionEnumGeneric or ConfigOptionEnum - this->value = rhs->getInt(); + this->value = rhs->get_int(); this->flags = rhs->flags; } @@ -2391,6 +2391,7 @@ class DynamicConfig : public virtual ConfigBase // Be careful, as this method does not test the existence of opt_key in this->def(). bool set_key_value(const std::string &opt_key, ConfigOption *opt) { + assert(opt != nullptr); auto it = this->options.find(opt_key); if (it == this->options.end()) { this->options[opt_key].reset(opt); @@ -2424,9 +2425,9 @@ class DynamicConfig : public virtual ConfigBase int32_t opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } // In ConfigManipulation::toggle_print_fff_options, it is called on option with type ConfigOptionEnumGeneric* and also ConfigOptionEnum*. - // Thus the virtual method getInt() is used to retrieve the enum value. + // Thus the virtual method get_int() is used to retrieve the enum value. template - ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast(this->option(opt_key)->getInt()); } + ENUM opt_enum(const t_config_option_key &opt_key) const { return static_cast(this->option(opt_key)->get_int()); } bool opt_bool(const t_config_option_key &opt_key) const { return this->option(opt_key)->value != 0; } bool opt_bool(const t_config_option_key &opt_key, unsigned int idx) const { return this->option(opt_key)->get_at(idx) != 0; } diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp index 697fcb566a0..63de0d2d51b 100644 --- a/src/libslic3r/Fill/Fill.cpp +++ b/src/libslic3r/Fill/Fill.cpp @@ -170,7 +170,7 @@ std::vector group_fills(const Layer &layer) params.pattern = region_config.bridge_fill_pattern.value; params.connection = region_config.infill_connection_bridge.value; } - if (region_config.infill_dense.getBool() + if (region_config.infill_dense.get_bool() && region_config.fill_density < 40 && surface.maxNbSolidLayersOnTop == 1) { params.density = 0.42f; @@ -203,7 +203,7 @@ std::vector group_fills(const Layer &layer) params.role = erSolidInfill; } } - params.fill_exactly = region_config.enforce_full_fill_volume.getBool(); + params.fill_exactly = region_config.enforce_full_fill_volume.get_bool(); params.bridge_angle = float(surface.bridge_angle); params.angle = (is_denser) ? 0 : compute_fill_angle(region_config, layerm.layer()->id()); params.can_angle_cross = region_config.fill_angle_cross; diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index dcc5464c0a6..aa9e27e37ab 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -2945,7 +2945,7 @@ namespace Slic3r { log << "\n"; } if (config.option(opt_key) != nullptr && config.option(opt_key)->type() == ConfigOptionType::coEnum) { - log << "enum : " << config.option(opt_key)->getInt(); + log << "enum : " << config.option(opt_key)->get_int(); log << "\n"; const ConfigOptionDef* def = nullptr; try { @@ -2960,7 +2960,7 @@ namespace Slic3r { } } if (config.option(opt_key) != nullptr && config.option(opt_key)->type() == ConfigOptionType::coInt) { - log << "int : " << config.option(opt_key)->getInt(); + log << "int : " << config.option(opt_key)->get_int(); log << "\n"; } log.close(); @@ -3171,9 +3171,9 @@ namespace Slic3r { } if (obj->config.option(key) != nullptr && obj->config.option(key)->type() == ConfigOptionType::coEnum) { try{ - log << "raw_int_value : " << obj->config.option(key)->getInt() << "\n"; + log << "raw_int_value : " << obj->config.option(key)->get_int() << "\n"; } catch (std::exception ex) {} - log << "enum : " << obj->config.option(key)->getInt(); + log << "enum : " << obj->config.option(key)->get_int(); log << "\n"; const ConfigOptionDef* def = nullptr; try { @@ -3188,7 +3188,7 @@ namespace Slic3r { } } if (obj->config.option(key) != nullptr && obj->config.option(key)->type() == ConfigOptionType::coInt) { - log << "int : " << obj->config.option(key)->getInt(); + log << "int : " << obj->config.option(key)->get_int(); log << "\n"; } log.close(); @@ -3279,9 +3279,9 @@ namespace Slic3r { } if (volume->config.option(key) != nullptr && volume->config.option(key)->type() == ConfigOptionType::coEnum) { try{ - log << "raw_int_value : " << volume->config.option(key)->getInt() << "\n"; + log << "raw_int_value : " << volume->config.option(key)->get_int() << "\n"; } catch (std::exception ex) {} - log << "enum : " << volume->config.option(key)->getInt(); + log << "enum : " << volume->config.option(key)->get_int(); log << "\n"; const ConfigOptionDef* def = nullptr; try { @@ -3296,7 +3296,7 @@ namespace Slic3r { } } if (volume->config.option(key) != nullptr && volume->config.option(key)->type() == ConfigOptionType::coInt) { - log << "int : " << volume->config.option(key)->getInt(); + log << "int : " << volume->config.option(key)->get_int(); log << "\n"; } log.close(); diff --git a/src/libslic3r/Format/CWS.cpp b/src/libslic3r/Format/CWS.cpp index 395be504402..229bd64fa07 100644 --- a/src/libslic3r/Format/CWS.cpp +++ b/src/libslic3r/Format/CWS.cpp @@ -60,7 +60,7 @@ void fill_iniconf(ConfMap &m, const SLAPrint &print) double used_material = (stats.objects_used_material + stats.support_used_material) / 1000; - int num_fade = print.default_object_config().faded_layers.getInt(); + int num_fade = print.default_object_config().faded_layers.get_int(); num_fade = num_fade >= 0 ? num_fade : 0; m["usedMaterial"] = std::to_string(used_material); diff --git a/src/libslic3r/Format/SL1.cpp b/src/libslic3r/Format/SL1.cpp index 1f6b1aa90f0..deb70b25585 100644 --- a/src/libslic3r/Format/SL1.cpp +++ b/src/libslic3r/Format/SL1.cpp @@ -232,7 +232,7 @@ SliceParams get_slice_params(const DynamicPrintConfig &cfg) if (!opt_layerh || !opt_init_layerh) throw MissingProfileError("Invalid SL1 / SL1S file"); - return SliceParams{opt_layerh->getFloat(), opt_init_layerh->getFloat()}; + return SliceParams{opt_layerh->get_float(), opt_init_layerh->get_float()}; } std::vector extract_slices_from_sla_archive( @@ -400,7 +400,7 @@ void fill_iniconf(ConfMap &m, const SLAPrint &print) double used_material = (stats.objects_used_material + stats.support_used_material) / 1000; - int num_fade = print.default_object_config().faded_layers.getInt(); + int num_fade = print.default_object_config().faded_layers.get_int(); num_fade = num_fade >= 0 ? num_fade : 0; m["usedMaterial"] = std::to_string(used_material); diff --git a/src/libslic3r/Format/SLAArchive.cpp b/src/libslic3r/Format/SLAArchive.cpp index d6b77c41628..337c7f26158 100644 --- a/src/libslic3r/Format/SLAArchive.cpp +++ b/src/libslic3r/Format/SLAArchive.cpp @@ -25,15 +25,15 @@ std::unique_ptr SLAAbstractArchive::create_raster() const sla::RasterBase::PixelDim pxdim; std::array mirror; - double w = this->config().display_width.getFloat(); - double h = this->config().display_height.getFloat(); - auto pw = size_t(this->config().display_pixels_x.getInt()); - auto ph = size_t(this->config().display_pixels_y.getInt()); + double w = this->config().display_width.get_float(); + double h = this->config().display_height.get_float(); + auto pw = size_t(this->config().display_pixels_x.get_int()); + auto ph = size_t(this->config().display_pixels_y.get_int()); - mirror[X] = this->config().display_mirror_x.getBool(); - mirror[Y] = this->config().display_mirror_y.getBool(); + mirror[X] = this->config().display_mirror_x.get_bool(); + mirror[Y] = this->config().display_mirror_y.get_bool(); - auto ro = this->config().display_orientation.getInt(); + auto ro = this->config().display_orientation.get_int(); sla::RasterBase::Orientation orientation = ro == sla::RasterBase::roPortrait ? sla::RasterBase::roPortrait : sla::RasterBase::roLandscape; @@ -47,7 +47,7 @@ std::unique_ptr SLAAbstractArchive::create_raster() const pxdim = sla::RasterBase::PixelDim{w / pw, h / ph}; sla::RasterBase::Trafo tr{orientation, mirror}; - double gamma = this->config().gamma_correction.getFloat(); + double gamma = this->config().gamma_correction.get_float(); return sla::create_raster_grayscale_aa(res, pxdim, gamma, tr); } diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index fd2078787ca..798b1710bc7 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1752,9 +1752,9 @@ int ModelVolume::extruder_id() const int extruder_id = -1; if (this->is_model_part()) { const ConfigOption *opt = this->config.option("extruder"); - if ((opt == nullptr) || (opt->getInt() == 0)) + if ((opt == nullptr) || (opt->get_int() == 0)) opt = this->object->config.option("extruder"); - extruder_id = (opt == nullptr) ? 0 : opt->getInt(); + extruder_id = (opt == nullptr) ? 0 : opt->get_int(); } return extruder_id; } diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index f6a380d1a41..dc1448cb808 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1691,7 +1691,7 @@ std::vector> multi_material_segmentation_by_painting(con std::vector edge_grids(num_layers); const ConstLayerPtrsAdaptor layers = print_object.layers(); std::vector input_expolygons(num_layers); - coord_t resolution = scale_t(print_object.config().option("resolution")->getFloat()); + coord_t resolution = scale_t(print_object.config().option("resolution")->get_float()); throw_on_cancel_callback(); diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index b13d689dba8..bd32837407b 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -770,7 +770,7 @@ namespace client if (vector_opt->is_extruder_size()) { if (raw_opt->type() == coFloats || raw_opt->type() == coInts || raw_opt->type() == coBools) - return vector_opt->getFloat(int(current_extruder_id)); + return vector_opt->get_float(int(current_extruder_id)); if (raw_opt->type() == coFloatsOrPercents) { const ConfigOptionFloatsOrPercents* opt_fl_per = static_cast(raw_opt); if (!opt_fl_per->values[current_extruder_id].percent) @@ -869,7 +869,7 @@ namespace client ctx->throw_exception("Variable does not exist", opt_key); if (opt_index->type() != coInt) ctx->throw_exception("Indexing variable has to be integer", opt_key); - int idx = opt_index->getInt(); + int idx = opt_index->get_int(); if (idx < 0) ctx->throw_exception("Negative vector index", opt_key); output = vec->vserialize()[(idx >= (int)vec->size()) ? 0 : idx]; @@ -936,12 +936,12 @@ namespace client } const ConfigOptionDef* opt_def; switch (opt.opt->type()) { - case coFloat: output.set_d(opt.opt->getFloat()); break; - case coInt: output.set_i(opt.opt->getInt()); break; + case coFloat: output.set_d(opt.opt->get_float()); break; + case coInt: output.set_i(opt.opt->get_int()); break; case coString: output.set_s(static_cast(opt.opt)->value); break; - case coPercent: output.set_d(opt.opt->getFloat()); break; + case coPercent: output.set_d(opt.opt->get_float()); break; case coPoint: output.set_s(opt.opt->serialize()); break; - case coBool: output.set_b(opt.opt->getBool()); break; + case coBool: output.set_b(opt.opt->get_bool()); break; case coFloatOrPercent: { if (boost::ends_with(opt_key, "extrusion_width")) { @@ -949,12 +949,12 @@ namespace client output.set_d(Flow::extrusion_width(opt_key, *ctx, static_cast(ctx->current_extruder_id))); } else if (! static_cast(opt.opt)->percent) { // Not a percent, just return the value. - output.set_d(opt.opt->getFloat()); + output.set_d(opt.opt->get_float()); } else { // Resolve dependencies using the "ratio_over" link to a parent value. opt_def = print_config_def.get(opt_key); assert(opt_def != nullptr); - double v = opt.opt->getFloat() * 0.01; // percent to ratio + double v = opt.opt->get_float() * 0.01; // percent to ratio for (;;) { const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over); if (opt_parent == nullptr) @@ -969,7 +969,7 @@ namespace client v *= val; break; // if (opt_parent->type() == coFloat || opt_parent->type() == coFloatOrPercent) { - // v *= opt_parent->getFloat(); + // v *= opt_parent->get_float(); // if (opt_parent->type() == coFloat || ! static_cast(opt_parent)->percent) // break; // v *= 0.01; // percent to ratio @@ -985,7 +985,7 @@ namespace client case coInts: opt_def = print_config_def.get(opt_key); if (opt_def->is_vector_extruder) { - output.set_i(int(((ConfigOptionVectorBase*)opt.opt)->getFloat(int(ctx->current_extruder_id)))); + output.set_i(int(((ConfigOptionVectorBase*)opt.opt)->get_float(int(ctx->current_extruder_id)))); break; } else ctx->throw_exception("Unknown scalar variable type", opt.it_range); @@ -993,7 +993,7 @@ namespace client case coPercents: vector_opt = static_cast(opt.opt); if (vector_opt->is_extruder_size()) { - output.set_d(((ConfigOptionVectorBase*)opt.opt)->getFloat(int(ctx->current_extruder_id))); + output.set_d(((ConfigOptionVectorBase*)opt.opt)->get_float(int(ctx->current_extruder_id))); break; } else ctx->throw_exception("Unknown scalar variable type", opt.it_range); diff --git a/src/libslic3r/PrintApply.cpp b/src/libslic3r/PrintApply.cpp index 1c62773d053..585f5a0be7f 100644 --- a/src/libslic3r/PrintApply.cpp +++ b/src/libslic3r/PrintApply.cpp @@ -92,7 +92,7 @@ static inline void layer_height_ranges_copy_configs(t_layer_config_ranges &lr_ds assert(std::abs(kvp_dst.first.first - kvp_src.first.first ) <= EPSILON); assert(std::abs(kvp_dst.first.second - kvp_src.first.second) <= EPSILON); // Layer heights are allowed do differ in case the layer height table is being overriden by the smooth profile. - // assert(std::abs(kvp_dst.second.option("layer_height")->getFloat() - kvp_src.second.option("layer_height")->getFloat()) <= EPSILON); + // assert(std::abs(kvp_dst.second.option("layer_height")->get_float() - kvp_src.second.option("layer_height")->get_float()) <= EPSILON); kvp_dst.second = kvp_src.second; } } @@ -159,7 +159,7 @@ static bool layer_height_ranges_equal(const t_layer_config_ranges &lr1, const t_ const auto &kvp2 = *it2 ++; if (std::abs(kvp1.first.first - kvp2.first.first ) > EPSILON || std::abs(kvp1.first.second - kvp2.first.second) > EPSILON || - (check_layer_height && std::abs(kvp1.second.option("layer_height")->getFloat() - kvp2.second.option("layer_height")->getFloat()) > EPSILON)) + (check_layer_height && std::abs(kvp1.second.option("layer_height")->get_float() - kvp2.second.option("layer_height")->get_float()) > EPSILON)) return false; } return true; diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index e5f299b22ff..29bdc1301d0 100644 --- a/src/libslic3r/PrintBase.cpp +++ b/src/libslic3r/PrintBase.cpp @@ -76,7 +76,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str cfg.set_key_value("input_filename_base", new ConfigOptionString(filename_base)); } try { - uint16_t extruder_initial = config_override->option("initial_extruder") != nullptr && config_override->option("initial_extruder")->type() == coInt ? config_override->option("initial_extruder")->getInt() : 0; + uint16_t extruder_initial = config_override->option("initial_extruder") != nullptr && config_override->option("initial_extruder")->type() == coInt ? config_override->option("initial_extruder")->get_int() : 0; boost::filesystem::path filepath = format.empty() ? cfg.opt_string("input_filename_base") + default_ext : this->placeholder_parser().process(format, extruder_initial, &cfg); diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 4aada338432..6746cc9557e 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -7963,7 +7963,7 @@ std::map PrintConfigDef::to_prusa(t_config_option_key& } else if ("monotonicgapfill" == value) { value = "monotonic"; } - if (all_conf.has("fill_angle_increment") && ((int(all_conf.option("fill_angle_increment")->getFloat())-90)%180) == 0 && "rectilinear" == value + if (all_conf.has("fill_angle_increment") && ((int(all_conf.option("fill_angle_increment")->get_float())-90)%180) == 0 && "rectilinear" == value && ("fill_pattern" == opt_key || "top_fill_pattern" == opt_key)) { value = "alignedrectilinear"; } @@ -8126,10 +8126,10 @@ PrinterTechnology printer_technology(const ConfigBase& cfg) if (opt) return opt->value; const ConfigOptionBool* export_opt = cfg.option("export_sla"); - if (export_opt && export_opt->getBool()) return ptSLA; + if (export_opt && export_opt->get_bool()) return ptSLA; export_opt = cfg.option("export_gcode"); - if (export_opt && export_opt->getBool()) return ptFFF; + if (export_opt && export_opt->get_bool()) return ptFFF; return ptUnknown; } @@ -8185,7 +8185,7 @@ double min_object_distance(const ConfigBase *config, double ref_height /* = 0*/) double base_dist = 0; //std::cout << "START min_object_distance =>" << base_dist << "\n"; const ConfigOptionBool* co_opt = config->option("complete_objects"); - if (config->option("parallel_objects_step")->getFloat() > 0 || co_opt && co_opt->value) { + if (config->option("parallel_objects_step")->get_float() > 0 || co_opt && co_opt->value) { double skirt_dist = 0; try { std::vector vals = dynamic_cast(config->option("nozzle_diameter"))->values; @@ -8195,7 +8195,7 @@ double min_object_distance(const ConfigBase *config, double ref_height /* = 0*/) // min object distance is max(duplicate_distance, clearance_radius) // /2 becasue we only count the grawing for the current object //add 1 as safety offset. - double extruder_clearance_radius = config->option("extruder_clearance_radius")->getFloat() / 2; + double extruder_clearance_radius = config->option("extruder_clearance_radius")->get_float() / 2; if (extruder_clearance_radius > base_dist) { base_dist = extruder_clearance_radius; } @@ -8204,15 +8204,15 @@ double min_object_distance(const ConfigBase *config, double ref_height /* = 0*/) //ideally, we should use print::first_layer_height() const double first_layer_height = dynamic_cast(config->option("first_layer_height"))->get_abs_value(max_nozzle_diam); //add the skirt - int skirts = config->option("skirts")->getInt(); + int skirts = config->option("skirts")->get_int(); if (skirts > 0 && ref_height == 0) - skirts += config->option("skirt_brim")->getInt(); - if (skirts > 0 && config->option("skirt_height")->getInt() >= 1 && !config->option("complete_objects_one_skirt")->getBool()) { + skirts += config->option("skirt_brim")->get_int(); + if (skirts > 0 && config->option("skirt_height")->get_int() >= 1 && !config->option("complete_objects_one_skirt")->get_bool()) { float overlap_ratio = 1; //can't know the extruder, so we settle on the worst: 100% //if (config->option("filament_max_overlap")) overlap_ratio = config->get_computed_value("filament_max_overlap"); if (ref_height == 0) { - skirt_dist = config->option("skirt_distance")->getFloat(); + skirt_dist = config->option("skirt_distance")->get_float(); Flow skirt_flow = Flow::new_from_config_width( frPerimeter, *Flow::extrusion_width_option("skirt", *config), @@ -8227,9 +8227,9 @@ double min_object_distance(const ConfigBase *config, double ref_height /* = 0*/) //set to 0 becasue it's incorporated into the base_dist, so we don't want to be added in to it again. skirt_dist = 0; } else { - double skirt_height = ((double)config->option("skirt_height")->getInt() - 1) * config->get_computed_value("layer_height") + first_layer_height; + double skirt_height = ((double)config->option("skirt_height")->get_int() - 1) * config->get_computed_value("layer_height") + first_layer_height; if (ref_height <= skirt_height) { - skirt_dist = config->option("skirt_distance")->getFloat(); + skirt_dist = config->option("skirt_distance")->get_float(); Flow skirt_flow = Flow::new_from_config_width( frPerimeter, *Flow::extrusion_width_option("skirt", *config), @@ -8255,13 +8255,13 @@ double min_object_distance(const ConfigBase *config, double ref_height /* = 0*/) void DynamicPrintConfig::normalize_fdm() { if (this->has("extruder")) { - int extruder = this->option("extruder")->getInt(); + int extruder = this->option("extruder")->get_int(); this->erase("extruder"); if (extruder != 0) { if (!this->has("infill_extruder")) - this->option("infill_extruder", true)->setInt(extruder); + this->option("infill_extruder", true)->value = (extruder); if (!this->has("perimeter_extruder")) - this->option("perimeter_extruder", true)->setInt(extruder); + this->option("perimeter_extruder", true)->value = (extruder); // Don't propagate the current extruder to support. // For non-soluble supports, the default "0" extruder means to use the active extruder, // for soluble supports one certainly does not want to set the extruder to non-soluble. @@ -8275,7 +8275,7 @@ void DynamicPrintConfig::normalize_fdm() this->erase("first_layer_extruder"); if (!this->has("solid_infill_extruder") && this->has("infill_extruder")) - this->option("solid_infill_extruder", true)->setInt(this->option("infill_extruder")->getInt()); + this->option("solid_infill_extruder", true)->value = (this->option("infill_extruder")->get_int()); if (this->has("spiral_vase") && this->opt("spiral_vase", true)->value) { { diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 4c9e9be0eda..27928a2cfd3 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1297,7 +1297,7 @@ bool PrintObject::invalidate_state_by_config_options( for (const PrintRegion* region : this->m_print->print_regions_mutable()) { //count how many surface there are on each one - if (region->config().infill_dense.getBool() && region->config().fill_density < 40) { + if (region->config().infill_dense.get_bool() && region->config().fill_density < 40) { std::vector layeridx2lregion; std::vector new_surfaces; //surface store, as you can't modify them when working in // // store the LayerRegion on which we are working @@ -2543,10 +2543,11 @@ static constexpr const std::initializer_list keys_extrud if (it->first != key_extruder) if (ConfigOption* my_opt = out.option(it->first, false); my_opt != nullptr) { if (one_of(it->first, keys_extruders)) { + assert(dynamic_cast(my_opt)); // Ignore "default" extruders. int extruder = static_cast(it->second.get())->value; if (extruder > 0) - my_opt->setInt(extruder); + static_cast(my_opt)->value = (extruder); } else my_opt->set(it->second.get()); } diff --git a/src/libslic3r/SLA/Rotfinder.cpp b/src/libslic3r/SLA/Rotfinder.cpp index 196646dc9ee..042c0fab346 100644 --- a/src/libslic3r/SLA/Rotfinder.cpp +++ b/src/libslic3r/SLA/Rotfinder.cpp @@ -195,8 +195,8 @@ XYRotation from_transform3f(const Transform3f &tr) inline bool is_on_floor(const SLAPrintObjectConfig &cfg) { - auto opt_elevation = cfg.support_object_elevation.getFloat(); - auto opt_padaround = cfg.pad_around_object.getBool(); + auto opt_elevation = cfg.support_object_elevation.get_float(); + auto opt_padaround = cfg.pad_around_object.get_bool(); return opt_elevation < EPSILON || opt_padaround; } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 69b80fbf62d..d7b53a4325e 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -30,7 +30,7 @@ namespace Slic3r { bool is_zero_elevation(const SLAPrintObjectConfig &c) { - return c.pad_enable.getBool() && c.pad_around_object.getBool(); + return c.pad_enable.get_bool() && c.pad_around_object.get_bool(); } // Compile the argument for support creation from the static print config. @@ -38,20 +38,20 @@ sla::SupportTreeConfig make_support_cfg(const SLAPrintObjectConfig& c) { sla::SupportTreeConfig scfg; - scfg.enabled = c.supports_enable.getBool(); - scfg.head_front_radius_mm = 0.5*c.support_head_front_diameter.getFloat(); - double pillar_r = 0.5 * c.support_pillar_diameter.getFloat(); + scfg.enabled = c.supports_enable.get_bool(); + scfg.head_front_radius_mm = 0.5*c.support_head_front_diameter.get_float(); + double pillar_r = 0.5 * c.support_pillar_diameter.get_float(); scfg.head_back_radius_mm = pillar_r; scfg.head_fallback_radius_mm = - 0.01 * c.support_small_pillar_diameter_percent.getFloat() * pillar_r; - scfg.head_penetration_mm = c.support_head_penetration.getFloat(); - scfg.head_width_mm = c.support_head_width.getFloat(); + 0.01 * c.support_small_pillar_diameter_percent.get_float() * pillar_r; + scfg.head_penetration_mm = c.support_head_penetration.get_float(); + scfg.head_width_mm = c.support_head_width.get_float(); scfg.object_elevation_mm = is_zero_elevation(c) ? - 0. : c.support_object_elevation.getFloat(); - scfg.bridge_slope = c.support_critical_angle.getFloat() * PI / 180.0 ; - scfg.max_bridge_length_mm = c.support_max_bridge_length.getFloat(); - scfg.max_pillar_link_distance_mm = c.support_max_pillar_link_distance.getFloat(); - switch(c.support_pillar_connection_mode.getInt()) { + 0. : c.support_object_elevation.get_float(); + scfg.bridge_slope = c.support_critical_angle.get_float() * PI / 180.0 ; + scfg.max_bridge_length_mm = c.support_max_bridge_length.get_float(); + scfg.max_pillar_link_distance_mm = c.support_max_pillar_link_distance.get_float(); + switch(c.support_pillar_connection_mode.get_int()) { case slapcmZigZag: scfg.pillar_connection_mode = sla::PillarConnectionMode::zigzag; break; case slapcmCross: @@ -59,15 +59,15 @@ sla::SupportTreeConfig make_support_cfg(const SLAPrintObjectConfig& c) case slapcmDynamic: scfg.pillar_connection_mode = sla::PillarConnectionMode::dynamic; break; } - scfg.ground_facing_only = c.support_buildplate_only.getBool(); - scfg.pillar_widening_factor = c.support_pillar_widening_factor.getFloat(); - scfg.base_radius_mm = 0.5*c.support_base_diameter.getFloat(); - scfg.base_height_mm = c.support_base_height.getFloat(); + scfg.ground_facing_only = c.support_buildplate_only.get_bool(); + scfg.pillar_widening_factor = c.support_pillar_widening_factor.get_float(); + scfg.base_radius_mm = 0.5*c.support_base_diameter.get_float(); + scfg.base_height_mm = c.support_base_height.get_float(); scfg.pillar_base_safety_distance_mm = - c.support_base_safety_distance.getFloat() < EPSILON ? - scfg.safety_distance_mm : c.support_base_safety_distance.getFloat(); + c.support_base_safety_distance.get_float() < EPSILON ? + scfg.safety_distance_mm : c.support_base_safety_distance.get_float(); - scfg.max_bridges_on_pillar = unsigned(c.support_max_bridges_on_pillar.getInt()); + scfg.max_bridges_on_pillar = unsigned(c.support_max_bridges_on_pillar.get_int()); return scfg; } @@ -79,12 +79,12 @@ sla::PadConfig::EmbedObject builtin_pad_cfg(const SLAPrintObjectConfig& c) ret.enabled = is_zero_elevation(c); if(ret.enabled) { - ret.everywhere = c.pad_around_object_everywhere.getBool(); - ret.object_gap_mm = c.pad_object_gap.getFloat(); - ret.stick_width_mm = c.pad_object_connector_width.getFloat(); - ret.stick_stride_mm = c.pad_object_connector_stride.getFloat(); + ret.everywhere = c.pad_around_object_everywhere.get_bool(); + ret.object_gap_mm = c.pad_object_gap.get_float(); + ret.stick_width_mm = c.pad_object_connector_width.get_float(); + ret.stick_stride_mm = c.pad_object_connector_stride.get_float(); ret.stick_penetration_mm = c.pad_object_connector_penetration - .getFloat(); + .get_float(); } return ret; @@ -94,12 +94,12 @@ sla::PadConfig make_pad_cfg(const SLAPrintObjectConfig& c) { sla::PadConfig pcfg; - pcfg.wall_thickness_mm = c.pad_wall_thickness.getFloat(); - pcfg.wall_slope = c.pad_wall_slope.getFloat() * PI / 180.0; + pcfg.wall_thickness_mm = c.pad_wall_thickness.get_float(); + pcfg.wall_slope = c.pad_wall_slope.get_float() * PI / 180.0; - pcfg.max_merge_dist_mm = c.pad_max_merge_distance.getFloat(); - pcfg.wall_height_mm = c.pad_wall_height.getFloat(); - pcfg.brim_size_mm = c.pad_brim_size.getFloat(); + pcfg.max_merge_dist_mm = c.pad_max_merge_distance.get_float(); + pcfg.wall_height_mm = c.pad_wall_height.get_float(); + pcfg.brim_size_mm = c.pad_brim_size.get_float(); // set builtin pad implicitly ON pcfg.embed_object = builtin_pad_cfg(c); @@ -620,7 +620,7 @@ std::pair SLAPrint::validate(std:: for(SLAPrintObject * po : m_objects) { const ModelObject *mo = po->model_object(); - bool supports_en = po->config().supports_enable.getBool(); + bool supports_en = po->config().supports_enable.get_bool(); if(supports_en && mo->sla_points_status == sla::PointsStatus::UserModified && @@ -653,16 +653,16 @@ std::pair SLAPrint::validate(std:: if (!pval.empty()) return { PrintBase::PrintValidationError::pveWrongSettings, pval }; } - double expt_max = m_printer_config.max_exposure_time.getFloat(); - double expt_min = m_printer_config.min_exposure_time.getFloat(); - double expt_cur = m_material_config.exposure_time.getFloat(); + double expt_max = m_printer_config.max_exposure_time.get_float(); + double expt_min = m_printer_config.min_exposure_time.get_float(); + double expt_cur = m_material_config.exposure_time.get_float(); if (expt_cur < expt_min || expt_cur > expt_max) return { PrintBase::PrintValidationError::pveWrongSettings, L("Exposition time is out of printer profile bounds.") }; - double iexpt_max = m_printer_config.max_initial_exposure_time.getFloat(); - double iexpt_min = m_printer_config.min_initial_exposure_time.getFloat(); - double iexpt_cur = m_material_config.initial_exposure_time.getFloat(); + double iexpt_max = m_printer_config.max_initial_exposure_time.get_float(); + double iexpt_min = m_printer_config.min_initial_exposure_time.get_float(); + double iexpt_cur = m_material_config.initial_exposure_time.get_float(); if (iexpt_cur < iexpt_min || iexpt_cur > iexpt_max) return { PrintBase::PrintValidationError::pveWrongSettings, L("Initial exposition time is out of printer profile bounds.") }; @@ -1031,11 +1031,11 @@ bool SLAPrintObject::invalidate_all_steps() double SLAPrintObject::get_elevation() const { if (is_zero_elevation(m_config)) return 0.; - bool en = m_config.supports_enable.getBool(); + bool en = m_config.supports_enable.get_bool(); - double ret = en ? m_config.support_object_elevation.getFloat() : 0.; + double ret = en ? m_config.support_object_elevation.get_float() : 0.; - if(m_config.pad_enable.getBool()) { + if(m_config.pad_enable.get_bool()) { // Normally the elevation for the pad itself would be the thickness of // its walls but currently it is half of its thickness. Whatever it // will be in the future, we provide the config to the get_pad_elevation @@ -1057,7 +1057,7 @@ double SLAPrintObject::get_current_elevation() const if(!has_supports && !has_pad) return 0; else if(has_supports && !has_pad) { - return m_config.support_object_elevation.getFloat(); + return m_config.support_object_elevation.get_float(); } return get_elevation(); @@ -1148,7 +1148,7 @@ TriangleMesh SLAPrintObject::get_mesh(SLAPrintObjectStep step) const const TriangleMesh& SLAPrintObject::support_mesh() const { - if(m_config.supports_enable.getBool() && m_supportdata) + if(m_config.supports_enable.get_bool() && m_supportdata) return m_supportdata->tree_mesh; return EMPTY_MESH; @@ -1156,7 +1156,7 @@ const TriangleMesh& SLAPrintObject::support_mesh() const const TriangleMesh& SLAPrintObject::pad_mesh() const { - if(m_config.pad_enable.getBool() && m_supportdata) + if(m_config.pad_enable.get_bool() && m_supportdata) return m_supportdata->pad_mesh; return EMPTY_MESH; @@ -1165,7 +1165,7 @@ const TriangleMesh& SLAPrintObject::pad_mesh() const const indexed_triangle_set &SLAPrintObject::hollowed_interior_mesh() const { if (m_hollowing_data && m_hollowing_data->interior && - m_config.hollowing_enable.getBool()) + m_config.hollowing_enable.get_bool()) return sla::get_mesh(*m_hollowing_data->interior); return EMPTY_TRIANGLE_SET; diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index 0a0b5015c5f..261d74894dc 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -78,7 +78,7 @@ SLAPrint::Steps::Steps(SLAPrint *print) : m_print{print} , m_rng{std::random_device{}()} , objcount{m_print->m_objects.size()} - , ilhd{m_print->m_material_config.initial_layer_height.getFloat()} + , ilhd{m_print->m_material_config.initial_layer_height.get_float()} , ilh{float(ilhd)} , ilhs{scaled(ilhd)} , objectstep_scale{(max_objstatus - min_objstatus) / (objcount * 100.0)} @@ -88,11 +88,11 @@ void SLAPrint::Steps::apply_printer_corrections(SLAPrintObject &po, SliceOrigin { if (o == soSupport && !po.m_supportdata) return; - auto faded_lyrs = size_t(po.m_config.faded_layers.getInt()); - double min_w = m_print->m_printer_config.elephant_foot_min_width.getFloat() / 2.; - double start_efc = m_print->m_printer_config.first_layer_size_compensation.getFloat(); + auto faded_lyrs = size_t(po.m_config.faded_layers.get_int()); + double min_w = m_print->m_printer_config.elephant_foot_min_width.get_float() / 2.; + double start_efc = m_print->m_printer_config.first_layer_size_compensation.get_float(); - double doffs = m_print->m_printer_config.absolute_correction.getFloat(); + double doffs = m_print->m_printer_config.absolute_correction.get_float(); coord_t clpr_offs = scaled(doffs); faded_lyrs = std::min(po.m_slice_index.size(), faded_lyrs); @@ -123,16 +123,16 @@ void SLAPrint::Steps::hollow_model(SLAPrintObject &po) { po.m_hollowing_data.reset(); - if (! po.m_config.hollowing_enable.getBool()) { + if (! po.m_config.hollowing_enable.get_bool()) { BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!"; return; } BOOST_LOG_TRIVIAL(info) << "Performing hollowing step!"; - double thickness = po.m_config.hollowing_min_thickness.getFloat(); - double quality = po.m_config.hollowing_quality.getFloat(); - double closing_d = po.m_config.hollowing_closing_distance.getFloat(); + double thickness = po.m_config.hollowing_min_thickness.get_float(); + double quality = po.m_config.hollowing_quality.get_float(); + double closing_d = po.m_config.hollowing_closing_distance.get_float(); sla::HollowingConfig hlwcfg{thickness, quality, closing_d}; sla::InteriorPtr interior = generate_interior(po.transformed_mesh(), hlwcfg); @@ -490,7 +490,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po) // We need to prepare the slice index... - double lhd = m_print->m_objects.front()->m_config.layer_height.getFloat(); + double lhd = m_print->m_objects.front()->m_config.layer_height.get_float(); float lh = float(lhd); coord_t lhs = scaled(lhd); auto && bb3d = mesh.bounding_box(); @@ -567,7 +567,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po) // We apply the printer correction offset here. apply_printer_corrections(po, soModel); - if(po.m_config.supports_enable.getBool() || po.m_config.pad_enable.getBool()) + if(po.m_config.supports_enable.get_bool() || po.m_config.pad_enable.get_bool()) { po.m_supportdata.reset(new SLAPrintObject::SupportData(po.get_mesh_to_print())); } @@ -578,7 +578,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po) void SLAPrint::Steps::support_points(SLAPrintObject &po) { // If supports are disabled, we can skip the model scan. - if(!po.m_config.supports_enable.getBool()) return; + if(!po.m_config.supports_enable.get_bool()) return; if (!po.m_supportdata) po.m_supportdata.reset(new SLAPrintObject::SupportData(po.get_mesh_to_print())); @@ -681,7 +681,7 @@ void SLAPrint::Steps::support_tree(SLAPrintObject &po) po.m_supportdata->create_support_tree(ctl); - if (!po.m_config.supports_enable.getBool()) return; + if (!po.m_config.supports_enable.get_bool()) return; throw_if_canceled(); @@ -706,7 +706,7 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) { // and before the supports had been sliced. (or the slicing has to be // repeated) - if(po.m_config.pad_enable.getBool()) { + if(po.m_config.pad_enable.get_bool()) { // Get the distilled pad configuration from the config sla::PadConfig pcfg = make_pad_cfg(po.m_config); @@ -714,13 +714,13 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) { double pad_h = pcfg.full_height(); const TriangleMesh &trmesh = po.transformed_mesh(); - if (!po.m_config.supports_enable.getBool() || pcfg.embed_object) { + if (!po.m_config.supports_enable.get_bool() || pcfg.embed_object) { // No support (thus no elevation) or zero elevation mode // we sometimes call it "builtin pad" is enabled so we will // get a sample from the bottom of the mesh and use it for pad // creation. sla::pad_blueprint(trmesh.its, bp, float(pad_h), - float(po.m_config.layer_height.getFloat()), + float(po.m_config.layer_height.get_float()), [this](){ throw_if_canceled(); }); } @@ -748,7 +748,7 @@ void SLAPrint::Steps::slice_supports(SLAPrintObject &po) { if(sd) sd->support_slices.clear(); // Don't bother if no supports and no pad is present. - if (!po.m_config.supports_enable.getBool() && !po.m_config.pad_enable.getBool()) + if (!po.m_config.supports_enable.get_bool() && !po.m_config.pad_enable.get_bool()) return; if(sd && sd->support_tree_ptr) { @@ -887,18 +887,18 @@ void SLAPrint::Steps::merge_slices_and_eval_stats() { print_statistics.clear(); - const double area_fill = printer_config.area_fill.getFloat()*0.01;// 0.5 (50%); - const double fast_tilt = printer_config.fast_tilt_time.getFloat();// 5.0; - const double slow_tilt = printer_config.slow_tilt_time.getFloat();// 8.0; - const double hv_tilt = printer_config.high_viscosity_tilt_time.getFloat();// 10.0; + const double area_fill = printer_config.area_fill.get_float()*0.01;// 0.5 (50%); + const double fast_tilt = printer_config.fast_tilt_time.get_float();// 5.0; + const double slow_tilt = printer_config.slow_tilt_time.get_float();// 8.0; + const double hv_tilt = printer_config.high_viscosity_tilt_time.get_float();// 10.0; - const double init_exp_time = material_config.initial_exposure_time.getFloat(); - const double exp_time = material_config.exposure_time.getFloat(); + const double init_exp_time = material_config.initial_exposure_time.get_float(); + const double exp_time = material_config.exposure_time.get_float(); - const int fade_layers_cnt = m_print->m_default_object_config.faded_layers.getInt();// 10 // [3;20] + const int fade_layers_cnt = m_print->m_default_object_config.faded_layers.get_int();// 10 // [3;20] - const auto width = scaled(printer_config.display_width.getFloat()); - const auto height = scaled(printer_config.display_height.getFloat()); + const auto width = scaled(printer_config.display_width.get_float()); + const auto height = scaled(printer_config.display_height.get_float()); const double display_area = width*height; double supports_volume(0.0); diff --git a/src/libslic3r/Slicing.cpp b/src/libslic3r/Slicing.cpp index 9e84279e6fa..844d40bb8b1 100644 --- a/src/libslic3r/Slicing.cpp +++ b/src/libslic3r/Slicing.cpp @@ -315,7 +315,7 @@ std::vector layer_height_profile_from_ranges( for (t_layer_config_ranges::const_iterator it_range = layer_config_ranges.begin(); it_range != layer_config_ranges.end(); ++ it_range) { coordf_t lo = it_range->first.first; coordf_t hi = std::min(it_range->first.second, slicing_params.object_print_z_height()); - coordf_t height = it_range->second.option("layer_height")->getFloat(); + coordf_t height = it_range->second.option("layer_height")->get_float(); if (! ranges_non_overlapping.empty()) // Trim current low with the last high. lo = std::max(lo, ranges_non_overlapping.back().first.second); diff --git a/src/slic3r/GUI/CalibrationBridgeDialog.cpp b/src/slic3r/GUI/CalibrationBridgeDialog.cpp index 476b78bdb58..0d703d42915 100644 --- a/src/slic3r/GUI/CalibrationBridgeDialog.cpp +++ b/src/slic3r/GUI/CalibrationBridgeDialog.cpp @@ -133,7 +133,7 @@ void CalibrationBridgeDialog::create_geometry(std::string setting_to_test, bool DynamicPrintConfig new_print_config = *print_config; //make a copy new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true)); //if skirt, use only one - if (print_config->option("skirts")->getInt() > 0 && print_config->option("skirt_height")->getInt() > 0) { + if (print_config->option("skirts")->get_int() > 0 && print_config->option("skirt_height")->get_int() > 0) { new_print_config.set_key_value("complete_objects_one_skirt", new ConfigOptionBool(true)); } diff --git a/src/slic3r/GUI/CalibrationFlowDialog.cpp b/src/slic3r/GUI/CalibrationFlowDialog.cpp index 040c7a79cee..d697aad6f20 100644 --- a/src/slic3r/GUI/CalibrationFlowDialog.cpp +++ b/src/slic3r/GUI/CalibrationFlowDialog.cpp @@ -132,7 +132,7 @@ void CalibrationFlowDialog::create_geometry(float start, float delta) { DynamicPrintConfig new_print_config = *print_config; //make a copy new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true)); //if skirt, use only one - if (print_config->option("skirts")->getInt() > 0 && print_config->option("skirt_height")->getInt() > 0) { + if (print_config->option("skirts")->get_int() > 0 && print_config->option("skirt_height")->get_int() > 0) { new_print_config.set_key_value("complete_objects_one_skirt", new ConfigOptionBool(true)); } diff --git a/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp b/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp index 344be6ba129..847edbf5e55 100644 --- a/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp +++ b/src/slic3r/GUI/CalibrationOverBridgeDialog.cpp @@ -93,8 +93,8 @@ void CalibrationOverBridgeDialog::create_geometry(bool over_bridge) { bool has_to_arrange = false; const ConfigOptionFloat* extruder_clearance_radius = print_config->option("extruder_clearance_radius"); const ConfigOptionPoints* bed_shape = printer_config->option("bed_shape"); - const float brim_width = print_config->option("brim_width")->getFloat(); - const float skirt_width = print_config->option("skirts")->getInt() == 0 ? 0 : print_config->option("skirt_distance")->getFloat() + print_config->option("skirts")->getInt() * nozzle_diameter * 2; + const float brim_width = print_config->option("brim_width")->get_float(); + const float skirt_width = print_config->option("skirts")->get_int() == 0 ? 0 : print_config->option("skirt_distance")->get_float() + print_config->option("skirts")->get_int() * nozzle_diameter * 2; Vec2d bed_size = BoundingBoxf(bed_shape->values).size(); Vec2d bed_min = BoundingBoxf(bed_shape->values).min; float offsetx = 3 + 30 * xyz_scale + extruder_clearance_radius->value + brim_width + (brim_width > extruder_clearance_radius->value ? brim_width - extruder_clearance_radius->value : 0); @@ -114,7 +114,7 @@ void CalibrationOverBridgeDialog::create_geometry(bool over_bridge) { DynamicPrintConfig new_print_config = *print_config; //make a copy new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true)); //if skirt, use only one - if (print_config->option("skirts")->getInt() > 0 && print_config->option("skirt_height")->getInt() > 0) { + if (print_config->option("skirts")->get_int() > 0 && print_config->option("skirt_height")->get_int() > 0) { new_print_config.set_key_value("complete_objects_one_skirt", new ConfigOptionBool(true)); } diff --git a/src/slic3r/GUI/CalibrationRetractionDialog.cpp b/src/slic3r/GUI/CalibrationRetractionDialog.cpp index 5604513cfe2..8dce80eb1c0 100644 --- a/src/slic3r/GUI/CalibrationRetractionDialog.cpp +++ b/src/slic3r/GUI/CalibrationRetractionDialog.cpp @@ -253,7 +253,7 @@ void CalibrationRetractionDialog::create_geometry(wxCommandEvent& event_args) { DynamicPrintConfig new_print_config = *print_config; //make a copy new_print_config.set_key_value("complete_objects", new ConfigOptionBool(true)); //if skirt, use only one - if (print_config->option("skirts")->getInt() > 0 && print_config->option("skirt_height")->getInt() > 0) { + if (print_config->option("skirts")->get_int() > 0 && print_config->option("skirt_height")->get_int() > 0) { new_print_config.set_key_value("complete_objects_one_skirt", new ConfigOptionBool(true)); } this->gui_app->get_tab(Preset::TYPE_FFF_PRINT)->load_config(new_print_config); diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index a1a5c876230..4e7b0e51838 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -86,9 +86,9 @@ void ConfigManipulation::update_print_fff_config(DynamicPrintConfig* config, con && config->opt_bool("overhangs_reverse") == false && config->opt_bool("gap_fill_last") == false && config->opt_int("solid_over_perimeters") == 0 - && config->option("seam_notch_all")->getFloat() == 0 - && config->option("seam_notch_inner")->getFloat() == 0 - && config->option("seam_notch_outer")->getFloat() == 0 + && config->option("seam_notch_all")->get_float() == 0 + && config->option("seam_notch_inner")->get_float() == 0 + && config->option("seam_notch_outer")->get_float() == 0 )) { wxString msg_text = _(L("The Spiral Vase mode requires:\n" "- no top solid layers\n" @@ -363,7 +363,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("overhangs_reverse_threshold", have_perimeters && config->opt_bool("overhangs_reverse")); toggle_field("overhangs_speed_enforce", have_perimeters && !config->opt_bool("perimeter_loop")); toggle_field("min_width_top_surface", have_perimeters && config->opt_bool("only_one_perimeter_top") && !have_arachne); - toggle_field("thin_perimeters_all", have_perimeters && config->option("thin_perimeters")->getFloat() != 0 && !have_arachne); + toggle_field("thin_perimeters_all", have_perimeters && config->option("thin_perimeters")->get_float() != 0 && !have_arachne); bool have_thin_wall = !have_arachne && have_perimeters; toggle_field("thin_walls", have_thin_wall); for (auto el : { "thin_walls_min_width", "thin_walls_overlap", "thin_walls_merge" }) @@ -374,9 +374,9 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("perimeter_loop_seam", config->opt_bool("perimeter_loop")); - bool have_notch = have_perimeters && (config->option("seam_notch_all")->getFloat() != 0 || - config->option("seam_notch_inner")->getFloat() != 0 || - config->option("seam_notch_outer")->getFloat() != 0); + bool have_notch = have_perimeters && (config->option("seam_notch_all")->get_float() != 0 || + config->option("seam_notch_inner")->get_float() != 0 || + config->option("seam_notch_outer")->get_float() != 0); toggle_field("seam_notch_angle", have_notch); bool have_gap_fill = !have_arachne; @@ -434,7 +434,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) //speed for (auto el : { "small_perimeter_min_length", "small_perimeter_max_length" }) - toggle_field(el, config->option("small_perimeter_speed")->getFloat() > 0); + toggle_field(el, config->option("small_perimeter_speed")->get_float() > 0); bool has_ironing_pattern = config->opt_enum("top_fill_pattern") == InfillPattern::ipSmooth || config->opt_enum("bottom_fill_pattern") == InfillPattern::ipSmooth @@ -511,14 +511,14 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field(el, have_raft); //for default_extrusion_width/spacing, you need to ahve at least an extrusion_width with 0 - bool have_default_width = config->option("first_layer_extrusion_width")->getFloat() == 0 || - (config->option("perimeter_extrusion_width")->getFloat() == 0 && (have_perimeters || have_brim)) || - (config->option("external_perimeter_extrusion_width")->getFloat() == 0 && have_perimeters) || - (config->option("infill_extrusion_width")->getFloat() == 0 && (have_infill || has_solid_infill)) || - (config->option("solid_infill_extrusion_width")->getFloat() == 0 && has_solid_infill) || - (config->option("top_infill_extrusion_width")->getFloat() == 0 && has_top_solid_infill) || - (config->option("support_material_extrusion_width")->getFloat() == 0 && have_support_material) || - (config->option("skirt_extrusion_width")->getFloat() == 0 && have_skirt); + bool have_default_width = config->option("first_layer_extrusion_width")->get_float() == 0 || + (config->option("perimeter_extrusion_width")->get_float() == 0 && (have_perimeters || have_brim)) || + (config->option("external_perimeter_extrusion_width")->get_float() == 0 && have_perimeters) || + (config->option("infill_extrusion_width")->get_float() == 0 && (have_infill || has_solid_infill)) || + (config->option("solid_infill_extrusion_width")->get_float() == 0 && has_solid_infill) || + (config->option("top_infill_extrusion_width")->get_float() == 0 && has_top_solid_infill) || + (config->option("support_material_extrusion_width")->get_float() == 0 && have_support_material) || + (config->option("skirt_extrusion_width")->get_float() == 0 && have_skirt); toggle_field("extrusion_width", have_default_width); toggle_field("extrusion_spacing", have_default_width); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index ecd9cc819f9..e046e152278 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -651,14 +651,14 @@ void TextCtrl::BUILD() { switch (m_opt.type) { case coFloatOrPercent: { - text_value = double_to_string(m_opt.default_value->getFloat(), m_opt.precision); + text_value = double_to_string(m_opt.default_value->get_float(), m_opt.precision); if (m_opt.get_default_value()->percent) text_value += "%"; break; } case coPercent: { - text_value = double_to_string(m_opt.default_value->getFloat(), m_opt.precision); + text_value = double_to_string(m_opt.default_value->get_float(), m_opt.precision); text_value += "%"; break; } @@ -669,7 +669,7 @@ void TextCtrl::BUILD() { double val = m_opt.type == coFloats ? m_opt.get_default_value()->get_at(m_opt_idx) : m_opt.type == coFloat ? - m_opt.default_value->getFloat() : + m_opt.default_value->get_float() : m_opt.get_default_value()->get_at(m_opt_idx); text_value = double_to_string(val, m_opt.precision); break; @@ -898,7 +898,7 @@ void CheckBox::BUILD() { if (m_opt.width >= 0) size.SetWidth(m_opt.width * m_em_unit); bool check_value = m_opt.type == coBool ? - m_opt.default_value->getBool() : m_opt.type == coBools ? + m_opt.default_value->get_bool() : m_opt.type == coBools ? m_opt.get_default_value()->get_at(m_opt_idx) : false; @@ -1055,7 +1055,7 @@ void SpinCtrl::BUILD() { switch (m_opt.type) { case coInt: - default_value = m_opt.default_value->getInt(); + default_value = m_opt.default_value->get_int(); text_value = wxString::Format(_T("%i"), default_value); break; case coInts: @@ -1357,17 +1357,17 @@ void Choice::set_selection() choice_ctrl* field = dynamic_cast(window); switch (m_opt.type) { case coEnum:{ - field->SetSelection(m_opt.default_value->getInt()); + field->SetSelection(m_opt.default_value->get_int()); break; } case coFloat: case coPercent: { - double val = m_opt.default_value->getFloat(); + double val = m_opt.default_value->get_float(); text_value = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 1); break; } case coInt:{ - text_value = wxString::Format(_T("%i"), int(m_opt.default_value->getInt())); + text_value = wxString::Format(_T("%i"), int(m_opt.default_value->get_int())); break; } case coStrings:{ @@ -1375,7 +1375,7 @@ void Choice::set_selection() break; } case coFloatOrPercent: { - text_value = double_to_string(m_opt.default_value->getFloat(), m_opt.precision); + text_value = double_to_string(m_opt.default_value->get_float(), m_opt.precision); if (m_opt.get_default_value()->percent) text_value += "%"; break; @@ -1529,7 +1529,7 @@ void Choice::convert_to_enum_value(int32_t ret_enum) { m_value = value; } else - m_value = m_opt.default_value.get()->getInt(); + m_value = m_opt.default_value.get()->get_int(); } //Please don't use that on Enum fields it will just break everything diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 2263616296f..2ba8dc8d53e 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -279,8 +279,8 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const assert(extruders_min_height->values.size() == extruders_max_height->values.size()); assert(extruders_min_height->values.size() == nozzle_diameter->values.size()); for (size_t idx_extruder = 0; idx_extruder < extruders_min_height->values.size(); ++idx_extruder) { - min_height = std::min(min_height, float(extruders_min_height->get_abs_value(idx_extruder, nozzle_diameter->getFloat(idx_extruder)))); - max_height = std::max(max_height, float(extruders_max_height->get_abs_value(idx_extruder, nozzle_diameter->getFloat(idx_extruder)))); + min_height = std::min(min_height, float(extruders_min_height->get_abs_value(idx_extruder, nozzle_diameter->get_float(idx_extruder)))); + max_height = std::max(max_height, float(extruders_max_height->get_abs_value(idx_extruder, nozzle_diameter->get_float(idx_extruder)))); } min_height = check_z_step(min_height, z_step); max_height = check_z_step(max_height, z_step); diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index ccd3cc08306..e89edfc9c2a 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -206,7 +206,7 @@ void change_opt_value(DynamicConfig& config, const t_config_option_key& opt_key, break; case coEnum:{ ConfigOption* opt = opt_def->default_value.get()->clone(); - opt->setInt(boost::any_cast(value)); // we transport an int convertion of the enum in the boost anycast. + opt->set_enum_int(boost::any_cast(value)); // we transport an int convertion of the enum in the boost anycast. BOOST_LOG_TRIVIAL(debug) << "Set enum "<< opt_key << " as int " << boost::any_cast(value) << " into enum " << opt->serialize(); config.set_key_value(opt_key, opt); } @@ -293,7 +293,7 @@ static void add_config_substitutions(const ConfigSubstitutions& conf_substitutio { const std::vector& labels = def->enum_labels; const std::vector& values = def->enum_values; - int val = conf_substitution.new_value->getInt(); + int val = conf_substitution.new_value->get_int(); bool is_infill = def->opt_key == "top_fill_pattern" || def->opt_key == "bottom_fill_pattern" || @@ -321,7 +321,7 @@ static void add_config_substitutions(const ConfigSubstitutions& conf_substitutio break; } case coBool: - new_val = conf_substitution.new_value->getBool() ? "true" : "false"; + new_val = conf_substitution.new_value->get_bool() ? "true" : "false"; break; case coBools: if (conf_substitution.new_value->nullable()) diff --git a/src/slic3r/GUI/GUI_ObjectLayers.cpp b/src/slic3r/GUI/GUI_ObjectLayers.cpp index 55fba0e332c..99a66d335d7 100644 --- a/src/slic3r/GUI/GUI_ObjectLayers.cpp +++ b/src/slic3r/GUI/GUI_ObjectLayers.cpp @@ -131,7 +131,7 @@ wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range, PlusMinus // Add control for the "Layer height" - editor = new LayerRangeEditor(this, double_to_string(m_object->layer_config_ranges[range].option("layer_height")->getFloat()), etLayerHeight, set_focus_data, + editor = new LayerRangeEditor(this, double_to_string(m_object->layer_config_ranges[range].option("layer_height")->get_float()), etLayerHeight, set_focus_data, [range](coordf_t layer_height, bool, bool) { return wxGetApp().obj_list()->edit_layer_range(range, layer_height); diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index bcdf8d594e6..2bd179abeea 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -844,26 +844,26 @@ void Preview::update_layers_slider_mode() if (!objects.empty()) { const int extruder = objects[0]->config.has("extruder") ? - objects[0]->config.option("extruder")->getInt() : 0; + objects[0]->config.option("extruder")->get_int() : 0; auto is_one_extruder_printed_model = [objects, extruder]() { for (ModelObject* object : objects) { if (object->config.has("extruder") && - object->config.option("extruder")->getInt() != extruder) + object->config.option("extruder")->get_int() != extruder) return false; for (ModelVolume* volume : object->volumes) if ((volume->config.has("extruder") && - volume->config.option("extruder")->getInt() != 0 && // extruder isn't default - volume->config.option("extruder")->getInt() != extruder) || + volume->config.option("extruder")->get_int() != 0 && // extruder isn't default + volume->config.option("extruder")->get_int() != extruder) || !volume->mmu_segmentation_facets.empty()) return false; for (const auto& range : object->layer_config_ranges) if (range.second.has("extruder") && - range.second.option("extruder")->getInt() != extruder) + range.second.option("extruder")->get_int() != extruder) return false; } return true; diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.cpp b/src/slic3r/GUI/Jobs/ArrangeJob.cpp index 3181b99b2d0..e41c1271f7a 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.cpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.cpp @@ -80,12 +80,12 @@ void ArrangeJob::clear_input() void add_brim(arrangement::ArrangePolygon &ap, const ModelConfigObject &config, const Plater* plater) { - if (plater->config()->option("brim_per_object")->getBool()) { + if (plater->config()->option("brim_per_object")->get_bool()) { // object-brim increase the size of the object // Should be using the "inflation" field but it's non-functional right now. - coord_t diff = scale_(plater->config()->option("brim_width")->getFloat() - plater->config()->option("extruder_clearance_radius")->getFloat() / 2); + coord_t diff = scale_(plater->config()->option("brim_width")->get_float() - plater->config()->option("extruder_clearance_radius")->get_float() / 2); if (config.option("brim_width")) - diff = scale_(config.option("brim_width")->getFloat() - plater->config()->option("extruder_clearance_radius")->getFloat() / 2); + diff = scale_(config.option("brim_width")->get_float() - plater->config()->option("extruder_clearance_radius")->get_float() / 2); if (diff > 0) { ExPolygons brimmed = offset_ex(ap.poly, diff); assert(brimmed.size() == 1); diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 7ad55dd2765..f282e7f9f6c 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -727,7 +727,7 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, ConfigOption* conf_opt = initial_conf.option(dep_key)->clone(); // update the field tab->set_value(dep_key, get_config_value(initial_conf, dep_key)); - tab->on_value_change(dep_key, conf_opt->getAny()); + tab->on_value_change(dep_key, conf_opt->get_any()); } } } @@ -1103,7 +1103,7 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicConfig& config, con ret = config.opt_int(opt_key, idx); break; case coEnum: - ret = config.option(opt_key)->getInt(); + ret = config.option(opt_key)->get_int(); break; case coPoint: ret = config.option(opt_key)->value; diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index 328df639204..42cc6b2d163 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -691,7 +691,7 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change) else if ((printer_change && !all_presets_are_from_mk3_family) || (!all_presets_are_from_mk3_family && m_config->option>("host_type")->value == htPrusaLink)) set_to_choice_and_config(htOctoPrint); else - choice->set_value(m_config->option("host_type")->getInt()); + choice->set_value(m_config->option("host_type")->get_int()); had_all_mk3 = all_presets_are_from_mk3_family; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 9d09ffb23f9..c07651e9219 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1281,11 +1281,11 @@ void Sidebar::update_sliced_info_sizer() wxString str_total_cost = "N/A"; DynamicPrintConfig* cfg = wxGetApp().get_tab(Preset::TYPE_SLA_MATERIAL)->get_config(); - if (cfg->option("bottle_cost")->getFloat() > 0.0 && - cfg->option("bottle_volume")->getFloat() > 0.0) + if (cfg->option("bottle_cost")->get_float() > 0.0 && + cfg->option("bottle_volume")->get_float() > 0.0) { - double material_cost = cfg->option("bottle_cost")->getFloat() / - cfg->option("bottle_volume")->getFloat(); + double material_cost = cfg->option("bottle_cost")->get_float() / + cfg->option("bottle_volume")->get_float(); str_total_cost = wxString::Format("%.3f", material_cost*(ps.objects_used_material + ps.support_used_material) / 1000); } p->sliced_info->SetTextAndShow(siCost, str_total_cost, "Cost"); diff --git a/src/slic3r/GUI/ScriptExecutor.cpp b/src/slic3r/GUI/ScriptExecutor.cpp index a84ac04ca60..99520021ab4 100644 --- a/src/slic3r/GUI/ScriptExecutor.cpp +++ b/src/slic3r/GUI/ScriptExecutor.cpp @@ -86,9 +86,9 @@ bool as_get_bool(std::string& key) throw NoDefinitionException("error, can't find bool option " + key); if (opt->is_vector()) { const ConfigOptionVectorBase* vector = static_cast(opt); - return vector->getFloat(0) != 0; + return vector->get_float(0) != 0; } else { - return opt->getBool(); + return opt->get_bool(); } } void as_set_bool(std::string& key, bool b) @@ -113,9 +113,9 @@ int32_t as_get_int(std::string& key) throw NoDefinitionException("error, can't find int option " + key); if (opt->is_vector()) { const ConfigOptionVectorBase* vector = static_cast(opt); - return (int32_t)vector->getFloat(0); + return (int32_t)vector->get_float(0); } else { - return (int32_t)(opt->getInt()); + return (int32_t)(opt->get_int()); } } void as_set_int(std::string& key, int val) @@ -149,7 +149,7 @@ void as_set_int(std::string& key, int val) // } // if (value >= 0 && value < def->enum_values.size()) { ConfigOption* copy = result.second->clone(); - copy->setInt(val); + copy->set_enum_int(val); conf.set_key_value(key, copy); // return; // } @@ -164,9 +164,9 @@ float as_get_float(std::string& key) throw NoDefinitionException("error, can't find float option " + key); if (opt->is_vector()) { const ConfigOptionVectorBase* vector = static_cast(opt); - return (float)vector->getFloat(0); + return (float)vector->get_float(0); } else { - return (float)(opt->getFloat()); + return (float)(opt->get_float()); } } @@ -187,7 +187,7 @@ void as_set_float(std::string& key, float f_val) DynamicPrintConfig& conf = current_script->to_update()[result.first->type()]; if (result.second->type() == ConfigOptionType::coFloat) { - double old_value = result.second->getFloat(); + double old_value = result.second->get_float(); double new_val = round(f_val); // only update if difference is significant if (std::abs(old_value - new_val) / std::abs(old_value) < 0.0000001) @@ -207,7 +207,7 @@ void as_set_float(std::string& key, float f_val) } else if (result.second->type() == ConfigOptionType::coPercent) { double percent_f = floor(f_val * 100000. + 0.5) / 1000.; // only update if difference is significant - double old_value = result.second->getFloat(); + double old_value = result.second->get_float(); if (std::abs(old_value - percent_f) / std::abs(old_value) < 0.0000001) percent_f = old_value; conf.set_key_value(key, new ConfigOptionPercent(percent_f)); @@ -226,7 +226,7 @@ void as_set_float(std::string& key, float f_val) double new_val = round(f_val); if (!static_cast(result.second)->percent) { // only update if difference is significant - double old_value = result.second->getFloat(); + double old_value = result.second->get_float(); if (std::abs(old_value - new_val) / std::abs(old_value) < 0.0000001) new_val = old_value; } @@ -263,7 +263,7 @@ void as_set_percent(std::string& key, float f_val) DynamicPrintConfig& conf = current_script->to_update()[result.first->type()]; if (result.second->type() == ConfigOptionType::coFloat) { // only update if difference is significant - double old_value = result.second->getFloat() * 100; + double old_value = result.second->get_float() * 100; if (std::abs(old_value - percent_f) / std::abs(old_value) < 0.0000001) percent_f = old_value; // don't return int these check, as it can escpae a refresh of the scripted widget conf.set_key_value(key, new ConfigOptionFloat(percent_f / 100.)); @@ -279,7 +279,7 @@ void as_set_percent(std::string& key, float f_val) conf.set_key_value(key, new_opt); } else if (result.second->type() == ConfigOptionType::coPercent) { // only update if difference is significant - double old_value = get_coll(key).second->getFloat(); + double old_value = get_coll(key).second->get_float(); if (std::abs(old_value - percent_f) / std::abs(old_value) < 0.0000001) percent_f = old_value; conf.set_key_value(key, new ConfigOptionPercent(percent_f)); @@ -296,7 +296,7 @@ void as_set_percent(std::string& key, float f_val) } else if (result.second->type() == ConfigOptionType::coFloatOrPercent) { if (static_cast(result.second)->percent) { // only update if difference is significant - double old_value = result.second->getFloat(); + double old_value = result.second->get_float(); if (std::abs(old_value - percent_f) / std::abs(old_value) < 0.0000001) percent_f = old_value; } @@ -346,7 +346,7 @@ void as_set_string(std::string& key, std::string& val) for (; idx < def->enum_values.size() && def->enum_values[idx] != val; idx++) {} if (idx >= 0 && idx < def->enum_values.size()) { ConfigOption* copy = result.second->clone(); - copy->setInt(idx); + copy->set_enum_int(idx); conf.set_key_value(key, copy); } } @@ -868,7 +868,7 @@ void ScriptContainer::call_script_function_set(const ConfigOptionDef& def, const for (const auto& data : to_update) { Tab* tab = wxGetApp().get_tab(data.first); for (auto opt_key : data.second.keys()) { - tab->on_value_change(opt_key, data.second.option(opt_key)->getAny()); + tab->on_value_change(opt_key, data.second.option(opt_key)->get_any()); } } // refresh the field if needed @@ -923,7 +923,7 @@ bool ScriptContainer::call_script_function_reset(const ConfigOptionDef& def) for (const auto& data : to_update) { Tab* tab = wxGetApp().get_tab(data.first); for (auto opt_key : data.second.keys()) { - tab->on_value_change(opt_key, data.second.option(opt_key)->getAny()); + tab->on_value_change(opt_key, data.second.option(opt_key)->get_any()); } } // refresh the field if needed diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index f20beba2736..91161f3b9d6 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1885,15 +1885,15 @@ std::vector Tab::create_pages(std::string setting_type_nam DynamicPrintConfig new_conf = *m_config; if (opt_key == "bottle_volume") { - double new_bottle_weight = boost::any_cast(value) / (new_conf.option("material_density")->getFloat() * 1000); + double new_bottle_weight = boost::any_cast(value) / (new_conf.option("material_density")->get_float() * 1000); new_conf.set_key_value("bottle_weight", new ConfigOptionFloat(new_bottle_weight)); } if (opt_key == "bottle_weight") { - double new_bottle_volume = boost::any_cast(value)*(new_conf.option("material_density")->getFloat() * 1000); + double new_bottle_volume = boost::any_cast(value)*(new_conf.option("material_density")->get_float() * 1000); new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume)); } if (opt_key == "material_density") { - double new_bottle_volume = new_conf.option("bottle_weight")->getFloat() * boost::any_cast(value) * 1000; + double new_bottle_volume = new_conf.option("bottle_weight")->get_float() * boost::any_cast(value) * 1000; new_conf.set_key_value("bottle_volume", new ConfigOptionFloat(new_bottle_volume)); } @@ -2732,7 +2732,7 @@ void TabPrint::update() { const Preset& selected_preset = m_preset_bundle->fff_prints.get_selected_preset(); bool is_user_and_saved_preset = !selected_preset.is_system && !selected_preset.is_dirty; - bool support_material_overhangs_queried = m_config->opt_bool("support_material") && m_config->option("overhangs_width_speed")->getFloat() == 0; + bool support_material_overhangs_queried = m_config->opt_bool("support_material") && m_config->option("overhangs_width_speed")->get_float() == 0; m_config_manipulation.initialize_support_material_overhangs_queried(is_user_and_saved_preset && support_material_overhangs_queried); } diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index cb0736e4e3c..96725c07d30 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -1039,7 +1039,7 @@ wxString get_string_from_enum(const std::string& opt_key, const DynamicPrintConf { const ConfigOptionDef& def = config.def()->options.at(opt_key); const std::vector& names = def.enum_labels.empty() ? def.enum_values : def.enum_labels; - int val = config.option(opt_key)->getInt(); + int val = config.option(opt_key)->get_int(); // if it doesn't use all list declared in PrintConfig.hpp. // So we should "convert" val to the correct one @@ -1119,7 +1119,7 @@ static wxString get_string_value(std::string opt_key, const DynamicPrintConfig& return _L("Undef"); } case coPercent: - return from_u8((boost::format("%1%%%") % int(config.optptr(opt_key)->getFloat())).str()); + return from_u8((boost::format("%1%%%") % int(config.optptr(opt_key)->get_float())).str()); case coPercents: { if (is_nullable) { auto values = config.opt(opt_key); From 814d9650f664f9d39deec95581926c653b5d41cd Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 27 Dec 2023 02:26:36 +0100 Subject: [PATCH 03/19] config: get_xxx() -> get_xxx(idx = 0) (vectorize getter) --- src/libslic3r/Config.hpp | 117 +++++++++++++++++++++--------- src/slic3r/GUI/OptionsGroup.cpp | 2 +- src/slic3r/GUI/ScriptExecutor.cpp | 4 +- 3 files changed, 84 insertions(+), 39 deletions(-) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 1c0a128fe27..4dafda168e5 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -395,11 +395,11 @@ class ConfigOption { virtual ConfigOption* clone() const = 0; // Set a value from a ConfigOption. The two options should be compatible. virtual void set(const ConfigOption *option) = 0; - virtual int32_t get_int() const { throw BadOptionTypeException("Calling ConfigOption::get_int on a non-int ConfigOption"); } - virtual double get_float() const { throw BadOptionTypeException("Calling ConfigOption::get_float on a non-float ConfigOption"); } - virtual bool get_bool() const { throw BadOptionTypeException("Calling ConfigOption::get_bool on a non-boolean ConfigOption"); } + virtual int32_t get_int(size_t idx = 0) const { throw BadOptionTypeException("Calling ConfigOption::get_int on a non-int ConfigOption"); } + virtual double get_float(size_t idx = 0) const { throw BadOptionTypeException("Calling ConfigOption::get_float on a non-float ConfigOption"); } + virtual bool get_bool(size_t idx = 0) const { throw BadOptionTypeException("Calling ConfigOption::get_bool on a non-boolean ConfigOption"); } virtual void set_enum_int(int32_t /* val */) { throw BadOptionTypeException("Calling ConfigOption::set_enum_int on a non-enum ConfigOption"); } - virtual boost::any get_any() const { throw BadOptionTypeException("Calling ConfigOption::get_any on a raw ConfigOption"); } + virtual boost::any get_any(int32_t idx = -1) const { throw BadOptionTypeException("Calling ConfigOption::get_any on a raw ConfigOption"); } virtual bool operator==(const ConfigOption &rhs) const = 0; bool operator!=(const ConfigOption &rhs) const { return ! (*this == rhs); } virtual size_t hash() const throw() = 0; @@ -407,8 +407,8 @@ class ConfigOption { bool is_vector() const { return ! this->is_scalar(); } // If this option is nullable, then it may have its value or values set to nil. virtual bool nullable() const { return false; } - // A scalar is nil, or all values of a vector are nil. - virtual bool is_nil() const { return false; } + // A scalar is nil, or all values of a vector are nil if idx < 0. + virtual bool is_nil(int32_t idx = -1) const { return false; } bool is_phony() const { return (flags & FCO_PHONY) != 0; } void set_phony(bool phony) { if (phony) this->flags |= FCO_PHONY; else this->flags &= uint8_t(0xFF ^ FCO_PHONY); } // Is this option overridden by another option? @@ -440,7 +440,7 @@ class ConfigOptionSingle : public ConfigOption { explicit ConfigOptionSingle(T value) : value(value) {} explicit ConfigOptionSingle(T value, bool phony) : ConfigOption(phony), value(value) {} operator T() const { return this->value; } - boost::any get_any() const override { return boost::any(value); } + boost::any get_any(int32_t idx = 0) const override { return boost::any(value); } void set(const ConfigOption *rhs) override { @@ -492,20 +492,16 @@ class ConfigOptionVectorBase : public ConfigOption { virtual size_t size() const = 0; // Is this vector empty? virtual bool empty() const = 0; - // Is the value nil? That should only be possible if this->nullable(). - virtual bool is_nil(size_t idx) const = 0; // Get if the size of this vector is/should be the same as nozzle_diameter bool is_extruder_size() const { return (flags & FCO_EXTRUDER_ARRAY) != 0; } ConfigOptionVectorBase* set_is_extruder_size(bool is_extruder_size) { if (is_extruder_size) this->flags |= FCO_EXTRUDER_ARRAY; else this->flags &= uint8_t(0xFF ^ FCO_EXTRUDER_ARRAY); return this; } - virtual double get_float(int idx) const { throw BadOptionTypeException("Calling ConfigOption::getFloat(idx) on a non-numeric arrray ConfigOptionVectorBase"); } // We just overloaded and hid two base class virtual methods. // Let's show it was intentional (warnings). using ConfigOption::set; - using ConfigOption::is_nil; protected: @@ -598,7 +594,7 @@ class ConfigOptionVector : public ConfigOptionVectorBase } T& get_at(size_t i) { return const_cast(std::as_const(*this).get_at(i)); } - virtual boost::any get_any() const { return boost::any(values); } + boost::any get_any(int32_t idx = -1) const override { return idx < 0 ? boost::any(values) : boost::any(get_at(idx)); } // Resize this vector by duplicating the /*last*/first value. // If the current vector is empty, the default value is used instead. @@ -722,7 +718,7 @@ class ConfigOptionFloat : public ConfigOptionSingle static ConfigOptionType static_type() { return coFloat; } ConfigOptionType type() const override { return static_type(); } - double get_float() const override { return this->value; } + double get_float(size_t idx = 0) const override { return this->value; } ConfigOption* clone() const override { return new ConfigOptionFloat(*this); } bool operator==(const ConfigOptionFloat &rhs) const throw() { return this->value == rhs.value; } bool operator< (const ConfigOptionFloat &rhs) const throw() { return this->value < rhs.value; } @@ -780,9 +776,20 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector // Special "nil" value to be stored into the vector if this->supports_nil(). static double nil_value() { return std::numeric_limits::quiet_NaN(); } // A scalar is nil, or all values of a vector are nil. - bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v)) return false; return true; } - bool is_nil(size_t idx) const override { return idx < values.size() ? std::isnan(this->values[idx]) : values.empty() ? std::isnan(this->default_value) : std::isnan(this->values.front()); } - double get_float(int idx) const override { return values[idx]; } + bool is_nil(int32_t idx = -1) const override + { + if (idx < 0) { + for (double v : this->values) + if (!std::isnan(v)) + return false; + return true; + } else { + return idx < values.size() ? std::isnan(this->values[idx]) : + values.empty() ? std::isnan(this->default_value) : + std::isnan(this->values.front()); + } + } + double get_float(size_t idx = 0) const override { return get_at(idx); } std::string serialize() const override { @@ -890,7 +897,8 @@ class ConfigOptionInt : public ConfigOptionSingle static ConfigOptionType static_type() { return coInt; } ConfigOptionType type() const override { return static_type(); } - int32_t get_int() const override { return this->value; } + int32_t get_int(size_t idx = 0) const override { return this->value; } + double get_float(size_t idx = 0) const override { return this->value; } ConfigOption* clone() const override { return new ConfigOptionInt(*this); } bool operator==(const ConfigOptionInt &rhs) const throw() { return this->value == rhs.value; } @@ -942,9 +950,21 @@ class ConfigOptionIntsTempl : public ConfigOptionVector // Special "nil" value to be stored into the vector if this->supports_nil(). static int32_t nil_value() { return std::numeric_limits::max(); } // A scalar is nil, or all values of a vector are nil. - bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } - bool is_nil(size_t idx) const override { return idx < values.size() ? this->values[idx] == nil_value() : values.empty() ? this->default_value == nil_value() : this->values.front() == nil_value(); } - double get_float(int idx) const override { return values[idx]; } + bool is_nil(int32_t idx = -1) const override + { + if (idx < 0) { + for (int32_t v : this->values) + if (v != nil_value()) + return false; + return true; + } else { + return idx < values.size() ? nil_value() == this->values[idx] : + values.empty() ? nil_value() == this->default_value : + nil_value() == this->values.front(); + } + } + int32_t get_int(size_t idx = 0) const override { return get_at(idx); } + double get_float(size_t idx = 0) const override { return get_at(idx); } std::string serialize() const override { @@ -1057,7 +1077,7 @@ class ConfigOptionStrings : public ConfigOptionVector ConfigOptionStrings& operator=(const ConfigOption *opt) { this->set(opt); return *this; } bool operator==(const ConfigOptionStrings &rhs) const throw() { return this->values == rhs.values; } bool operator< (const ConfigOptionStrings &rhs) const throw() { return this->values < rhs.values; } - bool is_nil(size_t) const override { return false; } + bool is_nil(int32_t idx = 0) const override { return false; } std::string serialize() const override { @@ -1206,6 +1226,7 @@ class ConfigOptionFloatOrPercent : public ConfigOptionPercent double get_abs_value(double ratio_over) const { return this->percent ? (ratio_over * this->value / 100) : this->value; } + double get_float(size_t idx = 0) const override { return get_abs_value(1.); } void set(const ConfigOption *rhs) override { if (rhs->type() != this->type()) @@ -1265,14 +1286,26 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVectorsupports_nil(). static FloatOrPercent nil_value() { return { std::numeric_limits::quiet_NaN(), false }; } // A scalar is nil, or all values of a vector are nil. - bool is_nil() const override { for (auto v : this->values) if (! std::isnan(v.value)) return false; return true; } - bool is_nil(size_t idx) const override { return idx < values.size() ? std::isnan(this->values[idx].value) : values.empty() ? std::isnan(this->default_value.value) : std::isnan(this->values.front().value); } + bool is_nil(int32_t idx = -1) const override + { + if (idx < 0) { + for (const FloatOrPercent &v : this->values) + if (! std::isnan(v.value)) + return false; + return true; + } else { + return idx < values.size() ? std::isnan(this->values[idx].value) : + values.empty() ? std::isnan(this->default_value.value) : + std::isnan(this->values.front().value); + } + } double get_abs_value(size_t i, double ratio_over) const { if (this->is_nil(i)) return 0; const FloatOrPercent& data = this->get_at(i); if (data.percent) return ratio_over * data.value / 100; return data.value; } + double get_float(size_t idx = 0) const override { return get_abs_value(idx, 1.); } std::string serialize() const override { @@ -1439,7 +1472,7 @@ class ConfigOptionPoints : public ConfigOptionVector bool operator==(const ConfigOptionPoints &rhs) const throw() { return this->values == rhs.values; } bool operator< (const ConfigOptionPoints &rhs) const throw() { return std::lexicographical_compare(this->values.begin(), this->values.end(), rhs.values.begin(), rhs.values.end(), [](const auto &l, const auto &r){ return l < r; }); } - bool is_nil(size_t) const override { return false; } + bool is_nil(int32_t idx = 0) const override { return false; } std::string serialize() const override { @@ -1548,7 +1581,9 @@ class ConfigOptionBool : public ConfigOptionSingle static ConfigOptionType static_type() { return coBool; } ConfigOptionType type() const override { return static_type(); } - bool get_bool() const override { return this->value; } + bool get_bool(size_t idx = 0) const override { return this->value; } + int32_t get_int(size_t idx = 0) const override { return this->value ? 1 : 0; } + double get_float(size_t idx = 0) const override { return this->value ? 1. : 0.; } ConfigOption* clone() const override { return new ConfigOptionBool(*this); } ConfigOptionBool& operator=(const ConfigOption *opt) { this->set(opt); return *this; } bool operator==(const ConfigOptionBool &rhs) const throw() { return this->value == rhs.value; } @@ -1600,17 +1635,22 @@ class ConfigOptionBoolsTempl : public ConfigOptionVector // Special "nil" value to be stored into the vector if this->supports_nil(). static unsigned char nil_value() { return std::numeric_limits::max(); } // A scalar is nil, or all values of a vector are nil. - bool is_nil() const override { for (auto v : this->values) if (v != nil_value()) return false; return true; } - bool is_nil(size_t idx) const override { return idx < values.size() ? this->values[idx] == nil_value() : values.empty() ? this->default_value == nil_value() : this->values.front() == nil_value(); } - double get_float(int idx) const override { return values[idx] ? 1 : 0; } - - bool& get_at(size_t i) { - assert(! this->values.empty()); - return *reinterpret_cast(&((i < this->values.size()) ? this->values[i] : this->values.front())); + bool is_nil(int32_t idx = -1) const override + { + if (idx < 0) { + for (uint8_t v : this->values) + if (v != nil_value()) + return false; + return true; + } else { + return idx < values.size() ? nil_value() == this->values[idx] : + values.empty() ? nil_value() == this->default_value : + nil_value() == this->values.front(); + } } - - //FIXME this smells, the parent class has the method declared returning (unsigned char&). - bool get_at(size_t i) const { return ((i < this->values.size()) ? this->values[i] : this->values.front()) != 0; } + bool get_bool(size_t idx = 0) const override { return ConfigOptionVector::get_at(idx) != 0; } + int32_t get_int(size_t idx = 0) const override { return ConfigOptionVector::get_at(idx) != 0 ? 1 : 0; } + double get_float(size_t idx = 0) const override { return ConfigOptionVector::get_at(idx) != 0 ? 1. : 0.; } std::string serialize() const override { @@ -1706,7 +1746,7 @@ class ConfigOptionEnum : public ConfigOptionSingle ConfigOptionEnum& operator=(const ConfigOption *opt) { this->set(opt); return *this; } bool operator==(const ConfigOptionEnum &rhs) const throw() { return this->value == rhs.value; } bool operator< (const ConfigOptionEnum &rhs) const throw() { return int(this->value) < int(rhs.value); } - int32_t get_int() const override { return (int32_t)this->value; } + int32_t get_int(size_t idx = 0) const override { return int32_t(this->value); } void set_enum_int(int32_t val) override { this->value = T(val); } bool operator==(const ConfigOption &rhs) const override @@ -2424,6 +2464,11 @@ class DynamicConfig : public virtual ConfigBase int32_t& opt_int(const t_config_option_key &opt_key, unsigned int idx) { return this->option(opt_key)->get_at(idx); } int32_t opt_int(const t_config_option_key &opt_key, unsigned int idx) const { return dynamic_cast(this->option(opt_key))->get_at(idx); } + // no dynamic_cast + bool get_bool(const t_config_option_key &opt_key, size_t idx = 0) const {return this->option(opt_key)->get_bool(idx);} + int32_t get_int(const t_config_option_key &opt_key, size_t idx = 0) const {return this->option(opt_key)->get_int(idx);} + double get_float(const t_config_option_key &opt_key, size_t idx = 0) const {return this->option(opt_key)->get_float(idx);} + // In ConfigManipulation::toggle_print_fff_options, it is called on option with type ConfigOptionEnumGeneric* and also ConfigOptionEnum*. // Thus the virtual method get_int() is used to retrieve the enum value. template diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index f282e7f9f6c..87f70a9825a 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -727,7 +727,7 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, ConfigOption* conf_opt = initial_conf.option(dep_key)->clone(); // update the field tab->set_value(dep_key, get_config_value(initial_conf, dep_key)); - tab->on_value_change(dep_key, conf_opt->get_any()); + tab->on_value_change(dep_key, conf_opt->get_any(-1)); } } } diff --git a/src/slic3r/GUI/ScriptExecutor.cpp b/src/slic3r/GUI/ScriptExecutor.cpp index 99520021ab4..8cb1ca6299e 100644 --- a/src/slic3r/GUI/ScriptExecutor.cpp +++ b/src/slic3r/GUI/ScriptExecutor.cpp @@ -868,7 +868,7 @@ void ScriptContainer::call_script_function_set(const ConfigOptionDef& def, const for (const auto& data : to_update) { Tab* tab = wxGetApp().get_tab(data.first); for (auto opt_key : data.second.keys()) { - tab->on_value_change(opt_key, data.second.option(opt_key)->get_any()); + tab->on_value_change(opt_key, data.second.option(opt_key)->get_any(-1)); } } // refresh the field if needed @@ -923,7 +923,7 @@ bool ScriptContainer::call_script_function_reset(const ConfigOptionDef& def) for (const auto& data : to_update) { Tab* tab = wxGetApp().get_tab(data.first); for (auto opt_key : data.second.keys()) { - tab->on_value_change(opt_key, data.second.option(opt_key)->get_any()); + tab->on_value_change(opt_key, data.second.option(opt_key)->get_any(-1)); } } // refresh the field if needed From 651f4994e4ae9d7c168d9a6957eea5f322453eec Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 27 Dec 2023 02:37:52 +0100 Subject: [PATCH 04/19] config: nil_value isn't nan for float (or maybe it can be changed) --- src/libslic3r/Config.hpp | 110 +++++++++++++++++++++++---------------- src/slic3r/GUI/Field.cpp | 12 ++--- src/slic3r/GUI/GUI.cpp | 2 +- 3 files changed, 71 insertions(+), 53 deletions(-) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 4dafda168e5..bdd211bb2aa 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -81,6 +81,7 @@ extern bool unescape_strings_cstyle(const std::string &str, std::vector< extern std::string escape_ampersand(const std::string& str); +constexpr char NIL_STR_VALUE[] = "nil"; enum class OptionCategory : int { @@ -773,24 +774,28 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector } // Could a special "nil" value be stored inside the vector, indicating undefined value? bool nullable() const override { return NULLABLE; } - // Special "nil" value to be stored into the vector if this->supports_nil(). - static double nil_value() { return std::numeric_limits::quiet_NaN(); } // A scalar is nil, or all values of a vector are nil. bool is_nil(int32_t idx = -1) const override { if (idx < 0) { for (double v : this->values) - if (!std::isnan(v)) + if (!std::isnan(v) && v != NIL_VALUE()) return false; return true; } else { - return idx < values.size() ? std::isnan(this->values[idx]) : - values.empty() ? std::isnan(this->default_value) : - std::isnan(this->values.front()); + return idx < values.size() ? (std::isnan(this->values[idx]) || NIL_VALUE() == this->values[idx]) : + values.empty() ? (std::isnan(this->default_value) || NIL_VALUE() == this->default_value) : + (std::isnan(this->values.front()) || NIL_VALUE() == this->values.front()); } } double get_float(size_t idx = 0) const override { return get_at(idx); } + static inline bool is_nil(const boost::any &to_check) { + return std::isnan(boost::any_cast(to_check)) || boost::any_cast(to_check) == NIL_VALUE(); + } + // don't use it to compare, use is_nil() to check. + static inline boost::any create_nil() { return boost::any(NIL_VALUE()); } + std::string serialize() const override { std::ostringstream ss; @@ -822,9 +827,9 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector std::string item_str; while (std::getline(is, item_str, ',')) { boost::trim(item_str); - if (item_str == "nil") { + if (item_str == NIL_STR_VALUE) { if (NULLABLE) - this->values.push_back(nil_value()); + this->values.push_back(NIL_VALUE()); else throw ConfigurationError("Deserializing nil into a non-nullable object"); } else { @@ -844,12 +849,15 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector } protected: + // Special "nil" value to be stored into the vector if this->supports_nil(). + //please use is_nil & create_nil, to better support nan + static double NIL_VALUE() { return std::numeric_limits::quiet_NaN(); } void serialize_single_value(std::ostringstream &ss, const double v) const { if (std::isfinite(v)) ss << v; - else if (std::isnan(v)) { + else if (std::isnan(v) || v == NIL_VALUE()) { if (NULLABLE) - ss << "nil"; + ss << NIL_STR_VALUE; else throw ConfigurationError("Serializing NaN"); } else @@ -860,7 +868,8 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector if (v1.size() != v2.size()) return false; for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end(); ++ it1, ++ it2) - if (! ((std::isnan(*it1) && std::isnan(*it2)) || *it1 == *it2)) + if (!(((std::isnan(*it1) || *it1 == NIL_VALUE()) && (std::isnan(*it2) || *it2 == NIL_VALUE())) || + *it1 == *it2)) return false; return true; } else @@ -870,8 +879,8 @@ class ConfigOptionFloatsTempl : public ConfigOptionVector static bool vectors_lower(const std::vector &v1, const std::vector &v2) { if (NULLABLE) { for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++ it1, ++ it2) { - auto null1 = int(std::isnan(*it1)); - auto null2 = int(std::isnan(*it2)); + auto null1 = int(std::isnan(*it1) || *it1 == NIL_VALUE()); + auto null2 = int(std::isnan(*it2) || *it2 == NIL_VALUE()); return (null1 < null2) || (null1 == null2 && *it1 < *it2); } return v1.size() < v2.size(); @@ -948,19 +957,19 @@ class ConfigOptionIntsTempl : public ConfigOptionVector // Could a special "nil" value be stored inside the vector, indicating undefined value? bool nullable() const override { return NULLABLE; } // Special "nil" value to be stored into the vector if this->supports_nil(). - static int32_t nil_value() { return std::numeric_limits::max(); } + static int32_t NIL_VALUE() { return std::numeric_limits::max(); } // A scalar is nil, or all values of a vector are nil. bool is_nil(int32_t idx = -1) const override { if (idx < 0) { for (int32_t v : this->values) - if (v != nil_value()) + if (v != NIL_VALUE()) return false; return true; } else { - return idx < values.size() ? nil_value() == this->values[idx] : - values.empty() ? nil_value() == this->default_value : - nil_value() == this->values.front(); + return idx < values.size() ? NIL_VALUE() == this->values[idx] : + values.empty() ? NIL_VALUE() == this->default_value : + NIL_VALUE() == this->values.front(); } } int32_t get_int(size_t idx = 0) const override { return get_at(idx); } @@ -997,9 +1006,9 @@ class ConfigOptionIntsTempl : public ConfigOptionVector std::string item_str; while (std::getline(is, item_str, ',')) { boost::trim(item_str); - if (item_str == "nil") { + if (item_str == NIL_STR_VALUE) { if (NULLABLE) - this->values.push_back(nil_value()); + this->values.push_back(NIL_VALUE()); else throw ConfigurationError("Deserializing nil into a non-nullable object"); } else { @@ -1014,9 +1023,9 @@ class ConfigOptionIntsTempl : public ConfigOptionVector private: void serialize_single_value(std::ostringstream &ss, const int32_t v) const { - if (v == nil_value()) { + if (v == NIL_VALUE()) { if (NULLABLE) - ss << "nil"; + ss << NIL_STR_VALUE; else throw ConfigurationError("Serializing NaN"); } else @@ -1166,7 +1175,7 @@ class ConfigOptionPercentsTempl : public ConfigOptionFloatsTempl if (&v != &this->values.front()) ss << ","; this->serialize_single_value(ss, v); - if (! std::isnan(v)) + if (! (std::isnan(v) || v == ConfigOptionFloatsTempl::NIL_VALUE())) ss << "%"; } std::string str = ss.str(); @@ -1180,7 +1189,7 @@ class ConfigOptionPercentsTempl : public ConfigOptionFloatsTempl for (const double v : this->values) { std::ostringstream ss; this->serialize_single_value(ss, v); - if (! std::isnan(v)) + if (! (std::isnan(v) || v == ConfigOptionFloatsTempl::NIL_VALUE())) ss << "%"; vv.push_back(ss.str()); } @@ -1283,20 +1292,18 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVectorsupports_nil(). - static FloatOrPercent nil_value() { return { std::numeric_limits::quiet_NaN(), false }; } // A scalar is nil, or all values of a vector are nil. bool is_nil(int32_t idx = -1) const override { if (idx < 0) { for (const FloatOrPercent &v : this->values) - if (! std::isnan(v.value)) + if (! std::isnan(v.value) || v != NIL_VALUE()) return false; return true; } else { - return idx < values.size() ? std::isnan(this->values[idx].value) : - values.empty() ? std::isnan(this->default_value.value) : - std::isnan(this->values.front().value); + return idx < values.size() ? (std::isnan(this->values[idx].value) || NIL_VALUE() == this->values[idx]) : + values.empty() ? (std::isnan(this->default_value.value) || NIL_VALUE() == this->default_value) : + (std::isnan(this->values.front().value) || NIL_VALUE() == this->values.front()); } } double get_abs_value(size_t i, double ratio_over) const { @@ -1307,6 +1314,12 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector(to_check).value) || boost::any_cast(to_check).value == NIL_VALUE().value; + } + // don't use it to compare, use is_nil() to check. + static inline boost::any create_nil() { return boost::any(NIL_VALUE()); } + std::string serialize() const override { std::ostringstream ss; @@ -1338,9 +1351,9 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVectorvalues.push_back(nil_value()); + this->values.push_back(NIL_VALUE()); else throw ConfigurationError("Deserializing nil into a non-nullable object"); } else { @@ -1361,14 +1374,17 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVectorsupports_nil(). + static FloatOrPercent NIL_VALUE() { return FloatOrPercent{ std::numeric_limits::max(), false }; } + void serialize_single_value(std::ostringstream &ss, const FloatOrPercent &v) const { if (std::isfinite(v.value)) { ss << v.value; if (v.percent) ss << "%"; - } else if (std::isnan(v.value)) { + } else if (std::isnan(v.value) || v.value == NIL_VALUE().value) { if (NULLABLE) - ss << "nil"; + ss << NIL_STR_VALUE; else throw ConfigurationError("Serializing NaN"); } else @@ -1379,7 +1395,9 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVectorvalue) && std::isnan(it2->value)) || *it1 == *it2)) + if (!(((std::isnan(it1->value) || it1->value == NIL_VALUE().value) && + (std::isnan(it2->value) || it2->value == NIL_VALUE().value)) || + *it1 == *it2)) return false; return true; } else @@ -1389,8 +1407,8 @@ class ConfigOptionFloatsOrPercentsTempl : public ConfigOptionVector &v1, const std::vector &v2) { if (NULLABLE) { for (auto it1 = v1.begin(), it2 = v2.begin(); it1 != v1.end() && it2 != v2.end(); ++ it1, ++ it2) { - auto null1 = int(std::isnan(it1->value)); - auto null2 = int(std::isnan(it2->value)); + auto null1 = int(std::isnan(it1->value) || it1->value == NIL_VALUE().value); + auto null2 = int(std::isnan(it2->value) || it2->value == NIL_VALUE().value); return (null1 < null2) || (null1 == null2 && *it1 < *it2); } return v1.size() < v2.size(); @@ -1633,19 +1651,19 @@ class ConfigOptionBoolsTempl : public ConfigOptionVector // Could a special "nil" value be stored inside the vector, indicating undefined value? bool nullable() const override { return NULLABLE; } // Special "nil" value to be stored into the vector if this->supports_nil(). - static unsigned char nil_value() { return std::numeric_limits::max(); } + static unsigned char NIL_VALUE() { return std::numeric_limits::max(); } // A scalar is nil, or all values of a vector are nil. bool is_nil(int32_t idx = -1) const override { if (idx < 0) { for (uint8_t v : this->values) - if (v != nil_value()) + if (v != NIL_VALUE()) return false; return true; } else { - return idx < values.size() ? nil_value() == this->values[idx] : - values.empty() ? nil_value() == this->default_value : - nil_value() == this->values.front(); + return idx < values.size() ? NIL_VALUE() == this->values[idx] : + values.empty() ? NIL_VALUE() == this->default_value : + NIL_VALUE() == this->values.front(); } } bool get_bool(size_t idx = 0) const override { return ConfigOptionVector::get_at(idx) != 0; } @@ -1684,9 +1702,9 @@ class ConfigOptionBoolsTempl : public ConfigOptionVector while (std::getline(is, item_str, ',')) { boost::trim(item_str); unsigned char new_value = 0; - if (item_str == "nil") { + if (item_str == NIL_STR_VALUE) { if (NULLABLE) - new_value = nil_value(); + new_value = NIL_VALUE(); else throw ConfigurationError("Deserializing nil into a non-nullable object"); } else if (item_str == "1") { @@ -1710,9 +1728,9 @@ class ConfigOptionBoolsTempl : public ConfigOptionVector protected: void serialize_single_value(std::ostringstream &ss, const unsigned char v) const { - if (v == nil_value()) { + if (v == NIL_VALUE()) { if (NULLABLE) - ss << "nil"; + ss << NIL_STR_VALUE; else throw ConfigurationError("Serializing NaN"); } else diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index e046e152278..d592f194183 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -378,7 +378,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true else { if (is_na_value) - val = ConfigOptionFloatsNullable::nil_value(); + val = boost::any_cast(ConfigOptionFloatsNullable::create_nil()); else if (!str.ToDouble(&val)) { if (!check_value) { @@ -474,7 +474,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true str.Replace("m", "", true); if (m_opt.nullable && str == na_value()) { - val = ConfigOptionFloatsNullable::nil_value(); + val = boost::any_cast(ConfigOptionFloatsNullable::create_nil()); str = "nan"; } else if (!str.ToDouble(&val)) { if (!check_value) { @@ -790,8 +790,8 @@ bool TextCtrl::value_was_changed() case coPercents: case coFloats: case coFloat: { - if (m_opt.nullable && std::isnan(boost::any_cast(m_value)) && - std::isnan(boost::any_cast(val))) + if (m_opt.nullable && ConfigOptionFloatsNullable::is_nil(m_value) && + ConfigOptionFloatsNullable::is_nil(val)) return false; return boost::any_cast(m_value) != boost::any_cast(val); } @@ -972,7 +972,7 @@ void CheckBox::set_value(const boost::any& value, bool change_event) { m_disable_change_event = !change_event; if (m_opt.nullable) { - m_is_na_val = boost::any_cast(value) == ConfigOptionBoolsNullable::nil_value(); + m_is_na_val = boost::any_cast(value) == ConfigOptionBoolsNullable::NIL_VALUE(); if (!m_is_na_val) m_last_meaningful_value = value; set_widget_value(m_is_na_val ? false : boost::any_cast(value) != 0); @@ -1023,7 +1023,7 @@ boost::any& CheckBox::get_value() if (m_opt.type == coBool) m_value = static_cast(value); else - m_value = m_is_na_val ? ConfigOptionBoolsNullable::nil_value() : static_cast(value); + m_value = m_is_na_val ? ConfigOptionBoolsNullable::NIL_VALUE() : static_cast(value); return m_value; } diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index e89edfc9c2a..bc7ff644f20 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -326,7 +326,7 @@ static void add_config_substitutions(const ConfigSubstitutions& conf_substitutio case coBools: if (conf_substitution.new_value->nullable()) for (const char v : static_cast(conf_substitution.new_value.get())->values) - new_val += std::string(v == ConfigOptionBoolsNullable::nil_value() ? "nil" : v ? "true" : "false") + ", "; + new_val += std::string(v == ConfigOptionBoolsNullable::NIL_VALUE() ? "nil" : v ? "true" : "false") + ", "; else for (const char v : static_cast(conf_substitution.new_value.get())->values) new_val += std::string(v ? "true" : "false") + ", "; From e91a33399902fecdb8c7b6bc6ba1a9acbdd1b29d Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 27 Dec 2023 02:52:15 +0100 Subject: [PATCH 05/19] Fix default value for filament override --- src/libslic3r/Config.hpp | 61 +++++++++++-------- src/libslic3r/PrintConfig.cpp | 33 ++++++++-- .../GUI/CalibrationRetractionDialog.cpp | 7 +-- 3 files changed, 68 insertions(+), 33 deletions(-) diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index bdd211bb2aa..5aebc4bba65 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -488,6 +488,10 @@ class ConfigOptionVectorBase : public ConfigOption { virtual void resize(size_t n, const ConfigOption *opt_default = nullptr) = 0; // Clear the values vector. virtual void clear() = 0; + // get the stored default value for filling empty vector. + // If you use it, double check if you shouldn't instead use the ConfigOptionDef.defaultvalue, which is the default value of a setting. + // currently, it's used to try to have a meaningful value for a Field if the default value is Nil (and to avoid cloning the option, clear it, asking for an item) + virtual boost::any get_default_value() const = 0; // Get size of this vector. virtual size_t size() const = 0; @@ -514,15 +518,26 @@ class ConfigOptionVectorBase : public ConfigOption { template class ConfigOptionVector : public ConfigOptionVectorBase { +private: + void set_default_from_values() { + assert(!values.empty()); + if (!values.empty()) + default_value = values.front(); + } + +protected: + // this default is used to fill this vector when resized. It's not the default of a setting, for it please use the + // ConfigOptionDef. + T default_value; public: + std::vector values; + ConfigOptionVector() {} explicit ConfigOptionVector(const T& default_val) : default_value(default_val) {} - explicit ConfigOptionVector(size_t n, const T& value) : values(n, value) {} - explicit ConfigOptionVector(std::initializer_list il) : values(std::move(il)) {} - explicit ConfigOptionVector(const std::vector &values) : values(values) {} - explicit ConfigOptionVector(std::vector &&values) : values(std::move(values)) {} - std::vector values; - T default_value; + explicit ConfigOptionVector(size_t n, const T &value) : values(n, value), default_value(value) {} + explicit ConfigOptionVector(std::initializer_list il) : values(std::move(il)) { set_default_from_values(); } + explicit ConfigOptionVector(const std::vector &values) : values(values) { set_default_from_values(); } + explicit ConfigOptionVector(std::vector &&values) : values(std::move(values)) { set_default_from_values(); } void set(const ConfigOption *rhs) override { @@ -558,12 +573,10 @@ class ConfigOptionVector : public ConfigOptionVectorBase // This function is useful to split values from multiple extrder / filament settings into separate configurations. void set_at(const ConfigOption *rhs, size_t i, size_t j) override { - // It is expected that the vector value has at least one value, which is the default, if not overwritten. - assert(! this->values.empty()); + // Fill with default value up to the needed position if (this->values.size() <= i) { // Resize this vector, fill in the new vector fields with the copy of the first field. - T v = this->values.front(); - this->values.resize(i + 1, v); + this->values.resize(i + 1, this->default_value); } if (rhs->type() == this->type()) { // Assign the first value of the rhs vector. @@ -578,12 +591,10 @@ class ConfigOptionVector : public ConfigOptionVectorBase } void set_at(T val, size_t i) { - // It is expected that the vector value has at least one value, which is the default, if not overwritten. - assert(!this->values.empty()); + // Fill with default value up to the needed position if (this->values.size() <= i) { // Resize this vector, fill in the new vector fields with the copy of the first field. - T v = this->values.front(); - this->values.resize(i + 1, v); + this->values.resize(i + 1, this->default_value); } this->values[i] = val; } @@ -597,13 +608,13 @@ class ConfigOptionVector : public ConfigOptionVectorBase T& get_at(size_t i) { return const_cast(std::as_const(*this).get_at(i)); } boost::any get_any(int32_t idx = -1) const override { return idx < 0 ? boost::any(values) : boost::any(get_at(idx)); } - // Resize this vector by duplicating the /*last*/first value. + // Resize this vector by duplicating the /*last*/first or default value. // If the current vector is empty, the default value is used instead. void resize(size_t n, const ConfigOption *opt_default = nullptr) override { assert(opt_default == nullptr || opt_default->is_vector()); // assert(opt_default == nullptr || dynamic_cast>(opt_default)); - assert(! this->values.empty() || opt_default != nullptr); + // assert(! this->values.empty() || opt_default != nullptr); if (n == 0) this->values.clear(); else if (n < this->values.size()) @@ -614,12 +625,12 @@ class ConfigOptionVector : public ConfigOptionVectorBase this->values.resize(n, this->default_value); if (opt_default->type() != this->type()) throw ConfigurationError("ConfigOptionVector::resize(): Extending with an incompatible type."); - if(static_cast*>(opt_default)->values.empty()) - this->values.resize(n, this->default_value); + if(auto other = static_cast*>(opt_default); other->values.empty()) + this->values.resize(n, other->default_value); else - this->values.resize(n, static_cast*>(opt_default)->values.front()); + this->values.resize(n, other->values.front()); } else { - // Resize by duplicating the last value. + // Resize by duplicating the /*last*/first value. this->values.resize(n, this->values./*back*/front()); } } @@ -629,6 +640,10 @@ class ConfigOptionVector : public ConfigOptionVectorBase void clear() override { this->values.clear(); } size_t size() const override { return this->values.size(); } bool empty() const override { return this->values.empty(); } + // get the stored default value for filling empty vector. + // If you use it, double check if you shouldn't instead use the ConfigOptionDef.defaultvalue, which is the default value of a setting. + // currently, it's used to try to have a meaningful value for a Field if the default value is Nil + boost::any get_default_value() const override { return boost::any(default_value); } bool operator==(const ConfigOption &rhs) const override { @@ -695,10 +710,7 @@ class ConfigOptionVector : public ConfigOptionVectorBase } for (; i < rhs_vec->size(); ++ i) if (! rhs_vec->is_nil(i)) { - if (this->values.empty()) - this->values.resize(i + 1); - else - this->values.resize(i + 1, this->values.front()); + this->values.resize(i + 1, this->default_value); this->values[i] = rhs_vec->values[i]; modified = true; } @@ -1636,6 +1648,7 @@ class ConfigOptionBoolsTempl : public ConfigOptionVector { public: ConfigOptionBoolsTempl() : ConfigOptionVector() {} + explicit ConfigOptionBoolsTempl(bool default_value) : ConfigOptionVector(default_value) {} explicit ConfigOptionBoolsTempl(size_t n, bool value) : ConfigOptionVector(n, (unsigned char)value) {} explicit ConfigOptionBoolsTempl(std::initializer_list il) { values.reserve(il.size()); for (bool b : il) values.emplace_back((unsigned char)b); } explicit ConfigOptionBoolsTempl(std::initializer_list il) { values.reserve(il.size()); for (unsigned char b : il) values.emplace_back(b); } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 6746cc9557e..5f1856758d9 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2294,7 +2294,7 @@ void PrintConfigDef::init_fff_params() def->max = 360; def->full_width = true; def->mode = comExpert | comSuSi; - def->set_default_value(new ConfigOptionFloats{}); + def->set_default_value(new ConfigOptionFloats(0.)); def = this->add("fill_density", coPercent); def->gui_type = ConfigOptionDef::GUIType::f_enum_open; @@ -6422,11 +6422,34 @@ void PrintConfigDef::init_fff_params() def->tooltip = it_opt->second.tooltip; def->sidetext = it_opt->second.sidetext; def->mode = it_opt->second.mode; + // create default value with the default value is taken from the default value of the config. + // put a nil value as first entry. switch (def->type) { - case coFloats : def->set_default_value(new ConfigOptionFloatsNullable (static_cast(it_opt->second.default_value.get())->values)); break; - case coPercents : def->set_default_value(new ConfigOptionPercentsNullable(static_cast(it_opt->second.default_value.get())->values)); break; - case coFloatsOrPercents : def->set_default_value(new ConfigOptionFloatsOrPercentsNullable(static_cast(it_opt->second.default_value.get())->values)); break; - case coBools : def->set_default_value(new ConfigOptionBoolsNullable (static_cast(it_opt->second.default_value.get())->values)); break; + case coBools: { + ConfigOptionBoolsNullable* opt = new ConfigOptionBoolsNullable(it_opt->second.default_value.get()->get_bool()); + opt->values.push_back(ConfigOptionBoolsNullable::NIL_VALUE()); + def->set_default_value(opt); + break; + } + case coFloats: { + ConfigOptionFloatsNullable *opt = new ConfigOptionFloatsNullable(it_opt->second.default_value.get()->get_float()); + opt->values.push_back(boost::any_cast(ConfigOptionFloatsNullable::create_nil())); + def->set_default_value(opt); + break; + } + case coPercents: { + ConfigOptionPercentsNullable *opt = new ConfigOptionPercentsNullable(it_opt->second.default_value.get()->get_float()); + opt->values.push_back(boost::any_cast(ConfigOptionPercentsNullable::create_nil())); + def->set_default_value(opt); + break; + } + case coFloatsOrPercents: { + ConfigOptionFloatsOrPercentsNullable*opt = new ConfigOptionFloatsOrPercentsNullable( + static_cast(it_opt->second.default_value.get())->get_at(0)); + opt->values.push_back(boost::any_cast(ConfigOptionFloatsOrPercentsNullable::create_nil())); + def->set_default_value(opt); + break; + } default: assert(false); } } diff --git a/src/slic3r/GUI/CalibrationRetractionDialog.cpp b/src/slic3r/GUI/CalibrationRetractionDialog.cpp index 8dce80eb1c0..3f9dd45eae4 100644 --- a/src/slic3r/GUI/CalibrationRetractionDialog.cpp +++ b/src/slic3r/GUI/CalibrationRetractionDialog.cpp @@ -81,14 +81,13 @@ void CalibrationRetractionDialog::remove_slowdown(wxCommandEvent& event_args) { DynamicPrintConfig new_filament_config = *filament_config; //make a copy const ConfigOptionFloats *fil_conf = filament_config->option("slowdown_below_layer_time"); - ConfigOptionFloats *new_fil_conf = new ConfigOptionFloats(); - new_fil_conf->default_value = 5; + ConfigOptionFloats *new_fil_conf = new ConfigOptionFloats(5); new_fil_conf->values = fil_conf->values; new_fil_conf->values[0] = 0; new_filament_config.set_key_value("slowdown_below_layer_time", new_fil_conf); - fil_conf = filament_config->option("fan_below_layer_time"); new_fil_conf = new ConfigOptionFloats(); - new_fil_conf->default_value = 60; + fil_conf = filament_config->option("fan_below_layer_time"); + new_fil_conf = new ConfigOptionFloats(60); new_fil_conf->values = fil_conf->values; new_fil_conf->values[0] = 0; new_filament_config.set_key_value("fan_below_layer_time", new_fil_conf); From 68cb741f6996451b170e2f030d35ec270a0abdc4 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 27 Dec 2023 02:57:12 +0100 Subject: [PATCH 06/19] Use optional<> instead of NaN for retract() --- src/libslic3r/Extruder.cpp | 36 +++++++++++++++++++++++++++++------ src/libslic3r/Extruder.hpp | 2 +- src/libslic3r/GCodeWriter.cpp | 22 +++++++++++++++------ src/libslic3r/GCodeWriter.hpp | 2 +- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/Extruder.cpp b/src/libslic3r/Extruder.cpp index 76b624e4334..ca156d5b8f5 100644 --- a/src/libslic3r/Extruder.cpp +++ b/src/libslic3r/Extruder.cpp @@ -31,6 +31,8 @@ Mill::Mill(uint16_t mill_id, GCodeConfig* config) : double Tool::extrude(double dE) { + assert(dE < std::numeric_limits::max()); + assert(dE > -std::numeric_limits::max()); // in case of relative E distances we always reset to 0 before any output if (m_config->use_relative_e_distances) m_E = 0.; @@ -48,8 +50,14 @@ double Tool::extrude(double dE) The restart_extra argument sets the extra length to be used for unretraction. If we're actually performing a retraction, any restart_extra value supplied will overwrite the previous one if any. */ -double Tool::retract(double length, double restart_extra, double restart_extra_toolchange) -{ +double Tool::retract(double length, std::optional restart_extra, std::optional restart_extra_toolchange) +{ + assert(length < std::numeric_limits::max()); + assert(length > 0); + assert(!restart_extra || *restart_extra < std::numeric_limits::max()); + assert(!restart_extra || *restart_extra > -std::numeric_limits::max()); + assert(!restart_extra_toolchange || *restart_extra_toolchange < std::numeric_limits::max()); + assert(!restart_extra_toolchange || *restart_extra_toolchange > -std::numeric_limits::max()); // in case of relative E distances we always reset to 0 before any output if (m_config->use_relative_e_distances) m_E = 0.; @@ -58,11 +66,11 @@ double Tool::retract(double length, double restart_extra, double restart_extra_t m_E -= to_retract; m_absolute_E -= to_retract; m_retracted += to_retract; - if(!std::isnan(restart_extra)) - m_restart_extra = restart_extra; + if(restart_extra) + m_restart_extra = *restart_extra; } - if (!std::isnan(restart_extra_toolchange)) - m_restart_extra_toolchange = restart_extra_toolchange; + if (restart_extra_toolchange) + m_restart_extra_toolchange = *restart_extra_toolchange; return to_retract; } @@ -204,11 +212,19 @@ double Extruder::retract_before_wipe() const double Extruder::retract_length() const { + assert(!m_config->retract_length.is_nil()); + assert(m_config->retract_length.get_at(m_id) < std::numeric_limits::max()); + assert(m_config->retract_length.get_at(m_id) > -std::numeric_limits::max()); + assert(m_config->retract_length.values.size() > m_id); return m_config->retract_length.get_at(m_id); } double Extruder::retract_lift() const { + assert(!m_config->retract_lift.is_nil()); + assert(m_config->retract_lift.get_at(m_id) < std::numeric_limits::max()); + assert(m_config->retract_lift.get_at(m_id) > -std::numeric_limits::max()); + assert(m_config->retract_lift.values.size() > m_id); return m_config->retract_lift.get_at(m_id); } @@ -225,6 +241,10 @@ int Extruder::deretract_speed() const double Extruder::retract_restart_extra() const { + assert(!m_config->retract_restart_extra.is_nil()); + assert(m_config->retract_restart_extra.get_at(m_id) < std::numeric_limits::max()); + assert(m_config->retract_restart_extra.get_at(m_id) > -std::numeric_limits::max()); + assert(m_config->retract_restart_extra.values.size() > m_id); return m_config->retract_restart_extra.get_at(m_id); } @@ -235,6 +255,10 @@ double Extruder::retract_length_toolchange() const double Extruder::retract_restart_extra_toolchange() const { + assert(!m_config->retract_restart_extra_toolchange.is_nil()); + assert(m_config->retract_restart_extra_toolchange.get_at(m_id) < std::numeric_limits::max()); + assert(m_config->retract_restart_extra_toolchange.get_at(m_id) > -std::numeric_limits::max()); + assert(m_config->retract_restart_extra_toolchange.values.size() > m_id); return m_config->retract_restart_extra_toolchange.get_at(m_id); } diff --git a/src/libslic3r/Extruder.hpp b/src/libslic3r/Extruder.hpp index 5e665f856d7..e4e16d2639e 100644 --- a/src/libslic3r/Extruder.hpp +++ b/src/libslic3r/Extruder.hpp @@ -25,7 +25,7 @@ class Tool uint16_t id() const { return m_id; } virtual double extrude(double dE); - virtual double retract(double length, double restart_extra, double restart_extra_from_toolchange); + virtual double retract(double length, std::optional restart_extra, std::optional restart_extra_from_toolchange); virtual double need_unretract(); virtual double unretract(); virtual void reset_retract(); diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index dd3fc8909c0..c204563dd9b 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -637,14 +637,16 @@ std::string GCodeWriter::retract(bool before_wipe) return this->_retract( factor * config_region->print_retract_length, factor * m_tool->retract_restart_extra(), - NAN, + std::nullopt, "retract" ); } + auto rect_length = m_tool->retract_length(); + auto rect_length2 = m_tool->retract_restart_extra(); return this->_retract( factor * m_tool->retract_length(), factor * m_tool->retract_restart_extra(), - NAN, + std::nullopt, "retract" ); } @@ -655,13 +657,13 @@ std::string GCodeWriter::retract_for_toolchange(bool before_wipe) assert(factor >= 0. && factor <= 1. + EPSILON); return this->_retract( factor * m_tool->retract_length_toolchange(), - NAN, + std::nullopt, factor * m_tool->retract_restart_extra_toolchange(), "retract for toolchange" ); } -std::string GCodeWriter::_retract(double length, double restart_extra, double restart_extra_toolchange, const std::string &comment) +std::string GCodeWriter::_retract(double length, std::optional restart_extra, std::optional restart_extra_toolchange, const std::string &comment) { std::ostringstream gcode; @@ -675,9 +677,17 @@ std::string GCodeWriter::_retract(double length, double restart_extra, double re if (this->config.use_volumetric_e) { double d = m_tool->filament_diameter(); double area = d * d * PI/4; + assert(length * area < std::numeric_limits::max()); + assert(length * area > 0); + assert(!restart_extra || *restart_extra * area < std::numeric_limits::max()); + assert(!restart_extra || *restart_extra * area > -std::numeric_limits::max()); + assert(!restart_extra_toolchange || *restart_extra_toolchange * area < std::numeric_limits::max()); + assert(!restart_extra_toolchange || *restart_extra_toolchange * area > -std::numeric_limits::max()); length = length * area; - restart_extra = restart_extra * area; - restart_extra_toolchange = restart_extra_toolchange * area; + if(restart_extra) + restart_extra = *restart_extra * area; + if(restart_extra_toolchange) + restart_extra_toolchange = *restart_extra_toolchange * area; } double dE = m_tool->retract(length, restart_extra, restart_extra_toolchange); diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 7d46974a7e1..a4f8d525c2c 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -115,7 +115,7 @@ class GCodeWriter { Vec3d m_pos = Vec3d::Zero(); std::string _travel_to_z(double z, const std::string &comment); - std::string _retract(double length, double restart_extra, double restart_extra_toolchange, const std::string &comment); + std::string _retract(double length, std::optional restart_extra, std::optional restart_extra_toolchange, const std::string &comment); }; From e8672b2d4f94376abae78c11ec493e9eed50d0ca Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 27 Dec 2023 03:49:47 +0100 Subject: [PATCH 07/19] * Simplify the field <-> config pipes allow all vector types in text field (';' separated, to avoid problem with ',' vs '.' locales) Change `post_process` to use the new way (no "serialized" needed anymore) Remove "one_string" gui type, as it's now a supported as vector with no id. Need to set all filament-setting id to 0, as the gui need them to update the first elt only (and always that one) for field <-> config pipe: - config now have get_any(id) and set_any(any, id). No need to special optiongroup or gui method. - any will carry a type that is in sync with the config type and the id. - if id is set or type is scalar, the any is scalara. else the any is a vector of scalar. - fields are responsible to cast the any correctly and to set it correctly. no more mess of wxstring & double --- resources/ui_layout/default/filament.ui | 140 ++-- resources/ui_layout/default/print.ui | 1 + resources/ui_layout/example/filament.ui | 138 ++-- src/libslic3r/Config.hpp | 24 +- src/libslic3r/PrintConfig.cpp | 8 +- src/slic3r/GUI/BedShapeDialog.cpp | 12 +- src/slic3r/GUI/Field.cpp | 818 ++++++++++++++++------- src/slic3r/GUI/Field.hpp | 84 ++- src/slic3r/GUI/GUI.cpp | 133 ---- src/slic3r/GUI/GUI.hpp | 3 - src/slic3r/GUI/OptionsGroup.cpp | 188 +----- src/slic3r/GUI/OptionsGroup.hpp | 5 +- src/slic3r/GUI/PhysicalPrinterDialog.cpp | 12 +- src/slic3r/GUI/Preferences.cpp | 2 +- src/slic3r/GUI/ScriptExecutor.cpp | 94 +-- src/slic3r/GUI/Tab.cpp | 15 +- 16 files changed, 874 insertions(+), 803 deletions(-) diff --git a/resources/ui_layout/default/filament.ui b/resources/ui_layout/default/filament.ui index 845f5e3773b..eeaa1973a75 100644 --- a/resources/ui_layout/default/filament.ui +++ b/resources/ui_layout/default/filament.ui @@ -1,97 +1,97 @@ - +#note: all settings are id$0 as the slicer consider there is only one value in the arrays in the gui. page:Filament:spool group:filament_spool_weight_event:Filament - setting:filament_colour - setting:filament_diameter - setting:extrusion_multiplier - setting:filament_density - setting:filament_cost - setting:filament_spool_weight + setting:id$0:filament_colour + setting:id$0:filament_diameter + setting:id$0:extrusion_multiplier + setting:id$0:filament_density + setting:id$0:filament_cost + setting:id$0:filament_spool_weight group:Temperature °C line:Extruder - setting:first_layer_temperature - setting:temperature + setting:id$0:first_layer_temperature + setting:id$0:temperature end_line line:Bed - setting:first_layer_bed_temperature - setting:label:Other layers:bed_temperature + setting:id$0:first_layer_bed_temperature + setting:id$0:label:Other layers:bed_temperature end_line - setting:chamber_temperature + setting:id$0:chamber_temperature group:Filament properties - setting:width$7:filament_type - setting:filament_soluble - setting:filament_shrink - setting:filament_max_overlap + setting:id$0:width$7:filament_type + setting:id$0:filament_soluble + setting:id$0:filament_shrink + setting:id$0:filament_max_overlap group:Print speed override - setting:filament_max_speed - setting:filament_max_volumetric_speed + setting:id$0:filament_max_speed + setting:id$0:filament_max_volumetric_speed volumetric_speed_description page:Cooling:time group:Fan speed - default - setting:label$Run the fan at default speed when possible:fan_always_on + setting:id$0:label$Run the fan at default speed when possible:fan_always_on line:Disable fan for the first - setting:width$5:label$_:sidetext_width$7:disable_fan_first_layers - setting:width$5:label_width$12:full_fan_speed_layer + setting:id$0:width$5:label$_:sidetext_width$7:disable_fan_first_layers + setting:id$0:width$5:label_width$12:full_fan_speed_layer end_line - setting:min_fan_speed + setting:id$0:min_fan_speed line:Perimeter fan speed - setting:label_width$12:label$Internal:perimeter_fan_speed - setting:label_width$12:label$External:external_perimeter_fan_speed + setting:id$0:label_width$12:label$Internal:perimeter_fan_speed + setting:id$0:label_width$12:label$External:external_perimeter_fan_speed line:Internal Infill fan speed - setting:label_width$12:label$Sparse:infill_fan_speed + setting:id$0:label_width$12:label$Sparse:infill_fan_speed line:Solid Infill fan speed - setting:label_width$12:label$Solid:solid_infill_fan_speed - setting:label_width$12:label$Top solid:top_fan_speed + setting:id$0:label_width$12:label$Solid:solid_infill_fan_speed + setting:id$0:label_width$12:label$Top solid:top_fan_speed line:Support Material fan speed - setting:label_width$12:label$Default:support_material_fan_speed - setting:label_width$12:label$Interface:support_material_interface_fan_speed + setting:id$0:label_width$12:label$Default:support_material_fan_speed + setting:id$0:label_width$12:label$Interface:support_material_interface_fan_speed line:Bridges fan speed - setting:label_width$12:label$Bridges:bridge_fan_speed - setting:label_width$12:label$Internal bridges:bridge_internal_fan_speed + setting:id$0:label_width$12:label$Bridges:bridge_fan_speed + setting:id$0:label_width$12:label$Internal bridges:bridge_internal_fan_speed line:Overhangs Perimeter fan speed - setting:label_width$12:label$Overhangs:overhangs_fan_speed + setting:id$0:label_width$12:label$Overhangs:overhangs_fan_speed line:Gap fill fan speed - setting:label_width$12:label$Gap fill:gap_fill_fan_speed + setting:id$0:label_width$12:label$Gap fill:gap_fill_fan_speed group:Short layer time - began to increase base fan speed - setting:fan_below_layer_time - setting:label$Max fan speed:max_fan_speed + setting:id$0:fan_below_layer_time + setting:id$0:label$Max fan speed:max_fan_speed group:Very short layer time - began to decrease extrusion rate - setting:label$Layer time goal:slowdown_below_layer_time - setting:width$4:max_speed_reduction - setting:width$4:min_print_speed + setting:id$0:label$Layer time goal:slowdown_below_layer_time + setting:id$0:width$4:max_speed_reduction + setting:id$0:width$4:min_print_speed group:Behavior cooling_description page:Multimaterial:funnel group:Multimaterial toolchange temperature - setting:filament_enable_toolchange_temp - setting:filament_toolchange_temp - setting:filament_use_fast_skinnydip - setting:filament_enable_toolchange_part_fan - setting:filament_toolchange_part_fan_speed + setting:id$0:filament_enable_toolchange_temp + setting:id$0:filament_toolchange_temp + setting:id$0:filament_use_fast_skinnydip + setting:id$0:filament_enable_toolchange_part_fan + setting:id$0:filament_toolchange_part_fan_speed group:Multimaterial toolchange string reduction - setting:filament_use_skinnydip - setting:filament_skinnydip_distance - setting:filament_melt_zone_pause - setting:filament_cooling_zone_pause - setting:filament_dip_insertion_speed - setting:filament_dip_extraction_speed + setting:id$0:filament_use_skinnydip + setting:id$0:filament_skinnydip_distance + setting:id$0:filament_melt_zone_pause + setting:id$0:filament_cooling_zone_pause + setting:id$0:filament_dip_insertion_speed + setting:id$0:filament_dip_extraction_speed group:Wipe tower parameters - setting:filament_minimal_purge_on_wipe_tower - setting:filament_max_wipe_tower_speed + setting:id$0:filament_minimal_purge_on_wipe_tower + setting:id$0:filament_max_wipe_tower_speed group:Toolchange parameters with single extruder MM printers - setting:filament_loading_speed_start - setting:filament_loading_speed - setting:filament_unloading_speed_start - setting:filament_unloading_speed - setting:filament_load_time - setting:filament_unload_time - setting:filament_toolchange_delay - setting:filament_cooling_moves - setting:filament_cooling_initial_speed - setting:filament_cooling_final_speed - setting:filament_wipe_advanced_pigment + setting:id$0:filament_loading_speed_start + setting:id$0:filament_loading_speed + setting:id$0:filament_unloading_speed_start + setting:id$0:filament_unloading_speed + setting:id$0:filament_load_time + setting:id$0:filament_unload_time + setting:id$0:filament_toolchange_delay + setting:id$0:filament_cooling_moves + setting:id$0:filament_cooling_initial_speed + setting:id$0:filament_cooling_final_speed + setting:id$0:filament_wipe_advanced_pigment filament_ramming_parameters @@ -99,20 +99,20 @@ filament_overrides_page page:Custom G-code:cog group:no_title:validate_gcode:Start G-code - setting:full_width:height$35:start_filament_gcode + setting:id$0:full_width:height$35:start_filament_gcode group:no_title:validate_gcode:End G-code - setting:full_width:height$35:end_filament_gcode + setting:id$0:full_width:height$35:end_filament_gcode page:Notes:note.png group:label_width$0:Notes - setting:full_width:height$25:filament_notes + setting:id$0:full_width:height$25:filament_notes group:label_width$0:Custom variables - setting:full_width:height$15:filament_custom_variables + setting:id$0:full_width:height$15:filament_custom_variables page:Dependencies:wrench.png group:Profile dependencies - setting:compatible_printers - setting:full_width:color:compatible_printers_condition - setting:compatible_prints - setting:full_width:color:compatible_prints_condition + setting:id$0:compatible_printers + setting:id$0:full_width:color:compatible_printers_condition + setting:id$0:compatible_prints + setting:id$0:full_width:color:compatible_prints_condition parent_preset_description diff --git a/resources/ui_layout/default/print.ui b/resources/ui_layout/default/print.ui index 196981ae37f..a1b54e6b2b7 100644 --- a/resources/ui_layout/default/print.ui +++ b/resources/ui_layout/default/print.ui @@ -202,6 +202,7 @@ group:sidetext_width$5:Infill angle setting:label_width$6:width$5:label$increment:fill_angle_increment setting:label_width$6:width$5:label$increment:fill_angle_cross vector_line:fill_angle_template +# setting:fill_angle_template group:sidetext_width$5:Advanced setting:solid_infill_every_layers setting:solid_infill_below_area diff --git a/resources/ui_layout/example/filament.ui b/resources/ui_layout/example/filament.ui index 845f5e3773b..7aefcd3fbd8 100644 --- a/resources/ui_layout/example/filament.ui +++ b/resources/ui_layout/example/filament.ui @@ -1,97 +1,97 @@ page:Filament:spool group:filament_spool_weight_event:Filament - setting:filament_colour - setting:filament_diameter - setting:extrusion_multiplier - setting:filament_density - setting:filament_cost - setting:filament_spool_weight + setting:id$0:filament_colour + setting:id$0:filament_diameter + setting:id$0:extrusion_multiplier + setting:id$0:filament_density + setting:id$0:filament_cost + setting:id$0:filament_spool_weight group:Temperature °C line:Extruder - setting:first_layer_temperature - setting:temperature + setting:id$0:first_layer_temperature + setting:id$0:temperature end_line line:Bed - setting:first_layer_bed_temperature - setting:label:Other layers:bed_temperature + setting:id$0:first_layer_bed_temperature + setting:id$0:label:Other layers:bed_temperature end_line - setting:chamber_temperature + setting:id$0:chamber_temperature group:Filament properties - setting:width$7:filament_type - setting:filament_soluble - setting:filament_shrink - setting:filament_max_overlap + setting:id$0:width$7:filament_type + setting:id$0:filament_soluble + setting:id$0:filament_shrink + setting:id$0:filament_max_overlap group:Print speed override - setting:filament_max_speed - setting:filament_max_volumetric_speed + setting:id$0:filament_max_speed + setting:id$0:filament_max_volumetric_speed volumetric_speed_description page:Cooling:time group:Fan speed - default - setting:label$Run the fan at default speed when possible:fan_always_on + setting:id$0:label$Run the fan at default speed when possible:fan_always_on line:Disable fan for the first - setting:width$5:label$_:sidetext_width$7:disable_fan_first_layers - setting:width$5:label_width$12:full_fan_speed_layer + setting:id$0:width$5:label$_:sidetext_width$7:disable_fan_first_layers + setting:id$0:width$5:label_width$12:full_fan_speed_layer end_line - setting:min_fan_speed + setting:id$0:min_fan_speed line:Perimeter fan speed - setting:label_width$12:label$Internal:perimeter_fan_speed - setting:label_width$12:label$External:external_perimeter_fan_speed + setting:id$0:label_width$12:label$Internal:perimeter_fan_speed + setting:id$0:label_width$12:label$External:external_perimeter_fan_speed line:Internal Infill fan speed - setting:label_width$12:label$Sparse:infill_fan_speed + setting:id$0:label_width$12:label$Sparse:infill_fan_speed line:Solid Infill fan speed - setting:label_width$12:label$Solid:solid_infill_fan_speed - setting:label_width$12:label$Top solid:top_fan_speed + setting:id$0:label_width$12:label$Solid:solid_infill_fan_speed + setting:id$0:label_width$12:label$Top solid:top_fan_speed line:Support Material fan speed - setting:label_width$12:label$Default:support_material_fan_speed - setting:label_width$12:label$Interface:support_material_interface_fan_speed + setting:id$0:label_width$12:label$Default:support_material_fan_speed + setting:id$0:label_width$12:label$Interface:support_material_interface_fan_speed line:Bridges fan speed - setting:label_width$12:label$Bridges:bridge_fan_speed - setting:label_width$12:label$Internal bridges:bridge_internal_fan_speed + setting:id$0:label_width$12:label$Bridges:bridge_fan_speed + setting:id$0:label_width$12:label$Internal bridges:bridge_internal_fan_speed line:Overhangs Perimeter fan speed - setting:label_width$12:label$Overhangs:overhangs_fan_speed + setting:id$0:label_width$12:label$Overhangs:overhangs_fan_speed line:Gap fill fan speed - setting:label_width$12:label$Gap fill:gap_fill_fan_speed + setting:id$0:label_width$12:label$Gap fill:gap_fill_fan_speed group:Short layer time - began to increase base fan speed - setting:fan_below_layer_time - setting:label$Max fan speed:max_fan_speed + setting:id$0:fan_below_layer_time + setting:id$0:label$Max fan speed:max_fan_speed group:Very short layer time - began to decrease extrusion rate - setting:label$Layer time goal:slowdown_below_layer_time - setting:width$4:max_speed_reduction - setting:width$4:min_print_speed + setting:id$0:label$Layer time goal:slowdown_below_layer_time + setting:id$0:width$4:max_speed_reduction + setting:id$0:width$4:min_print_speed group:Behavior cooling_description page:Multimaterial:funnel group:Multimaterial toolchange temperature - setting:filament_enable_toolchange_temp - setting:filament_toolchange_temp - setting:filament_use_fast_skinnydip - setting:filament_enable_toolchange_part_fan - setting:filament_toolchange_part_fan_speed + setting:id$0:filament_enable_toolchange_temp + setting:id$0:filament_toolchange_temp + setting:id$0:filament_use_fast_skinnydip + setting:id$0:filament_enable_toolchange_part_fan + setting:id$0:filament_toolchange_part_fan_speed group:Multimaterial toolchange string reduction - setting:filament_use_skinnydip - setting:filament_skinnydip_distance - setting:filament_melt_zone_pause - setting:filament_cooling_zone_pause - setting:filament_dip_insertion_speed - setting:filament_dip_extraction_speed + setting:id$0:filament_use_skinnydip + setting:id$0:filament_skinnydip_distance + setting:id$0:filament_melt_zone_pause + setting:id$0:filament_cooling_zone_pause + setting:id$0:filament_dip_insertion_speed + setting:id$0:filament_dip_extraction_speed group:Wipe tower parameters - setting:filament_minimal_purge_on_wipe_tower - setting:filament_max_wipe_tower_speed + setting:id$0:filament_minimal_purge_on_wipe_tower + setting:id$0:filament_max_wipe_tower_speed group:Toolchange parameters with single extruder MM printers - setting:filament_loading_speed_start - setting:filament_loading_speed - setting:filament_unloading_speed_start - setting:filament_unloading_speed - setting:filament_load_time - setting:filament_unload_time - setting:filament_toolchange_delay - setting:filament_cooling_moves - setting:filament_cooling_initial_speed - setting:filament_cooling_final_speed - setting:filament_wipe_advanced_pigment + setting:id$0:filament_loading_speed_start + setting:id$0:filament_loading_speed + setting:id$0:filament_unloading_speed_start + setting:id$0:filament_unloading_speed + setting:id$0:filament_load_time + setting:id$0:filament_unload_time + setting:id$0:filament_toolchange_delay + setting:id$0:filament_cooling_moves + setting:id$0:filament_cooling_initial_speed + setting:id$0:filament_cooling_final_speed + setting:id$0:filament_wipe_advanced_pigment filament_ramming_parameters @@ -99,20 +99,20 @@ filament_overrides_page page:Custom G-code:cog group:no_title:validate_gcode:Start G-code - setting:full_width:height$35:start_filament_gcode + setting:id$0:full_width:height$35:start_filament_gcode group:no_title:validate_gcode:End G-code - setting:full_width:height$35:end_filament_gcode + setting:id$0:full_width:height$35:end_filament_gcode page:Notes:note.png group:label_width$0:Notes - setting:full_width:height$25:filament_notes + setting:id$0:full_width:height$25:filament_notes group:label_width$0:Custom variables - setting:full_width:height$15:filament_custom_variables + setting:id$0:full_width:height$15:filament_custom_variables page:Dependencies:wrench.png group:Profile dependencies - setting:compatible_printers - setting:full_width:color:compatible_printers_condition - setting:compatible_prints - setting:full_width:color:compatible_prints_condition + setting:id$0:compatible_printers + setting:id$0:full_width:color:compatible_printers_condition + setting:id$0:compatible_prints + setting:id$0:full_width:color:compatible_prints_condition parent_preset_description diff --git a/src/libslic3r/Config.hpp b/src/libslic3r/Config.hpp index 5aebc4bba65..31c8e15d45f 100644 --- a/src/libslic3r/Config.hpp +++ b/src/libslic3r/Config.hpp @@ -401,6 +401,7 @@ class ConfigOption { virtual bool get_bool(size_t idx = 0) const { throw BadOptionTypeException("Calling ConfigOption::get_bool on a non-boolean ConfigOption"); } virtual void set_enum_int(int32_t /* val */) { throw BadOptionTypeException("Calling ConfigOption::set_enum_int on a non-enum ConfigOption"); } virtual boost::any get_any(int32_t idx = -1) const { throw BadOptionTypeException("Calling ConfigOption::get_any on a raw ConfigOption"); } + virtual void set_any(boost::any, int32_t idx = -1) { throw BadOptionTypeException("Calling ConfigOption::set_any on a raw ConfigOption"); } virtual bool operator==(const ConfigOption &rhs) const = 0; bool operator!=(const ConfigOption &rhs) const { return ! (*this == rhs); } virtual size_t hash() const throw() = 0; @@ -441,7 +442,8 @@ class ConfigOptionSingle : public ConfigOption { explicit ConfigOptionSingle(T value) : value(value) {} explicit ConfigOptionSingle(T value, bool phony) : ConfigOption(phony), value(value) {} operator T() const { return this->value; } - boost::any get_any(int32_t idx = 0) const override { return boost::any(value); } + boost::any get_any(int32_t idx = -1) const override { return boost::any(value); } + void set_any(boost::any anyval, int32_t idx = -1) override { value = boost::any_cast(anyval); } void set(const ConfigOption *rhs) override { @@ -607,6 +609,13 @@ class ConfigOptionVector : public ConfigOptionVectorBase T& get_at(size_t i) { return const_cast(std::as_const(*this).get_at(i)); } boost::any get_any(int32_t idx = -1) const override { return idx < 0 ? boost::any(values) : boost::any(get_at(idx)); } + void set_any(boost::any anyval, int32_t idx = -1) override + { + if (idx < 0) + values = boost::any_cast>(anyval); + else + set_at(boost::any_cast(anyval), idx); + } // Resize this vector by duplicating the /*last*/first or default value. // If the current vector is empty, the default value is used instead. @@ -1248,6 +1257,14 @@ class ConfigOptionFloatOrPercent : public ConfigOptionPercent double get_abs_value(double ratio_over) const { return this->percent ? (ratio_over * this->value / 100) : this->value; } double get_float(size_t idx = 0) const override { return get_abs_value(1.); } + // special case for get/set any: use a FloatOrPercent like for FloatsOrPercents, to have the is_percent + boost::any get_any(int32_t idx = 0) const override { return boost::any(FloatOrPercent{value, percent}); } + void set_any(boost::any anyval, int32_t idx = -1) override + { + auto fl_or_per = boost::any_cast(anyval); + this->value = fl_or_per.value; + this->percent = fl_or_per.percent; + } void set(const ConfigOption *rhs) override { if (rhs->type() != this->type()) @@ -1779,6 +1796,9 @@ class ConfigOptionEnum : public ConfigOptionSingle bool operator< (const ConfigOptionEnum &rhs) const throw() { return int(this->value) < int(rhs.value); } int32_t get_int(size_t idx = 0) const override { return int32_t(this->value); } void set_enum_int(int32_t val) override { this->value = T(val); } + // special case for get/set any: use a int like for ConfigOptionEnumGeneric, to simplify + boost::any get_any(int32_t idx = -1) const override { return boost::any(get_int()); } + void set_any(boost::any anyval, int32_t idx = -1) override { set_enum_int(boost::any_cast(anyval)); } bool operator==(const ConfigOption &rhs) const override { @@ -1910,7 +1930,7 @@ class ConfigOptionDef // Static text legend, // Vector value, but edited as a single string. - one_string, + // one_string, // it's now the default for vector without any idx. If you want to edit the first value, set the idx to 0 }; // Identifier of this option. It is stored here so that it is accessible through the by_serialization_key_ordinal map. diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 5f1856758d9..3807dcd1304 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -376,7 +376,6 @@ void PrintConfigDef::init_common_params() def->mode = comExpert | comPrusa; def->min = 0; def->max = 2048; - //def->gui_type = ConfigOptionDef::GUIType::one_string; // i prefer two boxes def->set_default_value(new ConfigOptionPoints{ std::initializer_list{ Vec2d(0,0), Vec2d(0,0) } }); def = this->add("thumbnails_color", coString); @@ -4217,7 +4216,6 @@ void PrintConfigDef::init_fff_params() "and they can access the Slic3r config settings by reading environment variables." "\nThe script, if passed as a relative path, will also be searched from the slic3r directory, " "the slic3r configuration directory and the user directory."); - def->gui_flags = "serialized"; def->multiline = true; def->full_width = true; def->height = 6; @@ -6433,20 +6431,20 @@ void PrintConfigDef::init_fff_params() } case coFloats: { ConfigOptionFloatsNullable *opt = new ConfigOptionFloatsNullable(it_opt->second.default_value.get()->get_float()); - opt->values.push_back(boost::any_cast(ConfigOptionFloatsNullable::create_nil())); + opt->set_any(ConfigOptionFloatsNullable::create_nil(), 0); def->set_default_value(opt); break; } case coPercents: { ConfigOptionPercentsNullable *opt = new ConfigOptionPercentsNullable(it_opt->second.default_value.get()->get_float()); - opt->values.push_back(boost::any_cast(ConfigOptionPercentsNullable::create_nil())); + opt->set_any(ConfigOptionPercentsNullable::create_nil(), 0); def->set_default_value(opt); break; } case coFloatsOrPercents: { ConfigOptionFloatsOrPercentsNullable*opt = new ConfigOptionFloatsOrPercentsNullable( static_cast(it_opt->second.default_value.get())->get_at(0)); - opt->values.push_back(boost::any_cast(ConfigOptionFloatsOrPercentsNullable::create_nil())); + opt->set_any(ConfigOptionFloatsOrPercentsNullable::create_nil(), 0); def->set_default_value(opt); break; } diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index 2cf116e3118..ec877bd4c14 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -42,7 +42,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para t_config_option_key key; switch (param) { case Parameter::RectSize: - def.type = coPoints; + def.type = coPoint; def.set_default_value(new ConfigOptionPoints{ Vec2d(200, 200) }); def.min = 0; def.max = 100000; @@ -51,7 +51,7 @@ void BedShape::append_option_line(ConfigOptionsGroupShp optgroup, Parameter para key = "rect_size"; break; case Parameter::RectOrigin: - def.type = coPoints; + def.type = coPoint; def.set_default_value(new ConfigOptionPoints{ Vec2d(0, 0) }); def.min = -100000; def.max = 100000; @@ -120,12 +120,14 @@ void BedShape::apply_optgroup_values(ConfigOptionsGroupShp optgroup) { switch (m_build_volume.type()) { case BuildVolume::Type::Circle: - optgroup->set_value("diameter", double_to_string(2. * unscaled(m_build_volume.circle().radius))); + optgroup->set_value("diameter", 2. * unscaled(m_build_volume.circle().radius)); break; default: // rectangle, convex, concave... - optgroup->set_value("rect_size" , new ConfigOptionPoints{ to_2d(m_build_volume.bounding_volume().size()) }); - optgroup->set_value("rect_origin" , new ConfigOptionPoints{ - to_2d(m_build_volume.bounding_volume().min) }); + optgroup->set_value("rect_size", Vec2d(m_build_volume.bounding_volume().size().x(), + m_build_volume.bounding_volume().size().y())); + optgroup->set_value("rect_origin", Vec2d(-m_build_volume.bounding_volume().min.x(), + -m_build_volume.bounding_volume().min.y())); } } diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index d592f194183..1995b8ce355 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -76,6 +76,34 @@ wxString get_points_string(const std::vector& values) return ret_str; } +std::pair get_strings_points(const wxString &str, double min, double max, std::vector &out_values) +{ + bool invalid_val = false; + bool out_of_range_val = false; + wxStringTokenizer points(str, ","); + while (points.HasMoreTokens()) { + wxString token = points.GetNextToken(); + double x, y; + wxStringTokenizer point(token, "x"); + if (point.HasMoreTokens()) { + wxString x_str = point.GetNextToken(); + if (x_str.ToDouble(&x) && point.HasMoreTokens()) { + wxString y_str = point.GetNextToken(); + if (y_str.ToDouble(&y) && !point.HasMoreTokens()) { + if (min <= x && x <= max && min <= y && y <= max) { + out_values.push_back(Vec2d(x, y)); + continue; + } + out_of_range_val = true; + break; + } + } + } + invalid_val = true; + break; + } + return {invalid_val, out_of_range_val}; +} Field::~Field() { @@ -110,6 +138,8 @@ void Field::PostInitialize() auto tag_pos = m_opt_id.find("#"); if (tag_pos != std::string::npos) m_opt_idx = stoi(m_opt_id.substr(tag_pos + 1, m_opt_id.size())); + else + m_opt_idx = -1; // no index, ie full vector in serialized form break; } default: @@ -326,122 +356,346 @@ void RichTooltipTimer::Notify() { } } -bool Field::is_matched(const std::string& string, const std::string& pattern) +bool Field::is_matched(const std::string &string, const std::string &pattern) { std::regex regex_pattern(pattern, std::regex_constants::icase); // use ::icase to make the matching case insensitive like /i in perl return std::regex_match(string, regex_pattern); } -static wxString na_value() { return _(L("N/A")); } +static wxString na_value() { return _L("N/A"); } -//TODO move value verification on another methos that won't be called at each value.get() -void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true*/) +// return the string to set, and bool if there is a nil value +std::pair any_to_wxstring(const boost::any &value, const ConfigOptionDef &opt, const int opt_idx) { + wxString text_value; + bool has_nil = false; + auto deserialize = [&text_value, &value, &opt, &has_nil](ConfigOptionVectorBase &&writer, bool check_nil = true) { + writer.set_any(value, -1); + text_value = writer.serialize(); + if (check_nil && opt.nullable) + has_nil = (text_value.Replace(NIL_STR_VALUE, na_value()) > 0); + //replace ',' by ';' + text_value.Replace(",", ";"); + if (!is_decimal_separator_point()) { + // adjust to locale: '.' -> ',' + //',' are the decimal separator, transform from '.' from serialization (which happens in C locale) + text_value.Replace(".", ","); + } + }; + // first, easy convert-to one-string + switch (opt.type) { + case coFloats: { + if (opt_idx < 0) { + deserialize(ConfigOptionFloats{}); + break; + } + } + case coPercents: { + if (opt_idx < 0) { + deserialize(ConfigOptionPercents{}); + break; + } + if (opt.nullable && ConfigOptionFloatsNullable::is_nil(value)) { + text_value = na_value(); + has_nil = true; + break; + } + } + case coFloat: + case coPercent: { + text_value = double_to_string(boost::any_cast(value), opt.precision); + break; + } + case coStrings: { + if (opt_idx < 0) { + // custom for strings, as we don't need the serialized form, the normal one with ';' in-between is enough + ConfigOptionStrings reader; + reader.set_any(value, opt_idx); + std::string good_str; + for (std::string s : reader.values) good_str += s + ";"; + if (!good_str.empty()) + good_str.pop_back(); + text_value = good_str; + break; + } + // can't be nullable + } + case coString: { + text_value = boost::any_cast(value); + break; + } + case coFloatsOrPercents: { + if (opt_idx < 0) { + deserialize(ConfigOptionFloatsOrPercents{}); + break; + } + if (opt.nullable && ConfigOptionFloatsOrPercentsNullable::is_nil(value)) { + text_value = na_value(); + has_nil = true; + break; + } + } + case coFloatOrPercent: { + FloatOrPercent fl_or_per = boost::any_cast(value); + text_value = double_to_string(fl_or_per.value); + if (fl_or_per.percent) + text_value.append("%"); + break; + } + case coBools: { + if (opt_idx < 0) { + deserialize(ConfigOptionBools{}); + } else { + if (opt.nullable && boost::any_cast(value) == ConfigOptionBoolsNullable::NIL_VALUE()) { + text_value = na_value(); + has_nil = true; + break; + } + text_value = boost::any_cast(value) != 0 ? "true" : "false"; + } + break; + } + case coBool: { + if (opt.is_script) + text_value = boost::any_cast(value) != 0 ? "true" : "false"; + else + text_value = boost::any_cast(value) ? "true" : "false"; + } + case coInts: { + if (opt_idx < 0) { + deserialize(ConfigOptionInts{}); + break; + } + if (opt.nullable && boost::any_cast(value) == ConfigOptionIntsNullable::NIL_VALUE()) { + text_value = na_value(); + has_nil = true; + break; + } + } + case coInt: { + text_value = wxString::Format(_T("%i"), int(boost::any_cast(value))); + break; + } + case coPoints: + if (opt_idx < 0) { + deserialize(ConfigOptionPoints{}); + assert(text_value == get_points_string(boost::any_cast>(value))); + break; + } + case coPoint: { + text_value = get_points_string({boost::any_cast(value)}); + break; + } + } + return {text_value, has_nil}; +} + +// return true if the field isn't the same as before +bool TextField::get_vector_value(const wxString &str, ConfigOptionVectorBase &reader) +{ + std::string vector_str = str.ToStdString(); + if (str.size() > 2 && str.at(0) == '[' && str.at(str.size() - 1) == ']') { + // validate data inside + // first, remove all spaces + vector_str = str.SubString(1, str.size() - 1).ToStdString(); + } + // FIXME: also remove other unwanted chars only "[0-9].-,;" should remain + boost::erase_all(vector_str, " "); + bool is_decimal_sep_point = is_decimal_separator_point(); + if (!is_decimal_sep_point) { + //',' are the decimal separator, transform to '.' for deserialization (which happens in C locale) + boost::replace_all(vector_str, ",", "."); + } + boost::replace_all(vector_str, ";", ","); + try { + reader.deserialize(vector_str); + } catch (std::exception) {} + std::string good_str = reader.serialize(); + // replace ',' by ';' + boost::replace_all(good_str, ",", ";"); + if (!is_decimal_sep_point) { + // adjust to locale: '.' -> ',' + //',' are the decimal separator, transform from '.' from serialization (which happens in C locale) + boost::replace_all(good_str, ".", ","); + } + return (str.ToStdString() != good_str); +} + +//TODO move value verification on another methods that won't be called at each value.get() +void TextField::get_value_by_opt_type(wxString &str, const bool check_value /* = true*/) +{ + bool need_update = false; + // convert nil values to serializable ones + if (m_opt.nullable && (m_opt.type != coString && m_opt.type != coStrings)) { + need_update = str.Replace(na_value(), NIL_STR_VALUE); + } + + // val is needed at the end of this function, for "max_volumetric_speed" || "gap_fill_speed" (bad practice) double val = 0; - switch (m_opt.type) { - case coInt: - m_value = wxAtoi(str); - val = wxAtoi(str); - break; - case coPercent: - case coPercents: - case coFloats: - case coFloat:{ - if (m_opt.type == coPercent && !str.IsEmpty() && str.Last() == '%') - str.RemoveLast(); - else if (!str.IsEmpty() && str.Last() == '%') - { + switch (m_opt.type) { + case coInts: // not used yet + if (m_opt_idx < 0) { + ConfigOptionInts reader; + need_update = get_vector_value(str, reader); + m_value = reader.values; + break; + } // else: one int on m_opt_idx, done below + case coInt: { + m_value = wxAtoi(str); + val = wxAtoi(str); + break; + } + case coBools: // not used + if (m_opt_idx < 0) { + ConfigOptionBools reader; + need_update = get_vector_value(str, reader); + m_value = reader.values; + break; + } // else: one bool on m_opt_idx, done below + case coBool: { + wxString lower = str; + lower.LowerCase(); + if (m_opt.is_script || m_opt.type == coBools) { + m_value = (lower == "true" || lower == "1") ? uint8_t(1) : uint8_t(0); + } else { + m_value = lower == "true" || lower == "1"; + } + break; + } + case coPercents: //% are optional & copercents uses cofloats deserialize anyway + case coFloats: + if (m_opt_idx < 0) { + ConfigOptionFloats reader; + need_update = get_vector_value(str, reader); + m_value = reader.values; + break; + } + case coPercent: + case coFloat: { + if (m_opt.type == coPercent && !str.IsEmpty() && str.Last() == '%') + str.RemoveLast(); + else if (!str.IsEmpty() && str.Last() == '%') { if (!check_value) { m_value.clear(); break; } - wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label); + wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label); show_error(m_parent, from_u8((boost::format(_utf8(L("%s doesn't support percentage"))) % label).str())); - set_value(double_to_string(m_opt.min, m_opt.precision), true); - m_value = double(m_opt.min); - break; - } + set_text_value(double_to_string(m_opt.min, m_opt.precision).ToStdString(), true); + m_value = double(m_opt.min); + break; + } - bool is_na_value = m_opt.nullable && str == na_value(); + bool is_na_value = m_opt.nullable && str == NIL_STR_VALUE; - const char dec_sep = is_decimal_separator_point() ? '.' : ','; + const char dec_sep = is_decimal_separator_point() ? '.' : ','; const char dec_sep_alt = dec_sep == '.' ? ',' : '.'; - // Replace the first incorrect separator in decimal number, + // Replace the first incorrect separator in decimal number, // if this value doesn't "N/A" value in some language // see https://github.com/prusa3d/PrusaSlicer/issues/6921 if (!is_na_value && str.Replace(dec_sep_alt, dec_sep, false) != 0) - set_value(str, false); + set_text_value(str.ToStdString(), false); if (str == dec_sep) val = 0.0; - else - { - if (is_na_value) - val = boost::any_cast(ConfigOptionFloatsNullable::create_nil()); - else if (!str.ToDouble(&val)) - { + else { + if (is_na_value) { + val = NAN; + m_value = ConfigOptionFloatsNullable::create_nil(); + break; + } else if (!str.ToDouble(&val)) { if (!check_value) { m_value.clear(); break; } + val = m_opt.min == INT_MIN ? std::max(0., m_opt.max) : m_opt.min; show_error(m_parent, _(L("Invalid numeric input."))); - set_value(double_to_string(val, m_opt.precision), true); + set_text_value(double_to_string(val, m_opt.precision).ToStdString(), true); } - if (m_opt.min > val || val > m_opt.max) - { + if (m_opt.min > val || val > m_opt.max) { if (!check_value) { m_value.clear(); break; } if (m_opt_id == "extrusion_multiplier") { if (m_value.empty() || boost::any_cast(m_value) != val) { - wxString msg_text = format_wxstr(_L("Input value is out of range\n" - "Are you sure that %s is a correct value and that you want to continue?"), str); -// wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxICON_WARNING | wxYES | wxNO); - WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxYES | wxNO); + wxString msg_text = + format_wxstr(_L("Input value is out of range\n" + "Are you sure that %s is a correct value and that you want to continue?"), + str); + // wxMessageDialog dialog(m_parent, msg_text, _L("Parameter + // validation") + ": " + m_opt_id, wxICON_WARNING | wxYES | wxNO); + WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, + wxYES | wxNO); if (dialog.ShowModal() == wxID_NO) { if (m_value.empty()) { - if (m_opt.min > val) val = m_opt.min; - if (val > m_opt.max) val = m_opt.max; - } - else + if (m_opt.min > val) + val = m_opt.min; + if (val > m_opt.max) + val = m_opt.max; + } else val = boost::any_cast(m_value); - set_value(double_to_string(val, m_opt.precision), true); + set_text_value(double_to_string(val, m_opt.precision).ToStdString(), true); } } - } - else { + } else { show_error(m_parent, _L("Input value is out of range")); - if (m_opt.min > val) val = m_opt.min; - if (val > m_opt.max) val = m_opt.max; - set_value(double_to_string(val, m_opt.precision), true); + if (m_opt.min > val) + val = m_opt.min; + if (val > m_opt.max) + val = m_opt.max; + set_text_value(double_to_string(val, m_opt.precision).ToStdString(), true); } } } m_value = val; - break; } - case coString: - case coStrings: - m_value = std::string(str.ToUTF8().data()); break; + } + case coStrings: + if (m_opt_idx < 0) { + ConfigOptionStrings reader; + //don't remove spaces and things like that + try { + reader.deserialize(str.ToStdString()); + } catch (std::exception) {} + std::string good_str; + for (std::string s : reader.values) good_str += s + ";"; + if (!good_str.empty()) + good_str.pop_back(); + need_update = (str.ToStdString() != good_str); + m_value = reader.values; + break; + } + case coString: m_value = std::string(str.ToUTF8().data()); break; case coFloatsOrPercents: + if (m_opt_idx < 0) { // not used yet + ConfigOptionFloatsOrPercents reader; + need_update = get_vector_value(str, reader); + m_value = reader.values; + break; + } case coFloatOrPercent: { + bool is_percent = false; if (!str.IsEmpty()) { if ("infill_overlap" == m_opt_id && m_last_validated_value != str) { bool bad = false; if (str.Last() != '%') { + is_percent = false; if (str.ToDouble(&val)) { - const DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; - const std::vector& nozzle_diameters = printer_config.option("nozzle_diameter")->values; - double nozzle_diameter = 0; - for (double diameter : nozzle_diameters) - nozzle_diameter = std::max(nozzle_diameter, diameter); + const DynamicPrintConfig &printer_config = + wxGetApp().preset_bundle->printers.get_edited_preset().config; + const std::vector &nozzle_diameters = + printer_config.option("nozzle_diameter")->values; + double nozzle_diameter = 0; + for (double diameter : nozzle_diameters) + nozzle_diameter = std::max(nozzle_diameter, diameter); if (val > nozzle_diameter / 2) { bad = true; } } } else { + is_percent = true; if (str.substr(0, str.size() - 1).ToCDouble(&val)) { if (val >= 50) { bad = true; @@ -449,65 +703,76 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true } } if (bad && check_value) { - const wxString msg_text = from_u8(_u8L("The infill / perimeter encroachment can't be higher than half of the perimeter width.\n" - "Are you sure to use this value?")); - wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxICON_WARNING | wxYES | wxNO); - auto ret = dialog.ShowModal(); + const wxString msg_text = from_u8( + _u8L("The infill / perimeter encroachment can't be higher than half of the perimeter width.\n" + "Are you sure to use this value?")); + wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, + wxICON_WARNING | wxYES | wxNO); + auto ret = dialog.ShowModal(); if (ret == wxID_NO) { - str = from_u8("49%"); + str = from_u8("49%"); m_last_validated_value = str; - set_value(str, false); + set_text_value(str.ToStdString(), false); str = m_last_validated_value; } m_last_validated_value = str; } - } - else if (str.Last() != '%') { - const char dec_sep = is_decimal_separator_point() ? '.' : ','; + } else if (str.Last() != '%') { + is_percent = false; + const char dec_sep = is_decimal_separator_point() ? '.' : ','; const char dec_sep_alt = dec_sep == '.' ? ',' : '.'; // Replace the first incorrect separator in decimal number. if (str.Replace(dec_sep_alt, dec_sep, false) != 0) - set_value(str, false); + set_text_value(str.ToStdString(), false); // remove space and "mm" substring, if any exists str.Replace(" ", "", true); str.Replace("m", "", true); - if (m_opt.nullable && str == na_value()) { - val = boost::any_cast(ConfigOptionFloatsNullable::create_nil()); - str = "nan"; + if (m_opt.nullable && str == NIL_STR_VALUE) { + m_value = ConfigOptionFloatsOrPercentsNullable::create_nil(); + break; } else if (!str.ToDouble(&val)) { if (!check_value) { m_value.clear(); break; } show_error(m_parent, _(L("Invalid numeric input."))); - set_value(double_to_string(val, m_opt.precision), true); + set_any_value(FloatOrPercent{val, is_percent}, true); } else { - - //at least check min, as we can want a 0 min - if (m_opt.min > val) - { + //convert m_value into str to compare + FloatOrPercent val_from_m_value = m_value.empty() ? FloatOrPercent{0, false} : + boost::any_cast(m_value); + wxString str_from_m_value = double_to_string(val_from_m_value.value, m_opt.precision); + if (val_from_m_value.percent) + str_from_m_value += '%'; + + // at least check min, as we can want a 0 min + if (m_opt.min > val) { if (!check_value) { m_value.clear(); break; } show_error(m_parent, _(L("Input value is out of range"))); - if (m_opt.min > val) val = m_opt.min; - set_value(double_to_string(val, m_opt.precision), true); - } else if (m_value.empty() || into_u8(str) != boost::any_cast(m_value)) { + if (m_opt.min > val) + val = m_opt.min; + set_any_value(FloatOrPercent{val, is_percent}, true); + } else if (m_value.empty() || str != str_from_m_value) { + // empty of not equal -> need check bool not_ok = (m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max); if (!not_ok && m_opt.max_literal.value != 0 && val != 0) { if (m_opt.max_literal.percent) { - const DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config; - const std::vector& nozzle_diameters = printer_config.option("nozzle_diameter")->values; + const DynamicPrintConfig &printer_config = + wxGetApp().preset_bundle->printers.get_edited_preset().config; + const std::vector &nozzle_diameters = + printer_config.option("nozzle_diameter")->values; double nozzle_diameter = 0; for (double diameter : nozzle_diameters) nozzle_diameter = std::max(nozzle_diameter, diameter); if (m_opt.max_literal.value > 0) not_ok = val > nozzle_diameter * m_opt.max_literal.value; else - not_ok = val < nozzle_diameter* (-m_opt.max_literal.value); + not_ok = val < nozzle_diameter * (-m_opt.max_literal.value); } else { if (m_opt.max_literal.value > 0) not_ok = val > m_opt.max_literal.value; @@ -521,102 +786,99 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true break; } - bool infill_anchors = m_opt.opt_key == "infill_anchor" || m_opt.opt_key == "infill_anchor_max"; - - const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm"; - const wxString stVal = double_to_string(val, m_opt.precision); - const wxString msg_text = from_u8((boost::format(_u8L("Do you mean %s%% instead of %s %s?\n" - "Select YES if you want to change this value to %s%%, \n" - "or NO if you are sure that %s %s is a correct value.")) % stVal % stVal % sidetext % stVal % stVal % sidetext).str()); - WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxYES | wxNO); + bool infill_anchors = m_opt.opt_key == "infill_anchor" || + m_opt.opt_key == "infill_anchor_max"; + + const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : + "mm"; + const wxString stVal = double_to_string(val, m_opt.precision); + const wxString msg_text = from_u8( + (boost::format(_u8L("Do you mean %s%% instead of %s %s?\n" + "Select YES if you want to change this value to %s%%, \n" + "or NO if you are sure that %s %s is a correct value.")) % + stVal % stVal % sidetext % stVal % stVal % sidetext) + .str()); + WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, + wxYES | wxNO); if ((!infill_anchors || val > 100) && dialog.ShowModal() == wxID_YES) { str += "%"; + is_percent = true; m_last_validated_value = str; - set_value(str, false/*true*/); + set_any_value(FloatOrPercent{val, is_percent}, false /*true*/); str = m_last_validated_value; } else - set_value(stVal, false); // it's no needed but can be helpful, when inputted value contained "," instead of "." + set_any_value(FloatOrPercent{val, is_percent}, false); // it's no needed but can be helpful, when inputted value + // contained "," instead of "." m_last_validated_value = str; } } } } else { str.ToDouble(&val); + is_percent = true; } } - m_value = into_u8(str); + m_value = FloatOrPercent{val, is_percent}; break; } case coPoints: { std::vector out_values; str.Replace(" ", wxEmptyString, true); if (!str.IsEmpty()) { - bool invalid_val = false; - bool out_of_range_val = false; - wxStringTokenizer points(str, ","); - while (points.HasMoreTokens()) { - wxString token = points.GetNextToken(); - double x, y; - wxStringTokenizer point(token, "x"); - if (point.HasMoreTokens()) { - wxString x_str = point.GetNextToken(); - if (x_str.ToDouble(&x) && point.HasMoreTokens()) { - wxString y_str = point.GetNextToken(); - if (y_str.ToDouble(&y) && !point.HasMoreTokens()) { - if (m_opt.min <= x && x <= m_opt.max && m_opt.min <= y && y <= m_opt.max) { - out_values.push_back(Vec2d(x, y)); - continue; - } - out_of_range_val = true; - break; - } - } - } - invalid_val = true; - break; - } + auto [/*bool*/ invalid_val, /*bool*/ out_of_range_val] = get_strings_points(str, m_opt.min, m_opt.max, + out_values); if (out_of_range_val) { wxString text_value; if (!m_value.empty()) text_value = get_points_string(boost::any_cast>(m_value)); - set_value(text_value, true); + set_text_value(text_value.ToStdString(), true); show_error(m_parent, _L("Input value is out of range")); - } - else if (invalid_val) { + } else if (invalid_val) { wxString text_value; if (!m_value.empty()) text_value = get_points_string(boost::any_cast>(m_value)); - set_value(text_value, true); - show_error(m_parent, format_wxstr(_L("Invalid input format. Expected vector of dimensions in the following format: \"%1%\""),"XxY, XxY, ..." )); + set_text_value(text_value.ToStdString(), true); + show_error(m_parent, format_wxstr(_L("Invalid input format. Expected vector of dimensions in the " + "following format: \"%1%\""), + "XxY, XxY, ...")); } } m_value = out_values; - break; } + break; + } - default: - break; - } + default: break; + } if (!Field::warn_zero_gapfillspeed && ("max_volumetric_speed" == m_opt_id || "gap_fill_speed" == m_opt_id)) { - bool show_warning = false; - const DynamicPrintConfig& print_config = wxGetApp().preset_bundle->fff_prints.get_edited_preset().config; + bool show_warning = false; + const DynamicPrintConfig &print_config = wxGetApp().preset_bundle->fff_prints.get_edited_preset().config; if ("max_volumetric_speed" == m_opt_id && val > 0) show_warning = print_config.option("gap_fill_speed")->value == 0; if ("gap_fill_speed" == m_opt_id && val == 0) show_warning = true; if (show_warning) { - const wxString msg_text = from_u8(_u8L("Auto Speed will try to maintain a constant flow rate accross all print moves." - "\nIt is not recommended to include gap moves to the Auto Speed calculation(by setting this value to 0)." - "\nVery thin gap extrusions will often not max out the flow rate of your printer." - "\nAs a result, this will cause Auto Speed to lower the speeds of all other print moves to match the low flow rate of these thin gaps.")); - wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxICON_WARNING | wxOK); + const wxString msg_text = from_u8( + _u8L("Auto Speed will try to maintain a constant flow rate accross all print moves." + "\nIt is not recommended to include gap moves to the Auto Speed calculation(by setting this " + "value to 0)." + "\nVery thin gap extrusions will often not max out the flow rate of your printer." + "\nAs a result, this will cause Auto Speed to lower the speeds of all other print moves to " + "match the low flow rate of these thin gaps.")); + wxMessageDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, + wxICON_WARNING | wxOK); dialog.ShowModal(); Field::warn_zero_gapfillspeed = true; } } + + if (need_update) { + wxString new_str = any_to_wxstring(m_value, m_opt, m_opt_idx).first; + set_text_value(new_str.ToStdString()); + } } void Field::msw_rescale() @@ -648,60 +910,16 @@ void TextCtrl::BUILD() { wxString text_value = wxString(""); - switch (m_opt.type) { - case coFloatOrPercent: - { - text_value = double_to_string(m_opt.default_value->get_float(), m_opt.precision); - if (m_opt.get_default_value()->percent) - text_value += "%"; - break; - } - case coPercent: - { - text_value = double_to_string(m_opt.default_value->get_float(), m_opt.precision); - text_value += "%"; - break; - } - case coPercents: - case coFloats: - case coFloat: - { - double val = m_opt.type == coFloats ? - m_opt.get_default_value()->get_at(m_opt_idx) : - m_opt.type == coFloat ? - m_opt.default_value->get_float() : - m_opt.get_default_value()->get_at(m_opt_idx); - text_value = double_to_string(val, m_opt.precision); - break; - } - case coFloatsOrPercents: - { - const ConfigOptionFloatsOrPercents* cofop = m_opt.get_default_value(); - text_value = double_to_string(cofop->get_at(m_opt_idx).value, m_opt.precision); - if (cofop->get_at(m_opt_idx).percent) - text_value += "%"; - break; - } - case coString: - text_value = m_opt.get_default_value()->value; - break; - case coStrings: - { - const ConfigOptionStrings *vec = m_opt.get_default_value(); - if (vec == nullptr || vec->empty()) break; //for the case of empty default value - text_value = vec->get_at(m_opt_idx); - break; - } - case coPoint: - text_value = get_points_string({ m_opt.get_default_value()->value }); - break; - case coPoints: - text_value = get_points_string(m_opt.get_default_value()->values); - break; - default: - break; - } + boost::any anyval = m_opt.default_value->get_any(m_opt_idx); + text_value = any_to_wxstring(m_opt.default_value->get_any(m_opt_idx), m_opt, m_opt_idx).first; + if (text_value == na_value()) { + // current value is nil, get the not-nil default value of the default option. + assert(m_opt.default_value->is_vector()); + m_last_meaningful_value = any_to_wxstring(static_cast(m_opt.default_value.get())->get_default_value(), m_opt, m_opt_idx).first; + } else { m_last_meaningful_value = text_value; + } + assert(m_last_meaningful_value != na_value()); long style = m_opt.multiline ? wxTE_MULTILINE : wxTE_PROCESS_ENTER; #ifdef _WIN32 @@ -770,7 +988,15 @@ void TextCtrl::BUILD() { window = dynamic_cast(temp); this->set_tooltip(text_value); -} +} + + +void TextCtrl::set_text_value(const std::string &value, bool change_event) +{ + m_disable_change_event = !change_event; + dynamic_cast(window)->SetValue(value); + m_disable_change_event = false; +} bool TextCtrl::value_was_changed() { @@ -784,22 +1010,75 @@ bool TextCtrl::value_was_changed() get_value_by_opt_type(ret_str); switch (m_opt.type) { + case coInts: + if (m_opt_idx < 0) { + return boost::any_cast>(m_value) != boost::any_cast>(val); + } + if (m_opt.nullable) { + uint8_t new_val = boost::any_cast(m_value); + uint8_t old_val = boost::any_cast(val); + if (new_val == ConfigOptionInts::NIL_VALUE() && old_val == ConfigOptionInts::NIL_VALUE()) + return false; + } case coInt: return boost::any_cast(m_value) != boost::any_cast(val); - case coPercent: case coPercents: case coFloats: - case coFloat: { - if (m_opt.nullable && ConfigOptionFloatsNullable::is_nil(m_value) && - ConfigOptionFloatsNullable::is_nil(val)) + if (m_opt_idx < 0) { + return boost::any_cast>(m_value) != boost::any_cast>(val); + } + if (m_opt.nullable) { + double new_val = boost::any_cast(m_value); + double old_val = boost::any_cast(val); + if ((std::isnan(new_val) || ConfigOptionFloats::is_nil(m_value)) && + (std::isnan(old_val) || ConfigOptionFloats::is_nil(val))) return false; + } + case coPercent: + case coFloat: { return boost::any_cast(m_value) != boost::any_cast(val); } - case coString: case coStrings: - case coFloatOrPercent: - case coFloatsOrPercents: + if (m_opt_idx < 0) { + return boost::any_cast>(m_value) != + boost::any_cast>(val); + } + case coString: return boost::any_cast(m_value) != boost::any_cast(val); + case coFloatsOrPercents: + if (m_opt_idx < 0) { + return boost::any_cast>(m_value) != + boost::any_cast>(val); + } + if (m_opt.nullable) { + if (ConfigOptionFloatsOrPercents::is_nil(m_value) &&ConfigOptionFloatsOrPercents::is_nil(val)) + return false; + } + case coFloatOrPercent: + return boost::any_cast(m_value) != boost::any_cast(val); + case coPoints: + if (m_opt_idx < 0) { + return boost::any_cast>(m_value) != boost::any_cast>(val); + } + case coPoint: + return boost::any_cast(m_value) != boost::any_cast(val); + case coBools: + if (m_opt_idx < 0) { + return boost::any_cast>(m_value) != boost::any_cast>(val); + } else { + if (m_opt.nullable) { + uint8_t new_val = boost::any_cast(m_value); + uint8_t old_val = boost::any_cast(val); + if (new_val == ConfigOptionBools::NIL_VALUE() && old_val == ConfigOptionBools::NIL_VALUE()) + return false; + } + return boost::any_cast(m_value) != boost::any_cast(val); + } + case coBool: + if(m_opt.is_script) + return boost::any_cast(m_value) != boost::any_cast(val); + else + return boost::any_cast(m_value) != boost::any_cast(val); default: return true; } @@ -813,18 +1092,29 @@ void TextCtrl::propagate_value() on_kill_focus(); else if (value_was_changed()) on_change_field(); -} - -void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) { + //update m_last_meaningful_value ? + if (!m_value.empty() && dynamic_cast(window)->GetValue() != na_value()) + m_last_meaningful_value = dynamic_cast(window)->GetValue(); +} + +void TextCtrl::set_any_value(const boost::any& value, bool change_event/* = false*/) { + //can be: + //case coFloat: + //case coFloats: + //case coPercent: + //case coPercents: + //case coFloatOrPercent: + //case coFloatsOrPercents: + //case coString: + //case coStrings: + // coBools (if all) + // coInts (if all) + // coPoints (if all) + auto [/*wxString*/text_value, /*bool*/ has_nil] = any_to_wxstring(value, m_opt, m_opt_idx); + if (!has_nil) + m_last_meaningful_value = text_value; m_disable_change_event = !change_event; - if (m_opt.nullable) { - const bool m_is_na_val = boost::any_cast(value) == na_value(); - if (!m_is_na_val) - m_last_meaningful_value = value; - dynamic_cast(window)->SetValue(m_is_na_val ? na_value() : boost::any_cast(value)); - } - else - dynamic_cast(window)->SetValue(boost::any_cast(value)); + dynamic_cast(window)->SetValue(text_value); m_disable_change_event = false; if (!change_event) { @@ -839,7 +1129,7 @@ void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/) void TextCtrl::set_last_meaningful_value() { - dynamic_cast(window)->SetValue(boost::any_cast(m_last_meaningful_value)); + dynamic_cast(window)->SetValue(m_last_meaningful_value); propagate_value(); } @@ -897,12 +1187,10 @@ void CheckBox::BUILD() { if (m_opt.height >= 0) size.SetHeight(m_opt.height * m_em_unit); if (m_opt.width >= 0) size.SetWidth(m_opt.width * m_em_unit); - bool check_value = m_opt.type == coBool ? - m_opt.default_value->get_bool() : m_opt.type == coBools ? - m_opt.get_default_value()->get_at(m_opt_idx) : - false; + bool check_value = m_opt.type == coBool || m_opt.type == coBools ? m_opt.default_value->get_bool(m_opt_idx) : + false; - m_last_meaningful_value = static_cast(check_value); + m_last_meaningful_value = static_cast(check_value); #ifdef __WXGTK2__ //gtk2 can't resize checkboxes, so we are using togglable buttons instead @@ -939,7 +1227,7 @@ void CheckBox::BUILD() { //set value (need the window for the set_value) if (m_opt.is_script && !m_opt.default_script_value.empty()) - set_value(m_opt.default_script_value, false); + set_any_value(m_opt.default_script_value, false); else set_widget_value(check_value); @@ -968,13 +1256,15 @@ void CheckBox::set_widget_value(bool new_val) #endif } -void CheckBox::set_value(const boost::any& value, bool change_event) +void CheckBox::set_any_value(const boost::any &value, bool change_event) { + //can be coBool and coBools (with idx) m_disable_change_event = !change_event; - if (m_opt.nullable) { - m_is_na_val = boost::any_cast(value) == ConfigOptionBoolsNullable::NIL_VALUE(); + assert(m_opt.type == coBool || (m_opt.type == coBools && m_opt_idx >= 0)); + if (m_opt.type == coBools && m_opt.nullable) { + m_is_na_val = boost::any_cast(value) == ConfigOptionBoolsNullable::NIL_VALUE(); if (!m_is_na_val) - m_last_meaningful_value = value; + m_last_meaningful_value = boost::any_cast(value); set_widget_value(m_is_na_val ? false : boost::any_cast(value) != 0); } else if (m_opt.is_script) { uint8_t val = boost::any_cast(value); @@ -982,8 +1272,12 @@ void CheckBox::set_value(const boost::any& value, bool change_event) dynamic_cast(window)->Set3StateValue(wxCheckBoxState::wxCHK_UNDETERMINED); else set_widget_value(val != 0); - } else + } else if (m_opt.type == coBools) { + set_widget_value(boost::any_cast(value) != 0); + } else { + assert(m_opt.type == coBool); set_widget_value(boost::any_cast(value)); + } m_disable_change_event = false; } @@ -991,7 +1285,7 @@ void CheckBox::set_last_meaningful_value() { if (m_opt.nullable) { m_is_na_val = false; - set_widget_value(boost::any_cast(m_last_meaningful_value) != 0); + set_widget_value(m_last_meaningful_value != 0); on_change_field(); } } @@ -1394,7 +1688,7 @@ void Choice::set_selection() } } -void Choice::set_value(const std::string& value, bool change_event) //! Redundant? +void Choice::set_text_value(const std::string &value, bool change_event) //! Redundant? { m_disable_change_event = !change_event; @@ -1439,8 +1733,16 @@ int32_t Choice::idx_from_enum_value(int32_t val) { return 0; } -void Choice::set_value(const boost::any& value, bool change_event) +void Choice::set_any_value(const boost::any &value, bool change_event) { + // can be + // GUIType::select_open + // GUIType::f_enum_open: + // GUIType::i_enum_open: + // coEnum + assert(m_opt.type == coEnum || m_opt.gui_type == ConfigOptionDef::GUIType::select_open || + m_opt.gui_type == ConfigOptionDef::GUIType::f_enum_open || + m_opt.gui_type == ConfigOptionDef::GUIType::i_enum_open); m_disable_change_event = !change_event; choice_ctrl* field = dynamic_cast(window); @@ -1452,11 +1754,8 @@ void Choice::set_value(const boost::any& value, bool change_event) case coFloatOrPercent: case coString: case coStrings: { - wxString text_value; - if (m_opt.type == coInt) - text_value = wxString::Format(_T("%i"), int(boost::any_cast(value))); - else - text_value = boost::any_cast(value); + auto [/*wxString*/ text_value, /*bool*/ has_nil] = any_to_wxstring(value, m_opt, m_opt_idx); + size_t idx = 0; const std::vector& enums = m_opt.enum_values.empty() ? m_opt.enum_labels : m_opt.enum_values; for (auto el : enums) @@ -1474,6 +1773,7 @@ void Choice::set_value(const boost::any& value, bool change_event) else field->SetSelection(idx); + // merill note: i don't like hacks like that. makes the code spagetti if (!m_value.empty() && m_opt.opt_key == "fill_density") { // If m_value was changed before, then update m_value here too to avoid case // when control's value is already changed from the ConfigManipulation::update_print_fff_config(), @@ -1529,7 +1829,7 @@ void Choice::convert_to_enum_value(int32_t ret_enum) { m_value = value; } else - m_value = m_opt.default_value.get()->get_int(); + m_value = m_opt.default_value->get_int(); } //Please don't use that on Enum fields it will just break everything @@ -1704,10 +2004,11 @@ void ColourPicker::set_undef_value(wxColourPickerCtrl* field) btn->SetBitmapLabel(bmp); } -void ColourPicker::set_value(const boost::any& value, bool change_event) +void ColourPicker::set_any_value(const boost::any &value, bool change_event) { + // can be ConfigOptionDef::GUIType::color m_disable_change_event = !change_event; - const wxString clr_str(boost::any_cast(value)); + const wxString clr_str(boost::any_cast(value)); auto field = dynamic_cast(window); wxColour clr(clr_str); @@ -1767,10 +2068,10 @@ void PointCtrl::BUILD() const wxSize field_size(4 * m_em_unit, -1); Vec2d default_pt; - if(m_opt.type==coPoint) + if (m_opt.type == coPoint) default_pt = m_opt.get_default_value()->value; else // coPoints - default_pt = m_opt.get_default_value()->values.at(0); + default_pt = m_opt.get_default_value()->get_at(0); double val = default_pt(0); wxString X = val - int(val) == 0 ? wxString::Format(_T("%i"), int(val)) : wxNumberFormatter::ToString(val, 2, wxNumberFormatter::Style_None); val = default_pt(1); @@ -1866,7 +2167,7 @@ void PointCtrl::propagate_value(wxTextCtrl* win) on_change_field(); } -void PointCtrl::set_value(const Vec2d& value, bool change_event) +void PointCtrl::set_vec2d_value(const Vec2d& value, bool change_event) { m_disable_change_event = !change_event; @@ -1878,22 +2179,12 @@ void PointCtrl::set_value(const Vec2d& value, bool change_event) m_disable_change_event = false; } -void PointCtrl::set_value(const boost::any& value, bool change_event) +void PointCtrl::set_any_value(const boost::any &value, bool change_event) { - Vec2d pt(Vec2d::Zero()); - const Vec2d *ptf = boost::any_cast(&value); - if (!ptf) - { - if (m_opt.type == coPoint) { - pt = boost::any_cast(value)->value; - } else { // coPoints - ConfigOptionPoints* pts = boost::any_cast(value); - pt = pts->values.at(0); - } - } - else - pt = *ptf; - set_value(pt, change_event); + // can be coPoint and coPoints (with idx) + assert(m_opt.type == coPoint || (m_opt.type == coPoints && m_opt_idx >= 0)); + Vec2d pt = boost::any_cast(value); + set_vec2d_value(pt, change_event); } boost::any& PointCtrl::get_value() @@ -1902,7 +2193,7 @@ boost::any& PointCtrl::get_value() if (!x_textctrl->GetValue().ToDouble(&x) || !y_textctrl->GetValue().ToDouble(&y)) { - set_value(m_value.empty() ? Vec2d(0.0, 0.0) : m_value, true); + set_any_value(m_value.empty() ? Vec2d(0.0, 0.0) : m_value, true); show_error(m_parent, _L("Invalid numeric input.")); } else @@ -1913,7 +2204,7 @@ boost::any& PointCtrl::get_value() if (x > m_opt.max) x = m_opt.max; if (m_opt.min > y) y = m_opt.min; if (y > m_opt.max) y = m_opt.max; - set_value(Vec2d(x, y), true); + set_vec2d_value(Vec2d(x, y), true); show_error(m_parent, _L("Input value is out of range")); } @@ -2005,22 +2296,35 @@ void SliderCtrl::BUILD() m_sizer = dynamic_cast(temp); } -void SliderCtrl::set_value(const boost::any& value, bool change_event) +void SliderCtrl::set_any_value(const boost::any &value, bool change_event) { + // only with ConfigOptionDef::GUIType::slider: & coFloat or coInt + assert(m_opt.gui_type == ConfigOptionDef::GUIType::slider && (m_opt.type == coFloat || m_opt.type == coInt)); m_disable_change_event = !change_event; - - m_slider->SetValue(boost::any_cast(value)*m_scale); - int val = boost::any_cast(get_value()); - m_textctrl->SetLabel(wxString::Format("%d", val)); + if (m_opt.type == coFloat) { + m_slider->SetValue(boost::any_cast(value) * m_scale); + double val = boost::any_cast(get_value()); + m_textctrl->SetLabel(wxString::Format("%d", val)); + } else if (m_opt.type == coInt) { + m_slider->SetValue(boost::any_cast(value) * m_scale); + int32_t val = boost::any_cast(get_value()); + m_textctrl->SetLabel(wxString::Format("%d", val)); + } m_disable_change_event = false; } -boost::any& SliderCtrl::get_value() +boost::any &SliderCtrl::get_value() { -// int ret_val; -// x_textctrl->GetValue().ToDouble(&val); - return m_value = int(m_slider->GetValue()/m_scale); + // int ret_val; + // x_textctrl->GetValue().ToDouble(&val); + if (m_opt.type == coFloat) { + return m_value = double(m_slider->GetValue() / m_scale); + } else if (m_opt.type == coInt) { + return m_value = int32_t(m_slider->GetValue() / m_scale); + } + assert(false); + return m_value; } diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index a567b5d67a5..db0c6aafc34 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -38,6 +38,8 @@ using t_back_to_init = std::function; wxString double_to_string(double const value, const int max_precision = 6); wxString get_points_string(const std::vector& values); +// return {invalid_val, out_of_range_val} +std::pair get_strings_points(const wxString &str, double min, double max, std::vector &out_values); class Field; class RichTooltipTimer : public wxTimer @@ -107,7 +109,7 @@ class Field { /// Copy of ConfigOption for deduction purposes const ConfigOptionDef m_opt {ConfigOptionDef()}; const t_config_option_key m_opt_id;//! {""}; - int m_opt_idx = 0; + int m_opt_idx = -1; // for saving state bool m_is_enable{true}; @@ -118,7 +120,7 @@ class Field { /// Sets a value for this control. /// subclasses should overload with a specific version /// Postcondition: Method does not fire the on_change event. - virtual void set_value(const boost::any& value, bool change_event) = 0; + virtual void set_any_value(const boost::any &value, bool change_event) = 0; virtual void set_last_meaningful_value() {} virtual void set_na_value() {} @@ -153,8 +155,7 @@ class Field { virtual wxSizer* getSizer() { return nullptr; } virtual wxWindow* getWindow() { return nullptr; } - bool is_matched(const std::string& string, const std::string& pattern); - void get_value_by_opt_type(wxString& str, const bool check_value = true); + bool is_matched(const std::string &string, const std::string &pattern); /// Factory method for generating new derived classes. template @@ -241,8 +242,6 @@ class Field { // current value boost::any m_value; - // last meaningful value - boost::any m_last_meaningful_value; // last validated value wxString m_last_validated_value; @@ -255,6 +254,23 @@ class Field { friend class OptionsGroup; }; +class TextField : public Field +{ + using Field::Field; +protected: + TextField(const ConfigOptionDef &opt, const t_config_option_key &id) : Field(opt, id) {} + TextField(wxWindow *parent, const ConfigOptionDef &opt, const t_config_option_key &id) : Field(parent, opt, id) + {} + ~TextField() {} + + void get_value_by_opt_type(wxString &str, const bool check_value = true); + bool get_vector_value(const wxString &str, ConfigOptionVectorBase &reader); + virtual void set_text_value(const std::string &str, bool change_event = false) = 0; + + // last meaningful value (can be whatever the child class want it to be) + wxString m_last_meaningful_value; +}; + /// Convenience function, accepts a const reference to t_field and checks to see whether /// or not both wx pointers are null. inline bool is_bad_field(const t_field& obj) { return obj->getSizer() == nullptr && obj->getWindow() == nullptr; } @@ -265,16 +281,16 @@ inline bool is_window_field(const t_field& obj) { return !is_bad_field(obj) && o /// Covenience function to determine whether this field is a valid sizer field. inline bool is_sizer_field(const t_field& obj) { return !is_bad_field(obj) && obj->getSizer() != nullptr; } -class TextCtrl : public Field { - using Field::Field; +class TextCtrl : public TextField { + using TextField::TextField; #ifdef __WXGTK__ bool bChangedValueEvent = true; void change_field_value(wxEvent& event); #endif //__WXGTK__ public: - TextCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} - TextCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} + TextCtrl(const ConfigOptionDef &opt, const t_config_option_key &id) : TextField(opt, id) {} + TextCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : TextField(parent, opt, id) {} ~TextCtrl() {} void BUILD() override; @@ -283,12 +299,8 @@ class TextCtrl : public Field { void propagate_value(); wxWindow* window {nullptr}; - void set_value(const std::string& value, bool change_event = false) { - m_disable_change_event = !change_event; - dynamic_cast(window)->SetValue(wxString(value)); - m_disable_change_event = false; - } - void set_value(const boost::any& value, bool change_event = false) override; + void set_text_value(const std::string &value, bool change_event = false) override; + void set_any_value(const boost::any& value, bool change_event = false) override; void set_last_meaningful_value() override; void set_na_value() override; @@ -304,6 +316,8 @@ class TextCtrl : public Field { class CheckBox : public Field { using Field::Field; bool m_is_na_val {false}; + // last meaningful value (can be whatever the child class want it to be) + uint8_t m_last_meaningful_value; void set_widget_value(bool new_val); public: @@ -314,12 +328,12 @@ class CheckBox : public Field { wxWindow* window{ nullptr }; void BUILD() override; - void set_value(const bool value, bool change_event = false) { + void set_bool_value(const bool value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetValue(value); m_disable_change_event = false; } - void set_value(const boost::any& value, bool change_event = false) override; + void set_any_value(const boost::any &value, bool change_event = false) override; void set_last_meaningful_value() override; void set_na_value() override; boost::any& get_value() override; @@ -348,12 +362,12 @@ class SpinCtrl : public Field { /// Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER void propagate_value() ; - void set_value(const std::string& value, bool change_event = false) { + void set_text_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetValue(value); m_disable_change_event = false; } - void set_value(const boost::any& value, bool change_event = false) override { + void set_any_value(const boost::any &value, bool change_event = false) override { m_disable_change_event = !change_event; tmp_value = boost::any_cast(value); m_value = value; @@ -373,16 +387,18 @@ class SpinCtrl : public Field { wxWindow* getWindow() override { return window; } }; -class Choice : public Field { - using Field::Field; +class Choice : public TextField +{ + using TextField::TextField; protected: //used by get_value when it's an enum //convert the value from the select to the enum value. store it in m_value void convert_to_enum_value(int32_t idx_val); int32_t idx_from_enum_value(int32_t enum_val); public: - Choice(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {} - Choice(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {} + Choice(const ConfigOptionDef &opt, const t_config_option_key &id) : TextField(opt, id) {} + Choice(wxWindow *parent, const ConfigOptionDef &opt, const t_config_option_key &id) : TextField(parent, opt, id) + {} ~Choice() {} wxWindow* window{ nullptr }; @@ -399,8 +415,8 @@ class Choice : public Field { int m_last_selected { wxNOT_FOUND }; void set_selection(); - void set_value(const std::string& value, bool change_event = false); - void set_value(const boost::any& value, bool change_event = false) override; + void set_text_value(const std::string &value, bool change_event = false); + void set_any_value(const boost::any &value, bool change_event = false) override; void set_values(const std::vector &values); void set_values(const wxArrayString &values); boost::any& get_value() override; @@ -426,12 +442,12 @@ class ColourPicker : public Field { wxWindow* window{ nullptr }; void BUILD() override; - void set_value(const std::string& value, bool change_event = false) { + void set_text_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetColour(value); m_disable_change_event = false; } - void set_value(const boost::any& value, bool change_event = false) override; + void set_any_value(const boost::any &value, bool change_event = false) override; boost::any& get_value() override; void msw_rescale() override; void sys_color_changed() override; @@ -456,8 +472,8 @@ class PointCtrl : public Field { bool value_was_changed(wxTextCtrl* win); // Propagate value from field to the OptionGroupe and Config after kill_focus/ENTER void propagate_value(wxTextCtrl* win); - void set_value(const Vec2d& value, bool change_event = false); - void set_value(const boost::any& value, bool change_event = false) override; + void set_vec2d_value(const Vec2d& value, bool change_event = false); + void set_any_value(const boost::any &value, bool change_event = false) override; boost::any& get_value() override; void msw_rescale() override; @@ -484,12 +500,12 @@ class StaticText : public Field { wxWindow* window{ nullptr }; void BUILD() override; - void set_value(const std::string& value, bool change_event = false) { + void set_text_value(const std::string& value, bool change_event = false) { m_disable_change_event = !change_event; dynamic_cast(window)->SetLabel(wxString::FromUTF8(value.data())); m_disable_change_event = false; } - void set_value(const boost::any& value, bool change_event = false) override { + void set_any_value(const boost::any& value, bool change_event = false) override { m_disable_change_event = !change_event; dynamic_cast(window)->SetLabel(boost::any_cast(value)); m_disable_change_event = false; @@ -519,8 +535,8 @@ class SliderCtrl : public Field { void BUILD() override; - void set_value(const int value, bool change_event = false); - void set_value(const boost::any& value, bool change_event = false) override; + void set_int_value(const int value, bool change_event = false); + void set_any_value(const boost::any& value, bool change_event = false) override; boost::any& get_value() override; void enable() override { diff --git a/src/slic3r/GUI/GUI.cpp b/src/slic3r/GUI/GUI.cpp index bc7ff644f20..f785487ce54 100644 --- a/src/slic3r/GUI/GUI.cpp +++ b/src/slic3r/GUI/GUI.cpp @@ -99,139 +99,6 @@ const std::string& shortkey_alt_prefix() return str; } -// opt_index = 0, by the reason of zero-index in ConfigOptionVector by default (in case only one element) -void change_opt_value(DynamicConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/) -{ - try{ - - if (config.def()->get(opt_key)->type == coBools && config.def()->get(opt_key)->nullable) { - ConfigOptionBoolsNullable* vec_new = new ConfigOptionBoolsNullable{ boost::any_cast(value) }; - config.option(opt_key)->set_at(vec_new, opt_index, 0); - return; - } - - const ConfigOptionDef *opt_def = config.def()->get(opt_key); - switch (opt_def->type) { - case coFloatOrPercent:{ - std::string str = boost::any_cast(value); - bool percent = false; - if (str.back() == '%') { - str.pop_back(); - percent = true; - } - double val = std::stod(str); // locale-dependent (on purpose - the input is the actual content of the field) - config.set_key_value(opt_key, new ConfigOptionFloatOrPercent(val, percent)); - break;} - case coFloatsOrPercents: { - std::string str = boost::any_cast(value); - bool percent = false; - if (str.back() == '%') { - str.pop_back(); - percent = true; - } - double val = stod(str); - ConfigOptionFloatsOrPercents* vec_new = new ConfigOptionFloatsOrPercents{ boost::any_cast(FloatOrPercent{val, percent}) }; - config.option(opt_key)->set_at(vec_new, opt_index, opt_index); - break; } - case coPercent: - config.set_key_value(opt_key, new ConfigOptionPercent(boost::any_cast(value))); - break; - case coFloat:{ - //config.set_key_value(opt_key, new ConfigOptionFloat(boost::any_cast(value))); - double& val_dbl = config.opt_float(opt_key); - val_dbl = boost::any_cast(value); - break; - } - case coPoint: { - config.set_key_value(opt_key, new ConfigOptionPoint(boost::any_cast(value))); - break; - } - case coPercents:{ - ConfigOptionPercents* vec_new = new ConfigOptionPercents{ boost::any_cast(value) }; - config.option(opt_key)->set_at(vec_new, opt_index, opt_index); - break; - } - case coFloats:{ - ConfigOptionFloats* vec_new = new ConfigOptionFloats{ boost::any_cast(value) }; - config.option(opt_key)->set_at(vec_new, opt_index, opt_index); - break; - } - case coString: { - //config.set_key_value(opt_key, new ConfigOptionString(boost::any_cast(value))); - std::string& val_str = config.opt_string(opt_key); - val_str = boost::any_cast(value); - break; - } - case coStrings:{ - if (opt_key == "compatible_prints" || opt_key == "compatible_printers" || opt_key == "gcode_substitutions") { - config.option(opt_key)->values = - boost::any_cast>(value); - } - else if (config.def()->get(opt_key)->gui_flags.compare("serialized") == 0) { - std::string str = boost::any_cast(value); - std::vector values {}; - if (!str.empty()) { - if (str.back() == ';') str.pop_back(); - // Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values. - // Currently used for the post_process config value only. - boost::split(values, str, boost::is_any_of(";")); - if (values.size() == 1 && values[0] == "") - values.resize(0); - } - config.option(opt_key)->values = values; - } - else{ - ConfigOptionStrings* vec_new = new ConfigOptionStrings{ boost::any_cast(value) }; - config.option(opt_key)->set_at(vec_new, opt_index, 0); - } - } - break; - case coBool: - config.set_key_value(opt_key, new ConfigOptionBool(boost::any_cast(value))); - break; - case coBools:{ - ConfigOptionBools* vec_new = new ConfigOptionBools{ boost::any_cast(value) != 0 }; - config.option(opt_key)->set_at(vec_new, opt_index, 0); - break;} - case coInt:{ - //config.set_key_value(opt_key, new ConfigOptionInt(boost::any_cast(value))); - int& val_int = config.opt_int(opt_key); - val_int = boost::any_cast(value); - } - break; - case coInts:{ - ConfigOptionInts* vec_new = new ConfigOptionInts{ boost::any_cast(value) }; - config.option(opt_key)->set_at(vec_new, opt_index, 0); - } - break; - case coEnum:{ - ConfigOption* opt = opt_def->default_value.get()->clone(); - opt->set_enum_int(boost::any_cast(value)); // we transport an int convertion of the enum in the boost anycast. - BOOST_LOG_TRIVIAL(debug) << "Set enum "<< opt_key << " as int " << boost::any_cast(value) << " into enum " << opt->serialize(); - config.set_key_value(opt_key, opt); - } - break; - case coPoints:{ - if (opt_key == "bed_shape") { - config.option(opt_key)->values = boost::any_cast>(value); - break; - } - ConfigOptionPoints* vec_new = new ConfigOptionPoints{ boost::any_cast(value) }; - config.option(opt_key)->set_at(vec_new, opt_index, 0); - } - break; - case coNone: - break; - default: - break; - } - } - catch (const std::exception &e) - { - wxLogError(format_wxstr("Internal error when changing value for %1%: %2%", opt_key, e.what())); - } -} - void show_error(wxWindow* parent, const wxString& message, bool monospaced_font) { ErrorDialog msg(parent, message, monospaced_font); diff --git a/src/slic3r/GUI/GUI.hpp b/src/slic3r/GUI/GUI.hpp index 21fb5c204a7..430826d9d20 100644 --- a/src/slic3r/GUI/GUI.hpp +++ b/src/slic3r/GUI/GUI.hpp @@ -36,9 +36,6 @@ extern AppConfig* get_app_config(); extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_language_change); -// Change option value in config -void change_opt_value(DynamicConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0); - // If monospaced_font is true, the error message is displayed using html
tags, // so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser. void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false); diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 87f70a9825a..e42f1e33c9b 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -49,9 +49,6 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co case ConfigOptionDef::GUIType::legend: // StaticText m_fields.emplace(id, StaticText::Create(this->ctrl_parent(), opt, id)); break; - case ConfigOptionDef::GUIType::one_string: - m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); - break; default: switch (opt.type) { case coFloatOrPercent: @@ -64,12 +61,22 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co case coStrings: m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); break; + case coBools: + if (id.find('#') == std::string::npos) { + // string field with vector serialization + m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); + break; + } case coBool: - case coBools: m_fields.emplace(id, CheckBox::Create(this->ctrl_parent(), opt, id)); break; + case coInts: + if (id.find('#') == std::string::npos) { + // string field with vector serialization + m_fields.emplace(id, TextCtrl::Create(this->ctrl_parent(), opt, id)); + break; + } case coInt: - case coInts: m_fields.emplace(id, SpinCtrl::Create(this->ctrl_parent(), opt, id)); break; case coEnum: @@ -658,7 +665,7 @@ void ConfigOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const b const std::string &opt_key = itOption.first; int opt_index = itOption.second; - this->change_opt_value(opt_key, value, opt_index == -1 ? 0 : opt_index); + this->change_opt_value(opt_key, value, opt_index); } OptionsGroup::on_change_OG(opt_id, value); @@ -726,8 +733,8 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, if (initial_conf.has(dep_key) && edited_conf.has(dep_key)) { ConfigOption* conf_opt = initial_conf.option(dep_key)->clone(); // update the field - tab->set_value(dep_key, get_config_value(initial_conf, dep_key)); - tab->on_value_change(dep_key, conf_opt->get_any(-1)); + tab->set_value(dep_key, initial_conf.option(dep_key)->get_any()); + tab->on_value_change(dep_key, conf_opt->get_any()); } } } @@ -740,14 +747,14 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, } else if (it_opt_map == m_opt_map.end() || // This option doesn't have corresponded field is_option_without_field(opt_key) ) { - value = get_config_value(config, opt_key); + value = config.option(opt_key)->get_any(); this->change_opt_value(opt_key, value); return; } else { auto opt_id = it_opt_map->first; std::string opt_short_key = m_opt_map.at(opt_id).first; int opt_index = m_opt_map.at(opt_id).second; - value = get_config_value(config, opt_short_key, opt_index); + value = config.option(opt_short_key)->get_any(opt_index); } if(set_value(opt_key, value)) @@ -772,7 +779,7 @@ void ConfigOptionsGroup::reload_config() // index in the vector option, zero for scalars int opt_index = kvp.second.second; const ConfigOptionDef &option = m_options.at(opt_id).opt; - this->set_value(opt_id, config_value(opt_key, opt_index, option.gui_flags == "serialized")); + this->set_value(opt_id, m_config->option(opt_key)->get_any(opt_index)); } update_script_presets(); } @@ -964,163 +971,6 @@ void ConfigOptionsGroup::refresh() custom_ctrl->Refresh(); } -boost::any ConfigOptionsGroup::config_value(const std::string& opt_key, int opt_index, bool deserialize) { - - if (deserialize) { - // Want to edit a vector value(currently only multi - strings) in a single edit box. - // Aggregate the strings the old way. - // Currently used for the post_process config value only. - if (opt_index != -1) - throw Slic3r::OutOfRange("Can't deserialize option indexed value"); -// return join(';', m_config->get(opt_key)}); - return get_config_value(*m_config, opt_key); - } - else { -// return opt_index == -1 ? m_config->get(opt_key) : m_config->get_at(opt_key, opt_index); - return get_config_value(*m_config, opt_key, opt_index); - } -} - -boost::any ConfigOptionsGroup::get_config_value(const DynamicConfig& config, const std::string& opt_key, int opt_index /*= -1*/) -{ - size_t idx = opt_index == -1 ? 0 : opt_index; - - boost::any ret; - wxString text_value = wxString(""); - const ConfigOptionDef* opt = config.def()->get(opt_key); - - if (opt->nullable) - { - switch (opt->type) - { - case coPercents: - case coFloats: { - if (config.option(opt_key)->is_nil()) - ret = _(L("N/A")); - else { - double val = opt->type == coFloats ? - config.option(opt_key)->get_at(idx) : - config.option(opt_key)->get_at(idx); - ret = double_to_string(val, opt->precision); } - } - break; - case coFloatsOrPercents: { - if (config.option(opt_key)->is_nil()) - ret = _(L("N/A")); - else { - FloatOrPercent float_percent = config.option(opt_key)->get_at(idx); - text_value = double_to_string(float_percent.value, opt->precision); - if (float_percent.percent) - text_value += "%"; - ret = text_value; - } - } - break; - case coBools: - ret = config.option(opt_key)->values[idx]; - break; - case coInts: - ret = config.option(opt_key)->get_at(idx); - break; - case coPoints: - default: - break; - } - return ret; - } - - switch (opt->type) { - case coFloatOrPercent:{ - const auto &value = *config.option(opt_key); - - text_value = double_to_string(value.value, opt->precision); - if (value.percent) - text_value += "%"; - - ret = text_value; - break; - } - case coFloatsOrPercents:{ - const ConfigOptionFloatsOrPercents &value = *config.option(opt_key); - - text_value = double_to_string(value.get_at(idx).value, opt->precision); - if (value.get_at(idx).percent) - text_value += "%"; - - ret = text_value; - break; - } - case coPercent:{ - double val = config.option(opt_key)->value; - text_value = double_to_string(val, opt->precision); - ret = text_value; - } - break; - case coPercents: - case coFloats: - case coFloat:{ - double val = opt->type == coFloats ? - config.opt_float(opt_key, idx) : - opt->type == coFloat ? config.opt_float(opt_key) : - config.option(opt_key)->get_at(idx); - ret = double_to_string(val, opt->precision); - } - break; - case coString: - ret = from_u8(config.opt_string(opt_key)); - break; - case coStrings: - if (opt_key == "compatible_printers" || opt_key == "compatible_prints" || opt_key == "gcode_substitutions") { - ret = config.option(opt_key)->values; - break; - } - if (opt_key == "filament_ramming_parameters") { - ret = config.opt_string(opt_key, static_cast(idx)); - break; - } - if (config.option(opt_key)->values.empty()) - ret = text_value; - else if (opt->gui_flags == "serialized") { - std::vector values = config.option(opt_key)->values; - if (!values.empty() && !values[0].empty()) - for (auto el : values) - text_value += el + ";"; - ret = text_value; - } - else - ret = from_u8(config.opt_string(opt_key, static_cast(idx))); - break; - case coBool: - ret = config.opt_bool(opt_key); - break; - case coBools: - ret = config.opt_bool(opt_key, idx); - break; - case coInt: - ret = config.opt_int(opt_key); - break; - case coInts: - ret = config.opt_int(opt_key, idx); - break; - case coEnum: - ret = config.option(opt_key)->get_int(); - break; - case coPoint: - ret = config.option(opt_key)->value; - break; - case coPoints: - if (opt_key == "bed_shape") - ret = config.option(opt_key)->values; - else - ret = config.option(opt_key)->get_at(idx); - break; - case coNone: - default: - break; - } - return ret; -} - Field* ConfigOptionsGroup::get_fieldc(const t_config_option_key& opt_key, int opt_index) { Field* field = get_field(opt_key); @@ -1155,7 +1005,7 @@ std::pair ConfigOptionsGroup::get_custom_ctrl_with_blinki void ConfigOptionsGroup::change_opt_value(const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/) { - Slic3r::GUI::change_opt_value(const_cast(*m_config), opt_key, value, opt_index); + const_cast(*m_config).option(opt_key)->set_any(value, opt_index); if (m_modelconfig) m_modelconfig->touch(); } diff --git a/src/slic3r/GUI/OptionsGroup.hpp b/src/slic3r/GUI/OptionsGroup.hpp index 7eca3b9231e..b40440d4ab2 100644 --- a/src/slic3r/GUI/OptionsGroup.hpp +++ b/src/slic3r/GUI/OptionsGroup.hpp @@ -157,7 +157,7 @@ class OptionsGroup { } bool set_value(const t_config_option_key& id, const boost::any& value, bool change_event = false) { if (m_fields.find(id) == m_fields.end()) return false; - m_fields.at(id)->set_value(value, change_event); + m_fields.at(id)->set_any_value(value, change_event); return true; } boost::any get_value(const t_config_option_key& id) { @@ -309,9 +309,6 @@ class ConfigOptionsGroup: public OptionsGroup { void msw_rescale(); void sys_color_changed(); void refresh(); - boost::any config_value(const std::string& opt_key, int opt_index, bool deserialize); - // return option value from config - boost::any get_config_value(const DynamicConfig& config, const std::string& opt_key, int opt_index = -1); Field* get_fieldc(const t_config_option_key& opt_key, int opt_index); std::pair get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index/* = -1*/); diff --git a/src/slic3r/GUI/PhysicalPrinterDialog.cpp b/src/slic3r/GUI/PhysicalPrinterDialog.cpp index 42cc6b2d163..7ca307ff9da 100644 --- a/src/slic3r/GUI/PhysicalPrinterDialog.cpp +++ b/src/slic3r/GUI/PhysicalPrinterDialog.cpp @@ -307,10 +307,10 @@ void PhysicalPrinterDialog::update_printers() boost::any any_string_type = std::string(""); auto value_idx = std::find(slugs.begin(), slugs.end(), m_config->opt("printhost_port")->value); if ((val.empty() || (any_string_type.type() == val.type() && boost::any_cast(val) == "")) && !slugs.empty() && value_idx == slugs.end()) { - change_opt_value(*m_config, "printhost_port", slugs[0]); - choice->set_value(slugs[0], false); + m_config->option("printhost_port")->set_any(slugs[0]); // change_opt_value(*m_config, "printhost_port", slugs[0]); + choice->set_text_value(slugs[0], false); } else if (value_idx != slugs.end()) { - choice->set_value(m_config->option("printhost_port")->value, false); + choice->set_any_value(m_config->option("printhost_port")->get_any(), false); } rs->enable(); } @@ -325,7 +325,7 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr if(opt_key == "printhost_client_cert_enabled") this->m_show_cert_fields = boost::any_cast(value); if (!this->m_show_cert_fields && !m_config->opt_string("printhost_client_cert").empty()) { - change_opt_value(*m_config, "printhost_client_cert", std::string("")); + m_config->option("printhost_client_cert")->set_any(std::string("")); //change_opt_value(*m_config, "printhost_client_cert", std::string("")); //change_opt_value(*m_config, "printhost_client_cert_password", ""); m_config->set_deserialize_strict("printhost_client_cert_password", ""); } @@ -683,7 +683,7 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change) Field* ht = m_optgroup->get_field("host_type"); Choice* choice = dynamic_cast(ht); auto set_to_choice_and_config = [this, choice](PrintHostType type) { - choice->set_value(static_cast(type)); + choice->set_any_value(static_cast(type)); m_config->set_key_value("host_type", new ConfigOptionEnum(type)); }; if ((printer_change && all_presets_are_from_mk3_family) || (!had_all_mk3 && all_presets_are_from_mk3_family)) @@ -691,7 +691,7 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change) else if ((printer_change && !all_presets_are_from_mk3_family) || (!all_presets_are_from_mk3_family && m_config->option>("host_type")->value == htPrusaLink)) set_to_choice_and_config(htOctoPrint); else - choice->set_value(m_config->option("host_type")->get_int()); + choice->set_any_value(m_config->option("host_type")->get_int()); had_all_mk3 = all_presets_are_from_mk3_family; } diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index ee0eb2c2f10..043fc282cc4 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -658,7 +658,7 @@ void PreferencesDialog::build(size_t selected_tab) if (is_editor) { // set Field for notify_release to its value to activate the object boost::any val = s_keys_map_NotifyReleaseMode.at(app_config->get("notify_release")); - m_optgroups_gui.back()->get_field("notify_release")->set_value(val, false); + m_optgroups_gui.back()->get_field("notify_release")->set_any_value(val, false); } //create layout options diff --git a/src/slic3r/GUI/ScriptExecutor.cpp b/src/slic3r/GUI/ScriptExecutor.cpp index 8cb1ca6299e..923d1a50dad 100644 --- a/src/slic3r/GUI/ScriptExecutor.cpp +++ b/src/slic3r/GUI/ScriptExecutor.cpp @@ -788,33 +788,35 @@ void ScriptContainer::call_script_function_set(const ConfigOptionDef& def, const ctx->Prepare(func); std::string str_arg; switch (def.type) { - case coBool: - case coBools: ctx->SetArgByte(0, boost::any_cast(value)); break; + case coBools: ctx->SetArgByte(0, boost::any_cast(value)); break; + case coBool: ctx->SetArgByte(0, boost::any_cast(value)); break; case coInt: - case coInts: ctx->SetArgDWord(0, boost::any_cast(value)); break; + case coInts: ctx->SetArgDWord(0, boost::any_cast(value)); break; case coPercent: case coPercents: case coFloat: case coFloats: ctx->SetArgFloat(0, (float)boost::any_cast(value)); break; case coFloatOrPercent: case coFloatsOrPercents: { - std::string flOrPercent = boost::any_cast(value); - float val = 0; - bool is_percent = false; - if (flOrPercent[flOrPercent.size() - 1] == '%') { - flOrPercent = flOrPercent.substr(0, flOrPercent.size() - 1); - val = std::stof(flOrPercent); - is_percent = true; - } else { - val = std::stof(flOrPercent); - } - ctx->SetArgDWord(0, boost::any_cast((float)val)); - ctx->SetArgByte(1, boost::any_cast(is_percent)); + FloatOrPercent fl_percent = boost::any_cast(value); + ctx->SetArgDWord(0, boost::any_cast((float) fl_percent.value)); + ctx->SetArgByte(1, boost::any_cast(fl_percent.percent)); break; } case coPoint: - case coPoints: { ctx->SetArgFloat(0, (float)boost::any_cast(value)); ctx->SetArgFloat(1, (float)boost::any_cast(value)); break; } //FIXME - case coPoint3: { ctx->SetArgFloat(0, (float)boost::any_cast(value)); ctx->SetArgFloat(1, (float)boost::any_cast(value)); ctx->SetArgFloat(2, (float)boost::any_cast(value)); break; } + case coPoints: { + Vec2d vec = boost::any_cast(value); + ctx->SetArgFloat(0, (float) vec.x()); + ctx->SetArgFloat(1, (float) vec.y()); + break; + } + case coPoint3: { + Vec3d vec = boost::any_cast(value); + ctx->SetArgFloat(0, (float) vec.x()); + ctx->SetArgFloat(1, (float) vec.y()); + ctx->SetArgFloat(2, (float) vec.z()); + break; + } case coString: case coStrings: { str_arg = boost::any_cast(value); @@ -875,7 +877,7 @@ void ScriptContainer::call_script_function_set(const ConfigOptionDef& def, const if (m_need_refresh && m_tab) { Field* f = m_tab->get_field(def.opt_key); if (f != nullptr) { - f->set_value(call_script_function_get_value(def), false); + f->set_any_value(call_script_function_get_value(def), false); } } } @@ -930,7 +932,7 @@ bool ScriptContainer::call_script_function_reset(const ConfigOptionDef& def) if (m_need_refresh && m_tab) { Field* f = m_tab->get_field(def.opt_key); if (f != nullptr) { - f->set_value(call_script_function_get_value(def), false); + f->set_any_value(call_script_function_get_value(def), false); } } return true; @@ -1028,55 +1030,71 @@ boost::any ScriptContainer::call_script_function_get_value(const ConfigOptionDef int res = ctx->Execute(); int32_t ret_int; float ret_float; - boost::any field_val; boost::any opt_val; switch (def.type) { case coBool: - case coBools: { ret_int = ctx->GetReturnDWord(); field_val = uint8_t(ret_int < 0 ? 2 : ret_int); opt_val = uint8_t((ret_int > 0)?1:0); break; } //CheckBox + case coBools: { + ret_int = ctx->GetReturnDWord(); + opt_val = uint8_t(ret_int < 0 ? 2 : ret_int); + break; + } case coInt: - case coInts: { ret_int = ctx->GetReturnDWord(); field_val = int32_t(ret_int); opt_val = int(ret_int); break; } //SpinCtrl + case coInts: { + ret_int = ctx->GetReturnDWord(); + opt_val = int32_t(ret_int); + break; + } // SpinCtrl case coString: - case coStrings: { field_val = from_u8(ret_str); opt_val = ret_str; break; } //TextCtrl + case coStrings: { + opt_val = ret_str; + break; + } // TextCtrl case coPercent: - case coPercents: ret_percent = true; + case coPercents: case coFloat: - case coFloats: opt_val = double(ctx->GetReturnFloat()); + case coFloats: { + opt_val = double(ctx->GetReturnFloat()); + break; + } case coFloatOrPercent: case coFloatsOrPercents: { ret_float = ctx->GetReturnFloat(); - wxString ret_wstring = double_to_string(ret_float); - if (ret_percent) - ret_wstring += '%'; - field_val = ret_wstring; //TextCtrl - if (opt_val.empty()) { opt_val = ret_wstring.ToStdString(); } + opt_val = FloatOrPercent{ret_float, ret_percent}; break; } case coPoint: - case coPoints: { ret_float = ctx->GetReturnFloat(); field_val = Vec2d{ ret_float, ret_float }; opt_val = double(ctx->GetReturnFloat()); break; } //FIXME PointCtrl - case coPoint3: { ret_float = ctx->GetReturnFloat(); field_val = Vec3d{ ret_float, ret_float, ret_float }; opt_val = double(ctx->GetReturnFloat()); break; } + case coPoints: { + double pt_x = ctx->GetReturnFloat(); + opt_val = Vec2d{pt_x, pt_x}; // FIXME + break; + } // FIXME PointCtrl + case coPoint3: { + double pt_x = ctx->GetReturnFloat(); + opt_val = Vec3d{pt_x, pt_x, pt_x}; + break; + } case coEnum: { ret_int = ctx->GetReturnDWord(); if (ret_int >= 0 && ret_int < def.enum_values.size()) { - field_val = int32_t(ret_int); + opt_val = int32_t(ret_int); } else { - field_val = int32_t(0); + opt_val = int32_t(0); for (size_t i = 0; i < def.enum_values.size(); i++) { if (ret_str == def.enum_values[i]) - field_val = int32_t(i); + opt_val = int32_t(i); } } - opt_val = field_val; break; //Choice } } if (m_need_refresh) { refresh(def, opt_val); } - if (field_val.empty()) { + if (opt_val.empty()) { std::cout << "Error nullptr for script\n"; } - return field_val; + return opt_val; } void ScriptContainer::refresh(const ConfigOptionDef& def, boost::any value) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 91161f3b9d6..2f93b90e0f2 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1253,7 +1253,8 @@ void Tab::toggle_option(const std::string& opt_key, bool toggle, int opt_index/* // and value can be some random value because in this case it will not been used void Tab::load_key_value(const std::string& opt_key, const boost::any& value, bool saved_value /*= false*/) { - if (!saved_value) change_opt_value(*m_config, opt_key, value); + if (!saved_value) + m_config->option(opt_key)->set_any(value, -1); // change_opt_value(*m_config, opt_key, value); // Mark the print & filament enabled if they are compatible with the currently selected preset. if (opt_key == "compatible_printers" || opt_key == "compatible_prints") { // Don't select another profile if this profile happens to become incompatible. @@ -1310,7 +1311,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) if (field) { boost::any script_val = this->m_script_exec.call_script_function_get_value(field->m_opt); if (!script_val.empty()) - field->set_value(script_val, false); + field->set_any_value(script_val, false); } } { // also check freq changed params @@ -1318,7 +1319,7 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) if (field) { boost::any script_val = this->m_script_exec.call_script_function_get_value(field->m_opt); if (!script_val.empty()) - field->set_value(script_val, false); + field->set_any_value(script_val, false); } } } @@ -1328,8 +1329,8 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value) // update unscripted freq params Field* field = og_freq_chng_params->get_field(opt_key); if (field) { - boost::any val = og_freq_chng_params->get_config_value(*m_config, opt_key); - field->set_value(val, false); + boost::any val = m_config->option(opt_key)->get_any(field->m_opt_idx); + field->set_any_value(val, false); } @@ -2800,11 +2801,11 @@ PageShp TabFilament::create_filament_overrides_page() { Line line {"",""}; if (opt_key == "filament_retract_lift_above" || opt_key == "filament_retract_lift_below") { - Option opt = optgroup->get_option_and_register(opt_key); + Option opt = optgroup->get_option_and_register(opt_key, 0); opt.opt.label = opt.opt.get_full_label(); line = optgroup->create_single_option_line(opt); } else { - line = optgroup->create_single_option_line(optgroup->get_option_and_register(opt_key)); + line = optgroup->create_single_option_line(optgroup->get_option_and_register(opt_key, 0)); } line.near_label_widget = [this, optgroup, opt_key, opt_index](wxWindow* parent) { From ae513e30e44e444bde30a37c5d4b4c741e44fc2a Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 27 Dec 2023 04:19:33 +0100 Subject: [PATCH 08/19] tab::m_config is protected --- src/slic3r/GUI/Tab.cpp | 2 +- src/slic3r/GUI/Tab.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 2f93b90e0f2..2ad295c03d9 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -820,7 +820,7 @@ void Tab::init_options_list() template void add_correct_opts_to_options_list(const std::string &opt_key, std::map& map, Tab *tab, const int& value) { - T *opt_cur = static_cast(tab->m_config->option(opt_key)); + T *opt_cur = static_cast(tab->get_config()->option(opt_key)); for (size_t i = 0; i < opt_cur->values.size(); i++) map.emplace(opt_key + "#" + std::to_string(i), value); } diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index b3a941af049..739c31f02dc 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -359,11 +359,11 @@ class Tab: public wxPanel bool m_page_switch_running = false; bool m_page_switch_planned = false; + DynamicPrintConfig* m_config; public: PresetBundle* m_preset_bundle; bool m_show_btn_incompatible_presets = false; PresetCollection* m_presets = nullptr; - DynamicPrintConfig* m_config; ogStaticText* m_parent_preset_description_line = nullptr; ScalableButton* m_detach_preset_btn = nullptr; From 23c861fa4aed72e67cf227b9d1481d4acda4f5eb Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 26 Dec 2023 18:12:37 +0100 Subject: [PATCH 09/19] creality thumbnail compatibility (jpg without tag) supermerill/SuperSlicer#3989 --- resources/ui_layout/default/printer_fff.ui | 1 + resources/ui_layout/default/printer_sla.ui | 1 + resources/ui_layout/example/printer_fff.ui | 1 + resources/ui_layout/example/printer_sla.ui | 1 + src/libslic3r/GCode.cpp | 8 ++++++-- src/libslic3r/GCode/Thumbnails.cpp | 2 +- src/libslic3r/GCode/Thumbnails.hpp | 20 ++++++++++++++++---- src/libslic3r/Preset.cpp | 2 ++ src/libslic3r/Print.cpp | 1 + src/libslic3r/PrintConfig.cpp | 15 ++++++++++++++- src/libslic3r/PrintConfig.hpp | 2 ++ src/libslic3r/SLAPrint.cpp | 1 + 12 files changed, 47 insertions(+), 8 deletions(-) diff --git a/resources/ui_layout/default/printer_fff.ui b/resources/ui_layout/default/printer_fff.ui index f7d8c48deae..36a9a8142d9 100644 --- a/resources/ui_layout/default/printer_fff.ui +++ b/resources/ui_layout/default/printer_fff.ui @@ -57,6 +57,7 @@ group:Thumbnails line:Thumbnail options setting:thumbnails_format setting:thumbnails_with_bed + setting:thumbnails_tag_format setting:thumbnails_end_file end_line group:Advanced diff --git a/resources/ui_layout/default/printer_sla.ui b/resources/ui_layout/default/printer_sla.ui index 6116f0e7b8f..a1e4566b090 100644 --- a/resources/ui_layout/default/printer_sla.ui +++ b/resources/ui_layout/default/printer_sla.ui @@ -53,6 +53,7 @@ group:Thumbnails line:Options setting:thumbnails_with_bed setting:thumbnails_with_support + setting:thumbnails_tag_format end_line group:Print Host upload build_printhost diff --git a/resources/ui_layout/example/printer_fff.ui b/resources/ui_layout/example/printer_fff.ui index 5c016f12231..497cc5659dd 100644 --- a/resources/ui_layout/example/printer_fff.ui +++ b/resources/ui_layout/example/printer_fff.ui @@ -56,6 +56,7 @@ group:Thumbnails line:Thumbnail options setting:thumbnails_format setting:thumbnails_with_bed + setting:thumbnails_tag_format setting:thumbnails_end_file end_line group:Advanced diff --git a/resources/ui_layout/example/printer_sla.ui b/resources/ui_layout/example/printer_sla.ui index 0619cdc1067..6c4b5814fe7 100644 --- a/resources/ui_layout/example/printer_sla.ui +++ b/resources/ui_layout/example/printer_sla.ui @@ -52,6 +52,7 @@ group:Thumbnails line:Options setting:thumbnails_with_bed setting:thumbnails_with_support + setting:thumbnails_tag_format end_line group:Print Host upload build_printhost diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index dd3fdefcedd..26ca933f63f 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1377,13 +1377,15 @@ void GCode::_do_export(Print& print_mod, GCodeOutputStream &file, ThumbnailsGene const ConfigOptionBool* thumbnails_end_file = print.full_print_config().option("thumbnails_end_file"); if(!thumbnails_end_file || !thumbnails_end_file->value) { const ConfigOptionBool* thumbnails_with_bed = print.full_print_config().option("thumbnails_with_bed"); + const ConfigOptionBool* thumbnails_tag_with_format = print.full_print_config().option("thumbnails_tag_format"); const ConfigOptionEnum* thumbnails_format = print.full_print_config().option>("thumbnails_format"); // Unit tests or command line slicing may not define "thumbnails" or "thumbnails_format". // If "thumbnails_format" is not defined, export to PNG. GCodeThumbnails::export_thumbnails_to_file(thumbnail_cb, print.full_print_config().option("thumbnails")->values, - thumbnails_with_bed == nullptr ? false : thumbnails_with_bed->value, + thumbnails_with_bed ? thumbnails_with_bed->value : false, thumbnails_format ? thumbnails_format->value : GCodeThumbnailsFormat::PNG, + thumbnails_tag_with_format ? thumbnails_tag_with_format->value : false, [&file](const char* sz) { file.write(sz); }, [&print]() { print.throw_if_canceled(); }); } @@ -2085,13 +2087,15 @@ void GCode::_do_export(Print& print_mod, GCodeOutputStream &file, ThumbnailsGene //print thumbnails at the end instead of the start if requested if (thumbnails_end_file && thumbnails_end_file->value) { const ConfigOptionBool* thumbnails_with_bed = print.full_print_config().option("thumbnails_with_bed"); + const ConfigOptionBool* thumbnails_tag_with_format = print.full_print_config().option("thumbnails_tag_format"); const ConfigOptionEnum* thumbnails_format = print.full_print_config().option>("thumbnails_format"); // Unit tests or command line slicing may not define "thumbnails" or "thumbnails_format". // If "thumbnails_format" is not defined, export to PNG. GCodeThumbnails::export_thumbnails_to_file(thumbnail_cb, print.full_print_config().option("thumbnails")->values, - thumbnails_with_bed==nullptr? false:thumbnails_with_bed->value, + thumbnails_with_bed ? thumbnails_with_bed->value : false, thumbnails_format ? thumbnails_format->value : GCodeThumbnailsFormat::PNG, + thumbnails_tag_with_format ? thumbnails_tag_with_format->value: false, [&file](const char* sz) { file.write(sz); }, [&print]() { print.throw_if_canceled(); }); } diff --git a/src/libslic3r/GCode/Thumbnails.cpp b/src/libslic3r/GCode/Thumbnails.cpp index 02b5e4f02d4..cfdcfff016e 100644 --- a/src/libslic3r/GCode/Thumbnails.cpp +++ b/src/libslic3r/GCode/Thumbnails.cpp @@ -12,7 +12,7 @@ using namespace std::literals; struct CompressedPNG : CompressedImageBuffer { ~CompressedPNG() override { if (data) mz_free(data); } - std::string_view tag() const override { return "thumbnail"sv; } + std::string_view tag() const override { return "thumbnail_PNG"sv; } }; struct CompressedJPG : CompressedImageBuffer diff --git a/src/libslic3r/GCode/Thumbnails.hpp b/src/libslic3r/GCode/Thumbnails.hpp index 45565d0647c..2b04415c9eb 100644 --- a/src/libslic3r/GCode/Thumbnails.hpp +++ b/src/libslic3r/GCode/Thumbnails.hpp @@ -13,6 +13,8 @@ namespace Slic3r::GCodeThumbnails { +constexpr std::string_view EMPTY_TAG = "thumbnail"; + struct CompressedImageBuffer { void *data { nullptr }; @@ -24,7 +26,13 @@ struct CompressedImageBuffer std::unique_ptr compress_thumbnail(const ThumbnailData &data, GCodeThumbnailsFormat format); template -inline void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, const std::vector &sizes, bool with_bed, GCodeThumbnailsFormat format, WriteToOutput output, ThrowIfCanceledCallback throw_if_canceled) +inline void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, + const std::vector & sizes, + bool with_bed, + GCodeThumbnailsFormat format, + bool with_tag_format, + WriteToOutput output, + ThrowIfCanceledCallback throw_if_canceled) { // Write thumbnails using base64 encoding if (thumbnail_cb != nullptr) { @@ -43,7 +51,9 @@ inline void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, auto compressed = compress_thumbnail(data, format); if (compressed->data && compressed->size) { if (format == GCodeThumbnailsFormat::BIQU) { - output((boost::format("\n;\n; %s begin %dx%d %d\n") % compressed->tag() % data.width % data.height % (compressed->size - 1)).str().c_str()); + output((boost::format("\n;\n; %s begin %dx%d %d\n") + % (with_tag_format ? compressed->tag() : EMPTY_TAG) + % data.width % data.height % (compressed->size - 1)).str().c_str()); //print size in hex std::stringstream ss; ss << std::setfill('0') << std::hex; @@ -60,7 +70,9 @@ inline void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, encoded.resize(boost::beast::detail::base64::encoded_size(compressed->size)); encoded.resize(boost::beast::detail::base64::encode((void*)encoded.data(), (const void*)compressed->data, compressed->size)); - output((boost::format("\n;\n; %s begin %dx%d %d\n") % compressed->tag() % data.width % data.height % encoded.size()).str().c_str()); + output((boost::format("\n;\n; %s begin %dx%d %d\n") + % (with_tag_format ? compressed->tag() : EMPTY_TAG) + % data.width % data.height % encoded.size()).str().c_str()); while (encoded.size() > max_row_length) { output((boost::format("; %s\n") % encoded.substr(0, max_row_length)).str().c_str()); encoded = encoded.substr(max_row_length); @@ -69,7 +81,7 @@ inline void export_thumbnails_to_file(ThumbnailsGeneratorCallback &thumbnail_cb, if (encoded.size() > 0) output((boost::format("; %s\n") % encoded).str().c_str()); } - output((boost::format("; %s end\n;\n") % compressed->tag()).str().c_str()); + output((boost::format("; %s end\n;\n") % (with_tag_format ? compressed->tag() : EMPTY_TAG)).str().c_str()); } throw_if_canceled(); } diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index df9e639bc84..62f53fd6727 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -849,6 +849,7 @@ static std::vector s_Preset_printer_options { "thumbnails_custom_color", "thumbnails_end_file", "thumbnails_format", + "thumbnails_tag_format", "thumbnails_with_bed", "wipe_advanced", "wipe_advanced_nozzle_melted_volume", @@ -960,6 +961,7 @@ static std::vector s_Preset_sla_printer_options { "thumbnails_color", "thumbnails_custom_color", "thumbnails_with_bed", + "thumbnails_tag_format", "thumbnails_with_support", }; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 75e588ede42..dbc6f89f469 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -187,6 +187,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver& /* ne "thumbnails_custom_color", "thumbnails_end_file", "thumbnails_format", + "thumbnails_tag_format", "thumbnails_with_bed", "time_estimation_compensation", "time_cost", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index c47b72aba5e..49e58f6ba8b 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -293,7 +293,7 @@ static const t_config_enum_values s_keys_map_GCodeThumbnailsFormat = { { "PNG", int(GCodeThumbnailsFormat::PNG) }, { "JPG", int(GCodeThumbnailsFormat::JPG) }, { "QOI", int(GCodeThumbnailsFormat::QOI) }, - { "BIQU", int(GCodeThumbnailsFormat::BIQU) } + { "BIQU",int(GCodeThumbnailsFormat::BIQU) }, }; CONFIG_OPTION_ENUM_DEFINE_STATIC_MAPS(GCodeThumbnailsFormat) @@ -422,6 +422,13 @@ void PrintConfigDef::init_common_params() def->enum_labels.push_back("Biqu"); def->set_default_value(new ConfigOptionEnum(GCodeThumbnailsFormat::PNG)); + def = this->add("thumbnails_tag_format", coBool); + def->label = L("Write the thumbnail type in gcode."); + def->tooltip = L("instead of writing 'thumbnails' as tag in the gcode, it will write 'thumbnails_PNG', thumbnails_JPG', 'thumbnail_QOI', etc.." + "\n Some firmware needs it to know how to decode the thumbnail, some others don't support it."); + def->mode = comExpert | comSuSi; + def->set_default_value(new ConfigOptionBool(false)); + def = this->add("thumbnails_with_support", coBool); def->label = L("Support on thumbnail"); def->tooltip = L("Show the supports (and pads) on the thumbnail picture."); @@ -7756,6 +7763,11 @@ std::map PrintConfigDef::from_prusa(t_config_option_key if (value != "1") output["default_fan_speed"] = "0"; } + if ("thumbnails_format" == opt_key) { + // by default, no thumbnails_tag_format for png output + if (value == "PNG") + output["thumbnails_tag_format"] = "0"; + } return output; } @@ -7989,6 +8001,7 @@ std::unordered_set prusa_export_to_remove_keys = { "thumbnails_color", "thumbnails_custom_color", "thumbnails_end_file", +"thumbnails_tag_format", "thumbnails_with_bed", "thumbnails_with_support", "time_cost", diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 2fd8d4d6150..ed471275f96 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -1237,6 +1237,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionBool, thumbnails_custom_color)) ((ConfigOptionBool, thumbnails_end_file)) ((ConfigOptionEnum, thumbnails_format)) + ((ConfigOptionBool, thumbnails_tag_format)) ((ConfigOptionBool, thumbnails_with_bed)) ((ConfigOptionPercent, time_estimation_compensation)) ((ConfigOptionFloat, time_cost)) @@ -1483,6 +1484,7 @@ PRINT_CONFIG_CLASS_DEFINE( ((ConfigOptionPoints, thumbnails)) ((ConfigOptionString, thumbnails_color)) ((ConfigOptionBool, thumbnails_custom_color)) + ((ConfigOptionBool, thumbnails_tag_format)) ((ConfigOptionBool, thumbnails_with_bed)) ((ConfigOptionBool, thumbnails_with_support)) ((ConfigOptionFloat, z_rotate)) diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index d7b53a4325e..22c2739f532 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -863,6 +863,7 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector Date: Tue, 26 Dec 2023 19:24:55 +0100 Subject: [PATCH 10/19] Search marker: adapt it to bitset. --- src/slic3r/GUI/Search.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/slic3r/GUI/Search.cpp b/src/slic3r/GUI/Search.cpp index 5b81566ecf8..1260d22545c 100644 --- a/src/slic3r/GUI/Search.cpp +++ b/src/slic3r/GUI/Search.cpp @@ -36,21 +36,18 @@ namespace Search { static char marker_by_type(Preset::Type type, PrinterTechnology pt) { - switch(type) { - case Preset::TYPE_FREQUENT_FFF: - case Preset::TYPE_FREQUENT_SLA: - case Preset::TYPE_FFF_PRINT: - case Preset::TYPE_SLA_PRINT: - return ImGui::PrintIconMarker; - case Preset::TYPE_FFF_FILAMENT: + if (Preset::TYPE_FFF_FILAMENT == type) { return ImGui::FilamentIconMarker; - case Preset::TYPE_SLA_MATERIAL: + } else if (Preset::TYPE_SLA_MATERIAL == type) { return ImGui::MaterialIconMarker; - case Preset::TYPE_PRINTER: + } else if ((Preset::TYPE_PRINTER & type) == Preset::TYPE_PRINTER) { return pt == ptSLA ? ImGui::PrinterSlaIconMarker : ImGui::PrinterIconMarker; - default: + } else if ((Preset::TYPE_PRINT1 & type) == Preset::TYPE_PRINT1 || + (Preset::TYPE_FREQUENT & type) == Preset::TYPE_FREQUENT) { return ImGui::PrintIconMarker; - } + } + assert(false); + return ImGui::PrintIconMarker; } std::string Option::opt_key_with_idx() const From 4d2d23f076b6bd8f95960145a5296f6a375227aa Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 26 Dec 2023 19:26:22 +0100 Subject: [PATCH 11/19] Fix cooling slowdown (fix 67b62c28d39395b431a50fc92379d6d6ea02e3b4) supermerill/SuperSlicer#4015 --- src/libslic3r/GCode.cpp | 2 +- src/libslic3r/GCode/CoolingBuffer.cpp | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 26ca933f63f..9eb51456396 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -5440,7 +5440,7 @@ double_t GCode::_compute_speed_mm_per_sec(const ExtrusionPath& path, double spee void GCode::cooldown_marker_init() { - if (!_cooldown_marker_speed[ExtrusionRole::erExternalPerimeter].empty()) { + if (_cooldown_marker_speed[ExtrusionRole::erExternalPerimeter].empty()) { std::string allow_speed_change = ";CM_extrude_speed;_EXTRUDE_SET_SPEED"; //only change speed on external perimeter (and similar) speed if really necessary. std::string maybe_allow_speed_change = ";CM_extrude_speed_external;_EXTRUDE_SET_SPEED_MAYBE"; diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index 07d4e02c467..a52bee44a0c 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -45,6 +45,7 @@ void CoolingBuffer::reset(const Vec3d &position) struct CoolingLine { enum Type : uint32_t { + TYPE_NONE = 0, //first 5 bits are for the extrusiontype (not a flag) TYPE_SET_TOOL = 1 << 7, @@ -401,6 +402,8 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: // Index of an existing CoolingLine of the current adjustment, which holds the feedrate setting command // for a sequence of extrusion moves. size_t active_speed_modifier = size_t(-1); + // type to add to each next G1 (just for adjustable for now) + size_t current_stamp = CoolingLine::TYPE_NONE; for (; *line_start != 0; line_start = line_end) { @@ -460,10 +463,13 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: if (wipe) line.type |= CoolingLine::TYPE_WIPE; if (boost::contains(sline, ";_EXTRUDE_SET_SPEED") && ! wipe) { - line.type |= CoolingLine::TYPE_ADJUSTABLE; active_speed_modifier = adjustment->lines.size(); - if (boost::contains(sline, ";_EXTRUDE_SET_SPEED_MAYBE")) + line.type |= CoolingLine::TYPE_ADJUSTABLE; + current_stamp |= CoolingLine::TYPE_ADJUSTABLE; + if (boost::contains(sline, ";_EXTRUDE_SET_SPEED_MAYBE")) { line.type |= CoolingLine::TYPE_ADJUSTABLE_MAYBE; + current_stamp |= CoolingLine::TYPE_ADJUSTABLE_MAYBE; + } } if ((line.type & CoolingLine::TYPE_G92) == 0) { // G0 or G1. Calculate the duration. @@ -494,6 +500,12 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: line.length = std::abs(dif[3]); } line.feedrate = new_pos[4]; + if (line.feedrate > 0.f && line.length > 0.f) { + assert((line.type & CoolingLine::TYPE_ADJUSTABLE) == 0); + // there can be no active_speed_modifier in custom gcode. + assert(active_speed_modifier != size_t(-1) || current_stamp == CoolingLine::TYPE_NONE); + line.type |= current_stamp; + } assert((line.type & CoolingLine::TYPE_ADJUSTABLE) == 0 || line.feedrate > 0.f); if (line.length > 0) { assert(line.feedrate > 0); @@ -546,6 +558,7 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: } } active_speed_modifier = size_t(-1); + current_stamp = CoolingLine::TYPE_NONE; } else if (boost::starts_with(sline, ";_TOOLCHANGE")) { //not using m_toolchange_prefix anymore because there is no use case for it, there is always a _TOOLCHANGE for when a fan change is needed. int prefix = 13; From 90c1058fa3123e87200582c8b9ce7e75b327a482 Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 26 Dec 2023 19:45:27 +0100 Subject: [PATCH 12/19] Fix slider ticks supermerill/SuperSlicer#3975 --- src/slic3r/GUI/DoubleSlider.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index f3735fc3397..c9fedc22575 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -1108,7 +1108,7 @@ void Control::Ruler::update(wxWindow* win, const std::vector& values, do int pow = -2; int step = 0; - auto end_it = std::find(values.begin() + 1, values.end(), values.front()); + auto end_it = std::find(values.begin() + 2, values.end(), values.front()); while (pow < 3) { for (int istep : {1, 2, 5}) { @@ -1119,11 +1119,11 @@ void Control::Ruler::update(wxWindow* win, const std::vector& values, do break; int tick = val_it - values.begin(); - // find next tick with istep - val *= 2; - val_it = std::lower_bound(values.begin(), end_it, val - epsilon()); - // count of short ticks between ticks - int short_ticks_cnt = val_it == values.end() ? tick : val_it - values.begin() - tick; + // find next tick with istep + val *= 2; + val_it = std::lower_bound(values.begin(), end_it, val - epsilon()); + // count of short ticks between ticks + int short_ticks_cnt = val_it == values.end() ? tick : val_it - values.begin() - tick; if (lround(short_ticks_cnt * scroll_step) > pixels_per_sm) { step = istep; @@ -1156,12 +1156,13 @@ void Control::draw_ruler(wxDC& dc) wxColour old_clr = dc.GetTextForeground(); dc.SetTextForeground(GREY_PEN.GetColour()); - if (m_ruler.long_step < 0) + if (m_ruler.long_step < 0) { for (size_t tick = 1; tick < m_values.size(); tick++) { wxCoord pos = get_position_from_value(tick); draw_ticks_pair(dc, pos, mid, 5); draw_tick_text(dc, wxPoint(mid, pos), tick); - } else { + } + } else { auto draw_short_ticks = [this, mid](wxDC& dc, double& current_tick, int max_tick) { while (current_tick < max_tick) { wxCoord pos = get_position_from_value(lround(current_tick)); From 9e51196d690f72a69c0b4784f277b344205a9596 Mon Sep 17 00:00:00 2001 From: supermerill Date: Tue, 26 Dec 2023 20:38:12 +0100 Subject: [PATCH 13/19] fix config_angle_template name & toogle fix 171a9156c8e267eb4172c82035127c1697b1272a --- src/libslic3r/PrintConfig.cpp | 6 +++--- src/slic3r/GUI/ConfigManipulation.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 49e58f6ba8b..a2a6699cdcd 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2302,9 +2302,9 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert | comSuSi; def->set_default_value(new ConfigOptionFloat(0)); - def = this->add("fill_angle_template", coFloats); - def->label = L("Fill angle pattern"); - def->full_label = L("Fill angle pattern"); + def = this->add("fill_angle_template", coFloats); + def->label = L("Fill angle template"); + def->full_label = L("Fill angle template"); def->category = OptionCategory::infill; def->tooltip = L("This define the succetion of infill angle. When defined, it replaces the fill_angle" ", and there won't be any extra 90° for each layer added, but the fill_angle_increment will still be used." diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 4e7b0e51838..9da3b0a930e 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -427,7 +427,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) "infill_extrusion_spacing", "infill_extrusion_change_odd_layers", "infill_speed" }) toggle_field(el, have_infill || has_solid_infill); - toggle_field("fill_angle", (have_infill || has_solid_infill) && ((ConfigOptionVectorBase*)config->option("fill_angle_template"))->size() != 0); + toggle_field("fill_angle", (have_infill || has_solid_infill) && ((ConfigOptionVectorBase*)config->option("fill_angle_template"))->size() == 0); toggle_field("top_solid_min_thickness", ! has_spiral_vase && has_top_solid_infill); toggle_field("bottom_solid_min_thickness", ! has_spiral_vase && has_bottom_solid_infill); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index d67e6c7c972..63022e01bfd 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2484,6 +2484,7 @@ std::vector Tab::create_pages(std::string setting_type_nam this->m_vector_managers.push_back(manager); manager->set_cb_edited([this]() { update_dirty(); + toggle_options(); wxGetApp().mainframe->on_config_changed(m_config); // invalidate print }); current_line = current_group->create_single_option_line(opt_key); From 3e8996a0ab0f0bc63789e1db175b8cb9f69dc58e Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 27 Dec 2023 14:04:38 +0100 Subject: [PATCH 14/19] only_one_perimeter_top for arachne (& not over bridges from orca) from pr by vovodroid from orca from SuSi supermerill/SuperSlicer#4022 --- src/libslic3r/ClipperUtils.cpp | 116 +++++++++ src/libslic3r/ClipperUtils.hpp | 18 +- src/libslic3r/PerimeterGenerator.cpp | 336 +++++++++++++++++--------- src/libslic3r/PerimeterGenerator.hpp | 8 +- src/libslic3r/PrintConfig.cpp | 3 +- src/slic3r/GUI/ConfigManipulation.cpp | 4 +- 6 files changed, 360 insertions(+), 125 deletions(-) diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp index 9dde9b176ef..2d339c0a104 100644 --- a/src/libslic3r/ClipperUtils.cpp +++ b/src/libslic3r/ClipperUtils.cpp @@ -59,8 +59,124 @@ bool export_clipper_input_polygons_bin(const char *path, const ClipperLib::Paths namespace ClipperUtils { Points EmptyPathsProvider::s_empty_points; Points SinglePathProvider::s_end; + + + // Clip source polygon to be used as a clipping polygon with a bouding box around the source (to be clipped) + // polygon. Useful as an optimization for expensive ClipperLib operations, for example when clipping source + // polygons one by one with a set of polygons covering the whole layer below. + template + inline void clip_clipper_polygon_with_subject_bbox_templ(const PointsType & src, + const BoundingBox &bbox, + PointsType & out) + { + using PointType = typename PointsType::value_type; + out.clear(); + const size_t cnt = src.size(); + if (cnt < 3) + return; + enum class Side { Left = 1, Right = 2, Top = 4, Bottom = 8 }; + auto sides = [bbox](const PointType &p) { + return int(p.x() < bbox.min.x()) * int(Side::Left) + int(p.x() > bbox.max.x()) * int(Side::Right) + + int(p.y() < bbox.min.y()) * int(Side::Bottom) + int(p.y() > bbox.max.y()) * int(Side::Top); + }; + int sides_prev = sides(src.back()); + int sides_this = sides(src.front()); + const size_t last = cnt - 1; + for (size_t i = 0; i < last; ++i) { + int sides_next = sides(src[i + 1]); + if ( // This point is inside. Take it. + sides_this == 0 || + // Either this point is outside and previous or next is inside, or + // the edge possibly cuts corner of the bounding box. + (sides_prev & sides_this & sides_next) == 0) { + out.emplace_back(src[i]); + sides_prev = sides_this; + } else { + // All the three points (this, prev, next) are outside at the same side. + // Ignore this point. + } + sides_this = sides_next; + } + // Never produce just a single point output polygon. + if (!out.empty()) + if (int sides_next = sides(out.front()); + // The last point is inside. Take it. + sides_this == 0 || + // Either this point is outside and previous or next is inside, or + // the edge possibly cuts corner of the bounding box. + (sides_prev & sides_this & sides_next) == 0) + out.emplace_back(src.back()); + } + void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out) + { + clip_clipper_polygon_with_subject_bbox_templ(src, bbox, out); + } + void clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox, ZPoints &out) + { + clip_clipper_polygon_with_subject_bbox_templ(src, bbox, out); + } + template + [[nodiscard]] PointsType clip_clipper_polygon_with_subject_bbox_templ(const PointsType & src, + const BoundingBox &bbox) + { + PointsType out; + clip_clipper_polygon_with_subject_bbox(src, bbox, out); + return out; + } + [[nodiscard]] Points clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox) + { + return clip_clipper_polygon_with_subject_bbox_templ(src, bbox); + } + [[nodiscard]] ZPoints clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox) + { + return clip_clipper_polygon_with_subject_bbox_templ(src, bbox); + } + void clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox, Polygon &out) + { + clip_clipper_polygon_with_subject_bbox(src.points, bbox, out.points); + } + [[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox) + { + Polygon out; + clip_clipper_polygon_with_subject_bbox(src.points, bbox, out.points); + return out; + } + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const Polygons &src, const BoundingBox &bbox) + { + Polygons out; + out.reserve(src.size()); + for (const Polygon &p : src) out.emplace_back(clip_clipper_polygon_with_subject_bbox(p, bbox)); + out.erase(std::remove_if(out.begin(), out.end(), [](const Polygon &polygon) { return polygon.empty(); }), + out.end()); + return out; + } + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon &src, const BoundingBox &bbox) + { + Polygons out; + out.reserve(src.num_contours()); + out.emplace_back(clip_clipper_polygon_with_subject_bbox(src.contour, bbox)); + for (const Polygon &p : src.holes) out.emplace_back(clip_clipper_polygon_with_subject_bbox(p, bbox)); + out.erase(std::remove_if(out.begin(), out.end(), [](const Polygon &polygon) { return polygon.empty(); }), + out.end()); + return out; + } + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons &src, const BoundingBox &bbox) + { + Polygons out; + out.reserve(number_polygons(src)); + for (const ExPolygon &p : src) { + Polygons temp = clip_clipper_polygons_with_subject_bbox(p, bbox); + out.insert(out.end(), temp.begin(), temp.end()); + } + + out.erase(std::remove_if(out.begin(), out.end(), [](const Polygon &polygon) { return polygon.empty(); }), + out.end()); + return out; + } } + + static ExPolygons PolyTreeToExPolygons(ClipperLib::PolyTree &&polytree) { struct Inner { diff --git a/src/libslic3r/ClipperUtils.hpp b/src/libslic3r/ClipperUtils.hpp index 35109821c6b..55a566851f5 100644 --- a/src/libslic3r/ClipperUtils.hpp +++ b/src/libslic3r/ClipperUtils.hpp @@ -297,7 +297,23 @@ namespace ClipperUtils { const SurfacesPtr &m_surfaces; size_t m_size; }; -} + + using ZPoint = Vec3i32; + using ZPoints = std::vector; + + // Clip source polygon to be used as a clipping polygon with a bouding box around the source (to be clipped) polygon. + // Useful as an optimization for expensive ClipperLib operations, for example when clipping source polygons one by + // one with a set of polygons covering the whole layer below. + void clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox, Points &out); + void clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox, ZPoints &out); + [[nodiscard]] Points clip_clipper_polygon_with_subject_bbox(const Points &src, const BoundingBox &bbox); + [[nodiscard]] ZPoints clip_clipper_polygon_with_subject_bbox(const ZPoints &src, const BoundingBox &bbox); + void clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox, Polygon &out); + [[nodiscard]] Polygon clip_clipper_polygon_with_subject_bbox(const Polygon &src, const BoundingBox &bbox); + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const Polygons &src, const BoundingBox &bbox); + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygon &src, const BoundingBox &bbox); + [[nodiscard]] Polygons clip_clipper_polygons_with_subject_bbox(const ExPolygons &src, const BoundingBox &bbox); + } // Perform union of input polygons using the non-zero rule, convert to ExPolygons. ExPolygons ClipperPaths_to_Slic3rExPolygons(const ClipperLib::Paths &input, bool do_union = false); diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index 00771703452..8500e91764b 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -200,10 +200,82 @@ ProcessSurfaceResult PerimeterGenerator::process_arachne(int& loop_number, const } } - Polygons last_p = to_polygons(last); + // only_one_perimeter_top, from orca + std::vector out_shell; + if (loop_number > 0 && this->config->only_one_perimeter_top && !surface.has_mod_bridge() && upper_slices != nullptr) { + // Check if current layer has surfaces that are not covered by upper layer (i.e., top surfaces) + ExPolygons non_top_polygons; + ExPolygons fill_clip; + + //has to set the outer polygon to the centerline of the external perimeter + split_top_surfaces(lower_slices, upper_slices, offset_ex(last, -this->ext_perimeter_spacing/2), result.top_fills, non_top_polygons, result.fill_clip); + + if (result.top_fills.empty()) { + // No top surfaces, no special handling needed + } else { + // First we slice the outer shell + const Polygons last_p = to_polygons(last); + Arachne::WallToolPaths wallToolPaths(last_p, this->get_ext_perimeter_spacing(),this->get_ext_perimeter_width(), + this->get_perimeter_spacing(), this->get_perimeter_width(), 1, coord_t(0), + this->layer->height, *this->object_config, *this->print_config); + out_shell = wallToolPaths.getToolPaths(); + // Make sure infill not overlap with wall + // offset the InnerContour as arachne use bounds and not centerline + result.top_fills = intersection_ex(result.top_fills, offset_ex(wallToolPaths.getInnerContour(), this->ext_perimeter_spacing/2)); + + if (!result.top_fills.empty()) { + // Then get the inner part that needs more walls + // reduce the not-top fill to the bound for arachne (as arachne doesn't use the centerline but the boundary) + // note: you can also diff_ex(offset_ex(result.top_fills, this->perimeter_spacing / 2), wallToolPaths.getInnerContour()); this should have similar results + last = intersection_ex(offset_ex(non_top_polygons, -this->perimeter_spacing / 2), wallToolPaths.getInnerContour()); + //{ + // static int i = 0; + // i++; + // std::stringstream stri; + // stri << this->layer->id() << "_M_" << i << "_only_one_peri" + // << ".svg"; + // SVG svg(stri.str()); + // //svg.draw(to_polylines(old_last), "green"); + // //svg.draw(to_polylines(offset_ex(old_last, -this->ext_perimeter_spacing / 2)), "lime"); + // //svg.draw(to_polylines(old_top), "blue"); + // svg.draw(to_polylines(result.top_fills), "cyan"); + // svg.draw(to_polylines(result.fill_clip), "pink"); + // svg.draw(to_polylines(wallToolPaths.getInnerContour()), "orange"); + // svg.draw(to_polylines(non_top_polygons), "red"); + // svg.draw(to_polylines(last), "brown"); + // svg.Close(); + //} + loop_number = 0; + } else { + // Give up the outer shell because we don't have any meaningful top surface + out_shell.clear(); + } + } + } - Arachne::WallToolPaths wallToolPaths(last_p, this->get_ext_perimeter_spacing(), this->get_ext_perimeter_width(), this->get_perimeter_spacing(), this->get_perimeter_width(), coord_t(loop_number + 1), 0, this->layer->height, *this->object_config, *this->print_config); + const Polygons last_p = to_polygons(last); + Arachne::WallToolPaths wallToolPaths(last_p, this->get_ext_perimeter_spacing(), this->get_ext_perimeter_width(), + this->get_perimeter_spacing(), this->get_perimeter_width(), loop_number + 1, coord_t(0), + this->layer->height, *this->object_config, *this->print_config); std::vector perimeters = wallToolPaths.getToolPaths(); + + // only_one_perimeter_top, from orca + if (!out_shell.empty()) { + // Combine outer shells + size_t inset_offset = 0; + for (auto &p : out_shell) { + for (auto &l : p) { + if (l.inset_idx + 1 > inset_offset) { + inset_offset = l.inset_idx + 1; + } + } + } + for (auto &p : perimeters) { + for (auto &l : p) { l.inset_idx += inset_offset; } + } + perimeters.insert(perimeters.begin(), out_shell.begin(), out_shell.end()); + } + loop_number = int(perimeters.size()) - 1; #ifdef ARACHNE_DEBUG @@ -372,6 +444,143 @@ ProcessSurfaceResult PerimeterGenerator::process_arachne(int& loop_number, const return result; } +void PerimeterGenerator::split_top_surfaces(const ExPolygons *lower_slices, + const ExPolygons *upper_slices, + const ExPolygons &orig_polygons, + ExPolygons & top_fills, + ExPolygons & non_top_polygons, + ExPolygons & fill_clip) +{ + // other perimeters + coord_t perimeter_width = this->perimeter_flow.scaled_width(); + coord_t perimeter_spacing = this->perimeter_flow.scaled_spacing(); + + // external perimeters + coord_t ext_perimeter_width = this->ext_perimeter_flow.scaled_width(); + coord_t ext_perimeter_spacing = this->ext_perimeter_flow.scaled_spacing(); + + double fill_nozzle_diameter = this->solid_infill_flow.nozzle_diameter(); + + bool has_gap_fill = this->config->gap_fill_enabled && + this->object_config->perimeter_generator.value == PerimeterGeneratorType::Classic; + + // split the polygons with top/not_top + // get the offset from solid surface anchor* + const int32_t peri_count = this->config->perimeters.value; + const double max_perimeters_width = unscaled(double(ext_perimeter_width + perimeter_spacing * int(peri_count - int(1)))); + coord_t offset_top_surface = scale_t(config->external_infill_margin.get_abs_value(peri_count == 0 ? 0. : max_perimeters_width)); + // if possible, try to not push the extra perimeters inside the sparse infill + if (offset_top_surface > 0.9 * (peri_count <= 1 ? 0. : (perimeter_spacing * (peri_count - 1)))) + offset_top_surface -= coord_t(0.9 * (peri_count <= 1 ? 0. : (perimeter_spacing * (peri_count - 1)))); + else + offset_top_surface = 0; + // don't takes into account too thin areas + // skip if the exposed area is smaller than "min_width_top_surface" + coordf_t min_width_top_surface = std::max(coordf_t(ext_perimeter_spacing / 2 + 10), + scale_d(this->config->min_width_top_surface.get_abs_value(unscaled(perimeter_width)))); + + Polygons grown_upper_slices; + if (!this->config->only_one_perimeter_top_other_algo.value) { + grown_upper_slices = offset(*upper_slices, min_width_top_surface); + } else { + ExPolygons grown_accumulator; + // make thin upper surfaces disapear with -+offset_top_surface + // do offset2 per island, to avoid big blob merging + // remove polygon too thin (but don't mess with holes) + for (const ExPolygon &expoly_to_grow : *this->upper_slices) { + // only offset the contour, as it can merge holes + Polygons contour = offset2(ExPolygons{ExPolygon{expoly_to_grow.contour}}, -offset_top_surface, + offset_top_surface + min_width_top_surface + + (this->mill_extra_size > SCALED_EPSILON ? (double) mill_extra_size : 0)); + if (!contour.empty()) { + if (expoly_to_grow.holes.empty()) { + for (Polygon &p : contour) grown_accumulator.push_back(ExPolygon{p}); + } else { + Polygons holes = expoly_to_grow.holes; + for (Polygon &h : holes) h.reverse(); + holes = offset(holes, + -min_width_top_surface - + ((this->mill_extra_size > SCALED_EPSILON) ? (double) mill_extra_size : 0)); + for (ExPolygon p : diff_ex(contour, holes)) grown_accumulator.push_back(p); + } + } + } + grown_upper_slices = union_(grown_accumulator); + } + + // get boungding box of last + BoundingBox last_box = get_extents(orig_polygons); + last_box.offset(SCALED_EPSILON); + + // get the Polygons upper the polygon this layer + Polygons upper_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(grown_upper_slices, last_box); + + // set the clip to a virtual "second perimeter" + fill_clip = offset_ex(orig_polygons, -coordf_t(ext_perimeter_spacing)); + // Check whether surface be bridge or not + ExPolygons bridge_checker; + if (lower_slices != nullptr) { + // BBS: get the Polygons below the polygon this layer + Polygons lower_polygons_series_clipped = ClipperUtils::clip_clipper_polygons_with_subject_bbox(*lower_slices, last_box); + coordf_t bridge_offset = std::max(coordf_t(ext_perimeter_spacing), coordf_t(perimeter_width)); + // SoftFever: improve bridging + const coordf_t bridge_margin = scale_d(this->config->bridged_infill_margin.get_abs_value(unscaled(perimeter_width))); + bridge_checker = offset_ex(diff_ex(orig_polygons, lower_polygons_series_clipped, ApplySafetyOffset::Yes), + 1.5 * bridge_offset + bridge_margin + perimeter_spacing / 2); + } + ExPolygons delete_bridge = diff_ex(orig_polygons, bridge_checker, ApplySafetyOffset::Yes); + // get the real top surface + ExPolygons top_polygons; + if (this->mill_extra_size < SCALED_EPSILON) { + top_polygons = diff_ex(delete_bridge, upper_polygons_series_clipped, ApplySafetyOffset::Yes); + } else if (this->unmillable.empty()) { + top_polygons = diff_ex(delete_bridge, offset_ex(upper_polygons_series_clipped, (double) mill_extra_size), ApplySafetyOffset::Yes); + } else { + top_polygons = diff_ex(delete_bridge, + diff_ex(offset_ex(upper_polygons_series_clipped, (double) mill_extra_size), + unmillable, ApplySafetyOffset::Yes)); + } + // save the top area for gap fill, or something. Made by BB/orca, but no comment. + ExPolygons temp_gap = diff_ex(top_polygons, fill_clip); + // get the not-top surface, from the "real top" but enlarged by external_infill_margin (and the + // min_width_top_surface we removed a bit before) + // also remove the ext_perimeter_spacing/2 width because we are faking the external perimeter, and we will remove ext_perimeter_spacing2 + ExPolygons inner_polygons = diff_ex(orig_polygons, + offset_ex(top_polygons, offset_top_surface + min_width_top_surface - double(ext_perimeter_spacing / 2)), + ApplySafetyOffset::Yes); + // get the enlarged top surface, by using inner_polygons instead of upper_slices, and clip it for it to be exactly + // the polygons to fill. + top_polygons = diff_ex(fill_clip, inner_polygons, ApplySafetyOffset::Yes); + // increase by half peri the inner space to fill the frontier between last and stored. + top_fills = union_ex(top_fills, top_polygons); + // set the clip to the external wall but go back inside by infill_extrusion_width/2 to be sure the extrusion won't + // go outside even with a 100% overlap. + double infill_spacing_unscaled = this->config->infill_extrusion_width.get_abs_value(fill_nozzle_diameter); + if (infill_spacing_unscaled == 0) + infill_spacing_unscaled = Flow::auto_extrusion_width(frInfill, fill_nozzle_diameter); + fill_clip = offset_ex(orig_polygons, double(ext_perimeter_spacing / 2) - scale_(infill_spacing_unscaled / 2)); + + non_top_polygons = intersection_ex(inner_polygons, orig_polygons); + // Made by BB/orca, but no comment. Plz test it and report the usefullness. + if (has_gap_fill) + non_top_polygons = union_ex(non_top_polygons, temp_gap); + + //if (!top_fills.empty() && !non_top_polygons.empty()) { + // static int i = 0; + // i++; + // std::stringstream stri; + // stri << this->layer->id() << "_1_" << i << "_only_one_peri" + // << ".svg"; + // SVG svg(stri.str()); + // svg.draw(to_polylines(top_fills), "green"); + // svg.draw(to_polylines(inner_polygons), "yellow"); + // svg.draw(to_polylines(top_polygons), "cyan"); + // svg.draw(to_polylines(orig_polygons), "orange"); + // svg.draw(to_polylines(non_top_polygons), "red"); + // svg.Close(); + //} +} + void PerimeterGenerator::process() { // other perimeters @@ -1219,125 +1428,12 @@ ProcessSurfaceResult PerimeterGenerator::process_classic(int& loop_number, const for(ExPolygon& exp : next_onion) exp.simplify((resolution < SCALED_EPSILON ? SCALED_EPSILON : resolution), &last); - //store surface for top infill if only_one_perimeter_top + // store surface for top infill if only_one_perimeter_top if (perimeter_idx == 0 && (config->only_one_perimeter_top && this->upper_slices != NULL)) { - if (this->config->only_one_perimeter_top_other_algo) { - //split the polygons with top/not_top - //get the offset from solid surface anchor - coord_t offset_top_surface = scale_(config->external_infill_margin.get_abs_value( - config->perimeters.value == 0 ? 0. : unscaled(double(ext_perimeter_width + perimeter_spacing * int(int(config->perimeters.value) - int(1)))))); - // if possible, try to not push the extra perimeters inside the sparse infill - if (offset_top_surface > 0.9 * (config->perimeters.value <= 1 ? 0. : (perimeter_spacing * (config->perimeters.value - 1)))) - offset_top_surface -= coord_t(0.9 * (config->perimeters.value <= 1 ? 0. : (perimeter_spacing * (config->perimeters.value - 1)))); - else offset_top_surface = 0; - //don't takes into account too thin areas - double min_width_top_surface = std::max(double(ext_perimeter_spacing / 2 + 10), scale_d(this->config->min_width_top_surface.get_abs_value(unscaled(perimeter_width)))); - //make thin upper surfaces disapear with -+offset_top_surface - ExPolygons grown_upper_slices; - //do offset2 per island, to avoid big blob merging - //remove polygon too thin (but don't mess with holes) - for (const ExPolygon& expoly_to_grow : *this->upper_slices) { - //only offset the contour, as it can merge holes - Polygons contour = offset2(ExPolygons{ ExPolygon{expoly_to_grow.contour} }, -offset_top_surface, offset_top_surface + min_width_top_surface + (this->mill_extra_size > SCALED_EPSILON ? (double)mill_extra_size : 0)); - if (!contour.empty()) { - if (expoly_to_grow.holes.empty()) { - for (Polygon& p : contour) - grown_upper_slices.push_back(ExPolygon{ p }); - } else { - Polygons holes = expoly_to_grow.holes; - for (Polygon& h : holes) - h.reverse(); - holes = offset(holes, -min_width_top_surface - ((this->mill_extra_size > SCALED_EPSILON) ? (double)mill_extra_size : 0)); - for (ExPolygon p : diff_ex(contour, holes)) - grown_upper_slices.push_back(p); - } - } - } - grown_upper_slices = union_ex(grown_upper_slices); - //set the clip to a virtual "second perimeter" - results.fill_clip = offset_ex(last, -double(ext_perimeter_spacing)); - auto fill_clip_old = results.fill_clip; - // get the real top surface - const ExPolygons top_grown_polygons = (!(this->mill_extra_size > SCALED_EPSILON)) - ? diff_ex(last, grown_upper_slices, ApplySafetyOffset::Yes) - : (unmillable.empty()) - ? diff_ex(last, grown_upper_slices, ApplySafetyOffset::Yes) - : diff_ex(last, diff_ex(grown_upper_slices, unmillable, ApplySafetyOffset::Yes)); - - //get the not-top surface, from the "real top" but enlarged by external_infill_margin (and the min_width_top_surface we removed a bit before) - const ExPolygons inner_polygons = diff_ex(last, - offset_ex(top_grown_polygons, offset_top_surface + min_width_top_surface - //also remove the ext_perimeter_spacing/2 width because we are faking the external periemter, and we will remove ext_perimeter_spacing2 - - double(ext_perimeter_spacing / 2)), ApplySafetyOffset::Yes); - // get the enlarged top surface, by using inner_polygons instead of upper_slices, and clip it for it to be exactly the polygons to fill. - const ExPolygons top_polygons = diff_ex(results.fill_clip, inner_polygons, ApplySafetyOffset::Yes); - // increase by half peri the inner space to fill the frontier between last and stored. - results.top_fills = union_ex(results.top_fills, top_polygons); - //set the clip to the external wall but go back inside by infill_extrusion_width/2 to be sure the extrusion won't go outside even with a 100% overlap. - double infill_spacing_unscaled = this->config->infill_extrusion_width.get_abs_value(this->solid_infill_flow.nozzle_diameter()); - if (infill_spacing_unscaled == 0) infill_spacing_unscaled = Flow::auto_extrusion_width(frInfill, this->solid_infill_flow.nozzle_diameter()); - results.fill_clip = offset_ex(last, double(ext_perimeter_spacing / 2) - scale_d(infill_spacing_unscaled / 2)); - last = intersection_ex(inner_polygons, last); - //{ - // static int isazfn = 0; - // std::stringstream stri; - // stri << this->layer->id() << "_" << perimeter_idx << "_"<< isazfn++ <<"_only_one_peri"<< ".svg"; - // SVG svg(stri.str()); - // svg.draw(to_polylines(oldLast), "orange"); - // svg.draw(to_polylines(fill_clip), "purple"); - // svg.draw(to_polylines(inner_polygons), "yellow"); - // svg.draw(to_polylines(top_polygons), "cyan"); - // svg.draw(to_polylines(last), "red"); - // svg.draw(to_polylines(fill_clip_old), "green"); - // svg.Close(); - //} - } else { - - //split the polygons with top/not_top - //get the offset from solid surface anchor - coord_t offset_top_surface = scale_(config->external_infill_margin.get_abs_value( - config->perimeters.value == 0 ? 0. : unscaled(double(ext_perimeter_width + perimeter_spacing * int(int(config->perimeters.value) - int(1)))))); - // if possible, try to not push the extra perimeters inside the sparse infill - if (offset_top_surface > 0.9 * (config->perimeters.value <= 1 ? 0. : (perimeter_spacing * (config->perimeters.value - 1)))) - offset_top_surface -= coord_t(0.9 * (config->perimeters.value <= 1 ? 0. : (perimeter_spacing * (config->perimeters.value - 1)))); - else offset_top_surface = 0; - //don't takes into account too thin areas - double min_width_top_surface = std::max(double(ext_perimeter_spacing / 2 + 10), scale_d(this->config->min_width_top_surface.get_abs_value(unscaled(perimeter_width)))); - ExPolygons grown_upper_slices = offset_ex(*this->upper_slices, min_width_top_surface); - //set the clip to a virtual "second perimeter" - results.fill_clip = offset_ex(last, -double(ext_perimeter_spacing)); - // get the real top surface - ExPolygons top_polygons = (!(this->mill_extra_size > SCALED_EPSILON)) - ? diff_ex(last, grown_upper_slices, ApplySafetyOffset::Yes) - : (unmillable.empty()) - ? diff_ex(last, offset_ex(grown_upper_slices, (double)mill_extra_size), ApplySafetyOffset::Yes) - : diff_ex(last, diff_ex(offset_ex(grown_upper_slices, (double)mill_extra_size), unmillable, ApplySafetyOffset::Yes)); - - - //get the not-top surface, from the "real top" but enlarged by external_infill_margin (and the min_width_top_surface we removed a bit before) - ExPolygons inner_polygons = diff_ex(last, offset_ex(top_polygons, offset_top_surface + min_width_top_surface - //also remove the ext_perimeter_spacing/2 width because we are faking the external perimeter, and we will remove ext_perimeter_spacing2 - - double(ext_perimeter_spacing / 2)), ApplySafetyOffset::Yes); - // get the enlarged top surface, by using inner_polygons instead of upper_slices, and clip it for it to be exactly the polygons to fill. - top_polygons = diff_ex(results.fill_clip, inner_polygons, ApplySafetyOffset::Yes); - // increase by half peri the inner space to fill the frontier between last and stored. - results.top_fills = union_ex(results.top_fills, top_polygons); - //set the clip to the external wall but go back inside by infill_extrusion_width/2 to be sure the extrusion won't go outside even with a 100% overlap. - results.fill_clip = offset_ex(last, double(ext_perimeter_spacing / 2) - this->config->infill_extrusion_width.get_abs_value(this->solid_infill_flow.nozzle_diameter()) / 2); - //ExPolygons oldLast = last; - last = intersection_ex(inner_polygons, last); - //{ - // std::stringstream stri; - // stri << this->layer->id() << "_1_"<< perimeter_idx <<"_only_one_peri"<< ".svg"; - // SVG svg(stri.str()); - // svg.draw(to_polylines(top_fills), "green"); - // svg.draw(to_polylines(inner_polygons), "yellow"); - // svg.draw(to_polylines(top_polygons), "cyan"); - // svg.draw(to_polylines(oldLast), "orange"); - // svg.draw(to_polylines(last), "red"); - // svg.Close(); - //} - } + ExPolygons next; + split_top_surfaces(this->lower_slices, this->upper_slices, last, results.top_fills, next, + results.fill_clip); + last = next; } } diff --git a/src/libslic3r/PerimeterGenerator.hpp b/src/libslic3r/PerimeterGenerator.hpp index f2c85cbb2b2..192d4691a91 100644 --- a/src/libslic3r/PerimeterGenerator.hpp +++ b/src/libslic3r/PerimeterGenerator.hpp @@ -172,7 +172,13 @@ class PerimeterGenerator { ExtrusionLoop _extrude_and_cut_loop(const PerimeterGeneratorLoop& loop, const Point entryPoint, const Line& direction = Line(Point(0, 0), Point(0, 0)), bool enforce_loop = false) const; // sub-function of _traverse_and_join_loops, find the good splot to cut a loop to be able to join it with an other one PerimeterIntersectionPoint _get_nearest_point(const PerimeterGeneratorLoops &children, ExtrusionLoop &myPolylines, const coord_t dist_cut, const coord_t max_dist) const; - + // for one_peri_on_top + void split_top_surfaces(const ExPolygons *lower_slices, + const ExPolygons *upper_slices, + const ExPolygons &orig_polygons, + ExPolygons & top_fills, + ExPolygons & non_top_polygons, + ExPolygons & fill_clip); }; diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index a2a6699cdcd..50f813b8ded 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1459,7 +1459,8 @@ void PrintConfigDef::init_fff_params() def->label = L("Default"); def->full_label = L("Default infill margin"); def->category = OptionCategory::infill; - def->tooltip = L("This parameter grows the top/bottom/solid layers by the specified mm to anchor them into the sparse infill and support the perimeters above. Put 0 to deactivate it. Can be a % of the width of the perimeters."); + def->tooltip = L("This parameter grows the top/bottom/solid layers by the specified mm to anchor them into the sparse infill and support the perimeters above." + " Put 0 to deactivate it. Can be a % of the width of the perimeters."); def->sidetext = L("mm or %"); def->ratio_over = "perimeter_extrusion_width"; def->min = 0; diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 9da3b0a930e..a0a03ba6de7 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -357,12 +357,12 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) "thin_perimeters", "overhangs_reverse", "perimeter_round_corners"}) toggle_field(el, have_perimeters && !have_arachne); - toggle_field("only_one_perimeter_top", have_perimeters); // with arachne, it will only do it for the last layer + toggle_field("only_one_perimeter_top", have_perimeters); toggle_field("only_one_perimeter_first_layer", config->opt_int("perimeters") > 1); toggle_field("overhangs_width", config->option("overhangs_width_speed")->value > 0); toggle_field("overhangs_reverse_threshold", have_perimeters && config->opt_bool("overhangs_reverse")); toggle_field("overhangs_speed_enforce", have_perimeters && !config->opt_bool("perimeter_loop")); - toggle_field("min_width_top_surface", have_perimeters && config->opt_bool("only_one_perimeter_top") && !have_arachne); + toggle_field("min_width_top_surface", have_perimeters && config->opt_bool("only_one_perimeter_top")); toggle_field("thin_perimeters_all", have_perimeters && config->option("thin_perimeters")->get_float() != 0 && !have_arachne); bool have_thin_wall = !have_arachne && have_perimeters; toggle_field("thin_walls", have_thin_wall); From fce5146fbe342e327589b7ec7b213a7e995443c9 Mon Sep 17 00:00:00 2001 From: supermerill Date: Wed, 27 Dec 2023 20:59:13 +0100 Subject: [PATCH 15/19] fix missing act_bt for filaments --- src/slic3r/GUI/Tab.cpp | 98 ++++++++++++++++++++++++------------------ src/slic3r/GUI/Tab.hpp | 7 ++- 2 files changed, 61 insertions(+), 44 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 63022e01bfd..a6c7b580ed8 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -569,25 +569,27 @@ void Tab::update_label_colours() m_phony_label_clr = wxGetApp().get_label_clr_phony(); //update options "decoration" - for (const std::pair &opt : m_options_list) - { + for (const auto &opt : m_options_list) { + const std::string &opt_key = opt.first; + const int & opt_idx = opt.second.first; + const int & opt_status = opt.second.second; const wxColour *color = &m_sys_label_clr; // value isn't equal to system value - if ((opt.second & osSystemValue) == 0) { + if ((opt_status & osSystemValue) == 0) { // value is equal to last saved - if ((opt.second & osInitValue) != 0) + if ((opt_status & osInitValue) != 0) color = &m_default_label_clr; // value is modified else color = &m_modified_label_clr; } - if ((opt.second & osCurrentPhony) != 0) + if ((opt_status & osCurrentPhony) != 0) color = &m_phony_label_clr; else { - if ((opt.second & osInitPhony) != 0) + if ((opt_status & osInitPhony) != 0) color = &m_modified_label_clr; - else if ((opt.second & osSystemPhony) != 0) + else if ((opt_status & osSystemPhony) != 0) color = &m_default_label_clr; } @@ -631,12 +633,14 @@ void Tab::decorate() { Field* field = nullptr; wxColour* colored_label_clr = nullptr; - + const std::string &opt_key = opt.first; + const int & opt_idx = opt.second.first; + const int & opt_status = opt.second.second; if (OptionsGroup::is_option_without_field(opt.first)) colored_label_clr = (m_colored_Label_colors.find(opt.first) == m_colored_Label_colors.end()) ? nullptr : &m_colored_Label_colors.at(opt.first); if (!colored_label_clr) { - field = get_field(opt.first); + field = get_field(opt_key, opt_idx); if (!field) continue; } @@ -652,18 +656,18 @@ void Tab::decorate() const wxString* tt = &m_tt_value_revert; // value isn't equal to system value - if ((opt.second & osSystemValue) == 0) { + if ((opt_status & osSystemValue) == 0) { is_nonsys_value = true; sys_icon = m_bmp_non_system; sys_tt = m_tt_non_system; // value is equal to last saved - if ((opt.second & osInitValue) != 0) + if ((opt_status & osInitValue) != 0) color = &m_default_label_clr; // value is modified else color = &m_modified_label_clr; } - if ((opt.second & osInitValue) != 0) + if ((opt_status & osInitValue) != 0) { is_modified_value = false; icon = &m_bmp_white_bullet; @@ -671,12 +675,12 @@ void Tab::decorate() } //color for phony things - if ((opt.second & osCurrentPhony) != 0) + if ((opt_status & osCurrentPhony) != 0) color = &m_phony_label_clr; else { - if ((opt.second & osInitPhony) != 0) + if ((opt_status & osInitPhony) != 0) color = &m_modified_label_clr; - else if ((opt.second & osSystemPhony) != 0) + else if ((opt_status & osSystemPhony) != 0) color = &m_default_label_clr; } @@ -714,8 +718,8 @@ void Tab::decorate() for (const std::string &dep : field->m_opt.depends_on) { const auto& it = m_options_list.find(dep); if (it != m_options_list.end()) { - is_not_sys |= ((it->second & osSystemValue) == 0); - is_not_initial |= ((it->second & osInitValue) == 0); + is_not_sys |= ((it->second.second & osSystemValue) == 0); + is_not_initial |= ((it->second.second & osInitValue) == 0); } } @@ -773,7 +777,7 @@ void Tab::update_changed_ui() } for (auto& it : m_options_list) - it.second = m_opt_status_value; + it.second.second = m_opt_status_value; dirty_options.insert(dirty_options.end(), m_options_dirty.begin(), m_options_dirty.end()); m_options_dirty.clear(); @@ -784,21 +788,21 @@ void Tab::update_changed_ui() for (auto& opt_key : m_presets->get_edited_preset().config.keys()) { if (edited_preset.config.option(opt_key)->is_phony()) //ensure that osCurrentPhony is in the bitmask - m_options_list[opt_key] |= osCurrentPhony; + m_options_list[opt_key].second |= osCurrentPhony; if (selected_preset.config.option(opt_key) && selected_preset.config.option(opt_key)->is_phony()) - m_options_list[opt_key] |= osInitPhony; + m_options_list[opt_key].second |= osInitPhony; if (system_preset && system_preset->config.option(opt_key) && system_preset->config.option(opt_key)->is_phony()) - m_options_list[opt_key] |= osSystemPhony; + m_options_list[opt_key].second |= osSystemPhony; } //don't let option that were phony be resetable. for (auto opt_key : dirty_options) - if( (m_options_list[opt_key] & osInitPhony) == 0) + if ((m_options_list[opt_key].second & osInitPhony) == 0) //ensure that osInitValue is not in the bitmask - m_options_list[opt_key] &= ~osInitValue; + m_options_list[opt_key].second &= ~osInitValue; for (auto opt_key : nonsys_options) - if ((m_options_list[opt_key] & osSystemPhony) == 0) - m_options_list[opt_key] &= ~osSystemValue; + if ((m_options_list[opt_key].second & osSystemPhony) == 0) + m_options_list[opt_key].second &= ~osSystemValue; decorate(); @@ -814,15 +818,15 @@ void Tab::init_options_list() m_options_list.clear(); for (const std::string& opt_key : m_config->keys()) - m_options_list.emplace(opt_key, m_opt_status_value); + m_options_list.emplace(opt_key, std::pair(-1, m_opt_status_value)); } template -void add_correct_opts_to_options_list(const std::string &opt_key, std::map& map, Tab *tab, const int& value) +void add_correct_opts_to_options_list(const std::string &opt_key, std::map>& map, Tab *tab, const int& value) { T *opt_cur = static_cast(tab->get_config()->option(opt_key)); for (size_t i = 0; i < opt_cur->values.size(); i++) - map.emplace(opt_key + "#" + std::to_string(i), value); + map.emplace(opt_key /* + "#" + std::to_string(i)*/, std::pair{i, value}); } void TabPrinter::init_options_list() @@ -833,7 +837,7 @@ void TabPrinter::init_options_list() for (const std::string& opt_key : m_config->keys()) { if (opt_key == "bed_shape") { - m_options_list.emplace(opt_key, m_opt_status_value); + m_options_list.emplace(opt_key, std::pair{-1, m_opt_status_value}); continue; } switch (m_config->option(opt_key)->type()) @@ -845,11 +849,11 @@ void TabPrinter::init_options_list() case coPercents:add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; case coFloatsOrPercents:add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; case coPoints: add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; - default: m_options_list.emplace(opt_key, m_opt_status_value); break; + default: m_options_list.emplace(opt_key, std::pair{-1, m_opt_status_value}); break; } } if (m_printer_technology == ptFFF) - m_options_list.emplace("extruders_count", m_opt_status_value); + m_options_list.emplace("extruders_count", std::pair{-1, m_opt_status_value}); } void TabPrinter::msw_rescale() @@ -862,6 +866,15 @@ void TabPrinter::msw_rescale() Layout(); } +void TabFilament::init_options_list() +{ + if (!m_options_list.empty()) + m_options_list.clear(); + + for (const std::string &opt_key : m_config->keys()) + m_options_list.emplace(opt_key, std::pair(0, m_opt_status_value)); +} + void TabSLAMaterial::init_options_list() { if (!m_options_list.empty()) @@ -870,7 +883,7 @@ void TabSLAMaterial::init_options_list() for (const std::string& opt_key : m_config->keys()) { if (opt_key == "compatible_prints" || opt_key == "compatible_printers") { - m_options_list.emplace(opt_key, m_opt_status_value); + m_options_list.emplace(opt_key, std::pair{0, m_opt_status_value}); continue; } switch (m_config->option(opt_key)->type()) @@ -882,7 +895,7 @@ void TabSLAMaterial::init_options_list() case coPercents:add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; case coFloatsOrPercents:add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; case coPoints: add_correct_opts_to_options_list(opt_key, m_options_list, this, m_opt_status_value); break; - default: m_options_list.emplace(opt_key, m_opt_status_value); break; + default: m_options_list.emplace(opt_key, std::pair{0, m_opt_status_value}); break; } } } @@ -893,8 +906,8 @@ void Tab::get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool if (opt == m_options_list.end()) return; - if (sys_page) sys_page = (opt->second & osSystemValue) != 0; - modified_page |= (opt->second & osInitValue) == 0; + if (sys_page) sys_page = (opt->second.second & osSystemValue) != 0; + modified_page |= (opt->second.second & osInitValue) == 0; } void Tab::update_changed_tree_ui() @@ -995,28 +1008,28 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/) for (auto group : m_active_page->m_optgroups) { if (group->title == "Capabilities") { - if ((m_options_list["extruders_count"] & os) == 0) + if ((m_options_list["extruders_count"].second & os) == 0) to_sys ? group->back_to_sys_value("extruders_count") : group->back_to_initial_value("extruders_count"); } if (group->title == "Size and coordinates") { - if ((m_options_list["bed_shape"] & os) == 0) { + if ((m_options_list["bed_shape"].second & os) == 0) { to_sys ? group->back_to_sys_value("bed_shape") : group->back_to_initial_value("bed_shape"); load_key_value("bed_shape", true/*some value*/, true); } } if (group->title == "Toolchange parameters with single extruder MM printers") { - if ((m_options_list["filament_ramming_parameters"] & os) == 0) + if ((m_options_list["filament_ramming_parameters"].second & os) == 0) to_sys ? group->back_to_sys_value("filament_ramming_parameters") : group->back_to_initial_value("filament_ramming_parameters"); } if (group->title == "G-code Substitutions") { - if ((m_options_list["gcode_substitutions"] & os) == 0) { + if ((m_options_list["gcode_substitutions"].second & os) == 0) { to_sys ? group->back_to_sys_value("gcode_substitutions") : group->back_to_initial_value("gcode_substitutions"); load_key_value("gcode_substitutions", true/*some value*/, true); } } if (group->title == "Profile dependencies") { // "compatible_printers" option doesn't exists in Printer Settimgs Tab - if (type() != Preset::TYPE_PRINTER && (m_options_list["compatible_printers"] & os) == 0) { + if (type() != Preset::TYPE_PRINTER && (m_options_list["compatible_printers"].second & os) == 0) { to_sys ? group->back_to_sys_value("compatible_printers") : group->back_to_initial_value("compatible_printers"); load_key_value("compatible_printers", true/*some value*/, true); @@ -1025,7 +1038,8 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/) is_empty ? m_compatible_printers.btn->Disable() : m_compatible_printers.btn->Enable(); } // "compatible_prints" option exists only in Filament Settimgs and Materials Tabs - if ((type() == Preset::TYPE_FFF_FILAMENT || type() == Preset::TYPE_SLA_MATERIAL) && (m_options_list["compatible_prints"] & os) == 0) { + if ((type() == Preset::TYPE_FFF_FILAMENT || type() == Preset::TYPE_SLA_MATERIAL) && + (m_options_list["compatible_prints"].second & os) == 0) { to_sys ? group->back_to_sys_value("compatible_prints") : group->back_to_initial_value("compatible_prints"); load_key_value("compatible_prints", true/*some value*/, true); @@ -1036,7 +1050,7 @@ void Tab::on_roll_back_value(const bool to_sys /*= true*/) } for (const auto &kvp : group->opt_map()) { const std::string& opt_key = kvp.first; - if ((m_options_list[opt_key] & os) == 0) + if ((m_options_list[opt_key].second & os) == 0) to_sys ? group->back_to_sys_value(opt_key) : group->back_to_initial_value(opt_key); } } diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp index 739c31f02dc..c3bf7b6dc16 100644 --- a/src/slic3r/GUI/Tab.hpp +++ b/src/slic3r/GUI/Tab.hpp @@ -321,8 +321,10 @@ class Tab: public wxPanel osInitPhony = 8, osCurrentPhony = 16, }; - std::map m_options_list; - std::map m_options_script; + // map> + std::map> m_options_list; + // map (script can't be vector) + std::map m_options_script; std::vector m_options_dirty; int m_opt_status_value = 0; @@ -550,6 +552,7 @@ class TabFilament : public Tab void toggle_options() override; void update() override; void clear_pages() override; + void init_options_list() override; PrinterTechnology get_printer_technology() const override { return ptFFF; } }; From b2070342e55c4a3361a7a77ad11d0a020bdb2649 Mon Sep 17 00:00:00 2001 From: supermerill Date: Fri, 29 Dec 2023 00:12:34 +0100 Subject: [PATCH 16/19] fix monotonic supermerill/SuperSlicer#3770 --- src/libslic3r/Fill/FillBase.cpp | 7 +++++-- src/libslic3r/Fill/FillRectilinear.cpp | 3 ++- src/libslic3r/Fill/FillRectilinear.hpp | 6 ++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index a6fff4aae49..08daf3c2222 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -211,7 +211,7 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ good_role, used_flow, used_flow.scaled_width() / 8, - true); + !params.monotonic); // compute the path of the nozzle -> extruded volume for (const ExtrusionEntity* entity : entities) { extruded_volume += entity->total_volume(); @@ -219,6 +219,8 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ //append (move so the pointers are reused, and won't need to be deleted) all_new_paths->append(std::move(entities)); } + if(params.monotonic) + all_new_paths->set_can_sort_reverse(false, false); thick_polylines.clear(); @@ -305,7 +307,8 @@ void Fill::fill_surface_extrusion(const Surface *surface, const FillParams ¶ good_role, params.flow.mm3_per_mm()* params.flow_mult * mult_flow, (float)(params.flow.width()* params.flow_mult * mult_flow), - (float)params.flow.height()); + (float)params.flow.height(), + !params.monotonic); } } catch (InfillFailedException&) { } diff --git a/src/libslic3r/Fill/FillRectilinear.cpp b/src/libslic3r/Fill/FillRectilinear.cpp index 74e74a70fe5..b171db95122 100644 --- a/src/libslic3r/Fill/FillRectilinear.cpp +++ b/src/libslic3r/Fill/FillRectilinear.cpp @@ -3532,7 +3532,8 @@ FillRectilinearWGapFill::fill_surface_extrusion(const Surface *surface, const Fi good_role, params.flow.mm3_per_mm() * params.flow_mult * flow_mult_exact_volume, params.flow.width() * params.flow_mult * float(flow_mult_exact_volume), - params.flow.height()); + params.flow.height(), + !is_monotonic()); coll_nosort->append(ExtrusionEntitiesPtr{ eec }); diff --git a/src/libslic3r/Fill/FillRectilinear.hpp b/src/libslic3r/Fill/FillRectilinear.hpp index d9151dab8b0..dae36dc6ca7 100644 --- a/src/libslic3r/Fill/FillRectilinear.hpp +++ b/src/libslic3r/Fill/FillRectilinear.hpp @@ -50,6 +50,12 @@ class FillMonotonic : public FillRectilinear public: Fill* clone() const override { return new FillMonotonic(*this); } ~FillMonotonic() override = default; + //apply monotonic + void fill_surface_extrusion(const Surface *surface, const FillParams ¶ms, ExtrusionEntitiesPtr &out) const override { + FillParams monotonic_params = params; + monotonic_params.monotonic = true; + FillRectilinear::fill_surface_extrusion(surface, monotonic_params, out); + } Polylines fill_surface(const Surface* surface, const FillParams& params) const override; bool no_sort() const override { return true; } }; From 200c24ae0c81dbb00655bb2a6a7412efe04e9657 Mon Sep 17 00:00:00 2001 From: supermerill Date: Fri, 29 Dec 2023 02:35:01 +0100 Subject: [PATCH 17/19] Fix strings field (post_process) supermerill/SuperSlicer#4017 fix e8672b2d4f94376abae78c11ec493e9eed50d0ca --- src/libslic3r/PrintConfig.cpp | 5 ++-- src/slic3r/GUI/Field.cpp | 48 +++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 50f813b8ded..42a6e1246a0 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -4238,8 +4238,9 @@ void PrintConfigDef::init_fff_params() def->label = L("Post-processing scripts"); def->category = OptionCategory::customgcode; def->tooltip = L("If you want to process the output G-code through custom scripts, " - "just list their absolute paths here. Separate multiple scripts with a semicolon. " - "Scripts will be passed the absolute path to the G-code file as the first argument, " + "just list their absolute paths here." + "\nSeparate multiple scripts with a semicolon or a line return.\n!! please use '\;' here if you want a not-line-separation ';'!!" + "\nScripts will be passed the absolute path to the G-code file as the first argument, " "and they can access the Slic3r config settings by reading environment variables." "\nThe script, if passed as a relative path, will also be searched from the slic3r directory, " "the slic3r configuration directory and the user directory."); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 1995b8ce355..5fd5ef73a7c 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -409,10 +409,23 @@ std::pair any_to_wxstring(const boost::any &value, const ConfigO case coStrings: { if (opt_idx < 0) { // custom for strings, as we don't need the serialized form, the normal one with ';' in-between is enough + // (use '\n' for multi-line opt) ConfigOptionStrings reader; reader.set_any(value, opt_idx); std::string good_str; - for (std::string s : reader.values) good_str += s + ";"; + for (std::string &s : reader.values) { + //ensure the separator isn't inside, not escaped. + if (s.find((opt.multiline ? '\n' : ';')) != std::string::npos) { + if (opt.multiline) { + //if multiline, all \n are escaped (again) + boost::replace_all(s, "\\n", "\\\\n"); + boost::replace_all(s, "\n", "\\n"); + } + // all ";" are escaped + boost::replace_all(s, ";","\\;"); + } + good_str.append(s).append((opt.multiline ? "\n" : ";")); + } if (!good_str.empty()) good_str.pop_back(); text_value = good_str; @@ -654,17 +667,36 @@ void TextField::get_value_by_opt_type(wxString &str, const bool check_value /* = } case coStrings: if (m_opt_idx < 0) { - ConfigOptionStrings reader; //don't remove spaces and things like that - try { - reader.deserialize(str.ToStdString()); - } catch (std::exception) {} + //don't use reader.deserialize(str.ToStdString()); as the current string isn't escaped. + std::string str_to_split = str.ToStdString(); + std::vector strings; + // ensure no in-string ';' to not mess up the split + boost::replace_all(str_to_split, "\\;", "@$@"); + //split + boost::split(strings, str_to_split, boost::is_any_of("\n;")); + //restore extra ';' and '\n' + for (std::string &line : strings) { + boost::replace_all(line, "@$@", ";"); + if (this->m_opt.multiline) { + boost::replace_all(line, "\\n", "\n"); + boost::replace_all(line, "\\\n", "\\n"); + } + } + // recreate field string std::string good_str; - for (std::string s : reader.values) good_str += s + ";"; + for (std::string s : strings) { + boost::replace_all(s, ";", "\\;"); + if (this->m_opt.multiline) { + boost::replace_all(s, "\\n", "\n"); + boost::replace_all(s, "\\\n", "\\n"); + } + good_str += s + (this->m_opt.multiline ? "\n" : ";"); + } if (!good_str.empty()) good_str.pop_back(); - need_update = (str.ToStdString() != good_str); - m_value = reader.values; + need_update = (str.ToStdString() != good_str); // mostly true, even when not needed + m_value = strings; break; } case coString: m_value = std::string(str.ToUTF8().data()); break; From 81bbbd17673369cc339b757b1581475005da2ede Mon Sep 17 00:00:00 2001 From: supermerill Date: Fri, 29 Dec 2023 02:35:14 +0100 Subject: [PATCH 18/19] fix doubleslider nan --- src/slic3r/GUI/DoubleSlider.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index c9fedc22575..9a1a7781998 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -1190,8 +1190,9 @@ void Control::draw_ruler(wxDC& dc) if (m_values[tick] < value) break; // short ticks from the last tick to the end of current sequence - assert(! std::isnan(short_tick)); - draw_short_ticks(dc, short_tick, tick); + //note: first sequence can be empty. + if(!std::isnan(short_tick)); + draw_short_ticks(dc, short_tick, tick); if (sequence < m_ruler.count() - 1) sequence++; } short_tick = tick; @@ -1215,6 +1216,7 @@ void Control::draw_ruler(wxDC& dc) prev_y_pos = pos; } + assert(!std::isnan(short_tick)); draw_short_ticks(dc, short_tick, tick); if (value == m_ruler.max_values[sequence]) { @@ -1224,6 +1226,7 @@ void Control::draw_ruler(wxDC& dc) } } // short ticks from the last tick to the end + assert(!std::isnan(short_tick)); draw_short_ticks(dc, short_tick, m_max_value); } From 9c7cf30a7ec1b5cbf7ea8bf5407f0ca0dc8def4f Mon Sep 17 00:00:00 2001 From: supermerill Date: Fri, 29 Dec 2023 02:36:06 +0100 Subject: [PATCH 19/19] fix Pressure equalizer usage of cooling tag (after cooling rework from 67b62c28d39395b431a50fc92379d6d6ea02e3b4) --- src/libslic3r/GCode.cpp | 4 +-- src/libslic3r/GCode/CoolingBuffer.cpp | 41 +++++++++++++---------- src/libslic3r/GCode/PressureEqualizer.cpp | 19 ++++++----- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 9eb51456396..ebe23a0dce7 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -5441,9 +5441,9 @@ double_t GCode::_compute_speed_mm_per_sec(const ExtrusionPath& path, double spee void GCode::cooldown_marker_init() { if (_cooldown_marker_speed[ExtrusionRole::erExternalPerimeter].empty()) { - std::string allow_speed_change = ";CM_extrude_speed;_EXTRUDE_SET_SPEED"; + std::string allow_speed_change = ";_EXTRUDE_SET_SPEED"; //only change speed on external perimeter (and similar) speed if really necessary. - std::string maybe_allow_speed_change = ";CM_extrude_speed_external;_EXTRUDE_SET_SPEED_MAYBE"; + std::string maybe_allow_speed_change = ";_EXTRUDE_SET_SPEED_MAYBE"; _cooldown_marker_speed[erNone] = ""; _cooldown_marker_speed[erPerimeter] = allow_speed_change; _cooldown_marker_speed[erExternalPerimeter] = maybe_allow_speed_change; diff --git a/src/libslic3r/GCode/CoolingBuffer.cpp b/src/libslic3r/GCode/CoolingBuffer.cpp index a52bee44a0c..c19f3d60b79 100644 --- a/src/libslic3r/GCode/CoolingBuffer.cpp +++ b/src/libslic3r/GCode/CoolingBuffer.cpp @@ -405,6 +405,26 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: // type to add to each next G1 (just for adjustable for now) size_t current_stamp = CoolingLine::TYPE_NONE; + auto finalize_sm = [&](bool ignore_empty) { + if (active_speed_modifier != size_t(-1)) { + assert(active_speed_modifier < adjustment->lines.size()); + CoolingLine &sm = adjustment->lines[active_speed_modifier]; + // There should be at least some extrusion move inside the adjustment block. + // However if the block has no extrusion (which is wrong), fix it for the cooling buffer to work. + //FIXME: Pressure equalizer add EXTRUDE_SET_SPEED_TAG withotu removing the previous one at the line before. + assert(ignore_empty || sm.length > 0); + assert(ignore_empty || sm.time > 0); + if (sm.time <= 0) { + // Likely a zero length extrusion, it should not be emitted, however the zero extrusions should + // not confuse firmware either. Prohibit time adjustment of a block of zero length extrusions by + // the cooling buffer. + sm.type &= ~CoolingLine::TYPE_ADJUSTABLE; + // But the start / end comment shall be removed. + sm.type |= CoolingLine::TYPE_ADJUSTABLE_EMPTY; + } + } + }; + for (; *line_start != 0; line_start = line_end) { while (*line_end != '\n' && *line_end != 0) @@ -462,7 +482,8 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: bool wipe = boost::contains(sline, ";_WIPE"); if (wipe) line.type |= CoolingLine::TYPE_WIPE; - if (boost::contains(sline, ";_EXTRUDE_SET_SPEED") && ! wipe) { + if (boost::contains(sline, ";_EXTRUDE_SET_SPEED") && !wipe) { + finalize_sm(true); active_speed_modifier = adjustment->lines.size(); line.type |= CoolingLine::TYPE_ADJUSTABLE; current_stamp |= CoolingLine::TYPE_ADJUSTABLE; @@ -542,21 +563,7 @@ std::vector CoolingBuffer::parse_layer_gcode(const std:: } else if (boost::starts_with(sline, ";_EXTRUDE_END")) { // Closing a block of non-zero length extrusion moves. line.type = CoolingLine::TYPE_EXTRUDE_END; - if (active_speed_modifier != size_t(-1)) { - assert(active_speed_modifier < adjustment->lines.size()); - CoolingLine &sm = adjustment->lines[active_speed_modifier]; - // There should be at least some extrusion move inside the adjustment block. - // However if the block has no extrusion (which is wrong), fix it for the cooling buffer to work. - assert(sm.length > 0); - assert(sm.time > 0); - if (sm.time <= 0) { - // Likely a zero length extrusion, it should not be emitted, however the zero extrusions should not confuse firmware either. - // Prohibit time adjustment of a block of zero length extrusions by the cooling buffer. - sm.type &= ~CoolingLine::TYPE_ADJUSTABLE; - // But the start / end comment shall be removed. - sm.type |= CoolingLine::TYPE_ADJUSTABLE_EMPTY; - } - } + finalize_sm(false); active_speed_modifier = size_t(-1); current_stamp = CoolingLine::TYPE_NONE; } else if (boost::starts_with(sline, ";_TOOLCHANGE")) { @@ -1042,8 +1049,6 @@ std::string CoolingBuffer::apply_layer_cooldown( } else if (line->type & CoolingLine::TYPE_EXTRUDE_END) { assert(extrude_tree.size() > 0); if (extrude_tree.size() > 0) { - new_gcode.append(std::string(";TYPE_EXTRUDE remove type ") + - ExtrusionEntity::role_to_string(extrude_tree.back()) + std::string("\n")); extrude_tree.pop_back(); fan_need_set = true; } diff --git a/src/libslic3r/GCode/PressureEqualizer.cpp b/src/libslic3r/GCode/PressureEqualizer.cpp index da8f833138d..fd3a8998914 100644 --- a/src/libslic3r/GCode/PressureEqualizer.cpp +++ b/src/libslic3r/GCode/PressureEqualizer.cpp @@ -17,7 +17,7 @@ namespace Slic3r { static const std::string EXTRUSION_ROLE_TAG = ";_EXTRUSION_ROLE:"; static const std::string EXTRUDE_END_TAG = ";_EXTRUDE_END"; static const std::string EXTRUDE_SET_SPEED_TAG = ";_EXTRUDE_SET_SPEED"; -static const std::string EXTERNAL_PERIMETER_TAG = ";_EXTERNAL_PERIMETER"; +//static const std::string EXTERNAL_PERIMETER_TAG = ";_EXTERNAL_PERIMETER"; // Maximum segment length to split a long segment if the initial and the final flow rate differ. // Smaller value means a smoother transition between two different flow rates. @@ -685,7 +685,7 @@ inline bool is_just_line_with_extrude_set_speed_tag(const std::string &line) break; else return false; -} + } parse_float(p_line, line_end - p_line); eatws(p_line); p_line += EXTRUDE_SET_SPEED_TAG.length(); @@ -700,16 +700,19 @@ void PressureEqualizer::push_line_to_output(const size_t line_idx, const float n output_buffer.begin() + int(this->output_buffer_length) + 1); if (is_just_line_with_extrude_set_speed_tag(prev_line_str)) this->output_buffer_length = this->output_buffer_prev_length; // Remove the last line because it only sets the speed for an empty block of g-code lines, so it is useless. - else - push_to_output(EXTRUDE_END_TAG.data(), EXTRUDE_END_TAG.length(), true); - } else - push_to_output(EXTRUDE_END_TAG.data(), EXTRUDE_END_TAG.length(), true); + //else + //push_to_output(EXTRUDE_END_TAG.data(), EXTRUDE_END_TAG.length(), true); // you don't need to extrude_end a EXTRUDE_SET_SPEED_TAG anymore, only for _EXTRUDETYPE_ + } else { + std::cout<<"\n"; + } + //else push_to_output(EXTRUDE_END_TAG.data(), EXTRUDE_END_TAG.length(), true); // you don't need to extrude_end a EXTRUDE_SET_SPEED_TAG anymore, only for _EXTRUDETYPE_ GCodeG1Formatter feedrate_formatter(m_gcode_precision_xyz, m_gcode_precision_e); feedrate_formatter.emit_f(new_feedrate); feedrate_formatter.emit_string(std::string(EXTRUDE_SET_SPEED_TAG.data(), EXTRUDE_SET_SPEED_TAG.length())); - if (line.extrusion_role == erExternalPerimeter) - feedrate_formatter.emit_string(std::string(EXTERNAL_PERIMETER_TAG.data(), EXTERNAL_PERIMETER_TAG.length())); + //you don't need to re-emit that. and now it's _EXTRUDETYPE_{code} anyway + //if (line.extrusion_role == erExternalPerimeter) + // feedrate_formatter.emit_string(std::string(EXTERNAL_PERIMETER_TAG.data(), EXTERNAL_PERIMETER_TAG.length())); push_to_output(feedrate_formatter); GCodeG1Formatter extrusion_formatter(m_gcode_precision_xyz, m_gcode_precision_e);