diff --git a/resources/shaders/gouraud.fs b/resources/shaders/gouraud.fs index dce033d7b..853a5512c 100644 --- a/resources/shaders/gouraud.fs +++ b/resources/shaders/gouraud.fs @@ -8,7 +8,7 @@ const float EPSILON = 0.0001; struct SlopeDetection { - bool active; + bool actived; // x = yellow, y = red vec2 z_range; mat3 volume_world_normal_matrix; @@ -37,7 +37,7 @@ void main() { if (any(lessThan(clipping_planes_dots, ZERO))) discard; - vec3 color = slope.active ? slope_color() : uniform_color.rgb; + vec3 color = slope.actived ? slope_color() : uniform_color.rgb; // if the fragment is outside the print volume -> use darker color color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(color, ZERO, 0.3333) : color; gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + color * intensity.x, uniform_color.a); diff --git a/resources/shaders/gouraud.vs b/resources/shaders/gouraud.vs index 72d6c18b3..a9f3f6118 100644 --- a/resources/shaders/gouraud.vs +++ b/resources/shaders/gouraud.vs @@ -20,7 +20,7 @@ const vec3 ZERO = vec3(0.0, 0.0, 0.0); struct PrintBoxDetection { - bool active; + bool actived; vec3 min; vec3 max; mat4 volume_world_matrix; @@ -28,7 +28,7 @@ struct PrintBoxDetection struct SlopeDetection { - bool active; + bool actived; // x = yellow, y = red vec2 z_range; mat3 volume_world_normal_matrix; @@ -72,7 +72,7 @@ void main() intensity.x += NdotL * LIGHT_FRONT_DIFFUSE; // compute deltas for out of print volume detection (world coordinates) - if (print_box.active) + if (print_box.actived) { vec3 v = (print_box.volume_world_matrix * gl_Vertex).xyz; delta_box_min = v - print_box.min; @@ -85,7 +85,7 @@ void main() } // z component of normal vector in world coordinate used for slope shading - world_normal_z = slope.active ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0; + world_normal_z = slope.actived ? (normalize(slope.volume_world_normal_matrix * gl_Normal)).z : 0.0; gl_Position = ftransform(); // Point in homogenous coordinates. diff --git a/src/libslic3r/CMakeLists.txt b/src/libslic3r/CMakeLists.txt index 73b7df5bc..b37e09ad0 100644 --- a/src/libslic3r/CMakeLists.txt +++ b/src/libslic3r/CMakeLists.txt @@ -64,6 +64,7 @@ add_library(libslic3r STATIC Fill/FillRectilinear3.hpp Flow.cpp Flow.hpp + format.hpp Format/3mf.cpp Format/3mf.hpp Format/AMF.cpp diff --git a/src/libslic3r/Config.cpp b/src/libslic3r/Config.cpp index 674410388..f3f365b47 100644 --- a/src/libslic3r/Config.cpp +++ b/src/libslic3r/Config.cpp @@ -1,4 +1,5 @@ #include "Config.hpp" +#include "format.hpp" #include "Utils.hpp" #include #include @@ -464,7 +465,7 @@ bool ConfigBase::set_deserialize_nothrow(const t_config_option_key &opt_key_src, void ConfigBase::set_deserialize(const t_config_option_key &opt_key_src, const std::string &value_src, bool append) { if (! this->set_deserialize_nothrow(opt_key_src, value_src, append)) - throw BadOptionTypeException((boost::format("ConfigBase::set_deserialize() failed for parameter \"%1%\", value \"%2%\"") % opt_key_src % value_src).str()); + throw BadOptionTypeException(format("ConfigBase::set_deserialize() failed for parameter \"%1%\", value \"%2%\"", opt_key_src, value_src)); } void ConfigBase::set_deserialize(std::initializer_list items) @@ -620,7 +621,7 @@ void ConfigBase::load_from_gcode_file(const std::string &file) size_t key_value_pairs = load_from_gcode_string(data.data()); if (key_value_pairs < 80) - throw std::runtime_error((boost::format("Suspiciously low number of configuration values extracted from %1%: %2%") % file % key_value_pairs).str()); + throw std::runtime_error(format("Suspiciously low number of configuration values extracted from %1%: %2%", file, key_value_pairs)); } // Load the config keys from the given string. diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp index 442d5ec83..73c20f1b5 100644 --- a/src/libslic3r/GCode/Analyzer.cpp +++ b/src/libslic3r/GCode/Analyzer.cpp @@ -18,7 +18,7 @@ static const float INCHES_TO_MM = 25.4f; static const float DEFAULT_FEEDRATE = 0.0f; static const unsigned int DEFAULT_EXTRUDER_ID = 0; static const unsigned int DEFAULT_COLOR_PRINT_ID = 0; -static const Slic3r::Vec3d DEFAULT_START_POSITION = Slic3r::Vec3d(0.0f, 0.0f, 0.0f); +static const Slic3r::Vec3f DEFAULT_START_POSITION = Slic3r::Vec3f::Zero(); static const float DEFAULT_START_EXTRUSION = 0.0f; static const float DEFAULT_FAN_SPEED = 0.0f; @@ -33,7 +33,7 @@ const std::string GCodeAnalyzer::Pause_Print_Tag = "_ANALYZER_PAUSE_PRINT"; const std::string GCodeAnalyzer::Custom_Code_Tag = "_ANALYZER_CUSTOM_CODE"; const std::string GCodeAnalyzer::End_Pause_Print_Or_Custom_Code_Tag = "_ANALYZER_END_PAUSE_PRINT_OR_CUSTOM_CODE"; -const double GCodeAnalyzer::Default_mm3_per_mm = 0.0; +const float GCodeAnalyzer::Default_mm3_per_mm = 0.0f; const float GCodeAnalyzer::Default_Width = 0.0f; const float GCodeAnalyzer::Default_Height = 0.0f; @@ -49,7 +49,7 @@ GCodeAnalyzer::Metadata::Metadata() { } -GCodeAnalyzer::Metadata::Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id/* = 0*/) +GCodeAnalyzer::Metadata::Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id/* = 0*/) : extrusion_role(extrusion_role) , extruder_id(extruder_id) , mm3_per_mm(mm3_per_mm) @@ -90,7 +90,7 @@ bool GCodeAnalyzer::Metadata::operator != (const GCodeAnalyzer::Metadata& other) return false; } -GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id/* = 0*/) +GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id/* = 0*/) : type(type) , data(extrusion_role, extruder_id, mm3_per_mm, width, height, feedrate, fan_speed, cp_color_id) , start_position(start_position) @@ -99,7 +99,7 @@ GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, ExtrusionRole extrusi { } -GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder) +GCodeAnalyzer::GCodeMove::GCodeMove(GCodeMove::EType type, const GCodeAnalyzer::Metadata& data, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder) : type(type) , data(data) , start_position(start_position) @@ -691,7 +691,7 @@ void GCodeAnalyzer::_process_extrusion_role_tag(const std::string& comment, size void GCodeAnalyzer::_process_mm3_per_mm_tag(const std::string& comment, size_t pos) { - _set_mm3_per_mm(::strtod(comment.substr(pos + Mm3_Per_Mm_Tag.length()).c_str(), nullptr)); + _set_mm3_per_mm((float)::strtod(comment.substr(pos + Mm3_Per_Mm_Tag.length()).c_str(), nullptr)); } void GCodeAnalyzer::_process_width_tag(const std::string& comment, size_t pos) @@ -784,12 +784,12 @@ unsigned int GCodeAnalyzer::_get_cp_color_id() const return m_state.data.cp_color_id; } -void GCodeAnalyzer::_set_mm3_per_mm(double value) +void GCodeAnalyzer::_set_mm3_per_mm(float value) { m_state.data.mm3_per_mm = value; } -double GCodeAnalyzer::_get_mm3_per_mm() const +float GCodeAnalyzer::_get_mm3_per_mm() const { return m_state.data.mm3_per_mm; } @@ -864,12 +864,12 @@ void GCodeAnalyzer::_reset_axes_origin() ::memset((void*)m_state.origin, 0, Num_Axis * sizeof(float)); } -void GCodeAnalyzer::_set_start_position(const Vec3d& position) +void GCodeAnalyzer::_set_start_position(const Vec3f& position) { m_state.start_position = position; } -const Vec3d& GCodeAnalyzer::_get_start_position() const +const Vec3f& GCodeAnalyzer::_get_start_position() const { return m_state.start_position; } @@ -900,9 +900,9 @@ float GCodeAnalyzer::_get_delta_extrusion() const return _get_axis_position(E) - m_state.start_extrusion; } -Vec3d GCodeAnalyzer::_get_end_position() const +Vec3f GCodeAnalyzer::_get_end_position() const { - return Vec3d(m_state.position[X], m_state.position[Y], m_state.position[Z]); + return Vec3f(m_state.position[X], m_state.position[Y], m_state.position[Z]); } void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type) @@ -913,14 +913,14 @@ void GCodeAnalyzer::_store_move(GCodeAnalyzer::GCodeMove::EType type) it = m_moves_map.insert(TypeToMovesMap::value_type(type, GCodeMovesList())).first; // store move - Vec3d extruder_offset = Vec3d::Zero(); + Vec3f extruder_offset = Vec3f::Zero(); unsigned int extruder_id = _get_extruder_id(); ExtruderOffsetsMap::iterator extr_it = m_extruder_offsets.find(extruder_id); if (extr_it != m_extruder_offsets.end()) - extruder_offset = Vec3d(extr_it->second(0), extr_it->second(1), 0.0); + extruder_offset = Vec3f((float)extr_it->second(0), (float)extr_it->second(1), 0.0f); - Vec3d start_position = _get_start_position() + extruder_offset; - Vec3d end_position = _get_end_position() + extruder_offset; + Vec3f start_position = _get_start_position() + extruder_offset; + Vec3f end_position = _get_end_position() + extruder_offset; it->second.emplace_back(type, _get_extrusion_role(), extruder_id, _get_mm3_per_mm(), _get_width(), _get_height(), _get_feedrate(), start_position, end_position, _get_delta_extrusion(), _get_fan_speed(), _get_cp_color_id()); } @@ -958,8 +958,8 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ GCodePreviewData::Extrusion::Path &path = paths.back(); path.polyline = polyline; path.extrusion_role = data.extrusion_role; - path.mm3_per_mm = float(data.mm3_per_mm); - path.width = data.width; + path.mm3_per_mm = data.mm3_per_mm; + path.width = data.width; path.height = data.height; path.feedrate = data.feedrate; path.extruder_id = data.extruder_id; @@ -976,7 +976,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ Metadata data; float z = FLT_MAX; Polyline polyline; - Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX); + Vec3f position(FLT_MAX, FLT_MAX, FLT_MAX); float volumetric_rate = FLT_MAX; GCodePreviewData::Range height_range; GCodePreviewData::Range width_range; @@ -996,7 +996,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ if (cancel_callback_curr == 0) cancel_callback(); - if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * (float)move.data.mm3_per_mm)) + if ((data != move.data) || (z != move.start_position.z()) || (position != move.start_position) || (volumetric_rate != move.data.feedrate * move.data.mm3_per_mm)) { // store current polyline polyline.remove_duplicate_points(); @@ -1012,7 +1012,7 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ // update current values data = move.data; z = (float)move.start_position.z(); - volumetric_rate = move.data.feedrate * (float)move.data.mm3_per_mm; + volumetric_rate = move.data.feedrate * move.data.mm3_per_mm; height_range.update_from(move.data.height); width_range.update_from(move.data.width); feedrate_range.update_from(move.data.feedrate, GCodePreviewData::FeedrateKind::EXTRUSION); @@ -1060,7 +1060,7 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s return; Polyline3 polyline; - Vec3d position(FLT_MAX, FLT_MAX, FLT_MAX); + Vec3f position(FLT_MAX, FLT_MAX, FLT_MAX); GCodePreviewData::Travel::EType type = GCodePreviewData::Travel::Num_Types; GCodePreviewData::Travel::Polyline::EDirection direction = GCodePreviewData::Travel::Polyline::Num_Directions; float feedrate = FLT_MAX; diff --git a/src/libslic3r/GCode/Analyzer.hpp b/src/libslic3r/GCode/Analyzer.hpp index cd5654a74..4ac383fea 100644 --- a/src/libslic3r/GCode/Analyzer.hpp +++ b/src/libslic3r/GCode/Analyzer.hpp @@ -24,7 +24,7 @@ public: static const std::string Custom_Code_Tag; static const std::string End_Pause_Print_Or_Custom_Code_Tag; - static const double Default_mm3_per_mm; + static const float Default_mm3_per_mm; static const float Default_Width; static const float Default_Height; @@ -53,7 +53,7 @@ public: { ExtrusionRole extrusion_role; unsigned int extruder_id; - double mm3_per_mm; + float mm3_per_mm; float width; // mm float height; // mm float feedrate; // mm/s @@ -61,7 +61,7 @@ public: unsigned int cp_color_id; Metadata(); - Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id = 0); + Metadata(ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, float fan_speed, unsigned int cp_color_id = 0); bool operator != (const Metadata& other) const; }; @@ -81,12 +81,12 @@ public: EType type; Metadata data; - Vec3d start_position; - Vec3d end_position; + Vec3f start_position; + Vec3f end_position; float delta_extruder; - GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, double mm3_per_mm, float width, float height, float feedrate, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id = 0); - GCodeMove(EType type, const Metadata& data, const Vec3d& start_position, const Vec3d& end_position, float delta_extruder); + GCodeMove(EType type, ExtrusionRole extrusion_role, unsigned int extruder_id, float mm3_per_mm, float width, float height, float feedrate, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder, float fan_speed, unsigned int cp_color_id = 0); + GCodeMove(EType type, const Metadata& data, const Vec3f& start_position, const Vec3f& end_position, float delta_extruder); }; typedef std::vector GCodeMovesList; @@ -101,7 +101,7 @@ private: EPositioningType global_positioning_type; EPositioningType e_local_positioning_type; Metadata data; - Vec3d start_position = Vec3d::Zero(); + Vec3f start_position = Vec3f::Zero(); float cached_position[5]; float start_extrusion; float position[Num_Axis]; @@ -246,8 +246,8 @@ private: void _set_cp_color_id(unsigned int id); unsigned int _get_cp_color_id() const; - void _set_mm3_per_mm(double value); - double _get_mm3_per_mm() const; + void _set_mm3_per_mm(float value); + float _get_mm3_per_mm() const; void _set_width(float width); float _get_width() const; @@ -272,8 +272,8 @@ private: // Sets origin position to zero void _reset_axes_origin(); - void _set_start_position(const Vec3d& position); - const Vec3d& _get_start_position() const; + void _set_start_position(const Vec3f& position); + const Vec3f& _get_start_position() const; void _set_cached_position(unsigned char axis, float position); float _get_cached_position(unsigned char axis) const; @@ -285,7 +285,7 @@ private: float _get_delta_extrusion() const; // Returns current xyz position (from m_state.position[]) - Vec3d _get_end_position() const; + Vec3f _get_end_position() const; // Adds a new move with the given data void _store_move(GCodeMove::EType type); diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 44b6a3d24..51293ed17 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -46,19 +46,19 @@ namespace Slic3r { ::memset(abs_axis_feedrate, 0, Num_Axis * sizeof(float)); } - float GCodeTimeEstimator::Block::Trapezoid::acceleration_time(float acceleration) const + float GCodeTimeEstimator::Block::Trapezoid::acceleration_time(float entry_feedrate, float acceleration) const { - return acceleration_time_from_distance(feedrate.entry, accelerate_until, acceleration); + return acceleration_time_from_distance(entry_feedrate, accelerate_until, acceleration); } float GCodeTimeEstimator::Block::Trapezoid::cruise_time() const { - return (feedrate.cruise != 0.0f) ? cruise_distance() / feedrate.cruise : 0.0f; + return (cruise_feedrate != 0.0f) ? cruise_distance() / cruise_feedrate : 0.0f; } - float GCodeTimeEstimator::Block::Trapezoid::deceleration_time(float acceleration) const + float GCodeTimeEstimator::Block::Trapezoid::deceleration_time(float distance, float acceleration) const { - return acceleration_time_from_distance(feedrate.cruise, (distance - decelerate_after), -acceleration); + return acceleration_time_from_distance(cruise_feedrate, (distance - decelerate_after), -acceleration); } float GCodeTimeEstimator::Block::Trapezoid::cruise_distance() const @@ -78,29 +78,9 @@ namespace Slic3r { return ::sqrt(value); } - GCodeTimeEstimator::Block::Block() - { - } - - float GCodeTimeEstimator::Block::move_length() const - { - float length = ::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); - return (length > 0.0f) ? length : std::abs(delta_pos[E]); - } - - float GCodeTimeEstimator::Block::is_extruder_only_move() const - { - return (delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f) && (delta_pos[E] != 0.0f); - } - - float GCodeTimeEstimator::Block::is_travel_move() const - { - return delta_pos[E] == 0.0f; - } - float GCodeTimeEstimator::Block::acceleration_time() const { - return trapezoid.acceleration_time(acceleration); + return trapezoid.acceleration_time(feedrate.entry, acceleration); } float GCodeTimeEstimator::Block::cruise_time() const @@ -110,7 +90,7 @@ namespace Slic3r { float GCodeTimeEstimator::Block::deceleration_time() const { - return trapezoid.deceleration_time(acceleration); + return trapezoid.deceleration_time(distance, acceleration); } float GCodeTimeEstimator::Block::cruise_distance() const @@ -120,10 +100,7 @@ namespace Slic3r { void GCodeTimeEstimator::Block::calculate_trapezoid() { - float distance = move_length(); - - trapezoid.distance = distance; - trapezoid.feedrate = feedrate; + trapezoid.cruise_feedrate = feedrate.cruise; float accelerate_distance = std::max(0.0f, estimate_acceleration_distance(feedrate.entry, feedrate.cruise, acceleration)); float decelerate_distance = std::max(0.0f, estimate_acceleration_distance(feedrate.cruise, feedrate.exit, -acceleration)); @@ -134,9 +111,9 @@ namespace Slic3r { // and start braking in order to reach the exit_feedrate exactly at the end of this block. if (cruise_distance < 0.0f) { - accelerate_distance = clamp(0.0f, distance, intersection_distance(feedrate.entry, feedrate.exit, acceleration, distance)); + accelerate_distance = std::clamp(intersection_distance(feedrate.entry, feedrate.exit, acceleration, distance), 0.0f, distance); cruise_distance = 0.0f; - trapezoid.feedrate.cruise = Trapezoid::speed_from_distance(feedrate.entry, accelerate_distance, acceleration); + trapezoid.cruise_feedrate = Trapezoid::speed_from_distance(feedrate.entry, accelerate_distance, acceleration); } trapezoid.accelerate_until = accelerate_distance; @@ -207,11 +184,8 @@ namespace Slic3r { { PROFILE_FUNC(); if (start_from_beginning) - { _reset_time(); - m_last_st_synchronized_block_id = -1; - } - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache }); @@ -221,6 +195,7 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS } +#if 0 void GCodeTimeEstimator::calculate_time_from_text(const std::string& gcode) { reset(); @@ -229,7 +204,7 @@ namespace Slic3r { [this](GCodeReader &reader, const GCodeReader::GCodeLine &line) { this->_process_gcode_line(reader, line); }); - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache }); @@ -244,7 +219,7 @@ namespace Slic3r { reset(); m_parser.parse_file(file, boost::bind(&GCodeTimeEstimator::_process_gcode_line, this, _1, _2)); - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache }); @@ -262,7 +237,7 @@ namespace Slic3r { { this->_process_gcode_line(reader, line); }; for (const std::string& line : gcode_lines) m_parser.parse_line(line, action); - _calculate_time(); + _calculate_time(0); if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache}); @@ -271,6 +246,7 @@ namespace Slic3r { _log_moves_stats(); #endif // ENABLE_MOVE_STATS } +#endif bool GCodeTimeEstimator::post_process(const std::string& filename, float interval_sec, const PostProcessData* const normal_mode, const PostProcessData* const silent_mode) { @@ -317,25 +293,25 @@ namespace Slic3r { if (data == nullptr) return; - assert((g1_line_id >= (int)data->g1_line_ids.size()) || (data->g1_line_ids[g1_line_id].first >= g1_lines_count)); - const Block* block = nullptr; - if (g1_line_id < (int)data->g1_line_ids.size()) + assert((g1_line_id >= (int)data->g1_times.size()) || (data->g1_times[g1_line_id].first >= (int)g1_lines_count)); + float elapsed_time = -1.0f; + if (g1_line_id < (int)data->g1_times.size()) { - const G1LineIdToBlockId& map_item = data->g1_line_ids[g1_line_id]; + const G1LineIdTime& map_item = data->g1_times[g1_line_id]; if (map_item.first == g1_lines_count) { - if (line.has_e() && (map_item.second < (unsigned int)data->blocks.size())) - block = &data->blocks[map_item.second]; + if (line.has_e()) + elapsed_time = map_item.second; ++g1_line_id; } } - if ((block != nullptr) && (block->elapsed_time != -1.0f)) + if (elapsed_time != -1.0f) { - float block_remaining_time = data->time - block->elapsed_time; + float block_remaining_time = data->time - elapsed_time; if (std::abs(last_recorded_time - block_remaining_time) > interval_sec) { - sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * block->elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str()); + sprintf(line_M73, time_mask.c_str(), std::to_string((int)(100.0f * elapsed_time / data->time)).c_str(), _get_time_minutes(block_remaining_time).c_str()); gcode_line += line_M73; last_recorded_time = block_remaining_time; @@ -643,22 +619,6 @@ namespace Slic3r { m_state.extruder_id = m_state.extruder_id_unloaded; } - void GCodeTimeEstimator::add_additional_time(float timeSec) - { - PROFILE_FUNC(); - m_state.additional_time += timeSec; - } - - void GCodeTimeEstimator::set_additional_time(float timeSec) - { - m_state.additional_time = timeSec; - } - - float GCodeTimeEstimator::get_additional_time() const - { - return m_state.additional_time; - } - void GCodeTimeEstimator::set_default() { set_units(Millimeters); @@ -788,7 +748,7 @@ namespace Slic3r { { size_t out = sizeof(*this); out += SLIC3R_STDVEC_MEMSIZE(this->m_blocks, Block); - out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_line_ids, G1LineIdToBlockId); + out += SLIC3R_STDVEC_MEMSIZE(this->m_g1_times, G1LineIdTime); return out; } @@ -807,13 +767,9 @@ namespace Slic3r { if (get_e_local_positioning_type() == Absolute) set_axis_position(E, 0.0f); - set_additional_time(0.0f); - reset_extruder_id(); reset_g1_line_id(); - m_g1_line_ids.clear(); - - m_last_st_synchronized_block_id = -1; + m_g1_times.clear(); m_needs_custom_gcode_times = false; m_custom_gcode_times.clear(); @@ -830,17 +786,19 @@ namespace Slic3r { m_blocks.clear(); } - void GCodeTimeEstimator::_calculate_time() + void GCodeTimeEstimator::_calculate_time(size_t keep_last_n_blocks) { PROFILE_FUNC(); + + assert(keep_last_n_blocks <= m_blocks.size()); + _forward_pass(); _reverse_pass(); _recalculate_trapezoids(); - m_time += get_additional_time(); - m_custom_gcode_time_cache += get_additional_time(); - - for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i) + size_t n_blocks_process = m_blocks.size() - keep_last_n_blocks; + m_g1_times.reserve(m_g1_times.size() + n_blocks_process); + for (size_t i = 0; i < n_blocks_process; ++ i) { Block& block = m_blocks[i]; float block_time = 0.0f; @@ -848,7 +806,8 @@ namespace Slic3r { block_time += block.cruise_time(); block_time += block.deceleration_time(); m_time += block_time; - block.elapsed_time = m_time; + if (block.g1_line_id >= 0) + m_g1_times.emplace_back(block.g1_line_id, m_time); #if ENABLE_MOVE_STATS MovesStatsMap::iterator it = _moves_stats.find(block.move_type); @@ -862,9 +821,10 @@ namespace Slic3r { m_custom_gcode_time_cache += block_time; } - m_last_st_synchronized_block_id = (int)m_blocks.size() - 1; - // The additional time has been consumed (added to the total time), reset it to zero. - set_additional_time(0.); + if (keep_last_n_blocks) + m_blocks.erase(m_blocks.begin(), m_blocks.begin() + n_blocks_process); + else + m_blocks.clear(); } void GCodeTimeEstimator::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line) @@ -1021,11 +981,22 @@ namespace Slic3r { return current_absolute_position; }; + // delta_pos must have size >= 4 + auto move_length = [](const float* delta_pos) { + float xyz_length = std::sqrt(sqr(delta_pos[X]) + sqr(delta_pos[Y]) + sqr(delta_pos[Z])); + return (xyz_length > 0.0f) ? xyz_length : std::abs(delta_pos[E]); + }; + + // delta_pos must have size >= 4 + auto is_extruder_only_move = [](const float* delta_pos) { + return (delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f) && (delta_pos[E] != 0.0f); + }; + PROFILE_FUNC(); increment_g1_line_id(); // updates axes positions from line - float new_pos[Num_Axis]; + std::array new_pos; for (unsigned char a = X; a < Num_Axis; ++a) { new_pos[a] = axis_absolute_position((EAxis)a, line); @@ -1040,10 +1011,11 @@ namespace Slic3r { // calculates block movement deltas float max_abs_delta = 0.0f; + std::array delta_pos; for (unsigned char a = X; a < Num_Axis; ++a) { - block.delta_pos[a] = new_pos[a] - get_axis_position((EAxis)a); - max_abs_delta = std::max(max_abs_delta, std::abs(block.delta_pos[a])); + delta_pos[a] = new_pos[a] - get_axis_position((EAxis)a); + max_abs_delta = std::max(max_abs_delta, std::abs(delta_pos[a])); } // is it a move ? @@ -1051,15 +1023,15 @@ namespace Slic3r { return; // calculates block feedrate - m_curr.feedrate = std::max(get_feedrate(), block.is_travel_move() ? get_minimum_travel_feedrate() : get_minimum_feedrate()); + m_curr.feedrate = std::max(get_feedrate(), (delta_pos[E] == 0.0f) ? get_minimum_travel_feedrate() : get_minimum_feedrate()); - float distance = block.move_length(); - float invDistance = 1.0f / distance; + block.distance = move_length(delta_pos.data()); + float invDistance = 1.0f / block.distance; float min_feedrate_factor = 1.0f; for (unsigned char a = X; a < Num_Axis; ++a) { - m_curr.axis_feedrate[a] = m_curr.feedrate * block.delta_pos[a] * invDistance; + m_curr.axis_feedrate[a] = m_curr.feedrate * delta_pos[a] * invDistance; if (a == E) m_curr.axis_feedrate[a] *= get_extrude_factor_override_percentage(); @@ -1080,12 +1052,12 @@ namespace Slic3r { } // calculates block acceleration - float acceleration = block.is_extruder_only_move() ? get_retract_acceleration() : get_acceleration(); + float acceleration = is_extruder_only_move(delta_pos.data()) ? get_retract_acceleration() : get_acceleration(); for (unsigned char a = X; a < Num_Axis; ++a) { float axis_max_acceleration = get_axis_max_acceleration((EAxis)a); - if (acceleration * std::abs(block.delta_pos[a]) * invDistance > axis_max_acceleration) + if (acceleration * std::abs(delta_pos[a]) * invDistance > axis_max_acceleration) acceleration = axis_max_acceleration; } @@ -1165,7 +1137,7 @@ namespace Slic3r { vmax_junction = m_curr.safe_feedrate; } - float v_allowable = Block::max_allowable_speed(-acceleration, m_curr.safe_feedrate, distance); + float v_allowable = Block::max_allowable_speed(-acceleration, m_curr.safe_feedrate, block.distance); block.feedrate.entry = std::min(vmax_junction, v_allowable); block.max_entry_speed = vmax_junction; @@ -1189,27 +1161,30 @@ namespace Slic3r { // detects block move type block.move_type = Block::Noop; - if (block.delta_pos[E] < 0.0f) + if (delta_pos[E] < 0.0f) { - if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f) || (block.delta_pos[Z] != 0.0f)) + if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f)) block.move_type = Block::Move; else block.move_type = Block::Retract; } - else if (block.delta_pos[E] > 0.0f) + else if (delta_pos[E] > 0.0f) { - if ((block.delta_pos[X] == 0.0f) && (block.delta_pos[Y] == 0.0f) && (block.delta_pos[Z] == 0.0f)) + if ((delta_pos[X] == 0.0f) && (delta_pos[Y] == 0.0f) && (delta_pos[Z] == 0.0f)) block.move_type = Block::Unretract; - else if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f)) + else if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f)) block.move_type = Block::Extrude; } - else if ((block.delta_pos[X] != 0.0f) || (block.delta_pos[Y] != 0.0f) || (block.delta_pos[Z] != 0.0f)) + else if ((delta_pos[X] != 0.0f) || (delta_pos[Y] != 0.0f) || (delta_pos[Z] != 0.0f)) block.move_type = Block::Move; #endif // ENABLE_MOVE_STATS // adds block to blocks list + block.g1_line_id = this->get_g1_line_id(); m_blocks.emplace_back(block); - m_g1_line_ids.emplace_back(G1LineIdToBlockIdMap::value_type(get_g1_line_id(), (unsigned int)m_blocks.size() - 1)); + + if (m_blocks.size() > planner_refresh_if_larger) + _calculate_time(planner_queue_size); } void GCodeTimeEstimator::_processG4(const GCodeReader::GCodeLine& line) @@ -1218,8 +1193,9 @@ namespace Slic3r { GCodeFlavor dialect = get_dialect(); float value; + float extra_time = 0.f; if (line.has_value('P', value)) - add_additional_time(value * MILLISEC_TO_SEC); + extra_time += value * MILLISEC_TO_SEC; // see: http://reprap.org/wiki/G-code#G4:_Dwell if ((dialect == gcfRepetier) || @@ -1228,10 +1204,10 @@ namespace Slic3r { (dialect == gcfRepRap)) { if (line.has_value('S', value)) - add_additional_time(value); + extra_time += value; } - _simulate_st_synchronize(); + _simulate_st_synchronize(extra_time); } void GCodeTimeEstimator::_processG20(const GCodeReader::GCodeLine& line) @@ -1296,7 +1272,7 @@ namespace Slic3r { anyFound = true; } else - _simulate_st_synchronize(); + _simulate_st_synchronize(0.f); if (!anyFound) { @@ -1310,7 +1286,7 @@ namespace Slic3r { void GCodeTimeEstimator::_processM1(const GCodeReader::GCodeLine& line) { PROFILE_FUNC(); - _simulate_st_synchronize(); + _simulate_st_synchronize(0.f); } void GCodeTimeEstimator::_processM82(const GCodeReader::GCodeLine& line) @@ -1462,9 +1438,9 @@ namespace Slic3r { // MK3 MMU2 specific M code: // M702 C is expected to be sent by the custom end G-code when finalizing a print. // The MK3 unit shall unload and park the active filament into the MMU2 unit. - add_additional_time(get_filament_unload_time(get_extruder_id())); + float extra_time = get_filament_unload_time(get_extruder_id()); reset_extruder_id(); - _simulate_st_synchronize(); + _simulate_st_synchronize(extra_time); } } @@ -1478,10 +1454,10 @@ namespace Slic3r { { // Specific to the MK3 MMU2: The initial extruder ID is set to -1 indicating // that the filament is parked in the MMU2 unit and there is nothing to be unloaded yet. - add_additional_time(get_filament_unload_time(get_extruder_id())); + float extra_time = get_filament_unload_time(get_extruder_id()); set_extruder_id(id); - add_additional_time(get_filament_load_time(get_extruder_id())); - _simulate_st_synchronize(); + extra_time += get_filament_load_time(get_extruder_id()); + _simulate_st_synchronize(extra_time); } } } @@ -1513,7 +1489,9 @@ namespace Slic3r { { PROFILE_FUNC(); m_needs_custom_gcode_times = true; - _calculate_time(); + //FIXME this simulates st_synchronize! is it correct? + // The estimated time may be longer than the real print time. + _simulate_st_synchronize(0.f); if (m_custom_gcode_time_cache != 0.0f) { m_custom_gcode_times.push_back({code, m_custom_gcode_time_cache}); @@ -1521,34 +1499,26 @@ namespace Slic3r { } } - void GCodeTimeEstimator::_simulate_st_synchronize() + void GCodeTimeEstimator::_simulate_st_synchronize(float extra_time) { PROFILE_FUNC(); - _calculate_time(); + m_time += extra_time; + m_custom_gcode_time_cache += extra_time; + _calculate_time(0); } void GCodeTimeEstimator::_forward_pass() { PROFILE_FUNC(); - if (m_blocks.size() > 1) - { - for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size() - 1; ++i) - { - _planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]); - } - } + for (int i = 0; i + 1 < (int)m_blocks.size(); ++i) + _planner_forward_pass_kernel(m_blocks[i], m_blocks[i + 1]); } void GCodeTimeEstimator::_reverse_pass() { PROFILE_FUNC(); - if (m_blocks.size() > 1) - { - for (int i = (int)m_blocks.size() - 1; i >= m_last_st_synchronized_block_id + 2; --i) - { - _planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]); - } - } + for (int i = (int)m_blocks.size() - 1; i > 0; -- i) + _planner_reverse_pass_kernel(m_blocks[i - 1], m_blocks[i]); } void GCodeTimeEstimator::_planner_forward_pass_kernel(Block& prev, Block& curr) @@ -1562,7 +1532,7 @@ namespace Slic3r { { if (prev.feedrate.entry < curr.feedrate.entry) { - float entry_speed = std::min(curr.feedrate.entry, Block::max_allowable_speed(-prev.acceleration, prev.feedrate.entry, prev.move_length())); + float entry_speed = std::min(curr.feedrate.entry, Block::max_allowable_speed(-prev.acceleration, prev.feedrate.entry, prev.distance)); // Check for junction speed change if (curr.feedrate.entry != entry_speed) @@ -1584,7 +1554,7 @@ namespace Slic3r { // If nominal length true, max junction speed is guaranteed to be reached. Only compute // for max allowable speed if block is decelerating and nominal length is false. if (!curr.flags.nominal_length && (curr.max_entry_speed > next.feedrate.entry)) - curr.feedrate.entry = std::min(curr.max_entry_speed, Block::max_allowable_speed(-curr.acceleration, next.feedrate.entry, curr.move_length())); + curr.feedrate.entry = std::min(curr.max_entry_speed, Block::max_allowable_speed(-curr.acceleration, next.feedrate.entry, curr.distance)); else curr.feedrate.entry = curr.max_entry_speed; @@ -1598,7 +1568,7 @@ namespace Slic3r { Block* curr = nullptr; Block* next = nullptr; - for (int i = m_last_st_synchronized_block_id + 1; i < (int)m_blocks.size(); ++i) + for (size_t i = 0; i < m_blocks.size(); ++ i) { Block& b = m_blocks[i]; @@ -1657,7 +1627,7 @@ namespace Slic3r { { char buffer[64]; - int minutes = std::round(time_in_secs / 60.); + int minutes = int(std::round(time_in_secs / 60.)); if (minutes <= 0) { ::sprintf(buffer, "%ds", (int)time_in_secs); } else { diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index 7c364d9eb..836d1ceb4 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -85,7 +85,6 @@ namespace Slic3r { // hard limit for the acceleration, to which the firmware will clamp. float max_acceleration; // mm/s^2 float retract_acceleration; // mm/s^2 - float additional_time; // s float minimum_feedrate; // mm/s float minimum_travel_feedrate; // mm/s float extrude_factor_override_percentage; @@ -125,14 +124,13 @@ namespace Slic3r { struct Trapezoid { - float distance; // mm float accelerate_until; // mm float decelerate_after; // mm - FeedrateProfile feedrate; + float cruise_feedrate; // mm/sec - float acceleration_time(float acceleration) const; + float acceleration_time(float entry_feedrate, float acceleration) const; float cruise_time() const; - float deceleration_time(float acceleration) const; + float deceleration_time(float distance, float acceleration) const; float cruise_distance() const; // This function gives the time needed to accelerate from an initial speed to reach a final distance. @@ -153,25 +151,16 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS Flags flags; - float delta_pos[Num_Axis]; // mm + float distance; // mm float acceleration; // mm/s^2 float max_entry_speed; // mm/s float safe_feedrate; // mm/s FeedrateProfile feedrate; Trapezoid trapezoid; - float elapsed_time; - Block(); - - // Returns the length of the move covered by this block, in mm - float move_length() const; - - // Returns true if this block is a retract/unretract move only - float is_extruder_only_move() const; - - // Returns true if this block is a move with no extrusion - float is_travel_move() const; + // Ordnary index of this G1 line in the file. + int g1_line_id { -1 }; // Returns the time spent accelerating toward cruise speed, in seconds float acceleration_time() const; @@ -217,16 +206,13 @@ namespace Slic3r { #endif // ENABLE_MOVE_STATS public: - typedef std::pair G1LineIdToBlockId; - typedef std::vector G1LineIdToBlockIdMap; + typedef std::pair G1LineIdTime; + typedef std::vector G1LineIdsTimes; struct PostProcessData { - const G1LineIdToBlockIdMap& g1_line_ids; - const BlocksList& blocks; + const G1LineIdsTimes& g1_times; float time; - - PostProcessData(const G1LineIdToBlockIdMap& g1_line_ids, const BlocksList& blocks, float time) : g1_line_ids(g1_line_ids), blocks(blocks), time(time) {} }; private: @@ -236,10 +222,14 @@ namespace Slic3r { Feedrates m_curr; Feedrates m_prev; BlocksList m_blocks; - // Map between g1 line id and blocks id, used to speed up export of remaining times - G1LineIdToBlockIdMap m_g1_line_ids; - // Index of the last block already st_synchronized - int m_last_st_synchronized_block_id; + // Size of the firmware planner queue. The old 8-bit Marlins usually just managed 16 trapezoidal blocks. + // Let's be conservative and plan for newer boards with more memory. + static constexpr size_t planner_queue_size = 64; + // The firmware recalculates last planner_queue_size trapezoidal blocks each time a new block is added. + // We are not simulating the firmware exactly, we calculate a sequence of blocks once a reasonable number of blocks accumulate. + static constexpr size_t planner_refresh_if_larger = planner_queue_size * 4; + // Map from g1 line id to its elapsed time from the start of the print. + G1LineIdsTimes m_g1_times; float m_time; // s // data to calculate custom code times @@ -267,13 +257,13 @@ namespace Slic3r { void calculate_time(bool start_from_beginning); // Calculates the time estimate from the given gcode in string format - void calculate_time_from_text(const std::string& gcode); + //void calculate_time_from_text(const std::string& gcode); // Calculates the time estimate from the gcode contained in the file with the given filename - void calculate_time_from_file(const std::string& file); + //void calculate_time_from_file(const std::string& file); // Calculates the time estimate from the gcode contained in given list of gcode lines - void calculate_time_from_lines(const std::vector& gcode_lines); + //void calculate_time_from_lines(const std::vector& gcode_lines); // Process the gcode contained in the file with the given filename, // replacing placeholders with correspondent new lines M73 @@ -350,10 +340,6 @@ namespace Slic3r { unsigned int get_extruder_id() const; void reset_extruder_id(); - void add_additional_time(float timeSec); - void set_additional_time(float timeSec); - float get_additional_time() const; - void set_default(); // Call this method before to start adding lines using add_gcode_line() when reusing an instance of GCodeTimeEstimator @@ -389,7 +375,7 @@ namespace Slic3r { // Return an estimate of the memory consumed by the time estimator. size_t memory_used() const; - PostProcessData get_post_process_data() const { return PostProcessData(m_g1_line_ids, m_blocks, m_time); } + PostProcessData get_post_process_data() const { return PostProcessData{ m_g1_times, m_time }; } private: void _reset(); @@ -397,7 +383,7 @@ namespace Slic3r { void _reset_blocks(); // Calculates the time estimate - void _calculate_time(); + void _calculate_time(size_t keep_last_n_blocks); // Processes the given gcode line void _process_gcode_line(GCodeReader&, const GCodeReader::GCodeLine& line); @@ -470,7 +456,7 @@ namespace Slic3r { void _process_custom_gcode_tag(CustomGcodeType code); // Simulates firmware st_synchronize() call - void _simulate_st_synchronize(); + void _simulate_st_synchronize(float additional_time); void _forward_pass(); void _reverse_pass(); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index b3a18f26b..59df8eb61 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -419,7 +419,7 @@ bool Model::arrange_objects(coordf_t dist, const BoundingBoxf* bb) if (input[i].bed_idx != 0) ret = false; if (input[i].bed_idx >= 0) { input[i].translation += Vec2crd{input[i].bed_idx * stride, 0}; - instances[i]->apply_arrange_result(input[i].translation, + instances[i]->apply_arrange_result(input[i].translation.cast(), input[i].rotation); } } diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 2fbd58461..2ddad9e59 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -668,7 +668,7 @@ public: arrangement::ArrangePolygon get_arrange_polygon() const; // Apply the arrange result on the ModelInstance - void apply_arrange_result(const Vec2crd& offs, double rotation) + void apply_arrange_result(const Vec2d& offs, double rotation) { // write the transformation data into the model instance set_rotation(Z, rotation); diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index c66cca8ea..8deed7502 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -44,19 +44,15 @@ // Enable fix for dragging mouse event handling for gizmobar #define ENABLE_GIZMO_TOOLBAR_DRAGGING_FIX (1 && ENABLE_2_2_0_FINAL) -//============ -// 2.3.0 techs -//============ -#define ENABLE_2_3_0 1 - -// Enable rendering of objects colored by facets' slope -#define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_3_0) //=================== // 2.3.0.alpha1 techs //=================== #define ENABLE_2_3_0_ALPHA1 1 +// Enable rendering of objects colored by facets' slope +#define ENABLE_SLOPE_RENDERING (1 && ENABLE_2_3_0_ALPHA1) + // Moves GLCanvas3DManager from being a static member of _3DScene to be a normal member of GUI_App #define ENABLE_NON_STATIC_CANVAS_MANAGER (1 && ENABLE_2_3_0_ALPHA1) diff --git a/src/libslic3r/format.hpp b/src/libslic3r/format.hpp new file mode 100644 index 000000000..c3747677b --- /dev/null +++ b/src/libslic3r/format.hpp @@ -0,0 +1,57 @@ +#ifndef slic3r_format_hpp_ +#define slic3r_format_hpp_ + +// Functional wrapper around boost::format. +// One day we may replace this wrapper with C++20 format +// https://en.cppreference.com/w/cpp/utility/format/format +// though C++20 format uses a different template pattern for position independent parameters. +// +// Boost::format works around the missing variadic templates by an ugly % chaining operator. The usage of boost::format looks like this: +// (boost::format("template") % arg1 %arg2).str() +// This wrapper allows for a nicer syntax: +// Slic3r::format("template", arg1, arg2) +// One can also override Slic3r::internal::format::cook() function to convert a Slic3r::format() argument to something that +// boost::format may convert to string, see slic3r/GUI/I18N.hpp for a "cook" function to convert wxString to UTF8. + +#include + +namespace Slic3r { + +// https://gist.github.com/gchudnov/6a90d51af004d97337ec +namespace internal { + namespace format { + // Default "cook" function - just forward. + template + inline T&& cook(T&& arg) { + return std::forward(arg); + } + + // End of the recursive chain. + inline std::string format_recursive(boost::format& message) { + return message.str(); + } + + template + std::string format_recursive(boost::format& message, TValue&& arg, TArgs&&... args) { + // Format, possibly convert the argument by the "cook" function. + message % cook(std::forward(arg)); + return format_recursive(message, std::forward(args)...); + } + } +}; + +template +inline std::string format(const char* fmt, TArgs&&... args) { + boost::format message(fmt); + return internal::format::format_recursive(message, std::forward(args)...); +} + +template +inline std::string format(const std::string& fmt, TArgs&&... args) { + boost::format message(fmt); + return internal::format::format_recursive(message, std::forward(args)...); +} + +} // namespace Slic3r + +#endif // slic3r_format_hpp_ diff --git a/src/libslic3r/pchheader.hpp b/src/libslic3r/pchheader.hpp index 1339368bd..a1d6da5fe 100644 --- a/src/libslic3r/pchheader.hpp +++ b/src/libslic3r/pchheader.hpp @@ -111,6 +111,7 @@ #include "BoundingBox.hpp" #include "ClipperUtils.hpp" #include "Config.hpp" +#include "format.hpp" #include "I18N.hpp" #include "MultiPoint.hpp" #include "Point.hpp" diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 1034b9673..7aaa1e622 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -22,6 +22,7 @@ set(SLIC3R_GUI_SOURCES GUI/ConfigSnapshotDialog.hpp GUI/3DScene.cpp GUI/3DScene.hpp + GUI/format.hpp GUI/GLShader.cpp GUI/GLShader.hpp GUI/GLCanvas3D.hpp diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index c13c1b937..e60676ca3 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -655,11 +655,11 @@ void GLVolumeCollection::render(GLVolumeCollection::ERenderType type, bool disab GLint print_box_min_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.min") : -1; GLint print_box_max_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.max") : -1; - GLint print_box_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.active") : -1; + GLint print_box_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.actived") : -1; GLint print_box_worldmatrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "print_box.volume_world_matrix") : -1; #if ENABLE_SLOPE_RENDERING - GLint slope_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.active") : -1; + GLint slope_active_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.actived") : -1; GLint slope_normal_matrix_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.volume_world_normal_matrix") : -1; GLint slope_z_range_id = (current_program_id > 0) ? ::glGetUniformLocation(current_program_id, "slope.z_range") : -1; #endif // ENABLE_SLOPE_RENDERING diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index 58c76fe26..4357a371a 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -74,6 +74,8 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf ConfigOptionDef def; def.type = coPoints; def.set_default_value(new ConfigOptionPoints{ Vec2d(200, 200) }); + def.min = 0; + def.max = 1200; def.label = L("Size"); def.tooltip = L("Size in X and Y of the rectangular plate."); Option option(def, "rect_size"); @@ -81,6 +83,8 @@ void BedShapePanel::build_panel(const ConfigOptionPoints& default_pt, const Conf def.type = coPoints; def.set_default_value(new ConfigOptionPoints{ Vec2d(0, 0) }); + def.min = -600; + def.max = 600; def.label = L("Origin"); def.tooltip = L("Distance of the 0,0 G-code coordinate from the front left corner of the rectangle."); option = Option(def, "rect_origin"); diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 7318153ef..4c4c1aa8d 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -20,11 +20,13 @@ #include #include #include "Field.hpp" +#include "format.hpp" namespace Slic3r { using GUI::from_u8; using GUI::into_u8; +using GUI::format_wxstr; namespace DoubleSlider { @@ -530,7 +532,7 @@ wxString Control::get_label(int tick) const const wxString str = m_values.empty() ? wxNumberFormatter::ToString(m_label_koef*value, 2, wxNumberFormatter::Style_None) : wxNumberFormatter::ToString(m_values[value], 2, wxNumberFormatter::Style_None); - return from_u8((boost::format("%1%\n(%2%)") % str % (m_values.empty() ? value : value+1)).str()); + return format_wxstr("%1%\n(%2%)", str, m_values.empty() ? value : value+1); } void Control::draw_tick_text(wxDC& dc, const wxPoint& pos, int tick, bool right_side/*=true*/) const @@ -1001,16 +1003,16 @@ wxString Control::get_tooltip(int tick/*=-1*/) // Show custom Gcode as a first string of tooltop tooltip = " "; - tooltip += tick_code_it->gcode == ColorChangeCode ? ( m_mode == t_mode::SingleExtruder ? - from_u8((boost::format(_utf8(L("Color change (\"%1%\")"))) % tick_code_it->gcode ).str()) : - from_u8((boost::format(_utf8(L("Color change (\"%1%\") for Extruder %2%"))) % - tick_code_it->gcode % tick_code_it->extruder).str()) ) : - tick_code_it->gcode == PausePrintCode ? - from_u8((boost::format(_utf8(L("Pause print (\"%1%\")"))) % tick_code_it->gcode ).str()) : - tick_code_it->gcode == ToolChangeCode ? - from_u8((boost::format(_utf8(L("Extruder (tool) is changed to Extruder \"%1%\""))) % - tick_code_it->extruder ).str()) : - from_u8(tick_code_it->gcode); + tooltip += + tick_code_it->gcode == ColorChangeCode ? + (m_mode == t_mode::SingleExtruder ? + format_wxstr(_L("Color change (\"%1%\")"), tick_code_it->gcode) : + format_wxstr(_L("Color change (\"%1%\") for Extruder %2%"), tick_code_it->gcode, tick_code_it->extruder)) : + tick_code_it->gcode == PausePrintCode ? + format_wxstr(_L("Pause print (\"%1%\")"), tick_code_it->gcode) : + tick_code_it->gcode == ToolChangeCode ? + format_wxstr(_L("Extruder (tool) is changed to Extruder \"%1%\""), tick_code_it->extruder) : + from_u8(tick_code_it->gcode); // If tick is marked as a conflict (exclamation icon), // we should to explain why @@ -1176,8 +1178,8 @@ void Control::append_add_color_change_menu_item(wxMenu* menu, bool switch_curren } const wxString menu_name = switch_current_code ? - from_u8((boost::format(_utf8(L("Switch code to Color change (%1%) for:"))) % ColorChangeCode).str()) : - from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % ColorChangeCode).str()); + format_wxstr(_L("Switch code to Color change (%1%) for:"), ColorChangeCode) : + format_wxstr(_L("Add color change (%1%) for:"), ColorChangeCode); wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, ""); add_color_change_menu_item->SetBitmap(create_scaled_bitmap("colorchange_add_m")); } @@ -1615,8 +1617,8 @@ static void upgrade_text_entry_dialog(wxTextEntryDialog* dlg, double min = -1.0, static std::string get_custom_code(const std::string& code_in, double height) { - wxString msg_text = from_u8(_utf8(L("Enter custom G-code used on current layer"))) + ":"; - wxString msg_header = from_u8((boost::format(_utf8(L("Custom G-code on current layer (%1% mm)."))) % height).str()); + wxString msg_text = _L("Enter custom G-code used on current layer") + ":"; + wxString msg_header = format_wxstr(_L("Custom G-code on current layer (%1% mm)."), height); // get custom gcode wxTextEntryDialog dlg(nullptr, msg_text, msg_header, code_in, @@ -1631,8 +1633,8 @@ static std::string get_custom_code(const std::string& code_in, double height) static std::string get_pause_print_msg(const std::string& msg_in, double height) { - wxString msg_text = from_u8(_utf8(L("Enter short message shown on Printer display when a print is paused"))) + ":"; - wxString msg_header = from_u8((boost::format(_utf8(L("Message for pause print on current layer (%1% mm)."))) % height).str()); + wxString msg_text = _L("Enter short message shown on Printer display when a print is paused") + ":"; + wxString msg_header = format_wxstr(_L("Message for pause print on current layer (%1% mm)."), height); // get custom gcode wxTextEntryDialog dlg(nullptr, msg_text, msg_header, from_u8(msg_in), diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index 6d9007974..a1a6583bc 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -1242,12 +1242,24 @@ void PointCtrl::msw_rescale(bool rescale_sidetext/* = false*/) y_textctrl->SetMinSize(field_size); } +bool PointCtrl::value_was_changed(wxTextCtrl* win) +{ + if (m_value.empty()) + return true; + + boost::any val = m_value; + // update m_value! + get_value(); + + return boost::any_cast(m_value) != boost::any_cast(val); +} + void PointCtrl::propagate_value(wxTextCtrl* win) { - if (!win->GetValue().empty()) - on_change_field(); - else + if (win->GetValue().empty()) on_kill_focus(); + else if (value_was_changed(win)) + on_change_field(); } void PointCtrl::set_value(const Vec2d& value, bool change_event) @@ -1281,6 +1293,19 @@ boost::any& PointCtrl::get_value() double x, y; x_textctrl->GetValue().ToDouble(&x); y_textctrl->GetValue().ToDouble(&y); + + if (m_opt.min > x || x > m_opt.max || + m_opt.min > y || y > m_opt.max) + { + if (m_opt.min > x) x = m_opt.min; + 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); + + show_error(m_parent, _(L("Input value is out of range"))); + } + return m_value = Vec2d(x, y); } diff --git a/src/slic3r/GUI/Field.hpp b/src/slic3r/GUI/Field.hpp index 03fa28b2b..7f7ee8ed8 100644 --- a/src/slic3r/GUI/Field.hpp +++ b/src/slic3r/GUI/Field.hpp @@ -445,6 +445,7 @@ public: wxTextCtrl* y_textctrl{ nullptr }; void BUILD() override; + 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); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e98d5d9ac..470aafe23 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1825,14 +1825,12 @@ void GLCanvas3D::set_color_by(const std::string& value) m_color_by = value; } +#if ENABLE_NON_STATIC_CANVAS_MANAGER void GLCanvas3D::refresh_camera_scene_box() { -#if ENABLE_NON_STATIC_CANVAS_MANAGER wxGetApp().plater()->get_camera().set_scene_box(scene_bounding_box()); -#else - m_camera.set_scene_box(scene_bounding_box()); -#endif // ENABLE_NON_STATIC_CANVAS_MANAGER } +#endif // ENABLE_NON_STATIC_CANVAS_MANAGER BoundingBoxf3 GLCanvas3D::volumes_bounding_box() const { @@ -3014,18 +3012,15 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) post_event(SimpleEvent(EVT_GLTOOLBAR_COPY)); break; -#ifdef __APPLE__ - case 'm': - case 'M': -#else /* __APPLE__ */ +#ifdef __linux__ case WXK_CONTROL_M: -#endif /* __APPLE__ */ - { - Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller(); - controller.show_settings_dialog(!controller.is_settings_dialog_shown()); - m_dirty = true; - break; - } + { + Mouse3DController& controller = wxGetApp().plater()->get_mouse3d_controller(); + controller.show_settings_dialog(!controller.is_settings_dialog_shown()); + m_dirty = true; + break; + } +#endif /* __linux__ */ #ifdef __APPLE__ case 'v': @@ -6608,7 +6603,7 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat case GCodePreviewData::Extrusion::FanSpeed: return path.fan_speed; case GCodePreviewData::Extrusion::VolumetricRate: - return path.feedrate * (float)path.mm3_per_mm; + return path.feedrate * path.mm3_per_mm; case GCodePreviewData::Extrusion::Tool: return (float)path.extruder_id; case GCodePreviewData::Extrusion::ColorPrint: diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 17270f759..58fd628d4 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -16,6 +16,9 @@ #include "GUI_ObjectLayers.hpp" #include "GLSelectionRectangle.hpp" #include "MeshUtils.hpp" +#if !ENABLE_NON_STATIC_CANVAS_MANAGER +#include "Camera.hpp" +#endif // !ENABLE_NON_STATIC_CANVAS_MANAGER #include diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index f5a4a3d92..234847bc4 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -47,6 +47,7 @@ #include "SysInfoDialog.hpp" #include "KBShortcutsDialog.hpp" #include "UpdateDialogs.hpp" +#include "Mouse3DController.hpp" #include "RemovableDriveManager.hpp" #ifdef __WXMSW__ @@ -193,6 +194,20 @@ static void register_win32_device_notification_event() } return true; }); + + wxWindow::MSWRegisterMessageHandler(WM_INPUT, [](wxWindow *win, WXUINT /* nMsg */, WXWPARAM wParam, WXLPARAM lParam) { + auto main_frame = dynamic_cast(Slic3r::GUI::find_toplevel_parent(win)); + auto plater = (main_frame == nullptr) ? nullptr : main_frame->plater(); +// if (wParam == RIM_INPUTSINK && plater != nullptr && main_frame->IsActive()) { + if (wParam == RIM_INPUT && plater != nullptr && main_frame->IsActive()) { + RAWINPUT raw; + UINT rawSize = sizeof(RAWINPUT); + ::GetRawInputData((HRAWINPUT)lParam, RID_INPUT, &raw, &rawSize, sizeof(RAWINPUTHEADER)); + if (raw.header.dwType == RIM_TYPEHID && plater->get_mouse3d_controller().handle_raw_input_win32(raw.data.hid.bRawData, raw.data.hid.dwSizeHid)) + return true; + } + return false; + }); } #endif // WIN32 diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index d05ecbcd8..79a6cad20 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -185,10 +185,12 @@ void KBShortcutsDialog::fill_shortcuts() { "Z", L("Zoom to selected object\nor all objects in scene, if none selected") }, { "I", L("Zoom in") }, { "O", L("Zoom out") }, - { ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") } +#ifdef __linux__ + { ctrl + "M", L("Show/Hide 3Dconnexion devices settings dialog") }, +#endif // __linux__ #if ENABLE_RENDER_PICKING_PASS // Don't localize debugging texts. - , { "T", "Toggle picking pass texture rendering on/off" } + { "T", "Toggle picking pass texture rendering on/off" }, #endif // ENABLE_RENDER_PICKING_PASS }; diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 26ceda7bf..c4a6f09b7 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -152,6 +152,16 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S // Failed to get desktop location assert(false); } + + { + static constexpr int device_count = 1; + RAWINPUTDEVICE devices[device_count] = { 0 }; + // multi-axis mouse (SpaceNavigator, etc.) + devices[0].usUsagePage = 0x01; + devices[0].usUsage = 0x08; + if (! RegisterRawInputDevices(devices, device_count, sizeof(RAWINPUTDEVICE))) + BOOST_LOG_TRIVIAL(error) << "RegisterRawInputDevices failed"; + } #endif // _WIN32 // propagate event @@ -204,6 +214,10 @@ void MainFrame::shutdown() // when closing the application using Command+Q, a mouse event is triggered after this lambda is completed, // causing a crash if (m_plater) m_plater->unbind_canvas_event_handlers(); + + // Cleanup of canvases' volumes needs to be done here or a crash may happen on some Linux Debian flavours + // see: https://github.com/prusa3d/PrusaSlicer/issues/3964 + if (m_plater) m_plater->reset_canvas_volumes(); #endif // ENABLE_NON_STATIC_CANVAS_MANAGER // Weird things happen as the Paint messages are floating around the windows being destructed. diff --git a/src/slic3r/GUI/Mouse3DController.cpp b/src/slic3r/GUI/Mouse3DController.cpp index 75ec9c3bc..8f80f6847 100644 --- a/src/slic3r/GUI/Mouse3DController.cpp +++ b/src/slic3r/GUI/Mouse3DController.cpp @@ -484,7 +484,10 @@ void Mouse3DController::init() assert(! m_thread.joinable()); if (! m_thread.joinable()) { m_stop = false; +#ifndef _WIN32 + // Don't start the background thread on Windows, as the HID messages are sent as Windows messages. m_thread = std::thread(&Mouse3DController::run, this); +#endif // _WIN32 } } @@ -600,7 +603,10 @@ bool Mouse3DController::connect_device() : path(path), usage_page(usage_page), usage(usage) {} - bool has_valid_usage() const { return (usage_page == 1) && (usage == 8); } + // https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf + // Usage page 1 - Generic Desktop Controls + // Usage page 1, usage 8 - Multi-axis Controller + bool has_valid_usage() const { return usage_page == 1 && usage == 8; } }; #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT @@ -688,7 +694,7 @@ bool Mouse3DController::connect_device() if (detected_devices.empty()) return false; - std::string path = ""; + std::string path; unsigned short vendor_id = 0; unsigned short product_id = 0; @@ -865,45 +871,60 @@ void Mouse3DController::collect_input() this->handle_input(packet, res, m_params, m_state); } -// Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by the worker thread. -bool Mouse3DController::handle_input(const DataPacketRaw& packet, const int packet_lenght, const Params ¶ms, State &state_in_out) +#ifdef _WIN32 +bool Mouse3DController::handle_raw_input_win32(const unsigned char *data, const int packet_length) { if (! wxGetApp().IsActive()) return false; - int res = packet_lenght; + if (packet_length == 7 || packet_length == 13) { + DataPacketRaw packet; + memcpy(packet.data(), data, packet_length); + handle_packet(packet, packet_length, m_params, m_state); + } + + return true; +} +#endif /* _WIN32 */ + +// Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by the worker thread. +bool Mouse3DController::handle_input(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out) +{ + if (! wxGetApp().IsActive()) + return false; + + int res = packet_length; bool updated = false; - if (res == 7) - updated = handle_packet(packet, params, state_in_out); - else if (res == 13) - updated = handle_wireless_packet(packet, params, state_in_out); - else if ((res == 3) && (packet[0] == 3)) + if (res == 7 || res == 13 || // On Mac button packets can be 3 bytes long - updated = handle_packet(packet, params, state_in_out); + ((res == 3) && (packet[0] == 3))) + updated = handle_packet(packet, res, params, state_in_out); #if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT else if (res > 0) std::cout << "Got unknown data packet of length: " << res << ", code:" << (int)packet[0] << std::endl; #endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT -#if 1 if (updated) { wxGetApp().plater()->set_current_canvas_as_dirty(); // ask for an idle event to update 3D scene wxWakeUpIdle(); } -#endif return updated; } // Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by handle_input() from the worker thread. -bool Mouse3DController::handle_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out) +bool Mouse3DController::handle_packet(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out) { switch (packet[0]) { - case 1: // Translation + case 1: // Translation + Rotation { - if (handle_packet_translation(packet, params, state_in_out)) + bool updated = handle_packet_translation(packet, params, state_in_out); + if (packet_length == 13) + updated |= handle_packet_rotation(packet, 7, params, state_in_out); + + if (updated) return true; break; @@ -941,47 +962,6 @@ bool Mouse3DController::handle_packet(const DataPacketRaw& packet, const Params return false; } -// Unpack raw 3DConnexion HID packet of a wireless 3D mouse into m_state. Called by handle_input() from the worker thread. -bool Mouse3DController::handle_wireless_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out) -{ - switch (packet[0]) - { - case 1: // Translation + Rotation - { - bool updated = handle_packet_translation(packet, params, state_in_out); - updated |= handle_packet_rotation(packet, 7, params, state_in_out); - - if (updated) - return true; - - break; - } - case 3: // Button - { - if (params.buttons_enabled && handle_packet_button(packet, 12, params, state_in_out)) - return true; - - break; - } - case 23: // Battery charge - { -#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - std::cout << "3DConnexion - battery level: " << (int)packet[1] << " percent" << std::endl; -#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - break; - } - default: - { -#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - std::cout << "3DConnexion - Got unknown data packet of code: " << (int)packet[0] << std::endl; -#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT - break; - } - } - - return false; -} - // Convert a signed 16bit word from a 3DConnexion mouse HID packet into a double coordinate, apply a dead zone. static double convert_input(int coord_byte_low, int coord_byte_high, double deadzone) { diff --git a/src/slic3r/GUI/Mouse3DController.hpp b/src/slic3r/GUI/Mouse3DController.hpp index eb1425b88..2c1d0bb6f 100644 --- a/src/slic3r/GUI/Mouse3DController.hpp +++ b/src/slic3r/GUI/Mouse3DController.hpp @@ -190,6 +190,8 @@ public: #endif // __APPLE__ #ifdef WIN32 + bool handle_raw_input_win32(const unsigned char *data, const int packet_lenght); + // Called by Win32 HID enumeration callback. void device_attached(const std::string &device); @@ -218,10 +220,9 @@ private: typedef std::array DataPacketRaw; // Unpack raw 3DConnexion HID packet of a wired 3D mouse into m_state. Called by the worker thread. - static bool handle_input(const DataPacketRaw& packet, const int packet_lenght, const Params ¶ms, State &state_in_out); + static bool handle_input(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out); // The following is called by handle_input() from the worker thread. - static bool handle_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out); - static bool handle_wireless_packet(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out); + static bool handle_packet(const DataPacketRaw& packet, const int packet_length, const Params ¶ms, State &state_in_out); static bool handle_packet_translation(const DataPacketRaw& packet, const Params ¶ms, State &state_in_out); static bool handle_packet_rotation(const DataPacketRaw& packet, unsigned int first_byte, const Params ¶ms, State &state_in_out); static bool handle_packet_button(const DataPacketRaw& packet, unsigned int packet_size, const Params ¶ms, State &state_in_out); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index a31b0aee2..d270b6e0d 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -59,6 +59,7 @@ #include "GUI_Utils.hpp" #include "wxExtensions.hpp" #include "MainFrame.hpp" +#include "format.hpp" #include "3DScene.hpp" #include "GLCanvas3D.hpp" #include "Selection.hpp" @@ -96,6 +97,7 @@ namespace fs = boost::filesystem; using Slic3r::_3DScene; using Slic3r::Preset; using Slic3r::PrintHostJob; +using Slic3r::GUI::format_wxstr; static const std::pair THUMBNAIL_SIZE_3MF = { 256, 256 }; @@ -140,7 +142,7 @@ public: }; ObjectInfo::ObjectInfo(wxWindow *parent) : - wxStaticBoxSizer(new wxStaticBox(parent, wxID_ANY, _(L("Info"))), wxVERTICAL) + wxStaticBoxSizer(new wxStaticBox(parent, wxID_ANY, _L("Info")), wxVERTICAL) { GetStaticBox()->SetFont(wxGetApp().bold_font()); @@ -159,13 +161,13 @@ ObjectInfo::ObjectInfo(wxWindow *parent) : return text; }; - init_info_label(&info_size, _(L("Size"))); - label_volume = init_info_label(&info_volume, _(L("Volume"))); - init_info_label(&info_facets, _(L("Facets"))); - label_materials = init_info_label(&info_materials, _(L("Materials"))); + init_info_label(&info_size, _L("Size")); + label_volume = init_info_label(&info_volume, _L("Volume")); + init_info_label(&info_facets, _L("Facets")); + label_materials = init_info_label(&info_materials, _L("Materials")); Add(grid_sizer, 0, wxEXPAND); - auto *info_manifold_text = new wxStaticText(parent, wxID_ANY, _(L("Manifold")) + ":"); + auto *info_manifold_text = new wxStaticText(parent, wxID_ANY, _L("Manifold") + ":"); info_manifold_text->SetFont(wxGetApp().small_font()); info_manifold = new wxStaticText(parent, wxID_ANY, ""); info_manifold->SetFont(wxGetApp().small_font()); @@ -215,7 +217,7 @@ private: }; SlicedInfo::SlicedInfo(wxWindow *parent) : - wxStaticBoxSizer(new wxStaticBox(parent, wxID_ANY, _(L("Sliced Info"))), wxVERTICAL) + wxStaticBoxSizer(new wxStaticBox(parent, wxID_ANY, _L("Sliced Info")), wxVERTICAL) { GetStaticBox()->SetFont(wxGetApp().bold_font()); @@ -234,13 +236,13 @@ SlicedInfo::SlicedInfo(wxWindow *parent) : info_vec.push_back(std::pair(text, info_label)); }; - init_info_label(_(L("Used Filament (m)"))); - init_info_label(_(L("Used Filament (mm³)"))); - init_info_label(_(L("Used Filament (g)"))); - init_info_label(_(L("Used Material (unit)"))); - init_info_label(_(L("Cost (money)"))); - init_info_label(_(L("Estimated printing time"))); - init_info_label(_(L("Number of tool changes"))); + init_info_label(_L("Used Filament (m)")); + init_info_label(_L("Used Filament (mm³)")); + init_info_label(_L("Used Filament (g)")); + init_info_label(_L("Used Material (unit)")); + init_info_label(_L("Cost (money)")); + init_info_label(_L("Estimated printing time")); + init_info_label(_L("Number of tool changes")); Add(grid_sizer, 0, wxEXPAND); this->Show(false); @@ -347,7 +349,7 @@ PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)), } edit_btn = new ScalableButton(parent, wxID_ANY, "cog"); - edit_btn->SetToolTip(_(L("Click to edit preset"))); + edit_btn->SetToolTip(_L("Click to edit preset")); edit_btn->Bind(wxEVT_BUTTON, ([preset_type, this](wxCommandEvent) { @@ -548,7 +550,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) : line.append_option(option); auto wiping_dialog_btn = [this](wxWindow* parent) { - m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); + m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _L("Purging volumes") + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT); m_wiping_dialog_button->SetFont(wxGetApp().normal_font()); auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(m_wiping_dialog_button, 0, wxALIGN_CENTER_VERTICAL); @@ -823,11 +825,11 @@ Sidebar::Sidebar(Plater *parent) }; p->combos_filament.push_back(nullptr); - init_combo(&p->combo_print, _(L("Print settings")), Preset::TYPE_PRINT, false); - init_combo(&p->combos_filament[0], _(L("Filament")), Preset::TYPE_FILAMENT, true); - init_combo(&p->combo_sla_print, _(L("SLA print settings")), Preset::TYPE_SLA_PRINT, false); - init_combo(&p->combo_sla_material, _(L("SLA material")), Preset::TYPE_SLA_MATERIAL, false); - init_combo(&p->combo_printer, _(L("Printer")), Preset::TYPE_PRINTER, false); + init_combo(&p->combo_print, _L("Print settings"), Preset::TYPE_PRINT, false); + init_combo(&p->combos_filament[0], _L("Filament"), Preset::TYPE_FILAMENT, true); + init_combo(&p->combo_sla_print, _L("SLA print settings"), Preset::TYPE_SLA_PRINT, false); + init_combo(&p->combo_sla_material, _L("SLA material"), Preset::TYPE_SLA_MATERIAL, false); + init_combo(&p->combo_printer, _L("Printer"), Preset::TYPE_PRINTER, false); const int margin_5 = int(0.5*wxGetApp().em_unit());// 5; @@ -886,9 +888,9 @@ Sidebar::Sidebar(Plater *parent) (*btn)->Hide(); }; - init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")) + "\tCtrl+Shift+G"); - init_scalable_btn(&p->btn_remove_device, "eject_sd" , _(L("Remove device")) + "\tCtrl+T"); - init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _(L("Export to SD card / Flash drive")) + "\tCtrl+U"); + init_scalable_btn(&p->btn_send_gcode , "export_gcode", _L("Send to printer") + "\tCtrl+Shift+G"); + init_scalable_btn(&p->btn_remove_device, "eject_sd" , _L("Remove device") + "\tCtrl+T"); + init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _L("Export to SD card / Flash drive") + "\tCtrl+U"); // regular buttons "Slice now" and "Export G-code" @@ -899,8 +901,8 @@ Sidebar::Sidebar(Plater *parent) (*btn)->SetFont(wxGetApp().bold_font()); }; - init_btn(&p->btn_export_gcode, _(L("Export G-code")) + dots , scaled_height); - init_btn(&p->btn_reslice , _(L("Slice now")) , scaled_height); + init_btn(&p->btn_export_gcode, _L("Export G-code") + dots , scaled_height); + init_btn(&p->btn_reslice , _L("Slice now") , scaled_height); enable_buttons(false); @@ -1050,7 +1052,7 @@ void Sidebar::update_reslice_btn_tooltip() const { wxString tooltip = wxString("Slice") + " [" + GUI::shortkey_ctrl_prefix() + "R]"; if (m_mode != comSimple) - tooltip += wxString("\n") + _(L("Hold Shift to Slice & Export G-code")); + tooltip += wxString("\n") + _L("Hold Shift to Slice & Export G-code"); p->btn_reslice->SetToolTip(tooltip); } @@ -1171,16 +1173,16 @@ void Sidebar::show_info_sizer() const auto& stats = model_object->get_object_stl_stats();//model_object->volumes.front()->mesh.stl.stats; p->object_info->info_volume->SetLabel(wxString::Format("%.2f", stats.volume)); - p->object_info->info_facets->SetLabel(wxString::Format(_(L("%d (%d shells)")), static_cast(model_object->facets_count()), stats.number_of_parts)); + p->object_info->info_facets->SetLabel(wxString::Format(_L("%d (%d shells)"), static_cast(model_object->facets_count()), stats.number_of_parts)); int errors = stats.degenerate_facets + stats.edges_fixed + stats.facets_removed + stats.facets_added + stats.facets_reversed + stats.backwards_edges; if (errors > 0) { - wxString tooltip = wxString::Format(_(L("Auto-repaired (%d errors)")), errors); + wxString tooltip = wxString::Format(_L("Auto-repaired (%d errors)"), errors); p->object_info->info_manifold->SetLabel(tooltip); - tooltip += ":\n" + wxString::Format(_(L("%d degenerate facets, %d edges fixed, %d facets removed, " - "%d facets added, %d facets reversed, %d backwards edges")), + tooltip += ":\n" + wxString::Format(_L("%d degenerate facets, %d edges fixed, %d facets removed, " + "%d facets added, %d facets reversed, %d backwards edges"), stats.degenerate_facets, stats.edges_fixed, stats.facets_removed, stats.facets_added, stats.facets_reversed, stats.backwards_edges); @@ -1189,7 +1191,7 @@ void Sidebar::show_info_sizer() p->object_info->manifold_warning_icon->SetToolTip(tooltip); } else { - p->object_info->info_manifold->SetLabel(_(L("Yes"))); + p->object_info->info_manifold->SetLabel(_L("Yes")); p->object_info->showing_manifold_warning_icon = false; p->object_info->info_manifold->SetToolTip(""); p->object_info->manifold_warning_icon->SetToolTip(""); @@ -1210,10 +1212,10 @@ void Sidebar::update_sliced_info_sizer() if (p->plater->printer_technology() == ptSLA) { const SLAPrintStatistics& ps = p->plater->sla_print().print_statistics(); - wxString new_label = _(L("Used Material (ml)")) + ":"; + wxString new_label = _L("Used Material (ml)") + ":"; const bool is_supports = ps.support_used_material > 0.0; if (is_supports) - new_label += from_u8((boost::format("\n - %s\n - %s") % _utf8(L("object(s)")) % _utf8(L("supports and pad"))).str()); + new_label += format_wxstr("\n - %s\n - %s", _L("object(s)"), _L("supports and pad")); wxString info_text = is_supports ? wxString::Format("%.2f \n%.2f \n%.2f", (ps.objects_used_material + ps.support_used_material) / 1000, @@ -1235,7 +1237,7 @@ void Sidebar::update_sliced_info_sizer() p->sliced_info->SetTextAndShow(siCost, str_total_cost, "Cost"); wxString t_est = std::isnan(ps.estimated_print_time) ? "N/A" : get_time_dhms(float(ps.estimated_print_time)); - p->sliced_info->SetTextAndShow(siEstimatedTime, t_est, _(L("Estimated printing time")) + ":"); + p->sliced_info->SetTextAndShow(siEstimatedTime, t_est, _L("Estimated printing time") + ":"); // Hide non-SLA sliced info parameters p->sliced_info->SetTextAndShow(siFilament_m, "N/A"); @@ -1248,9 +1250,9 @@ void Sidebar::update_sliced_info_sizer() const PrintStatistics& ps = p->plater->fff_print().print_statistics(); const bool is_wipe_tower = ps.total_wipe_tower_filament > 0; - wxString new_label = _(L("Used Filament (m)")); + wxString new_label = _L("Used Filament (m)"); if (is_wipe_tower) - new_label += from_u8((boost::format(":\n - %1%\n - %2%") % _utf8(L("objects")) % _utf8(L("wipe tower"))).str()); + new_label += format_wxstr(":\n - %1%\n - %2%", _L("objects"), _L("wipe tower")); wxString info_text = is_wipe_tower ? wxString::Format("%.2f \n%.2f \n%.2f", ps.total_used_filament / 1000, @@ -1262,9 +1264,9 @@ void Sidebar::update_sliced_info_sizer() p->sliced_info->SetTextAndShow(siFilament_mm3, wxString::Format("%.2f", ps.total_extruded_volume)); p->sliced_info->SetTextAndShow(siFilament_g, ps.total_weight == 0.0 ? "N/A" : wxString::Format("%.2f", ps.total_weight)); - new_label = _(L("Cost")); + new_label = _L("Cost"); if (is_wipe_tower) - new_label += from_u8((boost::format(":\n - %1%\n - %2%") % _utf8(L("objects")) % _utf8(L("wipe tower"))).str()); + new_label += format_wxstr(":\n - %1%\n - %2%", _L("objects"), _L("wipe tower")); info_text = ps.total_cost == 0.0 ? "N/A" : is_wipe_tower ? @@ -1277,10 +1279,10 @@ void Sidebar::update_sliced_info_sizer() if (ps.estimated_normal_print_time == "N/A" && ps.estimated_silent_print_time == "N/A") p->sliced_info->SetTextAndShow(siEstimatedTime, "N/A"); else { - new_label = _(L("Estimated printing time")) +":"; + new_label = _L("Estimated printing time") +":"; info_text = ""; - wxString str_color = _(L("Color")); - wxString str_pause = _(L("Pause")); + wxString str_color = _L("Color"); + wxString str_pause = _L("Pause"); auto fill_labels = [str_color, str_pause](const std::vector>& times, wxString& new_label, wxString& info_text) @@ -1293,25 +1295,25 @@ void Sidebar::update_sliced_info_sizer() for (int i = (int)times.size() - 1; i >= 0; --i) { if (i == 0 || times[i - 1].first == cgtPausePrint) - new_label += from_u8((boost::format("\n - %1%%2%") % (std::string(str_color.ToUTF8()) + " ") % color_change_count).str()); + new_label += format_wxstr("\n - %1%%2%", str_color + " ", color_change_count); else if (times[i - 1].first == cgtColorChange) - new_label += from_u8((boost::format("\n - %1%%2%") % (std::string(str_color.ToUTF8()) + " ") % color_change_count--).str()); + new_label += format_wxstr("\n - %1%%2%", str_color + " ", color_change_count--); if (i != (int)times.size() - 1 && times[i].first == cgtPausePrint) - new_label += from_u8((boost::format(" -> %1%") % std::string(str_pause.ToUTF8())).str()); + new_label += format_wxstr(" -> %1%", str_pause); - info_text += from_u8((boost::format("\n%1%") % times[i].second).str()); + info_text += format_wxstr("\n%1%", times[i].second); } }; if (ps.estimated_normal_print_time != "N/A") { - new_label += from_u8((boost::format("\n - %1%") % _utf8(L("normal mode"))).str()); - info_text += from_u8((boost::format("\n%1%") % ps.estimated_normal_print_time).str()); + new_label += format_wxstr("\n - %1%", _L("normal mode")); + info_text += format_wxstr("\n%1%", ps.estimated_normal_print_time); fill_labels(ps.estimated_normal_custom_gcode_print_times, new_label, info_text); } if (ps.estimated_silent_print_time != "N/A") { - new_label += from_u8((boost::format("\n - %1%") % _utf8(L("stealth mode"))).str()); - info_text += from_u8((boost::format("\n%1%") % ps.estimated_silent_print_time).str()); + new_label += format_wxstr("\n - %1%", _L("stealth mode")); + info_text += format_wxstr("\n%1%", ps.estimated_silent_print_time); fill_labels(ps.estimated_silent_custom_gcode_print_times, new_label, info_text); } p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label); @@ -1463,11 +1465,11 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi wxString snapshot_label; assert(! paths.empty()); if (paths.size() == 1) { - snapshot_label = _(L("Load File")); + snapshot_label = _L("Load File"); snapshot_label += ": "; snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str()); } else { - snapshot_label = _(L("Load Files")); + snapshot_label = _L("Load Files"); snapshot_label += ": "; snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str()); for (size_t i = 1; i < paths.size(); ++ i) { @@ -1555,7 +1557,7 @@ struct Plater::priv friend priv; public: - void apply_arrange_result(const Vec2crd& tr, double rotation) + void apply_arrange_result(const Vec2d& tr, double rotation) { m_pos = unscaled(tr); m_rotation = rotation; apply_wipe_tower(); @@ -1658,9 +1660,9 @@ struct Plater::priv } // Stride between logical beds - coord_t bed_stride() const { + double bed_stride() const { double bedwidth = plater().bed_shape_bb().size().x(); - return scaled((1. + LOGICAL_BED_GAP) * bedwidth); + return scaled((1. + LOGICAL_BED_GAP) * bedwidth); } // Set up arrange polygon for a ModelInstance and Wipe tower @@ -1670,7 +1672,7 @@ struct Plater::priv ap.bed_idx = ap.translation.x() / bed_stride(); ap.setter = [obj, this](const ArrangePolygon &p) { if (p.is_arranged()) { - auto t = p.translation; + Vec2d t = p.translation.cast(); t.x() += p.bed_idx * bed_stride(); obj->apply_arrange_result(t, p.rotation); } @@ -1903,6 +1905,7 @@ struct Plater::priv GLCanvas3D* get_current_canvas3D(); #if ENABLE_NON_STATIC_CANVAS_MANAGER void unbind_canvas_event_handlers(); + void reset_canvas_volumes(); #endif // ENABLE_NON_STATIC_CANVAS_MANAGER bool init_view_toolbar(); @@ -2271,11 +2274,11 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this](RemovableDriveEjectEvent &evt) { if (evt.data.second) { this->show_action_buttons(this->ready_to_slice); - Slic3r::GUI::show_info(this->q, (boost::format(_utf8(L("Unmounting successful. The device %s(%s) can now be safely removed from the computer."))) - % evt.data.first.name % evt.data.first.path).str()); + Slic3r::GUI::show_info(this->q, format_wxstr(_L("Unmounting successful. The device %s(%s) can now be safely removed from the computer."), + evt.data.first.name, evt.data.first.path)); } else - Slic3r::GUI::show_info(this->q, (boost::format(_utf8(L("Ejecting of device %s(%s) has failed."))) - % evt.data.first.name % evt.data.first.path).str()); + Slic3r::GUI::show_info(this->q, format_wxstr(_L("Ejecting of device %s(%s) has failed."), + evt.data.first.name, evt.data.first.path)); }); this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this](RemovableDrivesChangedEvent &) { this->show_action_buttons(this->ready_to_slice); }); // Start the background thread and register this window as a target for update events. @@ -2287,7 +2290,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) #endif /* _WIN32 */ // Initialize the Undo / Redo stack with a first snapshot. - this->take_snapshot(_(L("New Project"))); + this->take_snapshot(_L("New Project")); // collapse sidebar according to saved value sidebar->collapse(wxGetApp().app_config->get("collapsed_sidebar") == "1"); @@ -2404,7 +2407,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ } } - const auto loading = _(L("Loading")) + dots; + const auto loading = _L("Loading") + dots; wxProgressDialog dlg(loading, loading); dlg.Pulse(); @@ -2414,7 +2417,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ for (size_t i = 0; i < input_files.size(); i++) { const auto &path = input_files[i]; const auto filename = path.filename(); - const auto dlg_info = from_u8((boost::format(_utf8(L("Processing input file %s"))) % from_path(filename)).str()) + "\n"; + const auto dlg_info = format_wxstr(_L("Processing input file %s"), from_path(filename)) + "\n"; dlg.Update(100 * i / input_files.size(), dlg_info); const bool type_3mf = std::regex_match(path.string(), pattern_3mf); @@ -2442,9 +2445,9 @@ std::vector Plater::priv::load_files(const std::vector& input_ if (object->volumes.size() > 1) { Slic3r::GUI::show_info(nullptr, - _(L("You cannot load SLA project with a multi-part object on the bed")) + "\n\n" + - _(L("Please check your object list before preset changing.")), - _(L("Attention!"))); + _L("You cannot load SLA project with a multi-part object on the bed") + "\n\n" + + _L("Please check your object list before preset changing."), + _L("Attention!")); return obj_idxs; } } @@ -2487,19 +2490,19 @@ std::vector Plater::priv::load_files(const std::vector& input_ if (! is_project_file) { if (model.looks_like_multipart_object()) { - wxMessageDialog msg_dlg(q, _(L( + wxMessageDialog msg_dlg(q, _L( "This file contains several objects positioned at multiple heights.\n" "Instead of considering them as multiple objects, should I consider\n" - "this file as a single object having multiple parts?")) + "\n", - _(L("Multi-part object detected")), wxICON_WARNING | wxYES | wxNO); + "this file as a single object having multiple parts?") + "\n", + _L("Multi-part object detected"), wxICON_WARNING | wxYES | wxNO); if (msg_dlg.ShowModal() == wxID_YES) { model.convert_multipart_object(nozzle_dmrs->values.size()); } } } else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf) && model_has_advanced_features(model)) { - wxMessageDialog msg_dlg(q, _(L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?"))+"\n", - _(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO); + wxMessageDialog msg_dlg(q, _L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?")+"\n", + _L("Detected advanced data"), wxICON_WARNING | wxYES | wxNO); if (msg_dlg.ShowModal() == wxID_YES) { Slic3r::GUI::wxGetApp().save_mode(comAdvanced); @@ -2521,8 +2524,8 @@ std::vector Plater::priv::load_files(const std::vector& input_ for (auto obj : model.objects) if ( obj->volumes.size()>1 ) { Slic3r::GUI::show_error(nullptr, - from_u8((boost::format(_utf8(L("You can't to add the object(s) from %s because of one or some of them is(are) multi-part"))) - % from_path(filename)).str())); + format_wxstr(_L("You can't to add the object(s) from %s because of one or some of them is(are) multi-part"), + from_path(filename))); return obj_idxs; } } @@ -2540,11 +2543,11 @@ std::vector Plater::priv::load_files(const std::vector& input_ } if (new_model != nullptr && new_model->objects.size() > 1) { - wxMessageDialog msg_dlg(q, _(L( + wxMessageDialog msg_dlg(q, _L( "Multiple objects were loaded for a multi-material printer.\n" "Instead of considering them as multiple objects, should I consider\n" - "these files to represent a single object having multiple parts?")) + "\n", - _(L("Multi-part object detected")), wxICON_WARNING | wxYES | wxNO); + "these files to represent a single object having multiple parts?") + "\n", + _L("Multi-part object detected"), wxICON_WARNING | wxYES | wxNO); if (msg_dlg.ShowModal() == wxID_YES) { new_model->convert_multipart_object(nozzle_dmrs->values.size()); } @@ -2557,7 +2560,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ { wxGetApp().app_config->update_skein_dir(input_files[input_files.size() - 1].parent_path().string()); // XXX: Plater.pm had @loaded_files, but didn't seem to fill them with the filenames... - statusbar()->set_status_text(_(L("Loaded"))); + statusbar()->set_status_text(_L("Loaded")); } // automatic selection of added objects @@ -2659,8 +2662,8 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode if (scaled_down) { GUI::show_info(q, - _(L("Your object appears to be too large, so it was automatically scaled down to fit your print bed.")), - _(L("Object too large?"))); + _L("Your object appears to be too large, so it was automatically scaled down to fit your print bed."), + _L("Object too large?")); } for (const size_t idx : obj_idxs) { @@ -2722,26 +2725,26 @@ wxString Plater::priv::get_export_file(GUI::FileType file_type) case FT_STL: { output_file.replace_extension("stl"); - dlg_title = _(L("Export STL file:")); + dlg_title = _L("Export STL file:"); break; } case FT_AMF: { // XXX: Problem on OS X with double extension? output_file.replace_extension("zip.amf"); - dlg_title = _(L("Export AMF file:")); + dlg_title = _L("Export AMF file:"); break; } case FT_3MF: { output_file.replace_extension("3mf"); - dlg_title = _(L("Save file as:")); + dlg_title = _L("Save file as:"); break; } case FT_OBJ: { output_file.replace_extension("obj"); - dlg_title = _(L("Export OBJ file:")); + dlg_title = _L("Export OBJ file:"); break; } default: break; @@ -2813,15 +2816,12 @@ void Plater::priv::object_list_changed() void Plater::priv::select_all() { -// this->take_snapshot(_(L("Select All"))); - view3D->select_all(); this->sidebar->obj_list()->update_selections(); } void Plater::priv::deselect_all() { -// this->take_snapshot(_(L("Deselect All"))); view3D->deselect_all(); } @@ -2843,7 +2843,7 @@ void Plater::priv::remove(size_t obj_idx) void Plater::priv::delete_object_from_model(size_t obj_idx) { - wxString snapshot_label = _(L("Delete Object")); + wxString snapshot_label = _L("Delete Object"); if (! model.objects[obj_idx]->name.empty()) snapshot_label += ": " + wxString::FromUTF8(model.objects[obj_idx]->name.c_str()); Plater::TakeSnapshot snapshot(q, snapshot_label); @@ -2854,7 +2854,7 @@ void Plater::priv::delete_object_from_model(size_t obj_idx) void Plater::priv::reset() { - Plater::TakeSnapshot snapshot(q, _(L("Reset Project"))); + Plater::TakeSnapshot snapshot(q, _L("Reset Project")); set_project_filename(wxEmptyString); @@ -2885,7 +2885,7 @@ void Plater::priv::mirror(Axis axis) void Plater::priv::arrange() { - this->take_snapshot(_(L("Arrange"))); + this->take_snapshot(_L("Arrange")); m_ui_jobs.start(Jobs::Arrange); } @@ -2893,7 +2893,7 @@ void Plater::priv::arrange() // This method will find an optimal orientation for the currently selected item // Very similar in nature to the arrange method above... void Plater::priv::sla_optimize_rotation() { - this->take_snapshot(_(L("Optimize Rotation"))); + this->take_snapshot(_L("Optimize Rotation")); m_ui_jobs.start(Jobs::Rotoptimize); } @@ -2934,12 +2934,12 @@ void Plater::priv::find_new_position(const ModelInstancePtrs &instances, for (size_t i = 0; i < instances.size(); ++i) if (movable[i].bed_idx == 0) - instances[i]->apply_arrange_result(movable[i].translation, + instances[i]->apply_arrange_result(movable[i].translation.cast(), movable[i].rotation); } void Plater::priv::ArrangeJob::process() { - static const auto arrangestr = _(L("Arranging")); + static const auto arrangestr = _L("Arranging"); // FIXME: I don't know how to obtain the minimum distance, it depends // on printer technology. I guess the following should work but it crashes. @@ -2966,14 +2966,14 @@ void Plater::priv::ArrangeJob::process() { }, stopfn); } catch (std::exception & /*e*/) { GUI::show_error(plater().q, - _(L("Could not arrange model objects! " - "Some geometries may be invalid."))); + _L("Could not arrange model objects! " + "Some geometries may be invalid.")); } // finalize just here. update_status(int(count), - was_canceled() ? _(L("Arranging canceled.")) - : _(L("Arranging done."))); + was_canceled() ? _L("Arranging canceled.") + : _L("Arranging done.")); } void Plater::priv::RotoptimizeJob::process() @@ -2989,7 +2989,7 @@ void Plater::priv::RotoptimizeJob::process() [this](unsigned s) { if (s < 100) update_status(int(s), - _(L("Searching for optimal orientation"))); + _L("Searching for optimal orientation")); }, [this]() { return was_canceled(); }); @@ -3022,8 +3022,8 @@ void Plater::priv::RotoptimizeJob::process() } update_status(100, - was_canceled() ? _(L("Orientation search canceled.")) - : _(L("Orientation found."))); + was_canceled() ? _L("Orientation search canceled.") + : _L("Orientation found.")); } @@ -3040,7 +3040,7 @@ void Plater::priv::split_object() if (current_model_object->volumes.size() > 1) { - Slic3r::GUI::warning_catcher(q, _(L("The selected object can't be split because it contains more than one volume/material."))); + Slic3r::GUI::warning_catcher(q, _L("The selected object can't be split because it contains more than one volume/material.")); return; } @@ -3048,10 +3048,10 @@ void Plater::priv::split_object() ModelObjectPtrs new_objects; current_model_object->split(&new_objects); if (new_objects.size() == 1) - Slic3r::GUI::warning_catcher(q, _(L("The selected object couldn't be split because it contains only one part."))); + Slic3r::GUI::warning_catcher(q, _L("The selected object couldn't be split because it contains only one part.")); else { - Plater::TakeSnapshot snapshot(q, _(L("Split to Objects"))); + Plater::TakeSnapshot snapshot(q, _L("Split to Objects")); unsigned int counter = 1; for (ModelObject* m : new_objects) @@ -3176,7 +3176,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool if ((return_state & UPDATE_BACKGROUND_PROCESS_INVALID) != 0) { // Validation of the background data failed. - const wxString invalid_str = _(L("Invalid data")); + const wxString invalid_str = _L("Invalid data"); for (auto btn : {ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport}) sidebar->set_btn_label(btn, invalid_str); } @@ -3185,13 +3185,13 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool // Background data is valid. if ((return_state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 || (return_state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0 ) - this->statusbar()->set_status_text(_(L("Ready to slice"))); + this->statusbar()->set_status_text(_L("Ready to slice")); sidebar->set_btn_label(ActionButtonType::abExport, _(label_btn_export)); sidebar->set_btn_label(ActionButtonType::abSendGCode, _(label_btn_send)); const wxString slice_string = background_process.running() && wxGetApp().get_mode() == comSimple ? - _(L("Slicing")) + dots : _(L("Slice now")); + _L("Slicing") + dots : _L("Slice now"); sidebar->set_btn_label(ActionButtonType::abReslice, slice_string); if (background_process.finished()) @@ -3223,7 +3223,7 @@ bool Plater::priv::restart_background_process(unsigned int state) // The print is valid and it can be started. if (this->background_process.start()) { this->statusbar()->set_cancel_callback([this]() { - this->statusbar()->set_status_text(_(L("Cancelling"))); + this->statusbar()->set_status_text(_L("Cancelling")); this->background_process.stop(); }); return true; @@ -3240,7 +3240,7 @@ void Plater::priv::export_gcode(fs::path output_path, bool output_path_on_remova return; if (background_process.is_export_scheduled()) { - GUI::show_error(q, _(L("Another export job is currently running."))); + GUI::show_error(q, _L("Another export job is currently running.")); return; } @@ -3295,7 +3295,7 @@ void Plater::priv::update_sla_scene() void Plater::priv::reload_from_disk() { - Plater::TakeSnapshot snapshot(q, _(L("Reload from disk"))); + Plater::TakeSnapshot snapshot(q, _L("Reload from disk")); const Selection& selection = get_selection(); @@ -3356,7 +3356,7 @@ void Plater::priv::reload_from_disk() { // ask user to select the missing file fs::path search = missing_input_paths.back(); - wxString title = _(L("Please select the file to reload")); + wxString title = _L("Please select the file to reload"); #if defined(__APPLE__) title += " (" + from_u8(search.filename().string()) + ")"; #endif // __APPLE__ @@ -3391,7 +3391,7 @@ void Plater::priv::reload_from_disk() } else { - wxString message = _(L("It is not allowed to change the file to reload")) + " (" + from_u8(search.filename().string()) + ").\n" + _(L("Do you want to retry")) + " ?"; + wxString message = _L("It is not allowed to change the file to reload") + " (" + from_u8(search.filename().string()) + ").\n" + _L("Do you want to retry") + " ?"; wxMessageDialog dlg(q, message, wxMessageBoxCaptionStr, wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION); if (dlg.ShowModal() != wxID_YES) return; @@ -3409,7 +3409,7 @@ void Plater::priv::reload_from_disk() const auto& path = input_paths[i].string(); wxBusyCursor wait; - wxBusyInfo info(_(L("Reload from:")) + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas()); + wxBusyInfo info(_L("Reload from:") + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas()); Model new_model; try @@ -3498,12 +3498,12 @@ void Plater::priv::reload_from_disk() if (!fail_list.empty()) { - wxString message = _(L("Unable to reload:")) + "\n"; + wxString message = _L("Unable to reload:") + "\n"; for (const wxString& s : fail_list) { message += s + "\n"; } - wxMessageDialog dlg(q, message, _(L("Error during reload")), wxOK | wxOK_DEFAULT | wxICON_WARNING); + wxMessageDialog dlg(q, message, _L("Error during reload"), wxOK | wxOK_DEFAULT | wxICON_WARNING); dlg.ShowModal(); } @@ -3522,7 +3522,7 @@ void Plater::priv::reload_all_from_disk() if (model.objects.empty()) return; - Plater::TakeSnapshot snapshot(q, _(L("Reload all from disk"))); + Plater::TakeSnapshot snapshot(q, _L("Reload all from disk")); Plater::SuppressSnapshots suppress(q); Selection& selection = get_selection(); @@ -3543,7 +3543,7 @@ void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* = if (obj_idx < 0) return; - Plater::TakeSnapshot snapshot(q, _(L("Fix Throught NetFabb"))); + Plater::TakeSnapshot snapshot(q, _L("Fix Throught NetFabb")); fix_model_by_win10_sdk_gui(*model.objects[obj_idx], vol_idx); this->update(); @@ -3746,7 +3746,7 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) if (error) { wxString message = evt.GetString(); if (message.IsEmpty()) - message = _(L("Export failed")); + message = _L("Export failed"); if (q->m_tracking_popup_menu) // We don't want to pop-up a message box when tracking a pop-up menu. // We postpone the error message instead. @@ -3756,7 +3756,7 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt) this->statusbar()->set_status_text(message); } if (canceled) - this->statusbar()->set_status_text(_(L("Cancelled"))); + this->statusbar()->set_status_text(_L("Cancelled")); this->sidebar->show_sliced_info_sizer(success); @@ -3819,8 +3819,6 @@ void Plater::priv::on_action_layersediting(SimpleEvent&) void Plater::priv::on_object_select(SimpleEvent& evt) { -// this->take_snapshot(_(L("Object Selection"))); - wxGetApp().obj_list()->update_selections(); selection_changed(); } @@ -3870,7 +3868,7 @@ void Plater::priv::on_right_click(RBtnEvent& evt) */ const MenuIdentifier id = printer_technology == ptSLA ? miObjectSLA : miObjectFFF; if (wxGetApp().get_mode() == comSimple) { - if (menu->FindItem(_(L("Add instance"))) != wxNOT_FOUND) + if (menu->FindItem(_L("Add instance")) != wxNOT_FOUND) { /* Detach an items from the menu, but don't delete them * so that they can be added back later @@ -3882,7 +3880,7 @@ void Plater::priv::on_right_click(RBtnEvent& evt) } } else { - if (menu->FindItem(_(L("Add instance"))) == wxNOT_FOUND) + if (menu->FindItem(_L("Add instance")) == wxNOT_FOUND) { // Prepend items to the menu, if those aren't not there menu->Prepend(items_set_number_of_copies[id]); @@ -4011,20 +4009,20 @@ void Plater::priv::set_project_filename(const wxString& filename) bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/) { if (is_part) { - append_menu_item(menu, wxID_ANY, _(L("Delete")) + "\tDel", _(L("Remove the selected object")), + append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Remove the selected object"), [this](wxCommandEvent&) { q->remove_selected(); }, "delete", nullptr, [this]() { return can_delete(); }, q); - append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected volumes from disk")), + append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected volumes from disk"), [this](wxCommandEvent&) { q->reload_from_disk(); }, "", menu, [this]() { return can_reload_from_disk(); }, q); sidebar->obj_list()->append_menu_item_export_stl(menu); } else { - wxMenuItem* item_increase = append_menu_item(menu, wxID_ANY, _(L("Add instance")) + "\t+", _(L("Add one more instance of the selected object")), + wxMenuItem* item_increase = append_menu_item(menu, wxID_ANY, _L("Add instance") + "\t+", _L("Add one more instance of the selected object"), [this](wxCommandEvent&) { q->increase_instances(); }, "add_copies", nullptr, [this]() { return can_increase_instances(); }, q); - wxMenuItem* item_decrease = append_menu_item(menu, wxID_ANY, _(L("Remove instance")) + "\t-", _(L("Remove one instance of the selected object")), + wxMenuItem* item_decrease = append_menu_item(menu, wxID_ANY, _L("Remove instance") + "\t-", _L("Remove one instance of the selected object"), [this](wxCommandEvent&) { q->decrease_instances(); }, "remove_copies", nullptr, [this]() { return can_decrease_instances(); }, q); - wxMenuItem* item_set_number_of_copies = append_menu_item(menu, wxID_ANY, _(L("Set number of instances")) + dots, _(L("Change the number of instances of the selected object")), + wxMenuItem* item_set_number_of_copies = append_menu_item(menu, wxID_ANY, _L("Set number of instances") + dots, _L("Change the number of instances of the selected object"), [this](wxCommandEvent&) { q->set_number_of_copies(); }, "number_of_copies", nullptr, [this]() { return can_increase_instances(); }, q); @@ -4033,7 +4031,7 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ items_set_number_of_copies.push_back(item_set_number_of_copies); // Delete menu was moved to be after +/- instace to make it more difficult to be selected by mistake. - append_menu_item(menu, wxID_ANY, _(L("Delete")) + "\tDel", _(L("Remove the selected object")), + append_menu_item(menu, wxID_ANY, _L("Delete") + "\tDel", _L("Remove the selected object"), [this](wxCommandEvent&) { q->remove_selected(); }, "delete", nullptr, [this]() { return can_delete(); }, q); menu->AppendSeparator(); @@ -4043,10 +4041,10 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ wxMenuItem* menu_item_printable = sidebar->obj_list()->append_menu_item_printable(menu, q); menu->AppendSeparator(); - append_menu_item(menu, wxID_ANY, _(L("Reload from disk")), _(L("Reload the selected object from disk")), + append_menu_item(menu, wxID_ANY, _L("Reload from disk"), _L("Reload the selected object from disk"), [this](wxCommandEvent&) { reload_from_disk(); }, "", nullptr, [this]() { return can_reload_from_disk(); }, q); - append_menu_item(menu, wxID_ANY, _(L("Export as STL")) + dots, _(L("Export the selected object as STL file")), + append_menu_item(menu, wxID_ANY, _L("Export as STL") + dots, _L("Export the selected object as STL file"), [this](wxCommandEvent&) { q->export_stl(false, true); }, "", nullptr, [this]() { const Selection& selection = get_selection(); @@ -4075,14 +4073,14 @@ bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/ if (mirror_menu == nullptr) return false; - append_menu_item(mirror_menu, wxID_ANY, _(L("Along X axis")), _(L("Mirror the selected object along the X axis")), + append_menu_item(mirror_menu, wxID_ANY, _L("Along X axis"), _L("Mirror the selected object along the X axis"), [this](wxCommandEvent&) { mirror(X); }, "mark_X", menu); - append_menu_item(mirror_menu, wxID_ANY, _(L("Along Y axis")), _(L("Mirror the selected object along the Y axis")), + append_menu_item(mirror_menu, wxID_ANY, _L("Along Y axis"), _L("Mirror the selected object along the Y axis"), [this](wxCommandEvent&) { mirror(Y); }, "mark_Y", menu); - append_menu_item(mirror_menu, wxID_ANY, _(L("Along Z axis")), _(L("Mirror the selected object along the Z axis")), + append_menu_item(mirror_menu, wxID_ANY, _L("Along Z axis"), _L("Mirror the selected object along the Z axis"), [this](wxCommandEvent&) { mirror(Z); }, "mark_Z", menu); - append_submenu(menu, mirror_menu, wxID_ANY, _(L("Mirror")), _(L("Mirror the selected object")), "", + append_submenu(menu, mirror_menu, wxID_ANY, _L("Mirror"), _L("Mirror the selected object"), "", [this]() { return can_mirror(); }, q); return true; @@ -4094,12 +4092,12 @@ bool Plater::priv::complit_init_object_menu() if (split_menu == nullptr) return false; - append_menu_item(split_menu, wxID_ANY, _(L("To objects")), _(L("Split the selected object into individual objects")), + append_menu_item(split_menu, wxID_ANY, _L("To objects"), _L("Split the selected object into individual objects"), [this](wxCommandEvent&) { split_object(); }, "split_object_SMALL", &object_menu, [this]() { return can_split(); }, q); - append_menu_item(split_menu, wxID_ANY, _(L("To parts")), _(L("Split the selected object into individual sub-parts")), + append_menu_item(split_menu, wxID_ANY, _L("To parts"), _L("Split the selected object into individual sub-parts"), [this](wxCommandEvent&) { split_volume(); }, "split_parts_SMALL", &object_menu, [this]() { return can_split(); }, q); - append_submenu(&object_menu, split_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object")), "", + append_submenu(&object_menu, split_menu, wxID_ANY, _L("Split"), _L("Split the selected object"), "", [this]() { return can_split() && wxGetApp().get_mode() > comSimple; }, q); object_menu.AppendSeparator(); @@ -4114,13 +4112,13 @@ bool Plater::priv::complit_init_object_menu() bool Plater::priv::complit_init_sla_object_menu() { - append_menu_item(&sla_object_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object into individual objects")), + append_menu_item(&sla_object_menu, wxID_ANY, _L("Split"), _L("Split the selected object into individual objects"), [this](wxCommandEvent&) { split_object(); }, "split_object_SMALL", nullptr, [this]() { return can_split(); }, q); sla_object_menu.AppendSeparator(); // Add the automatic rotation sub-menu - append_menu_item(&sla_object_menu, wxID_ANY, _(L("Optimize orientation")), _(L("Optimize the rotation of the object for better print results.")), + append_menu_item(&sla_object_menu, wxID_ANY, _L("Optimize orientation"), _L("Optimize the rotation of the object for better print results."), [this](wxCommandEvent&) { sla_optimize_rotation(); }); return true; @@ -4128,7 +4126,7 @@ bool Plater::priv::complit_init_sla_object_menu() bool Plater::priv::complit_init_part_menu() { - append_menu_item(&part_menu, wxID_ANY, _(L("Split")), _(L("Split the selected object into individual sub-parts")), + append_menu_item(&part_menu, wxID_ANY, _L("Split"), _L("Split the selected object into individual sub-parts"), [this](wxCommandEvent&) { split_volume(); }, "split_parts_SMALL", nullptr, [this]() { return can_split(); }, q); part_menu.AppendSeparator(); @@ -4161,6 +4159,15 @@ void Plater::priv::unbind_canvas_event_handlers() if (preview != nullptr) preview->get_canvas3d()->unbind_event_handlers(); } + +void Plater::priv::reset_canvas_volumes() +{ + if (view3D != nullptr) + view3D->get_canvas3d()->reset_volumes(); + + if (preview != nullptr) + preview->get_canvas3d()->reset_volumes(); +} #endif // ENABLE_NON_STATIC_CANVAS_MANAGER bool Plater::priv::init_view_toolbar() @@ -4494,8 +4501,8 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator if (printer_technology_changed) { // Switching the printer technology when jumping forwards / backwards in time. Switch to the last active printer profile of the other type. std::string s_pt = (it_snapshot->snapshot_data.printer_technology == ptFFF) ? "FFF" : "SLA"; - if (! wxGetApp().check_unsaved_changes(from_u8((boost::format(_utf8( - L("%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."))) % s_pt).str()))) + if (! wxGetApp().check_unsaved_changes(format_wxstr(_L( + "%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."), s_pt))) // Don't switch the profiles. return; } @@ -4671,7 +4678,7 @@ void Plater::load_project(const wxString& filename) return; // Take the Undo / Redo snapshot. - Plater::TakeSnapshot snapshot(this, _(L("Load Project")) + ": " + wxString::FromUTF8(into_path(filename).stem().string().c_str())); + Plater::TakeSnapshot snapshot(this, _L("Load Project") + ": " + wxString::FromUTF8(into_path(filename).stem().string().c_str())); p->reset(); @@ -4699,11 +4706,11 @@ void Plater::add_model() wxString snapshot_label; assert(! paths.empty()); if (paths.size() == 1) { - snapshot_label = _(L("Import Object")); + snapshot_label = _L("Import Object"); snapshot_label += ": "; snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str()); } else { - snapshot_label = _(L("Import Objects")); + snapshot_label = _L("Import Objects"); snapshot_label += ": "; snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str()); for (size_t i = 1; i < paths.size(); ++ i) { @@ -4775,7 +4782,7 @@ void Plater::remove(size_t obj_idx) { p->remove(obj_idx); } void Plater::reset() { p->reset(); } void Plater::reset_with_confirm() { - if (wxMessageDialog((wxWindow*)this, _(L("All objects will be removed, continue?")), wxString(SLIC3R_APP_NAME) + " - " + _(L("Delete all")), wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxCENTRE).ShowModal() == wxID_YES) + if (wxMessageDialog((wxWindow*)this, _L("All objects will be removed, continue?"), wxString(SLIC3R_APP_NAME) + " - " + _L("Delete all"), wxYES_NO | wxCANCEL | wxYES_DEFAULT | wxCENTRE).ShowModal() == wxID_YES) reset(); } @@ -4783,7 +4790,7 @@ void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_mo void Plater::remove_selected() { - Plater::TakeSnapshot snapshot(this, _(L("Delete Selected Objects"))); + Plater::TakeSnapshot snapshot(this, _L("Delete Selected Objects")); this->p->view3D->delete_selected(); } @@ -4791,7 +4798,7 @@ void Plater::increase_instances(size_t num) { if (! can_increase_instances()) { return; } - Plater::TakeSnapshot snapshot(this, _(L("Increase Instances"))); + Plater::TakeSnapshot snapshot(this, _L("Increase Instances")); int obj_idx = p->get_selected_object_idx(); @@ -4826,7 +4833,7 @@ void Plater::decrease_instances(size_t num) { if (! can_decrease_instances()) { return; } - Plater::TakeSnapshot snapshot(this, _(L("Decrease Instances"))); + Plater::TakeSnapshot snapshot(this, _L("Decrease Instances")); int obj_idx = p->get_selected_object_idx(); @@ -4857,12 +4864,12 @@ void Plater::set_number_of_copies(/*size_t num*/) ModelObject* model_object = p->model.objects[obj_idx]; - const int num = wxGetNumberFromUser( " ", _(L("Enter the number of copies:")), - _(L("Copies of the selected object")), model_object->instances.size(), 0, 1000, this ); + const int num = wxGetNumberFromUser( " ", _L("Enter the number of copies:"), + _L("Copies of the selected object"), model_object->instances.size(), 0, 1000, this ); if (num < 0) return; - Plater::TakeSnapshot snapshot(this, wxString::Format(_(L("Set numbers of copies to %d")), num)); + Plater::TakeSnapshot snapshot(this, wxString::Format(_L("Set numbers of copies to %d"), num)); int diff = num - (int)model_object->instances.size(); if (diff > 0) @@ -4892,7 +4899,7 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe return; } - Plater::TakeSnapshot snapshot(this, _(L("Cut by Plane"))); + Plater::TakeSnapshot snapshot(this, _L("Cut by Plane")); wxBusyCursor wait; const auto new_objects = object->cut(instance_idx, z, keep_upper, keep_lower, rotate_lower); @@ -4943,7 +4950,7 @@ void Plater::export_gcode(bool prefer_removable) fs::path output_path; { - wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")), + wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _L("Save G-code file as:") : _L("Save SL1 file as:"), start_dir, from_path(default_output_file.filename()), GUI::file_wildcards((printer_technology() == ptFFF) ? FT_GCODE : FT_PNGZIP, default_output_file.extension().string()), @@ -5078,7 +5085,7 @@ void Plater::export_stl(bool extended, bool selection_only) } Slic3r::store_stl(path_u8.c_str(), &mesh, true); - p->statusbar()->set_status_text(from_u8((boost::format(_utf8(L("STL file exported to %s"))) % path).str())); + p->statusbar()->set_status_text(format_wxstr(_L("STL file exported to %s"), path)); } void Plater::export_amf() @@ -5095,10 +5102,10 @@ void Plater::export_amf() bool full_pathnames = wxGetApp().app_config->get("export_sources_full_pathnames") == "1"; if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames)) { // Success - p->statusbar()->set_status_text(from_u8((boost::format(_utf8(L("AMF file exported to %s"))) % path).str())); + p->statusbar()->set_status_text(format_wxstr(_L("AMF file exported to %s"), path)); } else { // Failure - p->statusbar()->set_status_text(from_u8((boost::format(_utf8(L("Error exporting AMF file %s"))) % path).str())); + p->statusbar()->set_status_text(format_wxstr(_L("Error exporting AMF file %s"), path)); } } @@ -5127,12 +5134,12 @@ void Plater::export_3mf(const boost::filesystem::path& output_path) p->generate_thumbnail(thumbnail_data, THUMBNAIL_SIZE_3MF.first, THUMBNAIL_SIZE_3MF.second, false, true, true, true); if (Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames, &thumbnail_data)) { // Success - p->statusbar()->set_status_text(from_u8((boost::format(_utf8(L("3MF file exported to %s"))) % path).str())); + p->statusbar()->set_status_text(format_wxstr(_L("3MF file exported to %s"), path)); p->set_project_filename(path); } else { // Failure - p->statusbar()->set_status_text(from_u8((boost::format(_utf8(L("Error exporting 3MF file %s"))) % path).str())); + p->statusbar()->set_status_text(format_wxstr(_L("Error exporting 3MF file %s"), path)); } } @@ -5192,10 +5199,10 @@ void Plater::reslice() if (p->background_process.running()) { if (wxGetApp().get_mode() == comSimple) - p->sidebar->set_btn_label(ActionButtonType::abReslice, _(L("Slicing")) + dots); + p->sidebar->set_btn_label(ActionButtonType::abReslice, _L("Slicing") + dots); else { - p->sidebar->set_btn_label(ActionButtonType::abReslice, _(L("Slice now"))); + p->sidebar->set_btn_label(ActionButtonType::abReslice, _L("Slice now")); p->show_action_buttons(false); } } @@ -5592,6 +5599,11 @@ void Plater::unbind_canvas_event_handlers() { p->unbind_canvas_event_handlers(); } + +void Plater::reset_canvas_volumes() +{ + p->reset_canvas_volumes(); +} #endif // ENABLE_NON_STATIC_CANVAS_MANAGER PrinterTechnology Plater::printer_technology() const @@ -5694,7 +5706,7 @@ void Plater::paste_from_clipboard() if (!can_paste_from_clipboard()) return; - Plater::TakeSnapshot snapshot(this, _(L("Paste From Clipboard"))); + Plater::TakeSnapshot snapshot(this, _L("Paste From Clipboard")); p->view3D->get_canvas3d()->get_selection().paste_from_clipboard(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index cf1c10681..1fb0eab30 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -275,6 +275,7 @@ public: void set_current_canvas_as_dirty(); #if ENABLE_NON_STATIC_CANVAS_MANAGER void unbind_canvas_event_handlers(); + void reset_canvas_volumes(); #endif // ENABLE_NON_STATIC_CANVAS_MANAGER PrinterTechnology printer_technology() const; diff --git a/src/slic3r/GUI/format.hpp b/src/slic3r/GUI/format.hpp new file mode 100644 index 000000000..5cb3aed4c --- /dev/null +++ b/src/slic3r/GUI/format.hpp @@ -0,0 +1,65 @@ +#ifndef slic3r_GUI_format_hpp_ +#define slic3r_GUI_format_hpp_ + +// Functional wrapper around boost::format. +// One day we may replace this wrapper with C++20 format +// https://en.cppreference.com/w/cpp/utility/format/format +// though C++20 format uses a different template pattern for position independent parameters. +// This wrapper also manages implicit conversion from wxString to UTF8 and format_wxstr() variants are provided to format into wxString. + +#include + +namespace Slic3r { +namespace GUI { + +// Format input mixing UTF8 encoded strings (const char*, std::string) and wxStrings, return a wxString. +template +inline wxString format_wxstr(const char* fmt, TArgs&&... args) { + boost::format message(fmt); + return wxString::FromUTF8(Slic3r::internal::format::format_recursive(message, std::forward(args)...).c_str()); +} +template +inline wxString format_wxstr(const std::string& fmt, TArgs&&... args) { + boost::format message(fmt); + return wxString::FromUTF8(Slic3r::internal::format::format_recursive(message, std::forward(args)...).c_str()); +} +template +inline wxString format_wxstr(const wxString& fmt, TArgs&&... args) { + return format_wxstr(fmt.ToUTF8().data(), std::forward(args)...); +} +template +inline std::string format(const wxString& fmt, TArgs&&... args) { + return format(fmt.ToUTF8().data(), std::forward(args)...); +} + +} // namespace GUI + +namespace internal { + namespace format { + // Wrapper around wxScopedCharBuffer to indicate that the content is UTF8 formatted. + struct utf8_buffer { + // wxScopedCharBuffer is reference counted, therefore copying by value is cheap. + wxScopedCharBuffer data; + }; + // Accept wxString and convert it to UTF8 to be processed by Slic3r::format(). + inline const utf8_buffer cook(const wxString &arg) { + return utf8_buffer { arg.ToUTF8() }; + } + } +} + +} // namespace Slic3r + +namespace boost { + namespace io { + namespace detail { + // Adaptor for boost::format to accept wxString converted to UTF8. + inline std::ostream& operator<<(std::ostream& os, const Slic3r::internal::format::utf8_buffer& str) { + os << str.data.data(); + return os; + } + } + } +} + +#endif /* slic3r_GUI_format_hpp_ */ diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 48b1fbf8a..b86775c88 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -17,6 +17,7 @@ #include #include "libslic3r/libslic3r.h" +#include "libslic3r/format.hpp" #include "libslic3r/Utils.hpp" #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" @@ -24,6 +25,7 @@ #include "slic3r/GUI/UpdateDialogs.hpp" #include "slic3r/GUI/ConfigWizard.hpp" #include "slic3r/GUI/GUI_App.hpp" +#include "slic3r/GUI/format.hpp" #include "slic3r/Utils/Http.hpp" #include "slic3r/Config/Version.hpp" #include "slic3r/Config/Snapshot.hpp" @@ -54,7 +56,7 @@ void copy_file_fix(const fs::path &source, const fs::path &target) { static const auto perms = fs::owner_read | fs::owner_write | fs::group_read | fs::others_read; // aka 644 - BOOST_LOG_TRIVIAL(debug) << boost::format("PresetUpdater: Copying %1% -> %2%") % source % target; + BOOST_LOG_TRIVIAL(debug) << format("PresetUpdater: Copying %1% -> %2%", source, target); // Make sure the file has correct permission both before and after we copy over it if (fs::exists(target)) { @@ -190,12 +192,12 @@ bool PresetUpdater::priv::get_file(const std::string &url, const fs::path &targe { bool res = false; fs::path tmp_path = target_path; - tmp_path += (boost::format(".%1%%2%") % get_current_pid() % TMP_EXTENSION).str(); + tmp_path += format(".%1%%2%", get_current_pid(), TMP_EXTENSION); - BOOST_LOG_TRIVIAL(info) << boost::format("Get: `%1%`\n\t-> `%2%`\n\tvia tmp path `%3%`") - % url - % target_path.string() - % tmp_path.string(); + BOOST_LOG_TRIVIAL(info) << format("Get: `%1%`\n\t-> `%2%`\n\tvia tmp path `%3%`", + url, + target_path.string(), + tmp_path.string()); Http::get(url) .on_progress([this](Http::Progress, bool &cancel) { @@ -203,10 +205,10 @@ bool PresetUpdater::priv::get_file(const std::string &url, const fs::path &targe }) .on_error([&](std::string body, std::string error, unsigned http_status) { (void)body; - BOOST_LOG_TRIVIAL(error) << boost::format("Error getting: `%1%`: HTTP %2%, %3%") - % url - % http_status - % error; + BOOST_LOG_TRIVIAL(error) << format("Error getting: `%1%`: HTTP %2%, %3%", + url, + http_status, + error); }) .on_complete([&](std::string body, unsigned /* http_status */) { fs::fstream file(tmp_path, std::ios::out | std::ios::binary | std::ios::trunc); @@ -235,7 +237,7 @@ void PresetUpdater::priv::sync_version() const { if (! enabled_version_check) { return; } - BOOST_LOG_TRIVIAL(info) << boost::format("Downloading %1% online version from: `%2%`") % SLIC3R_APP_NAME % version_check_url; + BOOST_LOG_TRIVIAL(info) << format("Downloading %1% online version from: `%2%`", SLIC3R_APP_NAME, version_check_url); Http::get(version_check_url) .size_limit(SLIC3R_VERSION_BODY_MAX) @@ -244,10 +246,10 @@ void PresetUpdater::priv::sync_version() const }) .on_error([&](std::string body, std::string error, unsigned http_status) { (void)body; - BOOST_LOG_TRIVIAL(error) << boost::format("Error getting: `%1%`: HTTP %2%, %3%") - % version_check_url - % http_status - % error; + BOOST_LOG_TRIVIAL(error) << format("Error getting: `%1%`: HTTP %2%, %3%", + version_check_url, + http_status, + error); }) .on_complete([&](std::string body, unsigned /* http_status */) { boost::trim(body); @@ -257,11 +259,11 @@ void PresetUpdater::priv::sync_version() const } if (! Semver::parse(body)) { - BOOST_LOG_TRIVIAL(warning) << boost::format("Received invalid contents from `%1%`: Not a correct semver: `%2%`") % SLIC3R_APP_NAME % body; + BOOST_LOG_TRIVIAL(warning) << format("Received invalid contents from `%1%`: Not a correct semver: `%2%`", SLIC3R_APP_NAME, body); return; } - BOOST_LOG_TRIVIAL(info) << boost::format("Got %1% online version: `%2%`. Sending to GUI thread...") % SLIC3R_APP_NAME % body; + BOOST_LOG_TRIVIAL(info) << format("Got %1% online version: `%2%`. Sending to GUI thread...", SLIC3R_APP_NAME, body); wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_VERSION_ONLINE); evt->SetString(GUI::from_u8(body)); @@ -315,11 +317,11 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors) try { new_index.load(idx_path_temp); } catch (const std::exception & /* err */) { - BOOST_LOG_TRIVIAL(error) << boost::format("Could not load downloaded index %1% for vendor %2%: invalid index?") % idx_path_temp % vendor.name; + BOOST_LOG_TRIVIAL(error) << format("Could not load downloaded index %1% for vendor %2%: invalid index?", idx_path_temp, vendor.name); continue; } if (new_index.version() < index.version()) { - BOOST_LOG_TRIVIAL(warning) << boost::format("The downloaded index %1% for vendor %2% is older than the active one. Ignoring the downloaded index.") % idx_path_temp % vendor.name; + BOOST_LOG_TRIVIAL(warning) << format("The downloaded index %1% for vendor %2% is older than the active one. Ignoring the downloaded index.", idx_path_temp, vendor.name); continue; } Slic3r::rename_file(idx_path_temp, idx_path); @@ -331,22 +333,22 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors) // See if a there's a new version to download const auto recommended_it = index.recommended(); if (recommended_it == index.end()) { - BOOST_LOG_TRIVIAL(error) << boost::format("No recommended version for vendor: %1%, invalid index?") % vendor.name; + BOOST_LOG_TRIVIAL(error) << format("No recommended version for vendor: %1%, invalid index?", vendor.name); continue; } const auto recommended = recommended_it->config_version; - BOOST_LOG_TRIVIAL(debug) << boost::format("Got index for vendor: %1%: current version: %2%, recommended version: %3%") - % vendor.name - % vendor.config_version.to_string() - % recommended.to_string(); + BOOST_LOG_TRIVIAL(debug) << format("Got index for vendor: %1%: current version: %2%, recommended version: %3%", + vendor.name, + vendor.config_version.to_string(), + recommended.to_string()); if (vendor.config_version >= recommended) { continue; } // Download a fresh bundle BOOST_LOG_TRIVIAL(info) << "Downloading new bundle for vendor: " << vendor.name; - const auto bundle_url = (boost::format("%1%/%2%.ini") % vendor.config_update_url % recommended.to_string()).str(); + const auto bundle_url = format("%1%/%2%.ini", vendor.config_update_url, recommended.to_string()); const auto bundle_path = cache_path / (vendor.id + ".ini"); if (! get_file(bundle_url, bundle_path)) { continue; } if (cancel) { return; } @@ -394,7 +396,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version auto bundle_path_idx = vendor_path / idx.path().filename(); if (! fs::exists(bundle_path)) { - BOOST_LOG_TRIVIAL(info) << boost::format("Confing bundle not installed for vendor %1%, skipping: ") % idx.vendor(); + BOOST_LOG_TRIVIAL(info) << format("Confing bundle not installed for vendor %1%, skipping: ", idx.vendor()); continue; } @@ -405,7 +407,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version // from the internet, or installed / updated from the installation resources. auto recommended = idx.recommended(); if (recommended == idx.end()) { - BOOST_LOG_TRIVIAL(error) << boost::format("No recommended version for vendor: %1%, invalid index? Giving up.") % idx.vendor(); + BOOST_LOG_TRIVIAL(error) << format("No recommended version for vendor: %1%, invalid index? Giving up.", idx.vendor()); // XXX: what should be done here? continue; } @@ -413,15 +415,15 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version const auto ver_current = idx.find(vp.config_version); const bool ver_current_found = ver_current != idx.end(); - BOOST_LOG_TRIVIAL(debug) << boost::format("Vendor: %1%, version installed: %2%%3%, version cached: %4%") - % vp.name - % vp.config_version.to_string() - % (ver_current_found ? "" : " (not found in index!)") - % recommended->config_version.to_string(); + BOOST_LOG_TRIVIAL(debug) << format("Vendor: %1%, version installed: %2%%3%, version cached: %4%", + vp.name, + vp.config_version.to_string(), + (ver_current_found ? "" : " (not found in index!)"), + recommended->config_version.to_string()); if (! ver_current_found) { // Any published config shall be always found in the latest config index. - auto message = (boost::format("Preset bundle `%1%` version not found in index: %2%") % idx.vendor() % vp.config_version.to_string()).str(); + auto message = format("Preset bundle `%1%` version not found in index: %2%", idx.vendor(), vp.config_version.to_string()); BOOST_LOG_TRIVIAL(error) << message; GUI::show_error(nullptr, message); continue; @@ -440,7 +442,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version } if (recommended->config_version < vp.config_version) { - BOOST_LOG_TRIVIAL(warning) << (boost::format("Recommended config version for the currently running PrusaSlicer is older than the currently installed config for vendor %1%. This should not happen.") % idx.vendor()).str(); + BOOST_LOG_TRIVIAL(warning) << format("Recommended config version for the currently running PrusaSlicer is older than the currently installed config for vendor %1%. This should not happen.", idx.vendor()); continue; } @@ -482,7 +484,7 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version found = true; } } catch (const std::exception &ex) { - BOOST_LOG_TRIVIAL(info) << boost::format("Failed to load the config bundle `%1%`: %2%") % path_in_cache.string() % ex.what(); + BOOST_LOG_TRIVIAL(info) << format("Failed to load the config bundle `%1%`: %2%", path_in_cache.string(), ex.what()); } } @@ -496,13 +498,13 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version try { rsrc_vp = VendorProfile::from_ini(path_in_rsrc, false); } catch (const std::exception &ex) { - BOOST_LOG_TRIVIAL(info) << boost::format("Cannot load the config bundle at `%1%`: %2%") % path_in_rsrc.string() % ex.what(); + BOOST_LOG_TRIVIAL(info) << format("Cannot load the config bundle at `%1%`: %2%", path_in_rsrc.string(), ex.what()); } if (rsrc_vp.valid()) { try { rsrc_idx.load(path_idx_in_rsrc); } catch (const std::exception &ex) { - BOOST_LOG_TRIVIAL(info) << boost::format("Cannot load the config index at `%1%`: %2%") % path_idx_in_rsrc.string() % ex.what(); + BOOST_LOG_TRIVIAL(info) << format("Cannot load the config index at `%1%`: %2%", path_idx_in_rsrc.string(), ex.what()); } recommended = rsrc_idx.recommended(); if (recommended != rsrc_idx.end() && recommended->config_version == rsrc_vp.config_version && recommended->config_version > vp.config_version) { @@ -510,8 +512,8 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version bundle_path_idx_to_install = path_idx_in_rsrc; found = true; } else { - BOOST_LOG_TRIVIAL(warning) << (boost::format("The recommended config version for vendor `%1%` in resources does not match the recommended\n" - " config version for this version of PrusaSlicer. Corrupted installation?") % idx.vendor()).str(); + BOOST_LOG_TRIVIAL(warning) << format("The recommended config version for vendor `%1%` in resources does not match the recommended\n" + " config version for this version of PrusaSlicer. Corrupted installation?", idx.vendor()); } } } @@ -529,11 +531,11 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version /*const auto existing_recommended = existing_idx.recommended(old_slic3r_version); if (existing_recommended != existing_idx.end() && recommended->config_version == existing_recommended->config_version) { // The user has already seen (and presumably rejected) this update - BOOST_LOG_TRIVIAL(info) << boost::format("Downloaded index for `%1%` is the same as installed one, not offering an update.") % idx.vendor(); + BOOST_LOG_TRIVIAL(info) << format("Downloaded index for `%1%` is the same as installed one, not offering an update.",idx.vendor()); continue; }*/ } catch (const std::exception &err) { - BOOST_LOG_TRIVIAL(error) << boost::format("Cannot load the installed index at `%1%`: %2%") % bundle_path_idx % err.what(); + BOOST_LOG_TRIVIAL(error) << format("Cannot load the installed index at `%1%`: %2%", bundle_path_idx, err.what()); } } @@ -542,10 +544,10 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version { const auto recommended_snap = SnapshotDB::singleton().snapshot_with_vendor_preset(vp.name, recommended->config_version); if (recommended_snap != SnapshotDB::singleton().end()) { - BOOST_LOG_TRIVIAL(info) << boost::format("Bundle update %1% %2% already found in snapshot %3%, skipping...") - % vp.name - % recommended->config_version.to_string() - % recommended_snap->id; + BOOST_LOG_TRIVIAL(info) << format("Bundle update %1% %2% already found in snapshot %3%, skipping...", + vp.name, + recommended->config_version.to_string(), + recommended_snap->id); continue; } } @@ -555,9 +557,9 @@ Updates PresetUpdater::priv::get_config_updates(const Semver &old_slic3r_version // offered updates and to not offer the same update again if it was cancelled by the user. copy_file_fix(bundle_path_idx_to_install, bundle_path_idx); } else { - BOOST_LOG_TRIVIAL(warning) << boost::format("Index for vendor %1% indicates update (%2%) but the new bundle was found neither in cache nor resources") - % idx.vendor() - % recommended->config_version.to_string(); + BOOST_LOG_TRIVIAL(warning) << format("Index for vendor %1% indicates update (%2%) but the new bundle was found neither in cache nor resources", + idx.vendor(), + recommended->config_version.to_string()); } } @@ -572,7 +574,7 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons SnapshotDB::singleton().take_snapshot(*GUI::wxGetApp().app_config, Snapshot::SNAPSHOT_DOWNGRADE); } - BOOST_LOG_TRIVIAL(info) << boost::format("Deleting %1% incompatible bundles") % updates.incompats.size(); + BOOST_LOG_TRIVIAL(info) << format("Deleting %1% incompatible bundles", updates.incompats.size()); for (auto &incompat : updates.incompats) { BOOST_LOG_TRIVIAL(info) << '\t' << incompat; @@ -587,7 +589,7 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons SnapshotDB::singleton().take_snapshot(*GUI::wxGetApp().app_config, Snapshot::SNAPSHOT_UPGRADE); } - BOOST_LOG_TRIVIAL(info) << boost::format("Performing %1% updates") % updates.updates.size(); + BOOST_LOG_TRIVIAL(info) << format("Performing %1% updates", updates.updates.size()); for (const auto &update : updates.updates) { BOOST_LOG_TRIVIAL(info) << '\t' << update; @@ -597,8 +599,7 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons PresetBundle bundle; bundle.load_configbundle(update.source.string(), PresetBundle::LOAD_CFGBNDLE_SYSTEM); - BOOST_LOG_TRIVIAL(info) << boost::format("Deleting %1% conflicting presets") - % (bundle.prints.size() + bundle.filaments.size() + bundle.printers.size()); + BOOST_LOG_TRIVIAL(info) << format("Deleting %1% conflicting presets", bundle.prints.size() + bundle.filaments.size() + bundle.printers.size()); auto preset_remover = [](const Preset &preset) { BOOST_LOG_TRIVIAL(info) << '\t' << preset.file; @@ -611,8 +612,8 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons // Also apply the `obsolete_presets` property, removing obsolete ini files - BOOST_LOG_TRIVIAL(info) << boost::format("Deleting %1% obsolete presets") - % (bundle.obsolete_presets.prints.size() + bundle.obsolete_presets.filaments.size() + bundle.obsolete_presets.printers.size()); + BOOST_LOG_TRIVIAL(info) << format("Deleting %1% obsolete presets", + bundle.obsolete_presets.prints.size() + bundle.obsolete_presets.filaments.size() + bundle.obsolete_presets.printers.size()); auto obsolete_remover = [](const char *subdir, const std::string &preset) { auto path = fs::path(Slic3r::data_dir()) / subdir / preset; @@ -694,7 +695,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver &old_slic3 auto updates = p->get_config_updates(old_slic3r_version); if (updates.incompats.size() > 0) { - BOOST_LOG_TRIVIAL(info) << boost::format("%1% bundles incompatible. Asking for action...") % updates.incompats.size(); + BOOST_LOG_TRIVIAL(info) << format("%1% bundles incompatible. Asking for action...", updates.incompats.size()); std::unordered_map incompats_map; for (const auto &incompat : updates.incompats) { @@ -702,15 +703,14 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver &old_slic3 const auto max_slic3r = incompat.version.max_slic3r_version; wxString restrictions; if (min_slic3r != Semver::zero() && max_slic3r != Semver::inf()) { - restrictions = GUI::from_u8((boost::format(_utf8(L("requires min. %s and max. %s"))) - % min_slic3r.to_string() - % max_slic3r.to_string()).str() - ); + restrictions = GUI::format_wxstr(_L("requires min. %s and max. %s"), + min_slic3r.to_string(), + max_slic3r.to_string()); } else if (min_slic3r != Semver::zero()) { - restrictions = GUI::from_u8((boost::format(_utf8(L("requires min. %s"))) % min_slic3r.to_string()).str()); + restrictions = GUI::format_wxstr(_L("requires min. %s"), min_slic3r.to_string()); BOOST_LOG_TRIVIAL(debug) << "Bundle is not downgrade, user will now have to do whole wizard. This should not happen."; } else { - restrictions = GUI::from_u8((boost::format(_utf8(L("requires max. %s"))) % max_slic3r.to_string()).str()); + restrictions = GUI::format_wxstr(_L("requires max. %s"), max_slic3r.to_string()); } incompats_map.emplace(std::make_pair(incompat.vendor, std::move(restrictions))); @@ -742,13 +742,13 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver &old_slic3 for (const auto& update : updates.updates) { incompatible_version = (update.forced_update ? true : incompatible_version); //td::cout << update.forced_update << std::endl; - //BOOST_LOG_TRIVIAL(info) << boost::format("Update requires higher version."); + //BOOST_LOG_TRIVIAL(info) << format("Update requires higher version."); } //forced update if(incompatible_version) { - BOOST_LOG_TRIVIAL(info) << boost::format("Update of %1% bundles available. At least one requires higher version of Slicer.") % updates.updates.size(); + BOOST_LOG_TRIVIAL(info) << format("Update of %1% bundles available. At least one requires higher version of Slicer.", updates.updates.size()); std::vector updates_msg; for (const auto& update : updates.updates) { @@ -778,7 +778,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver &old_slic3 } // regular update - BOOST_LOG_TRIVIAL(info) << boost::format("Update of %1% bundles available. Asking for confirmation ...") % updates.updates.size(); + BOOST_LOG_TRIVIAL(info) << format("Update of %1% bundles available. Asking for confirmation ...", updates.updates.size()); std::vector updates_msg; for (const auto &update : updates.updates) { @@ -813,7 +813,7 @@ void PresetUpdater::install_bundles_rsrc(std::vector bundles, bool { Updates updates; - BOOST_LOG_TRIVIAL(info) << boost::format("Installing %1% bundles from resources ...") % bundles.size(); + BOOST_LOG_TRIVIAL(info) << format("Installing %1% bundles from resources ...", bundles.size()); for (const auto &bundle : bundles) { auto path_in_rsrc = (p->rsrc_path / bundle).replace_extension(".ini"); diff --git a/src/slic3r/pchheader.hpp b/src/slic3r/pchheader.hpp index 3b321d960..ebdabe836 100644 --- a/src/slic3r/pchheader.hpp +++ b/src/slic3r/pchheader.hpp @@ -183,3 +183,7 @@ #include "libslic3r/BoundingBox.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/libslic3r.h" + +#ifdef _WIN32 +#include "GUI/format.hpp" +#endif // _WIN32