diff --git a/resources/localization/list.txt b/resources/localization/list.txt index 1c67fb49f0..875e92721c 100644 --- a/resources/localization/list.txt +++ b/resources/localization/list.txt @@ -87,6 +87,7 @@ src/slic3r/GUI/UpdateDialogs.cpp src/slic3r/GUI/WipeTowerDialog.cpp src/slic3r/GUI/wxExtensions.cpp src/slic3r/Utils/AstroBox.cpp +src/slic3r/Utils/AppUpdater.cpp src/slic3r/Utils/Duet.cpp src/slic3r/Utils/FixModelByWin10.cpp src/slic3r/Utils/FlashAir.cpp @@ -101,6 +102,7 @@ src/libslic3r/ExtrusionEntity.cpp src/libslic3r/Flow.cpp src/libslic3r/Format/3mf.cpp src/libslic3r/Format/AMF.cpp +src/libslic3r/Format/SLAArchiveReader.cpp src/libslic3r/GCode/PostProcessor.cpp src/libslic3r/miniz_extension.cpp src/libslic3r/Preset.cpp @@ -113,3 +115,4 @@ src/libslic3r/PrintBase.cpp src/libslic3r/PrintConfig.cpp src/libslic3r/Zipper.cpp src/libslic3r/PrintObject.cpp +src/libslic3r/PrintObjectSlice.cpp diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index be16a2015e..f88b80c92a 100644 --- a/src/libslic3r/AppConfig.cpp +++ b/src/libslic3r/AppConfig.cpp @@ -340,12 +340,6 @@ std::string AppConfig::load(const std::string &path) // Error while parsing config file. We'll customize the error message and rethrow to be displayed. // ! But to avoid the use of _utf8 (related to use of wxWidgets) // we will rethrow this exception from the place of load() call, if returned value wouldn't be empty - /* - throw Slic3r::RuntimeError( - _utf8(L("Error parsing PrusaSlicer config file, it is probably corrupted. " - "Try to manually delete the file to recover from the error. Your user profiles will not be affected.")) + - "\n\n" + AppConfig::config_path() + "\n\n" + ex.what()); - */ return ex.what(); } } diff --git a/src/libslic3r/ExtrusionRole.cpp b/src/libslic3r/ExtrusionRole.cpp index 1e91df2044..01ec73ed14 100644 --- a/src/libslic3r/ExtrusionRole.cpp +++ b/src/libslic3r/ExtrusionRole.cpp @@ -4,7 +4,6 @@ #include #include -#define L(s) (s) namespace Slic3r { diff --git a/src/libslic3r/Flow.cpp b/src/libslic3r/Flow.cpp index 9f4730261e..1084e6f102 100644 --- a/src/libslic3r/Flow.cpp +++ b/src/libslic3r/Flow.cpp @@ -6,9 +6,6 @@ #include -// Mark string for localization and translate. -#define L(s) Slic3r::I18N::translate(s) - namespace Slic3r { FlowErrorNegativeSpacing::FlowErrorNegativeSpacing() : @@ -58,7 +55,7 @@ static inline FlowRole opt_key_to_flow_role(const std::string &opt_key) static inline void throw_on_missing_variable(const std::string &opt_key, const char *dependent_opt_key) { - throw FlowErrorMissingVariable((boost::format(L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str()); + throw FlowErrorMissingVariable((boost::format(_u8L("Cannot calculate extrusion width for %1%: Variable \"%2%\" not accessible.")) % opt_key % dependent_opt_key).str()); } // Used to provide hints to the user on default extrusion width values, and to provide reasonable values to the PlaceholderParser. diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp index 34594240f5..5a608cb054 100644 --- a/src/libslic3r/Format/3mf.cpp +++ b/src/libslic3r/Format/3mf.cpp @@ -296,11 +296,6 @@ bool is_valid_object_type(const std::string& type) namespace Slic3r { -//! macro used to mark string used at localization, -//! return same string -#define L(s) (s) -#define _(s) Slic3r::I18N::translate(s) - // Base class with error messages management class _3MF_Base { @@ -1875,9 +1870,9 @@ namespace Slic3r { if (m_curr_metadata_name == SLIC3RPE_3MF_VERSION) { m_version = (unsigned int)atoi(m_curr_characters.c_str()); if (m_check_version && (m_version > VERSION_3MF_COMPATIBLE)) { - // std::string msg = _(L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible.")); + // std::string msg = _u8L("The selected 3mf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible."); // throw version_error(msg.c_str()); - const std::string msg = (boost::format(_(L("The selected 3mf file has been saved with a newer version of %1% and is not compatible."))) % std::string(SLIC3R_APP_NAME)).str(); + const std::string msg = (boost::format(_u8L("The selected 3mf file has been saved with a newer version of %1% and is not compatible.")) % std::string(SLIC3R_APP_NAME)).str(); throw version_error(msg); } } else if (m_curr_metadata_name == "Application") { @@ -1888,15 +1883,15 @@ namespace Slic3r { } else if (m_curr_metadata_name == SLIC3RPE_FDM_SUPPORTS_PAINTING_VERSION) { m_fdm_supports_painting_version = (unsigned int) atoi(m_curr_characters.c_str()); check_painting_version(m_fdm_supports_painting_version, FDM_SUPPORTS_PAINTING_VERSION, - _(L("The selected 3MF contains FDM supports painted object using a newer version of PrusaSlicer and is not compatible."))); + _u8L("The selected 3MF contains FDM supports painted object using a newer version of PrusaSlicer and is not compatible.")); } else if (m_curr_metadata_name == SLIC3RPE_SEAM_PAINTING_VERSION) { m_seam_painting_version = (unsigned int) atoi(m_curr_characters.c_str()); check_painting_version(m_seam_painting_version, SEAM_PAINTING_VERSION, - _(L("The selected 3MF contains seam painted object using a newer version of PrusaSlicer and is not compatible."))); + _u8L("The selected 3MF contains seam painted object using a newer version of PrusaSlicer and is not compatible.")); } else if (m_curr_metadata_name == SLIC3RPE_MM_PAINTING_VERSION) { m_mm_painting_version = (unsigned int) atoi(m_curr_characters.c_str()); check_painting_version(m_mm_painting_version, MM_PAINTING_VERSION, - _(L("The selected 3MF contains multi-material painted object using a newer version of PrusaSlicer and is not compatible."))); + _u8L("The selected 3MF contains multi-material painted object using a newer version of PrusaSlicer and is not compatible.")); } return true; diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp index a38960324c..c72855c885 100644 --- a/src/libslic3r/Format/AMF.cpp +++ b/src/libslic3r/Format/AMF.cpp @@ -57,10 +57,6 @@ const char* SLIC3R_CONFIG_TYPE = "slic3rpe_config"; namespace Slic3r { -//! macro used to mark string used at localization, -//! return same string -#define L(s) (s) -#define _(s) Slic3r::I18N::translate(s) struct AMFParserContext { @@ -997,7 +993,7 @@ bool extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_fi { // std::string msg = _(L("The selected amf file has been saved with a newer version of " + std::string(SLIC3R_APP_NAME) + " and is not compatible.")); // throw Slic3r::FileIOError(msg.c_str()); - const std::string msg = (boost::format(_(L("The selected amf file has been saved with a newer version of %1% and is not compatible."))) % std::string(SLIC3R_APP_NAME)).str(); + const std::string msg = (boost::format(_u8L("The selected amf file has been saved with a newer version of %1% and is not compatible.")) % std::string(SLIC3R_APP_NAME)).str(); throw Slic3r::FileIOError(msg); } diff --git a/src/libslic3r/Format/SLAArchiveReader.cpp b/src/libslic3r/Format/SLAArchiveReader.cpp index 09c1570590..f80b9a2ba6 100644 --- a/src/libslic3r/Format/SLAArchiveReader.cpp +++ b/src/libslic3r/Format/SLAArchiveReader.cpp @@ -7,7 +7,6 @@ #include #include -constexpr const char * L(const char * str) { return str; } #include #include diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 65549d2e8b..2fca25c96f 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -71,11 +71,6 @@ using namespace std::literals::string_view_literals; namespace Slic3r { - //! macro used to mark string used at localization, - //! return same string -#define L(s) (s) -#define _(s) Slic3r::I18N::translate(s) - // Only add a newline in case the current G-code does not end with a newline. static inline void check_add_eol(std::string& gcode) { @@ -487,8 +482,8 @@ GCode::ObjectsLayerToPrint GCode::collect_layers_to_print(const PrintObject& obj // first layer may result in skirt/brim in the air and maybe other issues. if (layers_to_print.size() == 1u) { if (!has_extrusions) - throw Slic3r::SlicingError(_(L("There is an object with no extrusions in the first layer.")) + "\n" + - _(L("Object name")) + ": " + object.model_object()->name); + throw Slic3r::SlicingError(_u8L("There is an object with no extrusions in the first layer.") + "\n" + + _u8L("Object name") + ": " + object.model_object()->name); } // In case there are extrusions on this layer, check there is a layer to lay it on. @@ -518,14 +513,14 @@ GCode::ObjectsLayerToPrint GCode::collect_layers_to_print(const PrintObject& obj std::string warning; size_t i = 0; for (i = 0; i < std::min(warning_ranges.size(), size_t(3)); ++i) - warning += Slic3r::format(_(L("Empty layer between %1% and %2%.")), + warning += Slic3r::format(_u8L("Empty layer between %1% and %2%."), warning_ranges[i].first, warning_ranges[i].second) + "\n"; if (i < warning_ranges.size()) - warning += _(L("(Some lines not shown)")) + "\n"; + warning += _u8L("(Some lines not shown)") + "\n"; warning += "\n"; - warning += Slic3r::format(_(L("Object name: %1%")), object.model_object()->name) + "\n\n" - + _(L("Make sure the object is printable. This is usually caused by negligibly small extrusions or by a faulty model. " - "Try to repair the model or change its orientation on the bed.")); + warning += Slic3r::format(_u8L("Object name: %1%"), object.model_object()->name) + "\n\n" + + _u8L("Make sure the object is printable. This is usually caused by negligibly small extrusions or by a faulty model. " + "Try to repair the model or change its orientation on the bed."); const_cast(object.print())->active_step_add_warning( PrintStateBase::WarningLevel::CRITICAL, warning); @@ -655,25 +650,25 @@ namespace DoExport { }; const GCodeConfig& config = print.config(); - check(_(L("Start G-code")), config.start_gcode.value); - if (ret.size() < MAX_TAGS_COUNT) check(_(L("End G-code")), config.end_gcode.value); - if (ret.size() < MAX_TAGS_COUNT) check(_(L("Before layer change G-code")), config.before_layer_gcode.value); - if (ret.size() < MAX_TAGS_COUNT) check(_(L("After layer change G-code")), config.layer_gcode.value); - if (ret.size() < MAX_TAGS_COUNT) check(_(L("Tool change G-code")), config.toolchange_gcode.value); - if (ret.size() < MAX_TAGS_COUNT) check(_(L("Between objects G-code (for sequential printing)")), config.between_objects_gcode.value); - if (ret.size() < MAX_TAGS_COUNT) check(_(L("Color Change G-code")), config.color_change_gcode.value); - if (ret.size() < MAX_TAGS_COUNT) check(_(L("Pause Print G-code")), config.pause_print_gcode.value); - if (ret.size() < MAX_TAGS_COUNT) check(_(L("Template Custom G-code")), config.template_custom_gcode.value); + check(_u8L("Start G-code"), config.start_gcode.value); + if (ret.size() < MAX_TAGS_COUNT) check(_u8L("End G-code"), config.end_gcode.value); + if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Before layer change G-code"), config.before_layer_gcode.value); + if (ret.size() < MAX_TAGS_COUNT) check(_u8L("After layer change G-code"), config.layer_gcode.value); + if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Tool change G-code"), config.toolchange_gcode.value); + if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Between objects G-code (for sequential printing)"), config.between_objects_gcode.value); + if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Color Change G-code"), config.color_change_gcode.value); + if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Pause Print G-code"), config.pause_print_gcode.value); + if (ret.size() < MAX_TAGS_COUNT) check(_u8L("Template Custom G-code"), config.template_custom_gcode.value); if (ret.size() < MAX_TAGS_COUNT) { for (const std::string& value : config.start_filament_gcode.values) { - check(_(L("Filament Start G-code")), value); + check(_u8L("Filament Start G-code"), value); if (ret.size() == MAX_TAGS_COUNT) break; } } if (ret.size() < MAX_TAGS_COUNT) { for (const std::string& value : config.end_filament_gcode.values) { - check(_(L("Filament End G-code")), value); + check(_u8L("Filament End G-code"), value); if (ret.size() == MAX_TAGS_COUNT) break; } @@ -681,7 +676,7 @@ namespace DoExport { if (ret.size() < MAX_TAGS_COUNT) { const CustomGCode::Info& custom_gcode_per_print_z = print.model().custom_gcode_per_print_z; for (const auto& gcode : custom_gcode_per_print_z.gcodes) { - check(_(L("Custom G-code")), gcode.extra); + check(_u8L("Custom G-code"), gcode.extra); if (ret.size() == MAX_TAGS_COUNT) break; } @@ -714,9 +709,9 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu reports += source + ": \"" + keyword + "\"\n"; } print->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, - _(L("In the custom G-code were found reserved keywords:")) + "\n" + + _u8L("In the custom G-code were found reserved keywords:") + "\n" + reports + - _(L("This may cause problems in g-code visualization and printing time estimation."))); + _u8L("This may cause problems in g-code visualization and printing time estimation.")); } BOOST_LOG_TRIVIAL(info) << "Exporting G-code..." << log_memory_info(); @@ -1111,7 +1106,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato } if (initial_extruder_id == static_cast(-1)) // No object to print was found, cancel the G-code export. - throw Slic3r::SlicingError(_(L("No extrusions were generated for objects."))); + throw Slic3r::SlicingError(_u8L("No extrusions were generated for objects.")); // We don't allow switching of extruders per layer by Model::custom_gcode_per_print_z in sequential mode. // Use the extruder IDs collected from Regions. this->set_extruders(print.extruders()); @@ -1122,7 +1117,7 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato tool_ordering.assign_custom_gcodes(print); if (tool_ordering.all_extruders().empty()) // No object to print was found, cancel the G-code export. - throw Slic3r::SlicingError(_(L("No extrusions were generated for objects."))); + throw Slic3r::SlicingError(_u8L("No extrusions were generated for objects.")); has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); initial_extruder_id = (has_wipe_tower && ! print.config().single_extruder_multi_material_priming) ? // The priming towers will be skipped. @@ -1316,8 +1311,8 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // (See https://github.com/prusa3d/PrusaSlicer/issues/5441.) if (overlap) { print.active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, - _(L("Your print is very close to the priming regions. " - "Make sure there is no collision."))); + _u8L("Your print is very close to the priming regions. " + "Make sure there is no collision.")); } else { // Just continue printing, no action necessary. } diff --git a/src/libslic3r/GCode/PostProcessor.cpp b/src/libslic3r/GCode/PostProcessor.cpp index de1807dbb8..c434aa5603 100644 --- a/src/libslic3r/GCode/PostProcessor.cpp +++ b/src/libslic3r/GCode/PostProcessor.cpp @@ -185,11 +185,6 @@ static int run_script(const std::string &script, const std::string &gcode, std:: namespace Slic3r { -//! macro used to mark string used at localization, -//! return same string -#define L(s) (s) -#define _(s) Slic3r::I18N::translate(s) - // Run post processing script / scripts if defined. // Returns true if a post-processing script was executed. // Returns false if no post-processing script was defined. @@ -285,10 +280,10 @@ bool run_post_process_scripts(std::string &src_path, bool make_copy, const std:: throw Slic3r::RuntimeError(msg); } if (! boost::filesystem::exists(gcode_file)) { - const std::string msg = (boost::format(_(L( + const std::string msg = (boost::format(_u8L( "Post-processing script %1% failed.\n\n" "The post-processing script is expected to change the G-code file %2% in place, but the G-code file was deleted and likely saved under a new name.\n" - "Please adjust the post-processing script to change the G-code in place and consult the manual on how to optionally rename the post-processed G-code file.\n"))) + "Please adjust the post-processing script to change the G-code in place and consult the manual on how to optionally rename the post-processed G-code file.\n")) % script % path).str(); BOOST_LOG_TRIVIAL(error) << msg; throw Slic3r::RuntimeError(msg); diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 4f4871366a..58af2da489 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -4,12 +4,17 @@ #include #include #include +#include #include #include +#include "ClipperUtils.hpp" #include "GCodeProcessor.hpp" #include "BoundingBox.hpp" #include "LocalesUtils.hpp" +#include "Geometry.hpp" +#include "Surface.hpp" +#include "Fill/FillRectilinear.hpp" #include @@ -512,6 +517,8 @@ WipeTower::WipeTower(const PrintConfig& config, const std::vector Polygon { + const auto [R, support_scale] = get_wipe_tower_cone_base(m_wipe_tower_width, m_wipe_tower_height, m_wipe_tower_depth, m_wipe_tower_cone_angle); + + double z = m_no_sparse_layers ? (m_current_height + m_layer_info->height) : m_layer_info->z; // the former should actually work in both cases, but let's stay on the safe side (the 2.6.0 is close) + + double r = std::tan(Geometry::deg2rad(m_wipe_tower_cone_angle/2.f)) * (m_wipe_tower_height - z); + Vec2f center = (wt_box.lu + wt_box.rd) / 2.; + double w = wt_box.lu.y() - wt_box.ld.y(); + enum Type { + Arc, + Corner, + ArcStart, + ArcEnd + }; + + // First generate vector of annotated point which form the boundary. + std::vector> pts = {{wt_box.ru, Corner}}; + if (double alpha_start = std::asin((0.5*w)/r); ! std::isnan(alpha_start) && r > 0.5*w+0.01) { + for (double alpha = alpha_start; alpha < M_PI-alpha_start+0.001; alpha+=(M_PI-2*alpha_start) / 20.) + pts.emplace_back(Vec2f(center.x() + r*std::cos(alpha)/support_scale, center.y() + r*std::sin(alpha)), alpha == alpha_start ? ArcStart : Arc); + pts.back().second = ArcEnd; + } + pts.emplace_back(wt_box.lu, Corner); + pts.emplace_back(wt_box.ld, Corner); + for (int i=int(pts.size())-3; i>0; --i) + pts.emplace_back(Vec2f(pts[i].first.x(), 2*center.y()-pts[i].first.y()), i == int(pts.size())-3 ? ArcStart : i == 1 ? ArcEnd : Arc); + pts.emplace_back(wt_box.rd, Corner); + + // Create a Polygon from the points. + Polygon poly; + for (const auto& [pt, tag] : pts) + poly.points.push_back(Point::new_scale(pt)); + + // Prepare polygons to be filled by infill. + Polylines polylines; + if (infill_cone && m_wipe_tower_width > 2*spacing && m_wipe_tower_depth > 2*spacing) { + ExPolygons infill_areas; + ExPolygon wt_contour(poly); + Polygon wt_rectangle(Points{Point::new_scale(wt_box.ld), Point::new_scale(wt_box.rd), Point::new_scale(wt_box.ru), Point::new_scale(wt_box.lu)}); + wt_rectangle = offset(wt_rectangle, scale_(-spacing/2.)).front(); + wt_contour = offset_ex(wt_contour, scale_(-spacing/2.)).front(); + infill_areas = diff_ex(wt_contour, wt_rectangle); + if (infill_areas.size() == 2) { + ExPolygon& bottom_expoly = infill_areas.front().contour.points.front().y() < infill_areas.back().contour.points.front().y() ? infill_areas[0] : infill_areas[1]; + std::unique_ptr filler(Fill::new_from_type(ipMonotonicLines)); + filler->angle = Geometry::deg2rad(45.f); + filler->spacing = spacing; + FillParams params; + params.density = 1.f; + Surface surface(stBottom, bottom_expoly); + filler->bounding_box = get_extents(bottom_expoly); + polylines = filler->fill_surface(&surface, params); + if (! polylines.empty()) { + if (polylines.front().points.front().x() > polylines.back().points.back().x()) { + std::reverse(polylines.begin(), polylines.end()); + for (Polyline& p : polylines) + p.reverse(); + } + } + } + } + + // Find the closest corner and travel to it. + int start_i = 0; + double min_dist = std::numeric_limits::max(); + for (int i=0; i() - center)); + for (size_t i=0; i() - center)); + } + writer.travel(pts[i].first); + } + } + if (++i == int(pts.size())) + i = 0; + } + writer.extrude(pts[start_i].first, feedrate); + return poly; + }; + + // outer contour (always) + bool infill_cone = first_layer && m_wipe_tower_width > 2*spacing && m_wipe_tower_depth > 2*spacing; + Polygon poly = supported_rectangle(wt_box, feedrate, infill_cone); + // brim (first layer only) if (first_layer) { box_coordinates box = wt_box; - float spacing = m_perimeter_width - m_layer_height*float(1.-M_PI_4); - // How many perimeters shall the brim have? size_t loops_num = (m_wipe_tower_brim_width + spacing/2.f) / spacing; - + for (size_t i = 0; i < loops_num; ++ i) { - box.expand(spacing); - writer.rectangle(box); + poly = offset(poly, scale_(spacing)).front(); + int cp = poly.closest_point_index(Point::new_scale(writer.x(), writer.y())); + writer.travel(unscale(poly.points[cp]).cast()); + for (int i=cp+1; true; ++i ) { + if (i==int(poly.points.size())) + i = 0; + writer.extrude(unscale(poly.points[i]).cast()); + if (i == cp) + break; + } } // Save actual brim width to be later passed to the Print object, which will use it // for skirt calculation and pass it to GLCanvas for precise preview box - m_wipe_tower_brim_width_real = wt_box.ld.x() - box.ld.x() + spacing/2.f; - wt_box = box; + m_wipe_tower_brim_width_real = loops_num * spacing; } - // Now prepare future wipe. box contains rectangle that was extruded last (ccw). - Vec2f target = (writer.pos() == wt_box.ld ? wt_box.rd : - (writer.pos() == wt_box.rd ? wt_box.ru : - (writer.pos() == wt_box.ru ? wt_box.lu : - wt_box.ld))); - writer.add_wipe_point(writer.pos()) - .add_wipe_point(target); - + // Now prepare future wipe. + int i = poly.closest_point_index(Point::new_scale(writer.x(), writer.y())); + writer.add_wipe_point(writer.pos()); + writer.add_wipe_point(unscale(poly.points[i==0 ? int(poly.points.size())-1 : i-1]).cast()); // Ask our writer about how much material was consumed. // Skip this in case the layer is sparse and config option to not print sparse layers is enabled. - if (! m_no_sparse_layers || toolchanges_on_layer || first_layer) + if (! m_no_sparse_layers || toolchanges_on_layer || first_layer) { if (m_current_tool < m_used_filament_length.size()) m_used_filament_length[m_current_tool] += writer.get_and_reset_used_filament_length(); + m_current_height += m_layer_info->height; + } return construct_tcr(writer, false, old_tool); } +// Static method to get the radius and x-scaling of the stabilizing cone base. +std::pair WipeTower::get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg) +{ + double R = std::tan(Geometry::deg2rad(angle_deg/2.)) * height; + double fake_width = 0.66 * width; + double diag = std::hypot(fake_width / 2., depth / 2.); + double support_scale = 1.; + if (R > diag) { + double w = fake_width; + double sin = 0.5 * depth / diag; + double tan = depth / w; + double t = (R - diag) * sin; + support_scale = (w / 2. + t / tan + t * tan) / (w / 2.); + } + return std::make_pair(R, support_scale); +} + // Appends a toolchange into m_plan and calculates neccessary depth of the corresponding box void WipeTower::plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, float wipe_volume) @@ -1250,6 +1383,8 @@ void WipeTower::plan_tower() m_wipe_tower_depth = 0.f; for (auto& layer : m_plan) layer.depth = 0.f; + m_wipe_tower_height = m_plan.empty() ? 0.f : m_plan.back().z; + m_current_height = 0.f; for (int layer_index = int(m_plan.size()) - 1; layer_index >= 0; --layer_index) { @@ -1334,8 +1469,6 @@ void WipeTower::generate(std::vector> & if (m_plan.empty()) return; - m_extra_spacing = 1.f; - plan_tower(); for (int i=0;i<5;++i) { save_on_last_wipe(); @@ -1343,6 +1476,7 @@ void WipeTower::generate(std::vector> & } m_layer_info = m_plan.begin(); + m_current_height = 0.f; // we don't know which extruder to start with - we'll set it according to the first toolchange for (const auto& layer : m_plan) { @@ -1358,7 +1492,7 @@ void WipeTower::generate(std::vector> & m_old_temperature = -1; // reset last temperature written in the gcode std::vector layer_result; - for (auto layer : m_plan) + for (const WipeTower::WipeTowerInfo& layer : m_plan) { set_layer(layer.z, layer.height, 0, false/*layer.z == m_plan.front().z*/, layer.z == m_plan.back().z); m_internal_rotation += 180.f; diff --git a/src/libslic3r/GCode/WipeTower.hpp b/src/libslic3r/GCode/WipeTower.hpp index 7f4a6bf9aa..561123d797 100644 --- a/src/libslic3r/GCode/WipeTower.hpp +++ b/src/libslic3r/GCode/WipeTower.hpp @@ -23,6 +23,8 @@ class WipeTower public: static const std::string never_skip_tag() { return "_GCODE_WIPE_TOWER_NEVER_SKIP_TAG"; } + static std::pair get_wipe_tower_cone_base(double width, double height, double depth, double angle_deg); + struct Extrusion { Extrusion(const Vec2f &pos, float width, unsigned int tool) : pos(pos), width(width), tool(tool) {} @@ -142,6 +144,7 @@ public: float get_depth() const { return m_wipe_tower_depth; } float get_brim_width() const { return m_wipe_tower_brim_width_real; } + float get_wipe_tower_height() const { return m_wipe_tower_height; } @@ -253,6 +256,8 @@ private: Vec2f m_wipe_tower_pos; // Left front corner of the wipe tower in mm. float m_wipe_tower_width; // Width of the wipe tower. float m_wipe_tower_depth = 0.f; // Depth of the wipe tower + float m_wipe_tower_height = 0.f; + float m_wipe_tower_cone_angle = 0.f; float m_wipe_tower_brim_width = 0.f; // Width of brim (mm) from config float m_wipe_tower_brim_width_real = 0.f; // Width of brim (mm) after generation float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis) @@ -359,6 +364,10 @@ private: std::vector m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...)) std::vector::iterator m_layer_info = m_plan.end(); + // This sums height of all extruded layers, not counting the layers which + // will be later removed when the "no_sparse_layers" is used. + float m_current_height = 0.f; + // Stores information about used filament length per extruder: std::vector m_used_filament_length; diff --git a/src/libslic3r/Geometry/VoronoiUtilsCgal.cpp b/src/libslic3r/Geometry/VoronoiUtilsCgal.cpp index c3348110b1..832152c5fd 100644 --- a/src/libslic3r/Geometry/VoronoiUtilsCgal.cpp +++ b/src/libslic3r/Geometry/VoronoiUtilsCgal.cpp @@ -128,7 +128,7 @@ inline static Linef make_linef(const VD::edge_type &edge) return {Vec2d(v0->x(), v0->y()), Vec2d(v1->x(), v1->y())}; } -inline static bool is_equal(const VD::vertex_type &first, const VD::vertex_type &second) { return first.x() == second.x() && first.y() == second.y(); } +[[maybe_unused]] inline static bool is_equal(const VD::vertex_type &first, const VD::vertex_type &second) { return first.x() == second.x() && first.y() == second.y(); } // FIXME Lukas H.: Also includes parabolic segments. bool VoronoiUtilsCgal::is_voronoi_diagram_planar_intersection(const VD &voronoi_diagram) diff --git a/src/libslic3r/I18N.hpp b/src/libslic3r/I18N.hpp index db4fd22dfe..3cc196b6ab 100644 --- a/src/libslic3r/I18N.hpp +++ b/src/libslic3r/I18N.hpp @@ -3,6 +3,12 @@ #include +#ifdef SLIC3R_CURRENTLY_COMPILING_GUI_MODULE + #ifndef SLIC3R_ALLOW_LIBSLIC3R_I18N_IN_SLIC3R + #error You included libslic3r/I18N.hpp into a file belonging to slic3r module. + #endif +#endif + namespace Slic3r { namespace I18N { @@ -15,4 +21,17 @@ namespace I18N { } // namespace Slic3r +// When this is included from slic3r, better do not define the translation functions. +// Macros from slic3r/GUI/I18N.hpp should be used there. +#ifndef SLIC3R_CURRENTLY_COMPILING_GUI_MODULE + #ifdef L + #error L macro is defined where it shouldn't be. Didn't you include slic3r/GUI/I18N.hpp in libslic3r by mistake? + #endif + namespace { + const char* L(const char* s) { return s; } + const char* L_CONTEXT(const char* s, const char* context) { return s; } + std::string _u8L(const char* s) { return Slic3r::I18N::translate(s); } + } +#endif + #endif /* slic3r_I18N_hpp_ */ diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 55e7235ebb..94a1259b6c 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -170,7 +170,7 @@ namespace client template struct OptWithPos { OptWithPos() {} - OptWithPos(ConfigOptionConstPtr opt, boost::iterator_range it_range) : opt(opt), it_range(it_range) {} + OptWithPos(ConfigOptionConstPtr opt, boost::iterator_range it_range, bool writable = false) : opt(opt), it_range(it_range), writable(writable) {} ConfigOptionConstPtr opt { nullptr }; bool writable { false }; // -1 means it is a scalar variable, or it is a vector variable and index was not assigned yet or the whole vector is considered. @@ -720,9 +720,14 @@ namespace client } struct MyContext : public ConfigOptionResolver { + // Config provided as a parameter to PlaceholderParser invocation, overriding PlaceholderParser stored config. const DynamicConfig *external_config = nullptr; + // Config stored inside PlaceholderParser. const DynamicConfig *config = nullptr; + // Config provided as a parameter to PlaceholderParser invocation, evaluated after the two configs above. const DynamicConfig *config_override = nullptr; + // Config provided as a parameter to PlaceholderParser invocation, containing variables that will be read out + // and processed by the PlaceholderParser callee. mutable DynamicConfig *config_outputs = nullptr; // Local variables, read / write mutable DynamicConfig config_local; @@ -737,6 +742,7 @@ namespace client // Table to translate symbol tag to a human readable error message. static std::map tag_to_error_message; + // Should the parser consider the parsed string to be a macro or a boolean expression? static bool evaluate_full_macro(const MyContext *ctx) { return ! ctx->just_boolean_expression; } const ConfigOption* optptr(const t_config_option_key &opt_key) const override @@ -762,13 +768,13 @@ namespace client out = this->config_local.optptr(opt_key); return out; } - void store_new_variable(const std::string &opt_key, ConfigOption *opt, bool global_variable) { - assert(opt != nullptr); + void store_new_variable(const std::string &opt_key, std::unique_ptr &&opt, bool global_variable) { + assert(opt); if (global_variable) { assert(this->context_data != nullptr && this->context_data->global_config); - this->context_data->global_config->set_key_value(opt_key, opt); + this->context_data->global_config->set_key_value(opt_key, opt.release()); } else - this->config_local.set_key_value(opt_key ,opt); + this->config_local.set_key_value(opt_key, opt.release()); } template @@ -844,9 +850,10 @@ namespace client boost::iterator_range &opt_key, OptWithPos &output) { - const ConfigOption *opt = ctx->resolve_symbol(std::string(opt_key.begin(), opt_key.end())); + const std::string key{ opt_key.begin(), opt_key.end() }; + const ConfigOption *opt = ctx->resolve_symbol(key); if (opt == nullptr) { - opt = ctx->resolve_output_symbol(std::string(opt_key.begin(), opt_key.end())); + opt = ctx->resolve_output_symbol(key); if (opt == nullptr) ctx->throw_exception("Not a variable name", opt_key); output.writable = true; @@ -872,83 +879,233 @@ namespace client output.it_range.end() = it_end; } + // Evaluating a scalar variable into expr, + // all possible ConfigOption types are supported. + template + static void scalar_variable_to_expr( + const MyContext *ctx, + OptWithPos &opt, + expr &output) + { + assert(opt.opt->is_scalar()); + + switch (opt.opt->type()) { + case coFloat: output.set_d(opt.opt->getFloat()); break; + case coInt: output.set_i(opt.opt->getInt()); break; + case coString: output.set_s(static_cast(opt.opt)->value); break; + case coPercent: output.set_d(opt.opt->getFloat()); break; + case coEnum: + case coPoint: output.set_s(opt.opt->serialize()); break; + case coBool: output.set_b(opt.opt->getBool()); break; + case coFloatOrPercent: + { + std::string opt_key(opt.it_range.begin(), opt.it_range.end()); + if (boost::ends_with(opt_key, "extrusion_width")) { + // Extrusion width supports defaults and a complex graph of dependencies. + output.set_d(Flow::extrusion_width(opt_key, *ctx, static_cast(ctx->current_extruder_id))); + } else if (! static_cast(opt.opt)->percent) { + // Not a percent, just return the value. + output.set_d(opt.opt->getFloat()); + } else { + // Resolve dependencies using the "ratio_over" link to a parent value. + const ConfigOptionDef *opt_def = print_config_def.get(opt_key); + assert(opt_def != nullptr); + double v = opt.opt->getFloat() * 0.01; // percent to ratio + for (;;) { + const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over); + if (opt_parent == nullptr) + ctx->throw_exception("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies", opt.it_range); + if (boost::ends_with(opt_def->ratio_over, "extrusion_width")) { + // Extrusion width supports defaults and a complex graph of dependencies. + assert(opt_parent->type() == coFloatOrPercent); + v *= Flow::extrusion_width(opt_def->ratio_over, static_cast(opt_parent), *ctx, static_cast(ctx->current_extruder_id)); + break; + } + if (opt_parent->type() == coFloat || opt_parent->type() == coFloatOrPercent) { + v *= opt_parent->getFloat(); + if (opt_parent->type() == coFloat || ! static_cast(opt_parent)->percent) + break; + v *= 0.01; // percent to ratio + } + // Continue one level up in the "ratio_over" hierarchy. + opt_def = print_config_def.get(opt_def->ratio_over); + assert(opt_def != nullptr); + } + output.set_d(v); + } + break; + } + default: + ctx->throw_exception("Unsupported scalar variable type", opt.it_range); + } + } + + // Evaluating one element of a vector variable. + // all possible ConfigOption types are supported. + template + static void vector_element_to_expr( + const MyContext *ctx, + OptWithPos &opt, + expr &output) + { + assert(opt.opt->is_vector()); + if (! opt.has_index()) + ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range); + const ConfigOptionVectorBase* vec = static_cast(opt.opt); + if (vec->empty()) + ctx->throw_exception("Indexing an empty vector variable", opt.it_range); + size_t idx = (opt.index < 0) ? 0 : (opt.index >= int(vec->size())) ? 0 : size_t(opt.index); + switch (opt.opt->type()) { + case coFloats: output.set_d(static_cast(opt.opt)->values[idx]); break; + case coInts: output.set_i(static_cast(opt.opt)->values[idx]); break; + case coStrings: output.set_s(static_cast(opt.opt)->values[idx]); break; + case coPercents: output.set_d(static_cast(opt.opt)->values[idx]); break; + case coPoints: output.set_s(to_string(static_cast(opt.opt)->values[idx])); break; + case coBools: output.set_b(static_cast(opt.opt)->values[idx] != 0); break; + //case coEnums: output.set_s(opt.opt->vserialize()[idx]); break; + default: + ctx->throw_exception("Unsupported vector variable type", opt.it_range); + } + } + + template + static void check_writable(const MyContext *ctx, OptWithPos &opt) { + if (! opt.writable) + ctx->throw_exception("Cannot modify a read-only variable", opt.it_range); + } + + template + static void check_numeric(const expr ¶m) { + if (! param.numeric_type()) + param.throw_exception("Right side is not a numeric expression"); + }; + + template + static size_t evaluate_count(const expr &expr_count) { + if (expr_count.type() != expr::TYPE_INT) + expr_count.throw_exception("Expected number of elements to fill a vector with."); + int count = expr_count.i(); + if (count < 0) + expr_count.throw_exception("Negative number of elements specified."); + return size_t(count); + }; + + template + static void scalar_variable_assign_scalar( + const MyContext *ctx, + OptWithPos &lhs, + const expr &rhs) + { + assert(lhs.opt->is_scalar()); + check_writable(ctx, lhs); + ConfigOption *wropt = const_cast(lhs.opt); + switch (wropt->type()) { + case coFloat: + check_numeric(rhs); + static_cast(wropt)->value = rhs.as_d(); + break; + case coInt: + check_numeric(rhs); + static_cast(wropt)->value = rhs.as_i(); + break; + case coString: + static_cast(wropt)->value = rhs.to_string(); + break; + case coPercent: + check_numeric(rhs); + static_cast(wropt)->value = rhs.as_d(); + break; + case coBool: + if (rhs.type() != expr::TYPE_BOOL) + ctx->throw_exception("Right side is not a boolean expression", rhs.it_range); + static_cast(wropt)->value = rhs.b(); + break; + default: + ctx->throw_exception("Unsupported output scalar variable type", lhs.it_range); + } + } + + template + static void vector_variable_element_assign_scalar( + const MyContext *ctx, + OptWithPos &lhs, + const expr &rhs) + { + assert(lhs.opt->is_vector()); + check_writable(ctx, lhs); + if (! lhs.has_index()) + ctx->throw_exception("Referencing an output vector variable when scalar is expected", lhs.it_range); + ConfigOptionVectorBase *vec = const_cast(static_cast(lhs.opt)); + if (vec->empty()) + ctx->throw_exception("Indexing an empty vector variable", lhs.it_range); + if (lhs.index >= int(vec->size())) + ctx->throw_exception("Index out of range", lhs.it_range); + switch (lhs.opt->type()) { + case coFloats: + check_numeric(rhs); + static_cast(vec)->values[lhs.index] = rhs.as_d(); + break; + case coInts: + check_numeric(rhs); + static_cast(vec)->values[lhs.index] = rhs.as_i(); + break; + case coStrings: + static_cast(vec)->values[lhs.index] = rhs.to_string(); + break; + case coPercents: + check_numeric(rhs); + static_cast(vec)->values[lhs.index] = rhs.as_d(); + break; + case coBools: + if (rhs.type() != expr::TYPE_BOOL) + ctx->throw_exception("Right side is not a boolean expression", rhs.it_range); + static_cast(vec)->values[lhs.index] = rhs.b(); + break; + default: + ctx->throw_exception("Unsupported output vector variable type", lhs.it_range); + } + } + + template + static void vector_variable_assign_expr_with_count( + const MyContext *ctx, + OptWithPos &lhs, + const expr &rhs_count, + const expr &rhs_value) + { + size_t count = evaluate_count(rhs_count); + auto *opt = const_cast(lhs.opt); + switch (lhs.opt->type()) { + case coFloats: + check_numeric(rhs_value); + static_cast(opt)->values.assign(count, rhs_value.as_d()); + break; + case coInts: + check_numeric(rhs_value); + static_cast(opt)->values.assign(count, rhs_value.as_i()); + break; + case coStrings: + static_cast(opt)->values.assign(count, rhs_value.to_string()); + break; + case coBools: + if (rhs_value.type() != expr::TYPE_BOOL) + rhs_value.throw_exception("Right side is not a boolean expression"); + static_cast(opt)->values.assign(count, rhs_value.b()); + break; + default: assert(false); + } + } + template static void variable_value( const MyContext *ctx, OptWithPos &opt, expr &output) { - if (opt.opt->is_vector()) { - if (! opt.has_index()) - ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range); - const ConfigOptionVectorBase *vec = static_cast(opt.opt); - if (vec->empty()) - ctx->throw_exception("Indexing an empty vector variable", opt.it_range); - size_t idx = (opt.index < 0) ? 0 : (opt.index >= int(vec->size())) ? 0 : size_t(opt.index); - switch (opt.opt->type()) { - case coFloats: output.set_d(static_cast(opt.opt)->values[idx]); break; - case coInts: output.set_i(static_cast(opt.opt)->values[idx]); break; - case coStrings: output.set_s(static_cast(opt.opt)->values[idx]); break; - case coPercents: output.set_d(static_cast(opt.opt)->values[idx]); break; - case coPoints: output.set_s(to_string(static_cast(opt.opt)->values[idx])); break; - case coBools: output.set_b(static_cast(opt.opt)->values[idx] != 0); break; - //case coEnums: output.set_s(opt.opt->vserialize()[idx]); break; - default: - ctx->throw_exception("Unknown vector variable type", opt.it_range); - } - } else { - assert(opt.opt->is_scalar()); - switch (opt.opt->type()) { - case coFloat: output.set_d(opt.opt->getFloat()); break; - case coInt: output.set_i(opt.opt->getInt()); break; - case coString: output.set_s(static_cast(opt.opt)->value); break; - case coPercent: output.set_d(opt.opt->getFloat()); break; - case coEnum: - case coPoint: output.set_s(opt.opt->serialize()); break; - case coBool: output.set_b(opt.opt->getBool()); break; - case coFloatOrPercent: - { - std::string opt_key(opt.it_range.begin(), opt.it_range.end()); - if (boost::ends_with(opt_key, "extrusion_width")) { - // Extrusion width supports defaults and a complex graph of dependencies. - output.set_d(Flow::extrusion_width(opt_key, *ctx, static_cast(ctx->current_extruder_id))); - } else if (! static_cast(opt.opt)->percent) { - // Not a percent, just return the value. - output.set_d(opt.opt->getFloat()); - } else { - // Resolve dependencies using the "ratio_over" link to a parent value. - const ConfigOptionDef *opt_def = print_config_def.get(opt_key); - assert(opt_def != nullptr); - double v = opt.opt->getFloat() * 0.01; // percent to ratio - for (;;) { - const ConfigOption *opt_parent = opt_def->ratio_over.empty() ? nullptr : ctx->resolve_symbol(opt_def->ratio_over); - if (opt_parent == nullptr) - ctx->throw_exception("FloatOrPercent variable failed to resolve the \"ratio_over\" dependencies", opt.it_range); - if (boost::ends_with(opt_def->ratio_over, "extrusion_width")) { - // Extrusion width supports defaults and a complex graph of dependencies. - assert(opt_parent->type() == coFloatOrPercent); - v *= Flow::extrusion_width(opt_def->ratio_over, static_cast(opt_parent), *ctx, static_cast(ctx->current_extruder_id)); - break; - } - if (opt_parent->type() == coFloat || opt_parent->type() == coFloatOrPercent) { - v *= opt_parent->getFloat(); - if (opt_parent->type() == coFloat || ! static_cast(opt_parent)->percent) - break; - v *= 0.01; // percent to ratio - } - // Continue one level up in the "ratio_over" hierarchy. - opt_def = print_config_def.get(opt_def->ratio_over); - assert(opt_def != nullptr); - } - output.set_d(v); - } - break; - } - default: - ctx->throw_exception("Unknown scalar variable type", opt.it_range); - } - } - + if (opt.opt->is_vector()) + vector_element_to_expr(ctx, opt, output); + else + scalar_variable_to_expr(ctx, opt, output); output.it_range = opt.it_range; } @@ -974,6 +1131,7 @@ namespace client output.it_range = opt.it_range; } + // Reference to an existing symbol, or a name of a new symbol. template struct NewOldVariable { std::string name; @@ -1010,240 +1168,157 @@ namespace client out.it_range = it_range; } - template - static void new_scalar_variable( - const MyContext *ctx, - bool global_variable, - NewOldVariable &output_variable, - const expr ¶m) - { - auto check_numeric = [](const expr ¶m) { - if (! param.numeric_type()) - param.throw_exception("Right side is not a numeric expression"); - }; - if (output_variable.opt) { - if (output_variable.opt->is_vector()) - param.throw_exception("Cannot assign a scalar value to a vector variable."); - switch (output_variable.opt->type()) { - case coFloat: - check_numeric(param); - static_cast(output_variable.opt)->value = param.as_d(); - break; - case coInt: - check_numeric(param); - static_cast(output_variable.opt)->value = param.as_i(); - break; - case coString: - static_cast(output_variable.opt)->value = param.to_string(); - break; - case coBool: - if (param.type() != expr::TYPE_BOOL) - param.throw_exception("Right side is not a boolean expression"); - static_cast(output_variable.opt)->value = param.b(); - break; - default: assert(false); - } - } else { - switch (param.type()) { - case expr::TYPE_BOOL: output_variable.opt = new ConfigOptionBool(param.b()); break; - case expr::TYPE_INT: output_variable.opt = new ConfigOptionInt(param.i()); break; - case expr::TYPE_DOUBLE: output_variable.opt = new ConfigOptionFloat(param.d()); break; - case expr::TYPE_STRING: output_variable.opt = new ConfigOptionString(param.s()); break; - default: assert(false); - } - const_cast(ctx)->store_new_variable(output_variable.name, output_variable.opt, global_variable); - } - } - - template - static void check_writable(const MyContext *ctx, OptWithPos &opt) { - if (! opt.writable) - ctx->throw_exception("Cannot modify a read-only variable", opt.it_range); - } - // Decoding a scalar variable symbol "opt", assigning it a value of "param". template - static void assign_scalar_variable( + static void scalar_variable_assign_scalar_expression( const MyContext *ctx, OptWithPos &opt, - expr ¶m) + const expr ¶m) { check_writable(ctx, opt); - auto check_numeric = [](const expr ¶m) { - if (! param.numeric_type()) - param.throw_exception("Right side is not a numeric expression"); - }; - if (opt.opt->is_vector()) { - if (! opt.has_index()) - ctx->throw_exception("Referencing an output vector variable when scalar is expected", opt.it_range); - ConfigOptionVectorBase *vec = const_cast(static_cast(opt.opt)); - if (vec->empty()) - ctx->throw_exception("Indexing an empty vector variable", opt.it_range); - if (opt.index >= int(vec->size())) - ctx->throw_exception("Index out of range", opt.it_range); - switch (opt.opt->type()) { - case coFloats: - check_numeric(param); - static_cast(vec)->values[opt.index] = param.as_d(); - break; - case coInts: - check_numeric(param); - static_cast(vec)->values[opt.index] = param.as_i(); - break; - case coStrings: - static_cast(vec)->values[opt.index] = param.to_string(); - break; - case coPercents: - check_numeric(param); - static_cast(vec)->values[opt.index] = param.as_d(); - break; - case coBools: - if (param.type() != expr::TYPE_BOOL) - ctx->throw_exception("Right side is not a boolean expression", param.it_range); - static_cast(vec)->values[opt.index] = param.b(); - break; - default: - ctx->throw_exception("Unsupported output vector variable type", opt.it_range); - } - } else { - assert(opt.opt->is_scalar()); - ConfigOption *wropt = const_cast(opt.opt); - switch (wropt->type()) { - case coFloat: - check_numeric(param); - static_cast(wropt)->value = param.as_d(); - break; - case coInt: - check_numeric(param); - static_cast(wropt)->value = param.as_i(); - break; - case coString: - static_cast(wropt)->value = param.to_string(); - break; - case coPercent: - check_numeric(param); - static_cast(wropt)->value = param.as_d(); - break; - case coBool: - if (param.type() != expr::TYPE_BOOL) - ctx->throw_exception("Right side is not a boolean expression", param.it_range); - static_cast(wropt)->value = param.b(); - break; - default: - ctx->throw_exception("Unsupported output scalar variable type", opt.it_range); - } - } + if (opt.opt->is_vector()) + vector_variable_element_assign_scalar(ctx, opt, param); + else + scalar_variable_assign_scalar(ctx, opt, param); } template - static void new_vector_variable_array( + static void scalar_variable_new_from_scalar_expression( const MyContext *ctx, bool global_variable, - NewOldVariable &output_variable, - const expr &expr_count, - const expr &expr_value) + NewOldVariable &lhs, + const expr &rhs) { - auto check_numeric = [](const expr ¶m) { - if (! param.numeric_type()) - param.throw_exception("Right side is not a numeric expression"); - }; - auto evaluate_count = [](const expr &expr_count) -> size_t { - if (expr_count.type() != expr::TYPE_INT) - expr_count.throw_exception("Expected number of elements to fill a vector with."); - int count = expr_count.i(); - if (count < 0) - expr_count.throw_exception("Negative number of elements specified."); - return size_t(count); - }; - if (output_variable.opt) { - if (output_variable.opt->is_scalar()) - expr_value.throw_exception("Cannot assign a vector value to a scalar variable."); - size_t count = evaluate_count(expr_count); - switch (output_variable.opt->type()) { - case coFloats: - check_numeric(expr_value); - static_cast(output_variable.opt)->values.assign(count, expr_value.as_d()); - break; - case coInts: - check_numeric(expr_value); - static_cast(output_variable.opt)->values.assign(count, expr_value.as_i()); - break; - case coStrings: - static_cast(output_variable.opt)->values.assign(count, expr_value.to_string()); - break; - case coBools: - if (expr_value.type() != expr::TYPE_BOOL) - expr_value.throw_exception("Right side is not a boolean expression"); - static_cast(output_variable.opt)->values.assign(count, expr_value.b()); - break; - default: assert(false); - } + if (lhs.opt) { + if (lhs.opt->is_vector()) + rhs.throw_exception("Cannot assign a scalar value to a vector variable."); + OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true }; + scalar_variable_assign_scalar(ctx, lhs_opt, rhs); } else { - size_t count = evaluate_count(expr_count); - switch (expr_value.type()) { - case expr::TYPE_BOOL: output_variable.opt = new ConfigOptionBools(count, expr_value.b()); break; - case expr::TYPE_INT: output_variable.opt = new ConfigOptionInts(count, expr_value.i()); break; - case expr::TYPE_DOUBLE: output_variable.opt = new ConfigOptionFloats(count, expr_value.d()); break; - case expr::TYPE_STRING: output_variable.opt = new ConfigOptionStrings(count, expr_value.s()); break; + std::unique_ptr opt_new; + switch (rhs.type()) { + case expr::TYPE_BOOL: opt_new = std::make_unique(rhs.b()); break; + case expr::TYPE_INT: opt_new = std::make_unique(rhs.i()); break; + case expr::TYPE_DOUBLE: opt_new = std::make_unique(rhs.d()); break; + case expr::TYPE_STRING: opt_new = std::make_unique(rhs.s()); break; default: assert(false); } - const_cast(ctx)->store_new_variable(output_variable.name, output_variable.opt, global_variable); + const_cast(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable); } } template - static void assign_vector_variable_array( + static void vector_variable_new_from_array( + const MyContext *ctx, + bool global_variable, + NewOldVariable &lhs, + const expr &rhs_count, + const expr &rhs_value) + { + if (lhs.opt) { + if (lhs.opt->is_scalar()) + rhs_value.throw_exception("Cannot assign a vector value to a scalar variable."); + OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true }; + vector_variable_assign_expr_with_count(ctx, lhs_opt, rhs_count, rhs_value); + } else { + size_t count = evaluate_count(rhs_count); + std::unique_ptr opt_new; + switch (rhs_value.type()) { + case expr::TYPE_BOOL: opt_new = std::make_unique(count, rhs_value.b()); break; + case expr::TYPE_INT: opt_new = std::make_unique(count, rhs_value.i()); break; + case expr::TYPE_DOUBLE: opt_new = std::make_unique(count, rhs_value.d()); break; + case expr::TYPE_STRING: opt_new = std::make_unique(count, rhs_value.s()); break; + default: assert(false); + } + const_cast(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable); + } + } + + template + static void vector_variable_assign_array( const MyContext *ctx, OptWithPos &lhs, - const expr &expr_count, - const expr &expr_value) + const expr &rhs_count, + const expr &rhs_value) { check_writable(ctx, lhs); - auto check_numeric = [](const expr ¶m) { - if (! param.numeric_type()) - param.throw_exception("Right side is not a numeric expression"); - }; - auto evaluate_count = [](const expr &expr_count) -> size_t { - if (expr_count.type() != expr::TYPE_INT) - expr_count.throw_exception("Expected number of elements to fill a vector with."); - int count = expr_count.i(); - if (count < 0) - expr_count.throw_exception("Negative number of elements specified."); - return size_t(count); - }; if (lhs.opt->is_scalar()) - expr_value.throw_exception("Cannot assign a vector value to a scalar variable."); - auto *opt = const_cast(lhs.opt); - size_t count = evaluate_count(expr_count); + rhs_value.throw_exception("Cannot assign a vector value to a scalar variable."); + vector_variable_assign_expr_with_count(ctx, lhs, rhs_count, rhs_value); + } + + template + static void fill_vector_from_initializer_list(ConfigOption *opt, const std::vector> &il, RightValueEvaluate rv_eval) { + auto& out = static_cast(opt)->values; + out.clear(); + out.reserve(il.size()); + for (const expr& i : il) + out.emplace_back(rv_eval(i)); + } + + template + static void vector_variable_assign_initializer_list( + const MyContext *ctx, + OptWithPos &lhs, + const std::vector> &il) + { + check_writable(ctx, lhs); + + if (lhs.opt->is_scalar()) { + if (il.size() == 1) + // scalar_var = ( scalar ) + scalar_variable_assign_scalar_expression(ctx, lhs, il.front()); + else + // scalar_var = () + // or + // scalar_var = ( scalar, scalar, ... ) + ctx->throw_exception("Cannot assign a vector value to a scalar variable.", lhs.it_range); + } + + auto check_numeric_vector = [](const std::vector> &il) { + for (auto &i : il) + if (! i.numeric_type()) + i.throw_exception("Right side is not a numeric expression"); + }; + + ConfigOption *opt = const_cast(lhs.opt); switch (lhs.opt->type()) { case coFloats: - check_numeric(expr_value); - static_cast(opt)->values.assign(count, expr_value.as_d()); + check_numeric_vector(il); + fill_vector_from_initializer_list(opt, il, [](auto &v){ return v.as_d(); }); break; case coInts: - check_numeric(expr_value); - static_cast(opt)->values.assign(count, expr_value.as_i()); + check_numeric_vector(il); + fill_vector_from_initializer_list(opt, il, [](auto &v){ return v.as_i(); }); break; case coStrings: - static_cast(opt)->values.assign(count, expr_value.to_string()); + fill_vector_from_initializer_list(opt, il, [](auto &v){ return v.to_string(); }); break; case coBools: - if (expr_value.type() != expr::TYPE_BOOL) - expr_value.throw_exception("Right side is not a boolean expression"); - static_cast(opt)->values.assign(count, expr_value.b()); + for (auto &i : il) + if (i.type() != expr::TYPE_BOOL) + i.throw_exception("Right side is not a boolean expression"); + fill_vector_from_initializer_list(opt, il, [](auto &v){ return v.b(); }); break; default: assert(false); } } template - static void new_vector_variable_initializer_list( + static void vector_variable_new_from_initializer_list( const MyContext *ctx, bool global_variable, - NewOldVariable &output_variable, + NewOldVariable &lhs, const std::vector> &il) { - if (! output_variable.opt) { + if (lhs.opt) { + // Assign to an existing vector variable. + OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true }; + vector_variable_assign_initializer_list(ctx, lhs_opt, il); + } else { + if (il.empty()) + ctx->throw_exception("Cannot create vector variable from an empty initializer list, because its type cannot be deduced.", lhs.it_range); + // Allocate a new vector variable. // First guesstimate type of the output vector. size_t num_bool = 0; size_t num_int = 0; @@ -1257,186 +1332,25 @@ namespace client case expr::TYPE_STRING: ++ num_string; break; default: assert(false); } + std::unique_ptr opt_new; if (num_string > 0) // Convert everything to strings. - output_variable.opt = new ConfigOptionStrings(); + opt_new = std::make_unique(); else if (num_bool > 0) { if (num_double + num_int > 0) ctx->throw_exception("Right side is not valid: Mixing numeric and boolean types.", boost::iterator_range{ il.front().it_range.begin(), il.back().it_range.end() }); - output_variable.opt = new ConfigOptionBools(); - } else + opt_new = std::make_unique(); + } else { // Output is numeric. - output_variable.opt = num_double == 0 ? static_cast(new ConfigOptionInts()) : static_cast(new ConfigOptionFloats()); - const_cast(ctx)->store_new_variable(output_variable.name, output_variable.opt, global_variable); + if (num_double == 0) + opt_new = std::make_unique(); + else + opt_new = std::make_unique(); + } + OptWithPos lhs_opt{ opt_new.get(), lhs.it_range, true }; + vector_variable_assign_initializer_list(ctx, lhs_opt, il); + const_cast(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable); } - - auto check_numeric = [](const std::vector> &il) { - for (auto& i : il) - if (!i.numeric_type()) - i.throw_exception("Right side is not a numeric expression"); - }; - - if (output_variable.opt->is_scalar()) - ctx->throw_exception("Cannot assign a vector value to a scalar variable.", output_variable.it_range); - - switch (output_variable.opt->type()) { - case coFloats: - { - check_numeric(il); - auto &out = static_cast(output_variable.opt)->values; - out.clear(); - out.reserve(il.size()); - for (auto &i : il) - out.emplace_back(i.as_d()); - break; - } - case coInts: - { - check_numeric(il); - auto &out = static_cast(output_variable.opt)->values; - out.clear(); - out.reserve(il.size()); - for (auto& i : il) - out.emplace_back(i.as_i()); - break; - } - case coStrings: - { - auto &out = static_cast(output_variable.opt)->values; - out.clear(); - out.reserve(il.size()); - for (auto &i : il) - out.emplace_back(i.to_string()); - break; - } - case coBools: - { - auto &out = static_cast(output_variable.opt)->values; - out.clear(); - out.reserve(il.size()); - for (auto &i : il) - if (i.type() == expr::TYPE_BOOL) - out.emplace_back(i.b()); - else - i.throw_exception("Right side is not a boolean expression"); - break; - } - default: - assert(false); - } - } - - template - static void assign_vector_variable_initializer_list( - const MyContext *ctx, - OptWithPos &lhs, - const std::vector> &il) - { - check_writable(ctx, lhs); - auto check_numeric = [](const std::vector> &il) { - for (auto &i : il) - if (! i.numeric_type()) - i.throw_exception("Right side is not a numeric expression"); - }; - - if (lhs.opt->is_scalar()) - ctx->throw_exception("Cannot assign a vector value to a scalar variable.", lhs.it_range); - - ConfigOption *opt = const_cast(lhs.opt); - switch (lhs.opt->type()) { - case coFloats: - { - check_numeric(il); - auto &out = static_cast(opt)->values; - out.clear(); - out.reserve(il.size()); - for (auto &i : il) - out.emplace_back(i.as_d()); - break; - } - case coInts: - { - check_numeric(il); - auto &out = static_cast(opt)->values; - out.clear(); - out.reserve(il.size()); - for (auto& i : il) - out.emplace_back(i.as_i()); - break; - } - case coStrings: - { - auto &out = static_cast(opt)->values; - out.clear(); - out.reserve(il.size()); - for (auto &i : il) - out.emplace_back(i.to_string()); - break; - } - case coBools: - { - auto &out = static_cast(opt)->values; - out.clear(); - out.reserve(il.size()); - for (auto &i : il) - if (i.type() == expr::TYPE_BOOL) - out.emplace_back(i.b()); - else - i.throw_exception("Right side is not a boolean expression"); - break; - } - default: - assert(false); - } - } - - template - static bool new_vector_variable_copy( - const MyContext *ctx, - bool global_variable, - NewOldVariable &output_variable, - const OptWithPos &src_variable) - { - if (! is_vector_variable_reference(src_variable)) - // Skip parsing this branch, bactrack. - return false; - - if (! output_variable.opt) { - if (one_of(src_variable.opt->type(), { coFloats, coInts, coStrings, coBools })) - output_variable.opt = src_variable.opt->clone(); - else if (src_variable.opt->type() == coPercents) - output_variable.opt = new ConfigOptionFloats(static_cast(src_variable.opt)->values); - else - ctx->throw_exception("Duplicating this vector variable is not supported", src_variable.it_range); - const_cast(ctx)->store_new_variable(output_variable.name, output_variable.opt, global_variable); - } - - switch (output_variable.opt->type()) { - case coFloats: - if (output_variable.opt->type() != coFloats) - ctx->throw_exception("Left hand side is a float vector, while the right hand side is not.", boost::iterator_range{ output_variable.it_range.begin(), src_variable.it_range.end() }); - static_cast(output_variable.opt)->values = static_cast(src_variable.opt)->values; - break; - case coInts: - if (output_variable.opt->type() != coInts) - ctx->throw_exception("Left hand side is an int vector, while the right hand side is not.", boost::iterator_range{ output_variable.it_range.begin(), src_variable.it_range.end() }); - static_cast(output_variable.opt)->values = static_cast(src_variable.opt)->values; - break; - case coStrings: - if (output_variable.opt->type() != coStrings) - ctx->throw_exception("Left hand side is a string vector, while the right hand side is not.", boost::iterator_range{ output_variable.it_range.begin(), src_variable.it_range.end() }); - static_cast(output_variable.opt)->values = static_cast(src_variable.opt)->values; - break; - case coBools: - if (output_variable.opt->type() != coBools) - ctx->throw_exception("Left hand side is a bool vector, while the right hand side is not.", boost::iterator_range{ output_variable.it_range.begin(), src_variable.it_range.end() }); - static_cast(output_variable.opt)->values = static_cast(src_variable.opt)->values; - break; - default: - assert(false); - } - // Continue parsing. - return true; } template @@ -1444,54 +1358,99 @@ namespace client return ! var.has_index() && var.opt->is_vector(); } + // Called when checking whether the NewOldVariable could be assigned a vectir right hand side. template - static bool assign_vector_variable_copy( - const MyContext *ctx, - OptWithPos &lhs, - const OptWithPos &src_variable) + static bool could_be_vector_variable_reference(const NewOldVariable &var) { + return var.opt == nullptr || var.opt->is_vector(); + } + + template + static void copy_vector_variable_to_vector_variable( + const MyContext *ctx, + OptWithPos &lhs, + const OptWithPos &rhs) { - if (! is_vector_variable_reference(src_variable)) - // Skip parsing this branch, bactrack. - return false; - check_writable(ctx, lhs); - - auto *opt = const_cast(lhs.opt); - switch (lhs.opt->type()) { - case coFloats: - if (lhs.opt->type() != coFloats) + assert(lhs.opt->is_vector()); + if (rhs.has_index() || ! rhs.opt->is_vector()) + ctx->throw_exception("Cannot assign scalar to a vector", lhs.it_range); + if (lhs.opt->type() != rhs.opt->type()) { + // Vector types are not compatible. + switch (lhs.opt->type()) { + case coFloats: ctx->throw_exception("Left hand side is a float vector, while the right hand side is not.", lhs.it_range); - static_cast(opt)->values = static_cast(src_variable.opt)->values; - break; - case coInts: - if (lhs.opt->type() != coInts) + case coInts: ctx->throw_exception("Left hand side is an int vector, while the right hand side is not.", lhs.it_range); - static_cast(opt)->values = static_cast(src_variable.opt)->values; - break; - case coStrings: - if (lhs.opt->type() != coStrings) + case coStrings: ctx->throw_exception("Left hand side is a string vector, while the right hand side is not.", lhs.it_range); - static_cast(opt)->values = static_cast(src_variable.opt)->values; - break; - case coBools: - if (lhs.opt->type() != coBools) + case coBools: ctx->throw_exception("Left hand side is a bool vector, while the right hand side is not.", lhs.it_range); - static_cast(opt)->values = static_cast(src_variable.opt)->values; - break; - default: - assert(false); + default: + ctx->throw_exception("Left hand side / right hand side vectors are not compatible.", lhs.it_range); + } } + const_cast(lhs.opt)->set(rhs.opt); + } + template + static bool vector_variable_new_from_copy( + const MyContext *ctx, + bool global_variable, + NewOldVariable &lhs, + const OptWithPos &rhs) + { + if (lhs.opt) { + assert(lhs.opt->is_vector()); + OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true }; + copy_vector_variable_to_vector_variable(ctx, lhs_opt, rhs); + } else { + if (rhs.has_index() || ! rhs.opt->is_vector()) + // Stop parsing, let the other rules resolve this case. + return false; + // Clone the vector variable. + std::unique_ptr opt_new; + if (one_of(rhs.opt->type(), { coFloats, coInts, coStrings, coBools })) + opt_new = std::unique_ptr(rhs.opt->clone()); + else if (rhs.opt->type() == coPercents) + opt_new = std::make_unique(static_cast(rhs.opt)->values); + else + ctx->throw_exception("Duplicating this type of vector variable is not supported", rhs.it_range); + const_cast(ctx)->store_new_variable(lhs.name, std::move(opt_new), global_variable); + } // Continue parsing. return true; } template - static void new_vector_variable_initializer_list_append(std::vector> &list, expr &expr) + static void initializer_list_append(std::vector> &list, expr &expr) { list.emplace_back(std::move(expr)); } + template + static void is_vector_empty( + const MyContext *ctx, + OptWithPos &opt, + expr &out) + { + if (opt.has_index() || ! opt.opt->is_vector()) + ctx->throw_exception("parameter of empty() is not a vector variable", opt.it_range); + out.set_b(static_cast(opt.opt)->size() == 0); + out.it_range = opt.it_range; + } + + template + static void vector_size( + const MyContext *ctx, + OptWithPos &opt, + expr &out) + { + if (opt.has_index() || ! opt.opt->is_vector()) + ctx->throw_exception("parameter of size() is not a vector variable", opt.it_range); + out.set_i(int(static_cast(opt.opt)->size())); + out.it_range = opt.it_range; + } + // Verify that the expression returns an integer, which may be used // to address a vector. template @@ -1635,12 +1594,12 @@ namespace client // Table to translate symbol tag to a human readable error message. std::map MyContext::tag_to_error_message = { - { "array", "Unknown syntax error" }, { "eoi", "Unknown syntax error" }, { "start", "Unknown syntax error" }, { "text", "Invalid text." }, { "text_block", "Invalid text block." }, { "macro", "Invalid macro." }, + { "repeat", "Unknown syntax error" }, { "if_else_output", "Not an {if}{else}{endif} macro." }, { "switch_output", "Not a {switch} macro." }, { "legacy_variable_expansion", "Expecting a legacy variable expansion format" }, @@ -1657,7 +1616,6 @@ namespace client { "optional_parameter", "Expecting a closing brace or an optional parameter." }, { "one_of_list", "Expecting a list of string patterns (simple text or rexep)" }, { "variable_reference", "Expecting a variable reference."}, - { "is_nil_test", "Expecting a scalar variable reference."}, { "variable", "Expecting a variable name."}, { "regular_expression", "Expecting a regular expression."} }; @@ -1909,37 +1867,39 @@ namespace client assignment_statement = variable_reference(_r1)[_a = _1] >> '=' > ( // Consumes also '(' conditional_expression ')', that means enclosing an expression into braces makes it a single value vector initializer. - (lit('(') > new_variable_initializer_list(_r1) > ')') - [px::bind(&MyContext::assign_vector_variable_initializer_list, _r1, _a, _1)] + initializer_list(_r1)[px::bind(&MyContext::vector_variable_assign_initializer_list, _r1, _a, _1)] // Process it before conditional_expression, as conditional_expression requires a vector reference to be augmented with an index. // Only process such variable references, which return a naked vector variable. - | variable_reference(_r1) - [px::ref(qi::_pass) = px::bind(&MyContext::assign_vector_variable_copy, _r1, _a, _1)] + | eps(px::bind(&MyContext::is_vector_variable_reference, _a)) >> + variable_reference(_r1)[px::bind(&MyContext::copy_vector_variable_to_vector_variable, _r1, _a, _1)] // Would NOT consume '(' conditional_expression ')' because such value was consumed with the expression above. | conditional_expression(_r1) - [px::bind(&MyContext::assign_scalar_variable, _r1, _a, _1)] - | (kw["array"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")") - [px::bind(&MyContext::assign_vector_variable_array, _r1, _a, _1, _2)] + [px::bind(&MyContext::scalar_variable_assign_scalar_expression, _r1, _a, _1)] + | (kw["repeat"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")") + [px::bind(&MyContext::vector_variable_assign_array, _r1, _a, _1, _2)] ); new_variable_statement = (kw["local"][_a = false] | kw["global"][_a = true]) > identifier[px::bind(&MyContext::new_old_variable, _r1, _a, _1, _b)] > lit('=') > ( // Consumes also '(' conditional_expression ')', that means enclosing an expression into braces makes it a single value vector initializer. - (lit('(') > new_variable_initializer_list(_r1) > ')') - [px::bind(&MyContext::new_vector_variable_initializer_list, _r1, _a, _b, _1)] + initializer_list(_r1)[px::bind(&MyContext::vector_variable_new_from_initializer_list, _r1, _a, _b, _1)] // Process it before conditional_expression, as conditional_expression requires a vector reference to be augmented with an index. // Only process such variable references, which return a naked vector variable. - | variable_reference(_r1) - [px::ref(qi::_pass) = px::bind(&MyContext::new_vector_variable_copy, _r1, _a, _b, _1)] + | eps(px::bind(&MyContext::could_be_vector_variable_reference, _b)) >> + variable_reference(_r1)[px::ref(qi::_pass) = px::bind(&MyContext::vector_variable_new_from_copy, _r1, _a, _b, _1)] // Would NOT consume '(' conditional_expression ')' because such value was consumed with the expression above. | conditional_expression(_r1) - [px::bind(&MyContext::new_scalar_variable, _r1, _a, _b, _1)] - | (kw["array"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")") - [px::bind(&MyContext::new_vector_variable_array, _r1, _a, _b, _1, _2)] + [px::bind(&MyContext::scalar_variable_new_from_scalar_expression, _r1, _a, _b, _1)] + | (kw["repeat"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")") + [px::bind(&MyContext::vector_variable_new_from_array, _r1, _a, _b, _1, _2)] + ); + initializer_list = lit('(') > + ( lit(')') | + ( conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append, _val, _1)] > + *(lit(',') > conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append, _val, _1)]) > + lit(')') + ) ); - new_variable_initializer_list = - conditional_expression(_r1)[px::bind(&MyContext::new_vector_variable_initializer_list_append, _val, _1)] >> - *(lit(',') > conditional_expression(_r1)[px::bind(&MyContext::new_vector_variable_initializer_list_append, _val, _1)]); struct FactorActions { static void set_start_pos(Iterator &start_pos, expr &out) @@ -1983,8 +1943,10 @@ namespace client [ px::bind(&expr::template digits, _val, _2, _3) ] | (kw["int"] > '(' > conditional_expression(_r1) > ')') [ px::bind(&FactorActions::to_int, _1, _val) ] | (kw["round"] > '(' > conditional_expression(_r1) > ')') [ px::bind(&FactorActions::round, _1, _val) ] - | (kw["is_nil"] > '(' > is_nil_test(_r1) > ')') [ _val = _1 ] + | (kw["is_nil"] > '(' > variable_reference(_r1) > ')') [px::bind(&MyContext::is_nil_test, _r1, _1, _val)] | (kw["one_of"] > '(' > one_of(_r1) > ')') [ _val = _1 ] + | (kw["empty"] > '(' > variable_reference(_r1) > ')') [px::bind(&MyContext::is_vector_empty, _r1, _1, _val)] + | (kw["size"] > '(' > variable_reference(_r1) > ')') [px::bind(&MyContext::vector_size, _r1, _1, _val)] | (kw["interpolate_table"] > '(' > interpolate_table(_r1) > ')') [ _val = _1 ] | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ] | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ] @@ -2024,9 +1986,6 @@ namespace client ); optional_parameter.name("optional_parameter"); - is_nil_test = variable_reference(_r1)[px::bind(&MyContext::is_nil_test, _r1, _1, _val)]; - is_nil_test.name("is_nil test"); - variable_reference = variable(_r1)[_a=_1] >> ( @@ -2044,9 +2003,9 @@ namespace client keywords.add ("and") - ("array") ("digits") ("zdigits") + ("empty") ("if") ("int") ("is_nil") @@ -2061,10 +2020,12 @@ namespace client ("min") ("max") ("random") + ("repeat") ("round") ("not") ("one_of") ("or") + ("size") ("true"); if (0) { @@ -2093,7 +2054,6 @@ namespace client debug(optional_parameter); debug(variable_reference); debug(variable); - debug(is_nil_test); debug(regular_expression); } } @@ -2152,7 +2112,7 @@ namespace client qi::rule>, spirit_encoding::space_type> assignment_statement; // Allocating new local or global variables. qi::rule>, spirit_encoding::space_type> new_variable_statement; - qi::rule>(const MyContext*), spirit_encoding::space_type> new_variable_initializer_list; + qi::rule>(const MyContext*), spirit_encoding::space_type> initializer_list; // qi::rule, bool, std::string>, spirit_encoding::space_type> switch_output; qi::symbols keywords; diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 09514200fa..3598d36aed 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -10,15 +10,6 @@ #include #endif /* _MSC_VER */ -// instead of #include "slic3r/GUI/I18N.hpp" : -#ifndef L -// !!! If you needed to translate some string, -// !!! please use _L(string) -// !!! _() - is a standard wxWidgets macro to translate -// !!! L() is used only for marking localizable string -// !!! It will be used in "xgettext" to create a Locating Message Catalog. -#define L(s) s -#endif /* L */ #include #include @@ -460,8 +451,8 @@ static std::vector s_Preset_print_options { "perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width", "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "infill_anchor", "infill_anchor_max", "bridge_flow_ratio", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "gcode_resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", - "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width", - "wipe_tower_no_sparse_layers", "compatible_printers", "compatible_printers_condition", "inherits", + "wipe_tower_width", "wipe_tower_cone_angle", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_bridging", "single_extruder_multi_material_priming", "mmu_segmented_region_max_width", + "wipe_tower_no_sparse_layers", "wipe_tower_extra_spacing", "compatible_printers", "compatible_printers_condition", "inherits", "perimeter_generator", "wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle", "wall_distribution_count", "min_feature_size", "min_bead_width" }; diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 4030e381a2..0dd20ea937 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -27,8 +27,6 @@ #include #include -// Mark string for localization and translate. -#define L(s) Slic3r::I18N::translate(s) namespace Slic3r { @@ -205,7 +203,9 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n || opt_key == "wipe_tower" || opt_key == "wipe_tower_width" || opt_key == "wipe_tower_brim_width" + || opt_key == "wipe_tower_cone_angle" || opt_key == "wipe_tower_bridging" + || opt_key == "wipe_tower_extra_spacing" || opt_key == "wipe_tower_no_sparse_layers" || opt_key == "wiping_volumes_matrix" || opt_key == "parking_pos_retraction" @@ -472,20 +472,20 @@ std::string Print::validate(std::string* warning) const std::vector extruders = this->extruders(); if (m_objects.empty()) - return L("All objects are outside of the print volume."); + return _u8L("All objects are outside of the print volume."); if (extruders.empty()) - return L("The supplied settings will cause an empty print."); + return _u8L("The supplied settings will cause an empty print."); if (m_config.complete_objects) { if (! sequential_print_horizontal_clearance_valid(*this)) - return L("Some objects are too close; your extruder will collide with them."); + return _u8L("Some objects are too close; your extruder will collide with them."); if (! sequential_print_vertical_clearance_valid(*this)) - return L("Some objects are too tall and cannot be printed without extruder collisions."); + return _u8L("Some objects are too tall and cannot be printed without extruder collisions."); } if (m_config.avoid_crossing_perimeters && m_config.avoid_crossing_curled_overhangs) { - return L("Avoid crossing perimeters option and avoid crossing curled overhangs option cannot be both enabled together."); + return _u8L("Avoid crossing perimeters option and avoid crossing curled overhangs option cannot be both enabled together."); } if (m_config.spiral_vase) { @@ -494,11 +494,11 @@ std::string Print::validate(std::string* warning) const total_copies_count += object->instances().size(); // #4043 if (total_copies_count > 1 && ! m_config.complete_objects.value) - return L("Only a single object may be printed at a time in Spiral Vase mode. " + return _u8L("Only a single object may be printed at a time in Spiral Vase mode. " "Either remove all but the last object, or enable sequential mode by \"complete_objects\"."); assert(m_objects.size() == 1); if (m_objects.front()->all_regions().size() > 1) - return L("The Spiral Vase option can only be used when printing single material objects."); + return _u8L("The Spiral Vase option can only be used when printing single material objects."); } // Cache of layer height profiles for checking: @@ -522,7 +522,7 @@ std::string Print::validate(std::string* warning) const //FIXME It is quite expensive to generate object layers just to get the print height! if (auto layers = generate_object_layers(print_object.slicing_parameters(), layer_height_profile(print_object_idx)); ! layers.empty() && layers.back() > this->config().max_print_height + EPSILON) { - return L("The print is taller than the maximum allowed height. You might want to reduce the size of your model" + return _u8L("The print is taller than the maximum allowed height. You might want to reduce the size of your model" " or change current print settings and retry."); } } @@ -539,7 +539,7 @@ std::string Print::validate(std::string* warning) const print_object.model_object()->has_custom_layering()) { if (const std::vector &layers = layer_height_profile(print_object_idx); ! layers.empty()) if (! check_object_layers_fixed(print_object.slicing_parameters(), layers)) - return L("Variable layer height is not supported with Organic supports."); + return _u8L("Variable layer height is not supported with Organic supports."); } if (this->has_wipe_tower() && ! m_objects.empty()) { @@ -552,21 +552,21 @@ std::string Print::validate(std::string* warning) const double filament_diam = m_config.filament_diameter.get_at(extruder_idx); if (nozzle_diam - EPSILON > first_nozzle_diam || nozzle_diam + EPSILON < first_nozzle_diam || std::abs((filament_diam-first_filament_diam)/first_filament_diam) > 0.1) - return L("The wipe tower is only supported if all extruders have the same nozzle diameter " + return _u8L("The wipe tower is only supported if all extruders have the same nozzle diameter " "and use filaments of the same diameter."); } if (m_config.gcode_flavor != gcfRepRapSprinter && m_config.gcode_flavor != gcfRepRapFirmware && m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlinLegacy && m_config.gcode_flavor != gcfMarlinFirmware) - return L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors."); + return _u8L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors."); if (! m_config.use_relative_e_distances) - return L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."); + return _u8L("The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1)."); if (m_config.ooze_prevention && m_config.single_extruder_multi_material) - return L("Ooze prevention is only supported with the wipe tower when 'single_extruder_multi_material' is off."); + return _u8L("Ooze prevention is only supported with the wipe tower when 'single_extruder_multi_material' is off."); if (m_config.use_volumetric_e) - return L("The Wipe Tower currently does not support volumetric E (use_volumetric_e=0)."); + return _u8L("The Wipe Tower currently does not support volumetric E (use_volumetric_e=0)."); if (m_config.complete_objects && extruders.size() > 1) - return L("The Wipe Tower is currently not supported for multimaterial sequential prints."); + return _u8L("The Wipe Tower is currently not supported for multimaterial sequential prints."); if (m_objects.size() > 1) { const SlicingParameters &slicing_params0 = m_objects.front()->slicing_parameters(); @@ -576,21 +576,21 @@ std::string Print::validate(std::string* warning) const const SlicingParameters &slicing_params = object->slicing_parameters(); if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON || std::abs(slicing_params.layer_height - slicing_params0.layer_height ) > EPSILON) - return L("The Wipe Tower is only supported for multiple objects if they have equal layer heights"); + return _u8L("The Wipe Tower is only supported for multiple objects if they have equal layer heights"); if (slicing_params.raft_layers() != slicing_params0.raft_layers()) - return L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers"); + return _u8L("The Wipe Tower is only supported for multiple objects if they are printed over an equal number of raft layers"); if (slicing_params0.gap_object_support != slicing_params.gap_object_support || slicing_params0.gap_support_object != slicing_params.gap_support_object) - return L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance"); + return _u8L("The Wipe Tower is only supported for multiple objects if they are printed with the same support_material_contact_distance"); if (! equal_layering(slicing_params, slicing_params0)) - return L("The Wipe Tower is only supported for multiple objects if they are sliced equally."); + return _u8L("The Wipe Tower is only supported for multiple objects if they are sliced equally."); if (has_custom_layering) { auto &lh = layer_height_profile(i); auto &lh_tallest = layer_height_profile(tallest_object_idx); if (*(lh.end()-2) > *(lh_tallest.end()-2)) tallest_object_idx = i; } - } + } if (has_custom_layering) { for (size_t idx_object = 0; idx_object < m_objects.size(); ++ idx_object) { @@ -608,7 +608,7 @@ std::string Print::validate(std::string* warning) const if (i%2 == 0 && layer_height_profiles[tallest_object_idx][i] > layer_height_profiles[idx_object][layer_height_profiles[idx_object].size() - 2 ]) break; if (std::abs(layer_height_profiles[idx_object][i] - layer_height_profiles[tallest_object_idx][i]) > eps) - return L("The Wipe tower is only supported if all objects have the same variable layer height"); + return _u8L("The Wipe tower is only supported if all objects have the same variable layer height"); ++i; } } @@ -632,7 +632,7 @@ std::string Print::validate(std::string* warning) const unsigned int total_extruders_count = m_config.nozzle_diameter.size(); for (const auto& extruder_idx : extruders) if ( extruder_idx >= total_extruders_count ) - return L("One or more object were assigned an extruder that the printer does not have."); + return _u8L("One or more object were assigned an extruder that the printer does not have."); #endif auto validate_extrusion_width = [/*min_nozzle_diameter,*/ max_nozzle_diameter](const ConfigBase &config, const char *opt_key, double layer_height, std::string &err_msg) -> bool { @@ -645,10 +645,10 @@ std::string Print::validate(std::string* warning) const if (extrusion_width_min == 0) { // Default "auto-generated" extrusion width is always valid. } else if (extrusion_width_min <= layer_height) { - err_msg = (boost::format(L("%1%=%2% mm is too low to be printable at a layer height %3% mm")) % opt_key % extrusion_width_min % layer_height).str(); + err_msg = (boost::format(_u8L("%1%=%2% mm is too low to be printable at a layer height %3% mm")) % opt_key % extrusion_width_min % layer_height).str(); return false; } else if (extrusion_width_max >= max_nozzle_diameter * 3.) { - err_msg = (boost::format(L("Excessive %1%=%2% mm to be printable with a nozzle diameter %3% mm")) % opt_key % extrusion_width_max % max_nozzle_diameter).str(); + err_msg = (boost::format(_u8L("Excessive %1%=%2% mm to be printable with a nozzle diameter %3% mm")) % opt_key % extrusion_width_max % max_nozzle_diameter).str(); return false; } return true; @@ -659,7 +659,7 @@ std::string Print::validate(std::string* warning) const // The object has some form of support and either support_material_extruder or support_material_interface_extruder // will be printed with the current tool without a forced tool change. Play safe, assert that all object nozzles // are of the same diameter. - return L("Printing with multiple extruders of differing nozzle diameters. " + return _u8L("Printing with multiple extruders of differing nozzle diameters. " "If support is to be printed with the current extruder (support_material_extruder == 0 or support_material_interface_extruder == 0), " "all nozzles have to be of the same diameter."); } @@ -667,11 +667,11 @@ std::string Print::validate(std::string* warning) const if (object->config().support_material_contact_distance == 0) { // Soluble interface if (! object->config().support_material_synchronize_layers) - return L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers."); + return _u8L("For the Wipe Tower to work with the soluble supports, the support layers need to be synchronized with the object layers."); } else { // Non-soluble interface if (object->config().support_material_extruder != 0 || object->config().support_material_interface_extruder != 0) - return L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. " + return _u8L("The Wipe Tower currently supports the non-soluble supports only if they are printed with the current extruder without triggering a tool change. " "(both support_material_extruder and support_material_interface_extruder need to be set to 0)."); } } @@ -707,12 +707,12 @@ std::string Print::validate(std::string* warning) const first_layer_min_nozzle_diameter = min_nozzle_diameter; } if (first_layer_height > first_layer_min_nozzle_diameter) - return L("First layer height can't be greater than nozzle diameter"); + return _u8L("First layer height can't be greater than nozzle diameter"); // validate layer_height double layer_height = object->config().layer_height.value; if (layer_height > min_nozzle_diameter) - return L("Layer height can't be greater than nozzle diameter"); + return _u8L("Layer height can't be greater than nozzle diameter"); // Validate extrusion widths. std::string err_msg; @@ -733,11 +733,11 @@ std::string Print::validate(std::string* warning) const // See GH issues #6336 #5073 if ((m_config.gcode_flavor == gcfMarlinLegacy || m_config.gcode_flavor == gcfMarlinFirmware) && ! before_layer_gcode_resets_extruder && ! layer_gcode_resets_extruder) - return L("Relative extruder addressing requires resetting the extruder position at each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to layer_gcode."); + return _u8L("Relative extruder addressing requires resetting the extruder position at each layer to prevent loss of floating point accuracy. Add \"G92 E0\" to layer_gcode."); } else if (before_layer_gcode_resets_extruder) - return L("\"G92 E0\" was found in before_layer_gcode, which is incompatible with absolute extruder addressing."); + return _u8L("\"G92 E0\" was found in before_layer_gcode, which is incompatible with absolute extruder addressing."); else if (layer_gcode_resets_extruder) - return L("\"G92 E0\" was found in layer_gcode, which is incompatible with absolute extruder addressing."); + return _u8L("\"G92 E0\" was found in layer_gcode, which is incompatible with absolute extruder addressing."); } return std::string(); @@ -879,7 +879,7 @@ void Print::process() BOOST_LOG_TRIVIAL(info) << "Starting the slicing process." << log_memory_info(); for (PrintObject *obj : m_objects) obj->make_perimeters(); - this->set_status(70, L("Infilling layers")); + this->set_status(70, _u8L("Infilling layers")); for (PrintObject *obj : m_objects) obj->infill(); for (PrintObject *obj : m_objects) @@ -896,7 +896,7 @@ void Print::process() m_wipe_tower_data.clear(); m_tool_ordering.clear(); if (this->has_wipe_tower()) { - //this->set_status(95, L("Generating wipe tower")); + //this->set_status(95, _u8L("Generating wipe tower")); this->_make_wipe_tower(); } else if (! this->config().complete_objects.value) { // Initialize the tool ordering, so it could be used by the G-code preview slider for planning tool changes and filament switches. @@ -907,7 +907,7 @@ void Print::process() this->set_done(psWipeTower); } if (this->set_started(psSkirtBrim)) { - this->set_status(88, L("Generating skirt and brim")); + this->set_status(88, _u8L("Generating skirt and brim")); m_skirt.clear(); m_skirt_convex_hull.clear(); @@ -955,11 +955,11 @@ std::string Print::export_gcode(const std::string& path_template, GCodeProcessor std::string message; if (!path.empty() && result == nullptr) { // Only show the path if preview_data is not set -> running from command line. - message = L("Exporting G-code"); + message = _u8L("Exporting G-code"); message += " to "; message += path; } else - message = L("Generating G-code"); + message = _u8L("Generating G-code"); this->set_status(90, message); // Create GCode on heap, it has quite a lot of data. @@ -1133,23 +1133,34 @@ Polygons Print::first_layer_islands() const std::vector Print::first_layer_wipe_tower_corners() const { - std::vector corners; + std::vector pts_scaled; + if (has_wipe_tower() && ! m_wipe_tower_data.tool_changes.empty()) { double width = m_config.wipe_tower_width + 2*m_wipe_tower_data.brim_width; double depth = m_wipe_tower_data.depth + 2*m_wipe_tower_data.brim_width; Vec2d pt0(-m_wipe_tower_data.brim_width, -m_wipe_tower_data.brim_width); - for (Vec2d pt : { - pt0, - Vec2d(pt0.x()+width, pt0.y() ), - Vec2d(pt0.x()+width, pt0.y()+depth), - Vec2d(pt0.x(), pt0.y()+depth) - }) { + + // First the corners. + std::vector pts = { pt0, + Vec2d(pt0.x()+width, pt0.y()), + Vec2d(pt0.x()+width, pt0.y()+depth), + Vec2d(pt0.x(),pt0.y()+depth) + }; + + // Now the stabilization cone. + Vec2d center = (pts[0] + pts[2])/2.; + const auto [cone_R, cone_x_scale] = WipeTower::get_wipe_tower_cone_base(m_config.wipe_tower_width, m_wipe_tower_data.height, m_wipe_tower_data.depth, m_config.wipe_tower_cone_angle); + double r = cone_R + m_wipe_tower_data.brim_width; + for (double alpha = 0.; alpha<2*M_PI; alpha += M_PI/20.) + pts.emplace_back(center + r*Vec2d(std::cos(alpha)/cone_x_scale, std::sin(alpha))); + + for (Vec2d& pt : pts) { pt = Eigen::Rotation2Dd(Geometry::deg2rad(m_config.wipe_tower_rotation_angle.value)) * pt; pt += Vec2d(m_config.wipe_tower_x.value, m_config.wipe_tower_y.value); - corners.emplace_back(Point(scale_(pt.x()), scale_(pt.y()))); + pts_scaled.emplace_back(Point(scale_(pt.x()), scale_(pt.y()))); } } - return corners; + return pts_scaled; } void Print::finalize_first_layer_convex_hull() @@ -1168,30 +1179,30 @@ void Print::alert_when_supports_needed() { if (this->set_started(psAlertWhenSupportsNeeded)) { BOOST_LOG_TRIVIAL(debug) << "psAlertWhenSupportsNeeded - start"; - set_status(69, L("Alert if supports needed")); + set_status(69, _u8L("Alert if supports needed")); auto issue_to_alert_message = [](SupportSpotsGenerator::SupportPointCause cause, bool critical) { std::string message; switch (cause) { //TRN Alert when support is needed. Describes that the model has long bridging extrusions which may print badly - case SupportSpotsGenerator::SupportPointCause::LongBridge: message = L("Long bridging extrusions"); break; + case SupportSpotsGenerator::SupportPointCause::LongBridge: message = _u8L("Long bridging extrusions"); break; //TRN Alert when support is needed. Describes bridge anchors/turns in the air, which will definitely print badly - case SupportSpotsGenerator::SupportPointCause::FloatingBridgeAnchor: message = L("Floating bridge anchors"); break; + case SupportSpotsGenerator::SupportPointCause::FloatingBridgeAnchor: message = _u8L("Floating bridge anchors"); break; case SupportSpotsGenerator::SupportPointCause::FloatingExtrusion: if (critical) { //TRN Alert when support is needed. Describes that the print has large overhang area which will print badly or not print at all. - message = L("Collapsing overhang"); + message = _u8L("Collapsing overhang"); } else { //TRN Alert when support is needed. Describes extrusions that are not supported enough and come out curled or loose. - message = L("Loose extrusions"); + message = _u8L("Loose extrusions"); } break; //TRN Alert when support is needed. Describes that the print has low bed adhesion and may became loose. - case SupportSpotsGenerator::SupportPointCause::SeparationFromBed: message = L("Low bed adhesion"); break; + case SupportSpotsGenerator::SupportPointCause::SeparationFromBed: message = _u8L("Low bed adhesion"); break; //TRN Alert when support is needed. Describes that the object has part that is not connected to the bed and will not print at all without supports. - case SupportSpotsGenerator::SupportPointCause::UnstableFloatingPart: message = L("Floating object part"); break; + case SupportSpotsGenerator::SupportPointCause::UnstableFloatingPart: message = _u8L("Floating object part"); break; //TRN Alert when support is needed. Describes that the object has thin part that may brake during printing - case SupportSpotsGenerator::SupportPointCause::WeakObjectPart: message = L("Thin fragile part"); break; + case SupportSpotsGenerator::SupportPointCause::WeakObjectPart: message = _u8L("Thin fragile part"); break; } return message; @@ -1299,13 +1310,13 @@ void Print::alert_when_supports_needed() } lines.push_back(""); - lines.push_back(L("Consider enabling supports.")); + lines.push_back(_u8L("Consider enabling supports.")); if (recommend_brim) { - lines.push_back(L("Also consider enabling brim.")); + lines.push_back(_u8L("Also consider enabling brim.")); } // TRN Alert message for detected print issues. first argument is a list of detected issues. - auto message = Slic3r::format(L("Detected print stability issues:\n%1%"), elements_to_translated_list(lines, multiline_list_rule)); + auto message = Slic3r::format(_u8L("Detected print stability issues:\n%1%"), elements_to_translated_list(lines, multiline_list_rule)); if (objects_isssues.size() > 0) { this->active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, message); @@ -1447,6 +1458,7 @@ void Print::_make_wipe_tower() wipe_tower.generate(m_wipe_tower_data.tool_changes); m_wipe_tower_data.depth = wipe_tower.get_depth(); m_wipe_tower_data.brim_width = wipe_tower.get_brim_width(); + m_wipe_tower_data.height = wipe_tower.get_wipe_tower_height(); // Unload the current filament over the purge tower. coordf_t layer_height = m_objects.front()->config().layer_height.value; diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 9fbbe378a1..60ef1403fc 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -434,6 +434,7 @@ struct WipeTowerData // Depth of the wipe tower to pass to GLCanvas3D for exact bounding box: float depth; float brim_width; + float height; void clear() { priming.reset(nullptr); diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index d9b3e9cdae..01c0ecfaa3 100644 --- a/src/libslic3r/PrintBase.cpp +++ b/src/libslic3r/PrintBase.cpp @@ -6,10 +6,6 @@ #include "I18N.hpp" -//! macro used to mark string used at localization, -//! return same string -#define L(s) Slic3r::I18N::translate(s) - namespace Slic3r { @@ -81,7 +77,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str filename = boost::filesystem::change_extension(filename, default_ext); return filename.string(); } catch (std::runtime_error &err) { - throw Slic3r::PlaceholderParserError(L("Failed processing of the output_filename_format template.") + "\n" + err.what()); + throw Slic3r::PlaceholderParserError(_u8L("Failed processing of the output_filename_format template.") + "\n" + err.what()); } } diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index dbdb36c7db..ed1a08b57f 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -16,11 +16,6 @@ namespace Slic3r { -//! macro used to mark string used at localization, -//! return same string -#define L(s) (s) -#define _(s) Slic3r::I18N::translate(s) - static t_config_enum_names enum_names_from_keys_map(const t_config_enum_values &enum_keys_map) { t_config_enum_names names; @@ -404,6 +399,7 @@ void PrintConfigDef::init_fff_params() const int max_temp = 1500; def = this->add("avoid_crossing_curled_overhangs", coBool); def->label = L("Avoid crossing curled overhangs (Experimental)"); + // TRN PrintSettings: "Avoid crossing curled overhangs (Experimental)" def->tooltip = L("Plan travel moves such that the extruder avoids areas where the filament may be curled up. " "This is mostly happening on steeper rounded overhangs and may cause a crash with the nozzle. " "This feature slows down both the print and the G-code generation."); @@ -461,8 +457,8 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionString("")); def = this->add("bottom_solid_layers", coInt); - //TRN To be shown in Print Settings "Bottom solid layers" - def->label = L("Bottom"); + //TRN Print Settings: "Bottom solid layers" + def->label = L_CONTEXT("Bottom", "Layers"); def->category = L("Layers and Perimeters"); def->tooltip = L("Number of solid layers to generate on bottom surfaces."); def->full_label = L("Bottom solid layers"); @@ -470,8 +466,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionInt(3)); def = this->add("bottom_solid_min_thickness", coFloat); - //TRN To be shown in Print Settings "Top solid layers" - def->label = L("Bottom"); + def->label = L_CONTEXT("Bottom", "Layers"); def->category = L("Layers and Perimeters"); def->tooltip = L("The number of bottom solid layers is increased above bottom_solid_layers if necessary to satisfy " "minimum thickness of bottom shell."); @@ -538,6 +533,7 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionBool(false)); + // TRN PrintSettings : "Dynamic overhang speed" auto overhang_speed_setting_description = L("Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: " "100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). " "Speeds for overhang sizes in between are calculated via linear interpolation. " @@ -585,10 +581,11 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionBools{false}); + // TRN FilamentSettings : "Dynamic fan speeds" auto fan_speed_setting_description = L( "Overhang size is expressed as a percentage of overlap of the extrusion with the previous layer: " "100% would be full overlap (no overhang), while 0% represents full overhang (floating extrusion, bridge). " - "Fan speeds for overhang sizes in between are calculated via linear interpolation. "); + "Fan speeds for overhang sizes in between are calculated via linear interpolation."); def = this->add("overhang_fan_speed_0", coInts); def->label = L("speed for 0% overlap (bridge)"); @@ -1966,7 +1963,8 @@ void PrintConfigDef::init_fff_params() def = this->add("ooze_prevention", coBool); def->label = L("Enable"); - def->tooltip = L("This option will drop the temperature of the inactive extruders to prevent oozing. "); + // TRN PrintSettings: Enable ooze prevention + def->tooltip = L("This option will drop the temperature of the inactive extruders to prevent oozing."); def->mode = comExpert; def->set_default_value(new ConfigOptionBool(false)); @@ -2304,6 +2302,7 @@ void PrintConfigDef::init_fff_params() def = this->add("staggered_inner_seams", coBool); def->label = L("Staggered inner seams"); + // TRN PrintSettings: "Staggered inner seams" def->tooltip = L("This option causes the inner seams to be shifted backwards based on their depth, forming a zigzag pattern."); def->mode = comAdvanced; def->set_default_value(new ConfigOptionBool(false)); @@ -2469,6 +2468,7 @@ void PrintConfigDef::init_fff_params() def = this->add("standby_temperature_delta", coInt); def->label = L("Temperature variation"); + // TRN PrintSettings : "Ooze prevention" > "Temperature variation" def->tooltip = L("Temperature difference to be applied when an extruder is not active. " "The value is not used when 'idle_temperature' in filament settings " "is defined."); @@ -2646,8 +2646,8 @@ void PrintConfigDef::init_fff_params() "If set to zero, support_material_contact_distance will be used for both top and bottom contact Z distances."); def->sidetext = L("mm"); // def->min = 0; - //TRN To be shown in Print Settings "Bottom contact Z distance". Have to be as short as possible def->set_enum_values(ConfigOptionDef::GUIType::f_enum_open, { + //TRN Print Settings: "Bottom contact Z distance". Have to be as short as possible { "0", L("Same as top") }, { "0.1", "0.1" }, { "0.2", "0.2" } @@ -2705,7 +2705,7 @@ void PrintConfigDef::init_fff_params() def->mode = comAdvanced; def->set_default_value(new ConfigOptionInt(1)); - auto support_material_interface_layers = def = this->add("support_material_interface_layers", coInt); + def = this->add("support_material_interface_layers", coInt); def->label = L("Top interface layers"); def->category = L("Support material"); def->tooltip = L("Number of interface layers to insert between the object(s) and support material."); @@ -2727,8 +2727,8 @@ void PrintConfigDef::init_fff_params() "Set to -1 to use support_material_interface_layers"); def->sidetext = L("layers"); def->min = -1; - //TRN To be shown in Print Settings "Bottom interface layers". Have to be as short as possible def->set_enum_values(ConfigOptionDef::GUIType::i_enum_open, { + //TRN Print Settings: "Bottom interface layers". Have to be as short as possible { "-1", L("Same as top") }, { "0", L("0 (off)") }, { "1", L("1 (light)") }, @@ -2829,6 +2829,7 @@ void PrintConfigDef::init_fff_params() def = this->add("support_material_synchronize_layers", coBool); def->label = L("Synchronize with object layers"); def->category = L("Support material"); + // TRN PrintSettings : "Synchronize with object layers" def->tooltip = L("Synchronize support layers with the object print layers. This is useful " "with multi-material printers, where the extruder switch is expensive. " "This option is only available when top contact Z distance is set to zero."); @@ -2860,6 +2861,7 @@ void PrintConfigDef::init_fff_params() def = this->add("support_tree_angle", coFloat); def->label = L("Maximum Branch Angle"); def->category = L("Support material"); + // TRN PrintSettings: "Organic supports" > "Maximum Branch Angle" def->tooltip = L("The maximum angle of the branches, when the branches have to avoid the model. " "Use a lower angle to make them more vertical and more stable. Use a higher angle to be able to have more reach."); def->sidetext = L("°"); @@ -2871,6 +2873,7 @@ void PrintConfigDef::init_fff_params() def = this->add("support_tree_angle_slow", coFloat); def->label = L("Preferred Branch Angle"); def->category = L("Support material"); + // TRN PrintSettings: "Organic supports" > "Preferred Branch Angle" def->tooltip = L("The preferred angle of the branches, when they do not have to avoid the model. " "Use a lower angle to make them more vertical and more stable. Use a higher angle for branches to merge faster."); def->sidetext = L("°"); @@ -2882,6 +2885,7 @@ void PrintConfigDef::init_fff_params() def = this->add("support_tree_tip_diameter", coFloat); def->label = L("Tip Diameter"); def->category = L("Support material"); + // TRN PrintSettings: "Organic supports" > "Tip Diameter" def->tooltip = L("The diameter of the top of the tip of the branches of organic support."); def->sidetext = L("mm"); def->min = 0; @@ -2891,6 +2895,7 @@ void PrintConfigDef::init_fff_params() def = this->add("support_tree_branch_diameter", coFloat); def->label = L("Branch Diameter"); def->category = L("Support material"); + // TRN PrintSettings: "Organic supports" > "Branch Diameter" def->tooltip = L("The diameter of the thinnest branches of organic support. Thicker branches are more sturdy. " "Branches towards the base will be thicker than this."); def->sidetext = L("mm"); @@ -2899,8 +2904,10 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionFloat(2)); def = this->add("support_tree_branch_diameter_angle", coFloat); + // TRN PrintSettings: #lmFIXME def->label = L("Branch Diameter Angle"); def->category = L("Support material"); + // TRN PrintSettings: "Organic supports" > "Branch Diameter Angle" def->tooltip = L("The angle of the branches' diameter as they gradually become thicker towards the bottom. " "An angle of 0 will cause the branches to have uniform thickness over their length. " "A bit of an angle can increase stability of the organic support."); @@ -2914,8 +2921,10 @@ void PrintConfigDef::init_fff_params() // How far apart the branches need to be when they touch the model. Making this distance small will cause // the tree support to touch the model at more points, causing better overhang but making support harder to remove. def = this->add("support_tree_branch_distance", coFloat); + // TRN PrintSettings: #lmFIXME def->label = L("Branch Distance"); def->category = L("Support material"); + // TRN PrintSettings: "Organic supports" > "Branch Distance" def->tooltip = L("How far apart the branches need to be when they touch the model. " "Making this distance small will cause the tree support to touch the model at more points, " "causing better overhang but making support harder to remove."); @@ -2925,6 +2934,7 @@ void PrintConfigDef::init_fff_params() def = this->add("support_tree_top_rate", coPercent); def->label = L("Branch Density"); def->category = L("Support material"); + // TRN PrintSettings: "Organic supports" > "Branch Density" def->tooltip = L("Adjusts the density of the support structure used to generate the tips of the branches. " "A higher value results in better overhangs but the supports are harder to remove, " "thus it is recommended to enable top support interfaces instead of a high branch density value " @@ -3013,8 +3023,8 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionFloatOrPercent(15, false)); def = this->add("top_solid_layers", coInt); - //TRN To be shown in Print Settings "Top solid layers" - def->label = L("Top"); + //TRN Print Settings: "Top solid layers" + def->label = L_CONTEXT("Top", "Layers"); def->category = L("Layers and Perimeters"); def->tooltip = L("Number of solid layers to generate on top surfaces."); def->full_label = L("Top solid layers"); @@ -3022,8 +3032,7 @@ void PrintConfigDef::init_fff_params() def->set_default_value(new ConfigOptionInt(3)); def = this->add("top_solid_min_thickness", coFloat); - //TRN To be shown in Print Settings "Top solid layers" - def->label = L("Top"); + def->label = L_CONTEXT("Top", "Layers"); def->category = L("Layers and Perimeters"); def->tooltip = L("The number of top solid layers is increased above top_solid_layers if necessary to satisfy " "minimum thickness of top shell." @@ -3150,6 +3159,25 @@ void PrintConfigDef::init_fff_params() def->min = 0.; def->set_default_value(new ConfigOptionFloat(2.)); + def = this->add("wipe_tower_cone_angle", coFloat); + def->label = L("Stabilization cone apex angle"); + def->tooltip = L("Angle at the apex of the cone that is used to stabilize the wipe tower. " + "Larger angle means wider base."); + def->sidetext = L("°"); + def->mode = comAdvanced; + def->min = 0.; + def->max = 90.; + def->set_default_value(new ConfigOptionFloat(0.)); + + def = this->add("wipe_tower_extra_spacing", coPercent); + def->label = L("Wipe tower purge lines spacing"); + def->tooltip = L("Spacing of purge lines on the wipe tower."); + def->sidetext = L("%"); + def->mode = comExpert; + def->min = 100.; + def->max = 300.; + def->set_default_value(new ConfigOptionPercent(100.)); + def = this->add("wipe_into_infill", coBool); def->category = L("Wipe options"); def->label = L("Wipe into this object's infill"); @@ -3860,7 +3888,9 @@ void PrintConfigDef::init_sla_params() def->tooltip = L("Support tree building strategy"); def->set_enum( ConfigOptionEnum::get_enum_names(), - { L("Default"), L("Branching (experimental)") }); + { L("Default"), + // TRN One of the "Support tree type"s on SLAPrintSettings : Supports + L("Branching (experimental)") }); // TODO: def->enum_def->labels[2] = L("Organic"); def->mode = comSimple; def->set_default_value(new ConfigOptionEnum(sla::SupportTreeType::Default)); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index e5a9f4c41a..52924bf91f 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -823,6 +823,8 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionFloat, wipe_tower_per_color_wipe)) ((ConfigOptionFloat, wipe_tower_rotation_angle)) ((ConfigOptionFloat, wipe_tower_brim_width)) + ((ConfigOptionFloat, wipe_tower_cone_angle)) + ((ConfigOptionPercent, wipe_tower_extra_spacing)) ((ConfigOptionFloat, wipe_tower_bridging)) ((ConfigOptionFloats, wiping_volumes_matrix)) ((ConfigOptionFloats, wiping_volumes_extruders)) diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index aa1216a0fb..7136617d82 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -56,10 +56,6 @@ using namespace std::literals; -//! macro used to mark string used at localization, -//! return same string -#define L(s) Slic3r::I18N::translate(s) - #ifdef SLIC3R_DEBUG_SLICE_PROCESSING #define SLIC3R_DEBUG #endif @@ -153,7 +149,7 @@ void PrintObject::make_perimeters() if (! this->set_started(posPerimeters)) return; - m_print->set_status(20, L("Generating perimeters")); + m_print->set_status(20, _u8L("Generating perimeters")); BOOST_LOG_TRIVIAL(info) << "Generating perimeters..." << log_memory_info(); // Revert the typed slices into untyped slices. @@ -258,7 +254,7 @@ void PrintObject::prepare_infill() if (! this->set_started(posPrepareInfill)) return; - m_print->set_status(30, L("Preparing infill")); + m_print->set_status(30, _u8L("Preparing infill")); if (m_typed_slices) { // To improve robustness of detect_surfaces_type() when reslicing (working with typed slices), see GH issue #7442. @@ -403,7 +399,8 @@ void PrintObject::infill() this->prepare_infill(); if (this->set_started(posInfill)) { - m_print->set_status(45, L("making infill")); + // TRN Status for the Print calculation + m_print->set_status(45, _u8L("Making infill")); const auto& adaptive_fill_octree = this->m_adaptive_fill_octrees.first; const auto& support_fill_octree = this->m_adaptive_fill_octrees.second; @@ -450,7 +447,7 @@ void PrintObject::generate_support_spots() { if (this->set_started(posSupportSpotsSearch)) { BOOST_LOG_TRIVIAL(debug) << "Searching support spots - start"; - m_print->set_status(65, L("Searching support spots")); + m_print->set_status(65, _u8L("Searching support spots")); if (!this->shared_regions()->generated_support_points.has_value()) { PrintTryCancel cancel_func = m_print->make_try_cancel(); SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.values, @@ -475,7 +472,7 @@ void PrintObject::generate_support_material() if (this->set_started(posSupportMaterial)) { this->clear_support_layers(); if ((this->has_support() && m_layers.size() > 1) || (this->has_raft() && ! m_layers.empty())) { - m_print->set_status(70, L("Generating support material")); + m_print->set_status(70, _u8L("Generating support material")); this->_generate_support_material(); m_print->throw_if_canceled(); } else { @@ -496,7 +493,7 @@ void PrintObject::estimate_curled_extrusions() if (this->set_started(posEstimateCurledExtrusions)) { if (this->print()->config().avoid_crossing_curled_overhangs) { BOOST_LOG_TRIVIAL(debug) << "Estimating areas with curled extrusions - start"; - m_print->set_status(88, L("Estimating curled extrusions")); + m_print->set_status(88, _u8L("Estimating curled extrusions")); // Estimate curling of support material and add it to the malformaition lines of each layer float support_flow_width = support_material_flow(this, this->config().layer_height).width(); diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 4cc5adff0d..6f6080cb8e 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -10,8 +10,6 @@ #include -//! macro used to mark string used at localization, return same string -#define L(s) Slic3r::I18N::translate(s) namespace Slic3r { @@ -499,7 +497,7 @@ void PrintObject::slice() { if (! this->set_started(posSlice)) return; - m_print->set_status(10, L("Processing triangulated mesh")); + m_print->set_status(10, _u8L("Processing triangulated mesh")); std::vector layer_height_profile; this->update_layer_height_profile(*this->model_object(), m_slicing_params, layer_height_profile); m_print->throw_if_canceled(); @@ -733,9 +731,9 @@ void PrintObject::slice_volumes() if (m_config.xy_size_compensation.value != 0.f) { this->active_step_add_warning( PrintStateBase::WarningLevel::CRITICAL, - L("An object has enabled XY Size compensation which will not be used because it is also multi-material painted.\nXY Size " + _u8L("An object has enabled XY Size compensation which will not be used because it is also multi-material painted.\nXY Size " "compensation cannot be combined with multi-material painting.") + - "\n" + (L("Object name")) + ": " + this->model_object()->name); + "\n" + (_u8L("Object name")) + ": " + this->model_object()->name); } BOOST_LOG_TRIVIAL(debug) << "Slicing volumes - MMU segmentation"; diff --git a/src/libslic3r/SLA/Hollowing.cpp b/src/libslic3r/SLA/Hollowing.cpp index 634cde4695..56cecdccd5 100644 --- a/src/libslic3r/SLA/Hollowing.cpp +++ b/src/libslic3r/SLA/Hollowing.cpp @@ -23,10 +23,6 @@ #include #include -//! macro used to mark string used at localization, -//! return same string -#define L(s) Slic3r::I18N::translate(s) - namespace Slic3r { namespace sla { @@ -83,12 +79,12 @@ InteriorPtr generate_interior(const VoxelGrid &vgrid, auto narrowb = 1.f; // voxel units (voxel count) if (ctl.stopcondition()) return {}; - else ctl.statuscb(0, L("Hollowing")); + else ctl.statuscb(0, _u8L("Hollowing")); auto gridptr = dilate_grid(vgrid, out_range, in_range); if (ctl.stopcondition()) return {}; - else ctl.statuscb(30, L("Hollowing")); + else ctl.statuscb(30, _u8L("Hollowing")); double iso_surface = D; if (D > EPSILON) { @@ -103,7 +99,7 @@ InteriorPtr generate_interior(const VoxelGrid &vgrid, } if (ctl.stopcondition()) return {}; - else ctl.statuscb(70, L("Hollowing")); + else ctl.statuscb(70, _u8L("Hollowing")); double adaptivity = 0.; InteriorPtr interior = InteriorPtr{new Interior{}}; @@ -112,7 +108,7 @@ InteriorPtr generate_interior(const VoxelGrid &vgrid, interior->gridptr = std::move(gridptr); if (ctl.stopcondition()) return {}; - else ctl.statuscb(100, L("Hollowing")); + else ctl.statuscb(100, _u8L("Hollowing")); interior->iso_surface = iso_surface; interior->thickness = offset; diff --git a/src/libslic3r/SLA/Pad.cpp b/src/libslic3r/SLA/Pad.cpp index ec9e216f55..34a1b5dd34 100644 --- a/src/libslic3r/SLA/Pad.cpp +++ b/src/libslic3r/SLA/Pad.cpp @@ -21,9 +21,6 @@ #include "I18N.hpp" #include -//! macro used to mark string used at localization, -//! return same string -#define L(s) Slic3r::I18N::translate(s) namespace Slic3r { namespace sla { @@ -530,7 +527,7 @@ std::string PadConfig::validate() const if (brim_size_mm < MIN_BRIM_SIZE_MM || bottom_offset() > brim_size_mm + wing_distance() || get_waffle_offset(*this) <= MIN_BRIM_SIZE_MM) - return L("Pad brim size is too small for the current configuration."); + return _u8L("Pad brim size is too small for the current configuration."); return ""; } diff --git a/src/libslic3r/SLA/SupportTree.cpp b/src/libslic3r/SLA/SupportTree.cpp index 3de05261a3..d066e02bfd 100644 --- a/src/libslic3r/SLA/SupportTree.cpp +++ b/src/libslic3r/SLA/SupportTree.cpp @@ -16,13 +16,9 @@ #include #include -#include #include -//! macro used to mark string used at localization, -//! return same string -#define L(s) Slic3r::I18N::translate(s) namespace Slic3r { namespace sla { diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index 202da5e003..6dc4a46206 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -23,7 +23,7 @@ //! macro used to mark string used at localization, //! return same string -#define L(s) Slic3r::I18N::translate(s) +#define _u8L(s) Slic3r::I18N::translate(s) namespace Slic3r { @@ -543,7 +543,7 @@ std::string SLAPrint::validate(std::string*) const if(supports_en && mo->sla_points_status == sla::PointsStatus::UserModified && mo->sla_support_points.empty()) - return L("Cannot proceed without support points! " + return _u8L("Cannot proceed without support points! " "Add support points or disable support generation."); sla::SupportTreeConfig cfg = make_support_cfg(po->config()); @@ -554,13 +554,13 @@ std::string SLAPrint::validate(std::string*) const sla::PadConfig::EmbedObject &builtinpad = padcfg.embed_object; if(supports_en && !builtinpad.enabled && elv < cfg.head_fullwidth()) - return L( + return _u8L( "Elevation is too low for object. Use the \"Pad around " "object\" feature to print the object without elevation."); if(supports_en && builtinpad.enabled && cfg.pillar_base_safety_distance_mm < builtinpad.object_gap_mm) { - return L( + return _u8L( "The endings of the support pillars will be deployed on the " "gap between the object and the pad. 'Support base safety " "distance' has to be greater than the 'Pad object gap' " @@ -576,14 +576,14 @@ std::string SLAPrint::validate(std::string*) const double expt_cur = m_material_config.exposure_time.getFloat(); if (expt_cur < expt_min || expt_cur > expt_max) - return L("Exposition time is out of printer profile bounds."); + return _u8L("Exposition time is out of printer profile bounds."); double iexpt_max = m_printer_config.max_initial_exposure_time.getFloat(); double iexpt_min = m_printer_config.min_initial_exposure_time.getFloat(); double iexpt_cur = m_material_config.initial_exposure_time.getFloat(); if (iexpt_cur < iexpt_min || iexpt_cur > iexpt_max) - return L("Initial exposition time is out of printer profile bounds."); + return _u8L("Initial exposition time is out of printer profile bounds."); return ""; } @@ -690,7 +690,7 @@ void SLAPrint::process() } // If everything vent well - m_report_status(*this, 100, L("Slicing done")); + m_report_status(*this, 100, _u8L("Slicing done")); #ifdef SLAPRINT_DO_BENCHMARK std::string csvbenchstr; diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index 3381304544..5ef8a27096 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -32,9 +32,6 @@ #include -//! macro used to mark string used at localization, -//! return same string -#define L(s) Slic3r::I18N::translate(s) namespace Slic3r { @@ -54,14 +51,15 @@ const std::array OBJ_STEP_LEVELS = { std::string OBJ_STEP_LABELS(size_t idx) { switch (idx) { - case slaposAssembly: return L("Assembling model from parts"); - case slaposHollowing: return L("Hollowing model"); - case slaposDrillHoles: return L("Drilling holes into model."); - case slaposObjectSlice: return L("Slicing model"); - case slaposSupportPoints: return L("Generating support points"); - case slaposSupportTree: return L("Generating support tree"); - case slaposPad: return L("Generating pad"); - case slaposSliceSupports: return L("Slicing supports"); + // TRN Status of the SLA print calculation + case slaposAssembly: return _u8L("Assembling model from parts"); + case slaposHollowing: return _u8L("Hollowing model"); + case slaposDrillHoles: return _u8L("Drilling holes into model."); + case slaposObjectSlice: return _u8L("Slicing model"); + case slaposSupportPoints: return _u8L("Generating support points"); + case slaposSupportTree: return _u8L("Generating support tree"); + case slaposPad: return _u8L("Generating pad"); + case slaposSliceSupports: return _u8L("Slicing supports"); default:; } assert(false); @@ -76,8 +74,8 @@ const std::array PRINT_STEP_LEVELS = { std::string PRINT_STEP_LABELS(size_t idx) { switch (idx) { - case slapsMergeSlicesAndEval: return L("Merging slices and calculating statistics"); - case slapsRasterize: return L("Rasterizing layers"); + case slapsMergeSlicesAndEval: return _u8L("Merging slices and calculating statistics"); + case slapsRasterize: return _u8L("Rasterizing layers"); default:; } assert(false); return "Out of bounds!"; @@ -252,14 +250,14 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st if (ret & static_cast(sla::HollowMeshResult::FaultyMesh)) { po.active_step_add_warning( PrintStateBase::WarningLevel::NON_CRITICAL, - L("Mesh to be hollowed is not suitable for hollowing (does not " + _u8L("Mesh to be hollowed is not suitable for hollowing (does not " "bound a volume).")); } if (ret & static_cast(sla::HollowMeshResult::FaultyHoles)) { po.active_step_add_warning( PrintStateBase::WarningLevel::NON_CRITICAL, - L("Unable to drill the current configuration of holes into the " + _u8L("Unable to drill the current configuration of holes into the " "model.")); } @@ -267,7 +265,7 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st if (ret & static_cast(sla::HollowMeshResult::DrillingFailed)) { po.active_step_add_warning( - PrintStateBase::WarningLevel::NON_CRITICAL, L( + PrintStateBase::WarningLevel::NON_CRITICAL, _u8L( "Drilling holes into the mesh failed. " "This is usually caused by broken model. Try to fix it first.")); @@ -276,7 +274,7 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st if (hole_fail) { po.active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, - L("Failed to drill some holes into the model")); + _u8L("Failed to drill some holes into the model")); handled = false; } @@ -286,7 +284,7 @@ void SLAPrint::Steps::generate_preview(SLAPrintObject &po, SLAPrintObjectStep st if (!handled) { // Last resort to voxelization. po.active_step_add_warning(PrintStateBase::WarningLevel::NON_CRITICAL, - L("Can't perform full mesh booleans! " + _u8L("Can't perform full mesh booleans! " "Some parts of the print will be previewed with approximated meshes. " "This does not affect the quality of slices or the physical print in any way.")); m = generate_preview_vdb(po, step); @@ -507,7 +505,7 @@ void SLAPrint::Steps::slice_model(SLAPrintObject &po) if(slindex_it == po.m_slice_index.end()) //TRN To be shown at the status bar on SLA slicing error. throw Slic3r::RuntimeError( - L("Slicing had to be stopped due to an internal error: " + _u8L("Slicing had to be stopped due to an internal error: " "Inconsistent slice index.")); po.m_model_height_levels.clear(); @@ -688,7 +686,7 @@ void SLAPrint::Steps::support_points(SLAPrintObject &po) // Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass // the update status to GLGizmoSlaSupports - report_status(-1, L("Generating support points"), + report_status(-1, _u8L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS); } else { // There are either some points on the front-end, or the user @@ -737,7 +735,7 @@ void SLAPrint::Steps::support_tree(SLAPrintObject &po) auto rc = SlicingStatus::RELOAD_SCENE; // This is to prevent "Done." being displayed during merged_mesh() - report_status(-1, L("Visualizing supports")); + report_status(-1, _u8L("Visualizing supports")); BOOST_LOG_TRIVIAL(debug) << "Processed support point count " << po.m_supportdata->input.pts.size(); @@ -746,7 +744,7 @@ void SLAPrint::Steps::support_tree(SLAPrintObject &po) if(po.support_mesh().empty()) BOOST_LOG_TRIVIAL(warning) << "Support mesh is empty"; - report_status(-1, L("Visualizing supports"), rc); + report_status(-1, _u8L("Visualizing supports"), rc); } void SLAPrint::Steps::generate_pad(SLAPrintObject &po) { @@ -776,7 +774,7 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) { if (!validate_pad(po.m_supportdata->pad_mesh.its, pcfg)) throw Slic3r::SlicingError( - L("No pad can be generated for this model with the " + _u8L("No pad can be generated for this model with the " "current configuration")); } else if(po.m_supportdata) { @@ -784,7 +782,7 @@ void SLAPrint::Steps::generate_pad(SLAPrintObject &po) { } throw_if_canceled(); - report_status(-1, L("Visualizing supports"), SlicingStatus::RELOAD_SCENE); + report_status(-1, _u8L("Visualizing supports"), SlicingStatus::RELOAD_SCENE); } // Slicing the support geometries similarly to the model slicing procedure. @@ -905,7 +903,7 @@ void SLAPrint::Steps::initialize_printer_input() for(const SliceRecord& slicerecord : o->get_slice_index()) { if (!slicerecord.is_valid()) throw Slic3r::SlicingError( - L("There are unprintable objects. Try to " + _u8L("There are unprintable objects. Try to " "adjust support settings to make the " "objects printable.")); diff --git a/src/libslic3r/Zipper.cpp b/src/libslic3r/Zipper.cpp index cebafa6333..53c39c3a75 100644 --- a/src/libslic3r/Zipper.cpp +++ b/src/libslic3r/Zipper.cpp @@ -6,10 +6,6 @@ #include #include "I18N.hpp" -//! macro used to mark string used at localization, -//! return same string -#define L(s) Slic3r::I18N::translate(s) - #if defined(_MSC_VER) && _MSC_VER <= 1800 || __cplusplus < 201103L #define SLIC3R_NORETURN #elif __cplusplus >= 201103L @@ -24,7 +20,7 @@ public: std::string formatted_errorstr() const { - return L("Error with zip archive") + " " + m_zipname + ": " + + return _u8L("Error with zip archive") + " " + m_zipname + ": " + get_errorstr(); } diff --git a/src/libslic3r/miniz_extension.cpp b/src/libslic3r/miniz_extension.cpp index 76b4cb4e55..b0eccbeb38 100644 --- a/src/libslic3r/miniz_extension.cpp +++ b/src/libslic3r/miniz_extension.cpp @@ -6,11 +6,7 @@ #include "boost/nowide/cstdio.hpp" #endif -#include "I18N.hpp" - -//! macro used to mark string used at localization, -//! return same string -#define L(s) Slic3r::I18N::translate(s) +#include "libslic3r/I18N.hpp" namespace Slic3r { @@ -88,67 +84,67 @@ std::string MZ_Archive::get_errorstr(mz_zip_error mz_err) case MZ_ZIP_NO_ERROR: return "no error"; case MZ_ZIP_UNDEFINED_ERROR: - return L("undefined error"); + return _u8L("undefined error"); case MZ_ZIP_TOO_MANY_FILES: - return L("too many files"); + return _u8L("too many files"); case MZ_ZIP_FILE_TOO_LARGE: - return L("file too large"); + return _u8L("file too large"); case MZ_ZIP_UNSUPPORTED_METHOD: - return L("unsupported method"); + return _u8L("unsupported method"); case MZ_ZIP_UNSUPPORTED_ENCRYPTION: - return L("unsupported encryption"); + return _u8L("unsupported encryption"); case MZ_ZIP_UNSUPPORTED_FEATURE: - return L("unsupported feature"); + return _u8L("unsupported feature"); case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR: - return L("failed finding central directory"); + return _u8L("failed finding central directory"); case MZ_ZIP_NOT_AN_ARCHIVE: - return L("not a ZIP archive"); + return _u8L("not a ZIP archive"); case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED: - return L("invalid header or archive is corrupted"); + return _u8L("invalid header or archive is corrupted"); case MZ_ZIP_UNSUPPORTED_MULTIDISK: - return L("unsupported multidisk archive"); + return _u8L("unsupported multidisk archive"); case MZ_ZIP_DECOMPRESSION_FAILED: - return L("decompression failed or archive is corrupted"); + return _u8L("decompression failed or archive is corrupted"); case MZ_ZIP_COMPRESSION_FAILED: - return L("compression failed"); + return _u8L("compression failed"); case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE: - return L("unexpected decompressed size"); + return _u8L("unexpected decompressed size"); case MZ_ZIP_CRC_CHECK_FAILED: - return L("CRC-32 check failed"); + return _u8L("CRC-32 check failed"); case MZ_ZIP_UNSUPPORTED_CDIR_SIZE: - return L("unsupported central directory size"); + return _u8L("unsupported central directory size"); case MZ_ZIP_ALLOC_FAILED: - return L("allocation failed"); + return _u8L("allocation failed"); case MZ_ZIP_FILE_OPEN_FAILED: - return L("file open failed"); + return _u8L("file open failed"); case MZ_ZIP_FILE_CREATE_FAILED: - return L("file create failed"); + return _u8L("file create failed"); case MZ_ZIP_FILE_WRITE_FAILED: - return L("file write failed"); + return _u8L("file write failed"); case MZ_ZIP_FILE_READ_FAILED: - return L("file read failed"); + return _u8L("file read failed"); case MZ_ZIP_FILE_CLOSE_FAILED: - return L("file close failed"); + return _u8L("file close failed"); case MZ_ZIP_FILE_SEEK_FAILED: - return L("file seek failed"); + return _u8L("file seek failed"); case MZ_ZIP_FILE_STAT_FAILED: - return L("file stat failed"); + return _u8L("file stat failed"); case MZ_ZIP_INVALID_PARAMETER: - return L("invalid parameter"); + return _u8L("invalid parameter"); case MZ_ZIP_INVALID_FILENAME: - return L("invalid filename"); + return _u8L("invalid filename"); case MZ_ZIP_BUF_TOO_SMALL: - return L("buffer too small"); + return _u8L("buffer too small"); case MZ_ZIP_INTERNAL_ERROR: - return L("internal error"); + return _u8L("internal error"); case MZ_ZIP_FILE_NOT_FOUND: - return L("file not found"); + return _u8L("file not found"); case MZ_ZIP_ARCHIVE_TOO_LARGE: - return L("archive is too large"); + return _u8L("archive is too large"); case MZ_ZIP_VALIDATION_FAILED: - return L("validation failed"); + return _u8L("validation failed"); case MZ_ZIP_WRITE_CALLBACK_FAILED: - return L("write calledback failed"); + return _u8L("write calledback failed"); default: break; } diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 2ca1998e31..db8cefa995 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -344,3 +344,6 @@ if (UNIX AND NOT APPLE) target_include_directories(libslic3r_gui PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS}) target_link_libraries(libslic3r_gui ${GTK${SLIC3R_GTK}_LIBRARIES} fontconfig) endif () + +# Add a definition so that we can tell we are compiling slic3r. +target_compile_definitions(libslic3r_gui PRIVATE SLIC3R_CURRENTLY_COMPILING_GUI_MODULE) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index f8b41da8a3..71361e68f6 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -480,11 +480,11 @@ int GLVolumeCollection::load_object_volume( #if ENABLE_OPENGL_ES int GLVolumeCollection::load_wipe_tower_preview( - float pos_x, float pos_y, float width, float depth, float height, + float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh) #else int GLVolumeCollection::load_wipe_tower_preview( - float pos_x, float pos_y, float width, float depth, float height, + float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width) #endif // ENABLE_OPENGL_ES { @@ -544,6 +544,21 @@ int GLVolumeCollection::load_wipe_tower_preview( brim_mesh.translate(-brim_width, -brim_width, 0.f); mesh.merge(brim_mesh); + // Now the stabilization cone and its base. + const auto [R, scale_x] = WipeTower::get_wipe_tower_cone_base(width, height, depth, cone_angle); + if (R > 0.) { + TriangleMesh cone_mesh(its_make_cone(R, height)); + cone_mesh.scale(Vec3f(1.f/scale_x, 1.f, 1.f)); + + TriangleMesh disk_mesh(its_make_cylinder(R, brim_height)); + disk_mesh.scale(Vec3f(1. / scale_x, 1., 1.)); // Now it matches the base, which may be elliptic. + disk_mesh.scale(Vec3f(1.f + scale_x*brim_width/R, 1.f + brim_width/R, 1.f)); // Scale so the brim is not deformed. + cone_mesh.merge(disk_mesh); + cone_mesh.translate(width / 2., depth / 2., 0.); + mesh.merge(cone_mesh); + } + + volumes.emplace_back(new GLVolume(color)); GLVolume& v = *volumes.back(); #if ENABLE_OPENGL_ES diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index 9095885fc8..f9eb4f2d41 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -424,10 +424,10 @@ public: #if ENABLE_OPENGL_ES int load_wipe_tower_preview( - float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh = nullptr); + float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width, TriangleMesh* out_mesh = nullptr); #else int load_wipe_tower_preview( - float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width); + float pos_x, float pos_y, float width, float depth, float height, float cone_angle, float rotation_angle, bool size_unknown, float brim_width); #endif // ENABLE_OPENGL_ES // Load SLA auxiliary GLVolumes (for support trees or pad). diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index 823a315b73..0d59f44330 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -41,9 +41,9 @@ void AboutDialogLogo::onRepaint(wxEvent &event) // CopyrightsDialog // ----------------------------------------- CopyrightsDialog::CopyrightsDialog() - : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, from_u8((boost::format("%1% - %2%") - % (wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME) - % _utf8(L("Portions copyright"))).str()), + : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, format_wxstr("%1% - %2%" + , wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME + , _L("Portions copyright")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { this->SetFont(wxGetApp().normal_font()); @@ -141,7 +141,6 @@ wxString CopyrightsDialog::get_html_text() const auto bgr_clr_str = encode_color(ColorRGB(bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue())); const wxString copyright_str = _L("Copyright") + "© "; - // TRN "Slic3r _is licensed under the_ License" const wxString header_str = _L("License agreements of all following programs (libraries) are part of application license agreement"); wxString text = wxString::Format( @@ -211,7 +210,7 @@ void CopyrightsDialog::onCloseDialog(wxEvent &) } AboutDialog::AboutDialog() - : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, from_u8((boost::format(_utf8(L("About %s"))) % (wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME)).str()), wxDefaultPosition, + : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, format_wxstr(_L("About %s"), wxGetApp().is_editor() ? SLIC3R_APP_NAME : GCODEVIEWER_APP_NAME), wxDefaultPosition, wxDefaultSize, /*wxCAPTION*/wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { SetFont(wxGetApp().normal_font()); @@ -267,14 +266,13 @@ AboutDialog::AboutDialog() int size[] = {fs,fs,fs,fs,fs,fs,fs}; m_html->SetFonts(font.GetFaceName(), font.GetFaceName(), size); m_html->SetBorders(2); - const std::string copyright_str = _utf8(L("Copyright")); - // TRN "Slic3r _is licensed under the_ License" - const std::string is_lecensed_str = _utf8(L("is licensed under the")); - const std::string license_str = _utf8(L("GNU Affero General Public License, version 3")); - const std::string based_on_str = _utf8(L("PrusaSlicer is based on Slic3r by Alessandro Ranellucci and the RepRap community.")); - const std::string contributors_str = _utf8(L("Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik and numerous others.")); - const auto text = from_u8( - (boost::format( + const wxString copyright_str = _L("Copyright"); + // TRN AboutDialog: "Slic3r %1% GNU Affero General Public License" + const wxString is_lecensed_str = _L("is licensed under the"); + const wxString license_str = _L("GNU Affero General Public License, version 3"); + const wxString based_on_str = _L("PrusaSlicer is based on Slic3r by Alessandro Ranellucci and the RepRap community."); + const wxString contributors_str = _L("Contributions by Henrik Brix Andersen, Nicolas Dandrimont, Mark Hindess, Petr Ledvina, Joseph Lenox, Y. Sapir, Mike Sheldrake, Vojtech Bubnik and numerous others."); + const auto text = format_wxstr( "" "" "" @@ -288,12 +286,12 @@ AboutDialog::AboutDialog() "%9%" "" "" - "") % bgr_clr_str % text_clr_str % text_clr_str - % copyright_str % copyright_str - % is_lecensed_str - % license_str - % based_on_str - % contributors_str).str()); + "", bgr_clr_str, text_clr_str, text_clr_str + , copyright_str, copyright_str + , is_lecensed_str + , license_str + , based_on_str + , contributors_str); m_html->SetPage(text); vsizer->Add(m_html, 1, wxEXPAND | wxBOTTOM, 10); m_html->Bind(wxEVT_HTML_LINK_CLICKED, &AboutDialog::onLinkClicked, this); diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp index 2348255081..9ee6946c61 100644 --- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp +++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp @@ -76,10 +76,10 @@ std::pair SlicingProcessCompletedEvent::format_error_message( try { this->rethrow_exception(); } catch (const std::bad_alloc &ex) { - wxString errmsg = GUI::from_u8((boost::format(_utf8(L("%s has encountered an error. It was likely caused by running out of memory. " + error = GUI::format(_L("%s has encountered an error. It was likely caused by running out of memory. " "If you are sure you have enough RAM on your system, this may also be a bug and we would " - "be glad if you reported it."))) % SLIC3R_APP_NAME).str()); - error = std::string(errmsg.ToUTF8()) + "\n\n" + std::string(ex.what()); + "be glad if you reported it."), SLIC3R_APP_NAME); + error += "\n\n" + std::string(ex.what()); } catch (const HardCrash &ex) { error = GUI::format(_L("PrusaSlicer has encountered a fatal error: \"%1%\""), ex.what()) + "\n\n" + _u8L("Please save your project and restart PrusaSlicer. " @@ -159,7 +159,7 @@ void BackgroundSlicingProcess::process_fff() wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id)); prepare_upload(); } else { - m_print->set_status(100, _utf8(L("Slicing complete"))); + m_print->set_status(100, _u8L("Slicing complete")); } this->set_step_done(bspsGCodeFinalize); } @@ -180,12 +180,12 @@ void BackgroundSlicingProcess::process_sla() m_sla_print->export_print(export_path, thumbnails); - m_print->set_status(100, (boost::format(_utf8(L("Masked SLA file exported to %1%"))) % export_path).str()); + m_print->set_status(100, GUI::format(_L("Masked SLA file exported to %1%"), export_path)); } else if (! m_upload_job.empty()) { wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id)); prepare_upload(); } else { - m_print->set_status(100, _utf8(L("Slicing complete"))); + m_print->set_status(100, _u8L("Slicing complete")); } this->set_step_done(bspsGCodeFinalize); } @@ -649,7 +649,7 @@ bool BackgroundSlicingProcess::invalidate_all_steps() // Copy the final G-code to target location (possibly a SD card, if it is a removable media, then verify that the file was written without an error). void BackgroundSlicingProcess::finalize_gcode() { - m_print->set_status(95, _utf8(L("Running post-processing scripts"))); + m_print->set_status(95, _u8L("Running post-processing scripts")); // Perform the final post-processing of the export path by applying the print statistics over the file name. std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path); @@ -680,32 +680,32 @@ void BackgroundSlicingProcess::finalize_gcode() catch (...) { remove_post_processed_temp_file(); - throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code."))); + throw Slic3r::ExportError(_u8L("Unknown error occured during exporting G-code.")); } switch (copy_ret_val) { case CopyFileResult::SUCCESS: break; // no error case CopyFileResult::FAIL_COPY_FILE: - throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str()); + throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"), error_message)); break; case CopyFileResult::FAIL_FILES_DIFFERENT: - throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str()); + throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."), export_path)); break; case CopyFileResult::FAIL_RENAMING: - throw Slic3r::ExportError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str()); + throw Slic3r::ExportError(GUI::format(_L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."), export_path)); break; case CopyFileResult::FAIL_CHECK_ORIGIN_NOT_OPENED: - throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % output_path % export_path).str()); + throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."), output_path, export_path)); break; case CopyFileResult::FAIL_CHECK_TARGET_NOT_OPENED: - throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str()); + throw Slic3r::ExportError(GUI::format(_L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."), export_path)); break; default: - throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code."))); + throw Slic3r::ExportError(_u8L("Unknown error occured during exporting G-code.")); BOOST_LOG_TRIVIAL(error) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << "."; break; } - m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str()); + m_print->set_status(100, GUI::format(_L("G-code file exported to %1%"), export_path)); } // A print host upload job has been scheduled, enqueue it to the printhost job queue @@ -716,10 +716,10 @@ void BackgroundSlicingProcess::prepare_upload() / boost::filesystem::unique_path("." SLIC3R_APP_KEY ".upload.%%%%-%%%%-%%%%-%%%%"); if (m_print == m_fff_print) { - m_print->set_status(95, _utf8(L("Running post-processing scripts"))); + m_print->set_status(95, _u8L("Running post-processing scripts")); std::string error_message; if (copy_file(m_temp_output_path, source_path.string(), error_message) != SUCCESS) - throw Slic3r::RuntimeError(_utf8(L("Copying of the temporary G-code to the output G-code failed"))); + throw Slic3r::RuntimeError(_u8L("Copying of the temporary G-code to the output G-code failed")); m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string()); // Make a copy of the source path, as run_post_process_scripts() is allowed to change it when making a copy of the source file // (not here, but when the final target is a file). @@ -735,7 +735,7 @@ void BackgroundSlicingProcess::prepare_upload() m_sla_print->export_print(source_path.string(),thumbnails, m_upload_job.upload_data.upload_path.filename().string()); } - m_print->set_status(100, (boost::format(_utf8(L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"))) % m_upload_job.printhost->get_host()).str()); + m_print->set_status(100, GUI::format(_L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"), m_upload_job.printhost->get_host())); m_upload_job.upload_data.source_path = std::move(source_path); diff --git a/src/slic3r/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index aadf605a10..759b176446 100644 --- a/src/slic3r/GUI/BedShapeDialog.cpp +++ b/src/slic3r/GUI/BedShapeDialog.cpp @@ -128,6 +128,9 @@ void BedShape::apply_optgroup_values(ConfigOptionsGroupShp optgroup) } } +BedShapeDialog::BedShapeDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _(L("Bed Shape")), + wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {} + void BedShapeDialog::build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model) { SetFont(wxGetApp().normal_font()); diff --git a/src/slic3r/GUI/BedShapeDialog.hpp b/src/slic3r/GUI/BedShapeDialog.hpp index 2f308a5073..2c828a58f3 100644 --- a/src/slic3r/GUI/BedShapeDialog.hpp +++ b/src/slic3r/GUI/BedShapeDialog.hpp @@ -5,7 +5,6 @@ #include "GUI_Utils.hpp" #include "2DBed.hpp" -#include "I18N.hpp" #include @@ -93,8 +92,7 @@ class BedShapeDialog : public DPIDialog { BedShapePanel* m_panel; public: - BedShapeDialog(wxWindow* parent) : DPIDialog(parent, wxID_ANY, _(L("Bed Shape")), - wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) {} + BedShapeDialog(wxWindow* parent); void build_dialog(const ConfigOptionPoints& default_pt, const ConfigOptionString& custom_texture, const ConfigOptionString& custom_model); diff --git a/src/slic3r/GUI/BonjourDialog.cpp b/src/slic3r/GUI/BonjourDialog.cpp index 9298aa615b..060643c1ff 100644 --- a/src/slic3r/GUI/BonjourDialog.cpp +++ b/src/slic3r/GUI/BonjourDialog.cpp @@ -224,14 +224,14 @@ void BonjourDialog::on_timer(wxTimerEvent &) // explicitly (wxTimerEvent should not be created by user code). void BonjourDialog::on_timer_process() { - const auto search_str = _utf8(L("Searching for devices")); + const auto search_str = _L("Searching for devices"); if (timer_state > 0) { const std::string dots(timer_state, '.'); - label->SetLabel(GUI::from_u8((boost::format("%1% %2%") % search_str % dots).str())); + label->SetLabel(search_str + dots); timer_state = (timer_state) % 3 + 1; } else { - label->SetLabel(GUI::from_u8((boost::format("%1%: %2%") % search_str % (_utf8(L("Finished"))+".")).str())); + label->SetLabel(search_str + ": " + _L("Finished") + "."); timer->Stop(); } } diff --git a/src/slic3r/GUI/ButtonsDescription.cpp b/src/slic3r/GUI/ButtonsDescription.cpp index e225c7db70..e6fd519dfa 100644 --- a/src/slic3r/GUI/ButtonsDescription.cpp +++ b/src/slic3r/GUI/ButtonsDescription.cpp @@ -160,7 +160,7 @@ void FillSizerWithModeColorDescriptions( wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(9, 5, 5); sizer->Add(grid_sizer, 0, wxEXPAND); - const std::vector names = { _L("Simple"), _CTX(L_CONTEXT("Advanced", "Mode"), "Mode"), _L("Expert") }; + const std::vector names = { _L("Simple"), _CTX("Advanced", "Mode"), _L("Expert") }; for (size_t mode = 0; mode < names.size(); ++mode) { wxColour& color = mode_palette[mode]; diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index c8c3923f7a..1bc2280d5f 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -319,8 +319,8 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) toggle_field("standby_temperature_delta", have_ooze_prevention); bool have_wipe_tower = config->opt_bool("wipe_tower"); - for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", - "wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming" }) + for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_cone_angle", + "wipe_tower_extra_spacing", "wipe_tower_bridging", "wipe_tower_no_sparse_layers", "single_extruder_multi_material_priming" }) toggle_field(el, have_wipe_tower); toggle_field("avoid_crossing_curled_overhangs", !config->opt_bool("avoid_crossing_perimeters")); diff --git a/src/slic3r/GUI/ConfigSnapshotDialog.cpp b/src/slic3r/GUI/ConfigSnapshotDialog.cpp index e2bea55d13..c1817a3baf 100644 --- a/src/slic3r/GUI/ConfigSnapshotDialog.cpp +++ b/src/slic3r/GUI/ConfigSnapshotDialog.cpp @@ -89,10 +89,10 @@ static wxString generate_html_row(const Config::Snapshot &snapshot, bool row_eve } if (! compatible) { - text += "

" + from_u8((boost::format(_utf8(L("Incompatible with this %s"))) % SLIC3R_APP_NAME).str()) + "

"; + text += "

" + format_wxstr(_L("Incompatible with this %s"), SLIC3R_APP_NAME) + "

"; } else if (! snapshot_active) - text += "

" + _(L("Activate")) + "

"; + text += "

" + _L("Activate") + "

"; text += ""; text += ""; return text; diff --git a/src/slic3r/GUI/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index b8956b948e..4aa8c9df6d 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -56,6 +56,7 @@ #include "MsgDialog.hpp" #include "UnsavedChangesDialog.hpp" #include "slic3r/Utils/AppUpdater.hpp" +#include "slic3r/GUI/I18N.hpp" #if defined(__linux__) && defined(__WXGTK3__) #define wxLinux_gtk3 true @@ -288,7 +289,7 @@ PrinterPicker::PrinterPicker(wxWindow *parent, const VendorProfile &vendor, wxSt const auto &variant = model.variants[i]; const auto label = model.technology == ptFFF - ? from_u8((boost::format("%1% %2% %3%") % variant.name % _utf8(L("mm")) % _utf8(L("nozzle"))).str()) + ? format_wxstr("%1% %2% %3%", variant.name, _L("mm"), _L("nozzle")) : from_u8(model.name); if (i == 1) { @@ -508,17 +509,17 @@ void ConfigWizardPage::append_spacer(int space) // Wizard pages PageWelcome::PageWelcome(ConfigWizard *parent) - : ConfigWizardPage(parent, from_u8((boost::format( + : ConfigWizardPage(parent, format_wxstr( #ifdef __APPLE__ - _utf8(L("Welcome to the %s Configuration Assistant")) + _L("Welcome to the %s Configuration Assistant") #else - _utf8(L("Welcome to the %s Configuration Wizard")) + _L("Welcome to the %s Configuration Wizard") #endif - ) % SLIC3R_APP_NAME).str()), _L("Welcome")) - , welcome_text(append_text(from_u8((boost::format( - _utf8(L("Hello, welcome to %s! This %s helps you with the initial configuration; just a few settings and you will be ready to print."))) - % SLIC3R_APP_NAME - % _utf8(ConfigWizard::name())).str()) + , SLIC3R_APP_NAME), _L("Welcome")) + , welcome_text(append_text(format_wxstr( + _L("Hello, welcome to %s! This %s helps you with the initial configuration; just a few settings and you will be ready to print.") + , SLIC3R_APP_NAME + , _(ConfigWizard::name())) )) , cbox_reset(append( new wxCheckBox(this, wxID_ANY, _L("Remove user profiles (a snapshot will be taken beforehand)")) @@ -576,7 +577,7 @@ PagePrinters::PagePrinters(ConfigWizard *parent, continue; } - const auto picker_title = family.empty() ? wxString() : from_u8((boost::format(_utf8(L("%s Family"))) % family).str()); + const auto picker_title = family.empty() ? wxString() : format_wxstr(_L("%s Family"), family); auto *picker = new PrinterPicker(this, vendor, picker_title, MAX_COLS, *appconfig, filter); picker->Bind(EVT_PRINTER_PICK, [this, appconfig](const PrinterPickerEvent &evt) { @@ -786,11 +787,14 @@ void PageMaterials::set_compatible_printers_html_window(const std::vectortechnology == T_FFF && template_shown) { + // TRN ConfigWizard: Materials : "%1%" = "Filaments"/"SLA materials" text = format_wxstr(_L("%1% visible for (\"Template\") printer are universal profiles available for all printers. These might not be compatible with your printer."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials")); } else { + // TRN ConfigWizard: Materials : "%1%" = "Filaments"/"SLA materials" wxString first_line = format_wxstr(_L("%1% marked with * are not compatible with some installed printers."), materials->technology == T_FFF ? _L("Filaments") : _L("SLA materials")); if (all_printers) { + // TRN ConfigWizard: Materials : "%1%" = "filament"/"SLA material" wxString second_line = format_wxstr(_L("All installed printers are compatible with the selected %1%."), materials->technology == T_FFF ? _L("filament") : _L("SLA material")); text = wxString::Format( "" @@ -1368,7 +1372,7 @@ Worker::Worker(wxWindow* parent) button_path->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event) { boost::filesystem::path chosen_dest(boost::nowide::narrow(m_input_path->GetValue())); - wxDirDialog dialog(m_parent, L("Choose folder:"), chosen_dest.string() ); + wxDirDialog dialog(m_parent, _L("Choose folder") + ":", chosen_dest.string() ); if (dialog.ShowModal() == wxID_OK) this->m_input_path->SetValue(dialog.GetPath()); }); @@ -1420,11 +1424,12 @@ PageDownloader::PageDownloader(ConfigWizard* parent) box_allow_downloads->SetValue(box_allow_value); append(box_allow_downloads); - append_text(wxString::Format(_L( - "If enabled, %s registers to start on custom URL on www.printables.com." - " You will be able to use button with %s logo to open models in this %s." + // TRN ConfigWizard : Downloader : %1% = "PrusaSlicer" + append_text(format_wxstr(_L( + "If enabled, %1% registers to start on custom URL on www.printables.com." + " You will be able to use button with %1% logo to open models in this %1%." " The model will be downloaded into folder you choose bellow." - ), SLIC3R_APP_NAME, SLIC3R_APP_NAME, SLIC3R_APP_NAME)); + ), SLIC3R_APP_NAME)); #ifdef __linux__ append_text(wxString::Format(_L( @@ -1455,7 +1460,7 @@ bool DownloaderUtils::Worker::perform_register(const std::string& path_override/ chosen_dest = aux_dest; ec.clear(); if (chosen_dest.empty() || !boost::filesystem::is_directory(chosen_dest, ec) || ec) { - std::string err_msg = GUI::format("%1%\n\n%2%",_L("Chosen directory for downloads does not Exists.") ,chosen_dest.string()); + std::string err_msg = GUI::format("%1%\n\n%2%",_L("Chosen directory for downloads does not exist.") ,chosen_dest.string()); BOOST_LOG_TRIVIAL(error) << err_msg; show_error(m_parent, err_msg); return false; @@ -1752,6 +1757,7 @@ void PageBedShape::apply_custom_config(DynamicPrintConfig &config) } PageBuildVolume::PageBuildVolume(ConfigWizard* parent) + // TRN ConfigWizard : Size of possible print, related on printer size : ConfigWizardPage(parent, _L("Build Volume"), _L("Build Volume"), 1) , build_volume(new DiamTextCtrl(this)) { @@ -1792,7 +1798,7 @@ PageBuildVolume::PageBuildVolume(ConfigWizard* parent) }, build_volume->GetId()); auto* sizer_volume = new wxFlexGridSizer(3, 5, 5); - auto* text_volume = new wxStaticText(this, wxID_ANY, _L("Max print height:")); + auto* text_volume = new wxStaticText(this, wxID_ANY, _L("Max print height") + ":"); auto* unit_volume = new wxStaticText(this, wxID_ANY, _L("mm")); sizer_volume->AddGrowableCol(0, 1); sizer_volume->Add(text_volume, 0, wxALIGN_CENTRE_VERTICAL); @@ -1828,7 +1834,7 @@ PageDiameters::PageDiameters(ConfigWizard *parent) append_text(_L("Enter the diameter of your printer's hot end nozzle.")); auto *sizer_nozzle = new wxFlexGridSizer(3, 5, 5); - auto *text_nozzle = new wxStaticText(this, wxID_ANY, _L("Nozzle Diameter:")); + auto *text_nozzle = new wxStaticText(this, wxID_ANY, _L("Nozzle Diameter") + ":"); auto *unit_nozzle = new wxStaticText(this, wxID_ANY, _L("mm")); sizer_nozzle->AddGrowableCol(0, 1); sizer_nozzle->Add(text_nozzle, 0, wxALIGN_CENTRE_VERTICAL); @@ -1842,7 +1848,7 @@ PageDiameters::PageDiameters(ConfigWizard *parent) append_text(_L("Good precision is required, so use a caliper and do multiple measurements along the filament, then compute the average.")); auto *sizer_filam = new wxFlexGridSizer(3, 5, 5); - auto *text_filam = new wxStaticText(this, wxID_ANY, _L("Filament Diameter:")); + auto *text_filam = new wxStaticText(this, wxID_ANY, _L("Filament Diameter") + ":"); auto *unit_filam = new wxStaticText(this, wxID_ANY, _L("mm")); sizer_filam->AddGrowableCol(0, 1); sizer_filam->Add(text_filam, 0, wxALIGN_CENTRE_VERTICAL); @@ -1934,7 +1940,7 @@ PageTemperatures::PageTemperatures(ConfigWizard *parent) append_text(_L("A rule of thumb is 60 °C for PLA and 110 °C for ABS. Leave zero if you have no heated bed.")); auto *sizer_bed = new wxFlexGridSizer(3, 5, 5); - auto *text_bed = new wxStaticText(this, wxID_ANY, _L("Bed Temperature:")); + auto *text_bed = new wxStaticText(this, wxID_ANY, _L("Bed Temperature") + ":"); auto *unit_bed = new wxStaticText(this, wxID_ANY, _L("°C")); sizer_bed->AddGrowableCol(0, 1); sizer_bed->Add(text_bed, 0, wxALIGN_CENTRE_VERTICAL); diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 99b8d73d55..a0816c22f8 100644 --- a/src/slic3r/GUI/DoubleSlider.cpp +++ b/src/slic3r/GUI/DoubleSlider.cpp @@ -106,7 +106,7 @@ Control::Control( wxWindow *parent, m_cog_icon_dim = m_bmp_cog.GetWidth(); m_selection = ssUndef; - m_ticks.set_pause_print_msg(_utf8(L("Place bearings in slots and resume printing"))); + m_ticks.set_pause_print_msg(_u8L("Place bearings in slots and resume printing")); m_ticks.set_extruder_colors(&m_extruder_colors); // slider events diff --git a/src/slic3r/GUI/Downloader.cpp b/src/slic3r/GUI/Downloader.cpp index 45ea436313..3d2a00106d 100644 --- a/src/slic3r/GUI/Downloader.cpp +++ b/src/slic3r/GUI/Downloader.cpp @@ -178,7 +178,7 @@ void Downloader::on_error(wxCommandEvent& event) BOOST_LOG_TRIVIAL(error) << "Download error: " << event.GetString(); NotificationManager* ntf_mngr = wxGetApp().notification_manager(); ntf_mngr->set_download_URL_error(id, boost::nowide::narrow(event.GetString())); - show_error(nullptr, format_wxstr(L"%1%\n%2%", _L("The download has failed:"), event.GetString())); + show_error(nullptr, format_wxstr(L"%1%\n%2%", _L("The download has failed") + ":", event.GetString())); } void Downloader::on_complete(wxCommandEvent& event) { diff --git a/src/slic3r/GUI/DownloaderFileGet.cpp b/src/slic3r/GUI/DownloaderFileGet.cpp index ee407afddd..ee64552592 100644 --- a/src/slic3r/GUI/DownloaderFileGet.cpp +++ b/src/slic3r/GUI/DownloaderFileGet.cpp @@ -190,6 +190,7 @@ void FileGet::priv::get_perform() //assert(file != NULL); if (file == NULL) { wxCommandEvent* evt = new wxCommandEvent(EVT_DWNLDR_FILE_ERROR); + // TRN %1% = file path evt->SetString(GUI::format_wxstr(_L("Can't create file at %1%."), temp_path_wstring)); evt->SetInt(m_id); m_evt_handler->QueueEvent(evt); diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp index c6ffa46ec4..74ad028d36 100644 --- a/src/slic3r/GUI/Field.cpp +++ b/src/slic3r/GUI/Field.cpp @@ -226,7 +226,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true } wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label); - show_error(m_parent, from_u8((boost::format(_utf8(L("%s doesn't support percentage"))) % label).str())); + show_error(m_parent, format_wxstr(_L("%s doesn't support percentage"), label)); set_value(double_to_string(m_opt.min), true); m_value = double(m_opt.min); break; @@ -299,7 +299,7 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true // Workaroud to avoid of using of the % for first layer height // see https://github.com/prusa3d/PrusaSlicer/issues/7418 wxString label = m_opt.full_label.empty() ? _(m_opt.label) : _(m_opt.full_label); - show_error(m_parent, from_u8((boost::format(_utf8(L("%s doesn't support percentage"))) % label).str())); + show_error(m_parent, format_wxstr(_L("%s doesn't support percentage"), label)); const wxString stVal = double_to_string(0.01, 2); set_value(stVal, true); m_value = into_u8(stVal);; @@ -341,9 +341,10 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm"; const wxString stVal = double_to_string(val, 2); - const wxString msg_text = from_u8((boost::format(_utf8(L("Do you mean %s%% instead of %s %s?\n" - "Select YES if you want to change this value to %s%%, \n" - "or NO if you are sure that %s %s is a correct value."))) % stVal % stVal % sidetext % stVal % stVal % sidetext).str()); + // TRN %1% = Value, %2% = units + const wxString msg_text = format_wxstr(_L("Do you mean %1%%% instead of %1% %2%?\n" + "Select YES if you want to change this value to %1%%%, \n" + "or NO if you are sure that %1% %2% is a correct value."), stVal, sidetext); WarningDialog dialog(m_parent, msg_text, _L("Parameter validation") + ": " + m_opt_id, wxYES | wxNO); if ((!infill_anchors || val > 100) && dialog.ShowModal() == wxID_YES) { set_value(from_u8((boost::format("%s%%") % stVal).str()), false/*true*/); diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 74f7bf50e1..62d4314dbf 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -2253,7 +2253,7 @@ void GCodeViewer::load_shells(const Print& print) const WipeTowerData& wipe_tower_data = print.wipe_tower_data(extruders_count); const float depth = wipe_tower_data.depth; const float brim_width = wipe_tower_data.brim_width; - m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle, + m_shells.volumes.load_wipe_tower_preview(config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_cone_angle, config.wipe_tower_rotation_angle, !print.is_step_done(psWipeTower), brim_width); } } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a433f6dbd5..dc4acebbc6 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -728,7 +728,7 @@ void GLCanvas3D::Labels::render(const std::vector& sorted_ return owner.model_instance_id == id; }); if (it != owners.end()) - it->print_order = std::string((_(L("Seq."))).ToUTF8()) + "#: " + std::to_string(i + 1); + it->print_order = _u8L("Seq.") + "#: " + std::to_string(i + 1); } } @@ -2144,17 +2144,18 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re const float w = dynamic_cast(m_config->option("wipe_tower_width"))->value; const float a = dynamic_cast(m_config->option("wipe_tower_rotation_angle"))->value; const float bw = dynamic_cast(m_config->option("wipe_tower_brim_width"))->value; + const float ca = dynamic_cast(m_config->option("wipe_tower_cone_angle"))->value; const Print *print = m_process->fff_print(); const float depth = print->wipe_tower_data(extruders_count).depth; #if ENABLE_OPENGL_ES int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( - x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower), + x, y, w, depth, (float)height, ca, a, !print->is_step_done(psWipeTower), bw, &m_wipe_tower_mesh); #else int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview( - x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower), + x, y, w, depth, (float)height, ca, a, !print->is_step_done(psWipeTower), bw); #endif // ENABLE_OPENGL_ES if (volume_idx_wipe_tower_old != -1) @@ -4819,7 +4820,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "add"; item.icon_filename = "add.svg"; - item.tooltip = _utf8(L("Add...")) + " [" + GUI::shortkey_ctrl_prefix() + "I]"; + item.tooltip = _u8L("Add...") + " [" + GUI::shortkey_ctrl_prefix() + "I]"; item.sprite_id = 0; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ADD)); }; if (!m_main_toolbar.add_item(item)) @@ -4827,7 +4828,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "delete"; item.icon_filename = "remove.svg"; - item.tooltip = _utf8(L("Delete")) + " [Del]"; + item.tooltip = _u8L("Delete") + " [Del]"; item.sprite_id = 1; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE)); }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_delete(); }; @@ -4836,7 +4837,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "deleteall"; item.icon_filename = "delete_all.svg"; - item.tooltip = _utf8(L("Delete all")) + " [" + GUI::shortkey_ctrl_prefix() + "Del]"; + item.tooltip = _u8L("Delete all") + " [" + GUI::shortkey_ctrl_prefix() + "Del]"; item.sprite_id = 2; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_delete_all(); }; @@ -4845,7 +4846,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "arrange"; item.icon_filename = "arrange.svg"; - item.tooltip = _utf8(L("Arrange")) + " [A]\n" + _utf8(L("Arrange selection")) + " [Shift+A]\n" + _utf8(L("Click right mouse button to show arrangement options")); + item.tooltip = _u8L("Arrange") + " [A]\n" + _u8L("Arrange selection") + " [Shift+A]\n" + _u8L("Click right mouse button to show arrangement options"); item.sprite_id = 3; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_ARRANGE)); }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_arrange(); }; @@ -4865,7 +4866,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "copy"; item.icon_filename = "copy.svg"; - item.tooltip = _utf8(L("Copy")) + " [" + GUI::shortkey_ctrl_prefix() + "C]"; + item.tooltip = _u8L("Copy") + " [" + GUI::shortkey_ctrl_prefix() + "C]"; item.sprite_id = 4; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_COPY)); }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_copy_to_clipboard(); }; @@ -4874,7 +4875,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "paste"; item.icon_filename = "paste.svg"; - item.tooltip = _utf8(L("Paste")) + " [" + GUI::shortkey_ctrl_prefix() + "V]"; + item.tooltip = _u8L("Paste") + " [" + GUI::shortkey_ctrl_prefix() + "V]"; item.sprite_id = 5; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_PASTE)); }; item.enabling_callback = []()->bool { return wxGetApp().plater()->can_paste_from_clipboard(); }; @@ -4886,7 +4887,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "more"; item.icon_filename = "instance_add.svg"; - item.tooltip = _utf8(L("Add instance")) + " [+]"; + item.tooltip = _u8L("Add instance") + " [+]"; item.sprite_id = 6; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_MORE)); }; item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; @@ -4897,7 +4898,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "fewer"; item.icon_filename = "instance_remove.svg"; - item.tooltip = _utf8(L("Remove instance")) + " [-]"; + item.tooltip = _u8L("Remove instance") + " [-]"; item.sprite_id = 7; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_FEWER)); }; item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; @@ -4910,7 +4911,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "splitobjects"; item.icon_filename = "split_objects.svg"; - item.tooltip = _utf8(L("Split to objects")); + item.tooltip = _u8L("Split to objects"); item.sprite_id = 8; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_OBJECTS)); }; item.visibility_callback = GLToolbarItem::Default_Visibility_Callback; @@ -4920,7 +4921,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "splitvolumes"; item.icon_filename = "split_parts.svg"; - item.tooltip = _utf8(L("Split to parts")); + item.tooltip = _u8L("Split to parts"); item.sprite_id = 9; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_SPLIT_VOLUMES)); }; item.visibility_callback = []()->bool { return wxGetApp().get_mode() != comSimple; }; @@ -4934,8 +4935,8 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "settings"; item.icon_filename = "settings.svg"; item.tooltip = _u8L("Switch to Settings") + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "2] - " + _u8L("Print Settings Tab") + - "\n" + "[" + GUI::shortkey_ctrl_prefix() + "3] - " + (current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab")) + - "\n" + "[" + GUI::shortkey_ctrl_prefix() + "4] - " + _u8L("Printer Settings Tab") ; + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "3] - " + (current_printer_technology() == ptFFF ? _u8L("Filament Settings Tab") : _u8L("Material Settings Tab") + + "\n" + "[" + GUI::shortkey_ctrl_prefix() + "4] - " + _u8L("Printer Settings Tab")) ; item.sprite_id = 10; item.enabling_callback = GLToolbarItem::Default_Enabling_Callback; item.visibility_callback = []() { return wxGetApp().app_config->get_bool("new_settings_layout_mode") || @@ -4951,7 +4952,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "search"; item.icon_filename = "search_.svg"; - item.tooltip = _utf8(L("Search")) + " [" + GUI::shortkey_ctrl_prefix() + "F]"; + item.tooltip = _u8L("Search") + " [" + GUI::shortkey_ctrl_prefix() + "F]"; item.sprite_id = 11; item.left.toggable = true; item.left.render_callback = [this](float left, float right, float, float) { @@ -4973,7 +4974,7 @@ bool GLCanvas3D::_init_main_toolbar() item.name = "layersediting"; item.icon_filename = "layers_white.svg"; - item.tooltip = _utf8(L("Variable layer height")); + item.tooltip = _u8L("Variable layer height"); item.sprite_id = 12; item.left.action_callback = [this]() { if (m_canvas != nullptr) wxPostEvent(m_canvas, SimpleEvent(EVT_GLTOOLBAR_LAYERSEDITING)); }; item.visibility_callback = [this]()->bool { @@ -5026,7 +5027,7 @@ bool GLCanvas3D::_init_undoredo_toolbar() item.name = "undo"; item.icon_filename = "undo_toolbar.svg"; - item.tooltip = _utf8(L("Undo")) + " [" + GUI::shortkey_ctrl_prefix() + "Z]\n" + _utf8(L("Click right mouse button to open/close History")); + item.tooltip = _u8L("Undo") + " [" + GUI::shortkey_ctrl_prefix() + "Z]\n" + _u8L("Click right mouse button to open/close History"); item.sprite_id = 0; item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_UNDO)); }; item.right.toggable = true; @@ -5048,7 +5049,7 @@ bool GLCanvas3D::_init_undoredo_toolbar() if (can_undo) { std::string action; wxGetApp().plater()->undo_redo_topmost_string_getter(true, action); - new_additional_tooltip = (boost::format(_utf8(L("Next Undo action: %1%"))) % action).str(); + new_additional_tooltip = format(_L("Next Undo action: %1%"), action); } if (new_additional_tooltip != curr_additional_tooltip) { @@ -5063,7 +5064,7 @@ bool GLCanvas3D::_init_undoredo_toolbar() item.name = "redo"; item.icon_filename = "redo_toolbar.svg"; - item.tooltip = _utf8(L("Redo")) + " [" + GUI::shortkey_ctrl_prefix() + "Y]\n" + _utf8(L("Click right mouse button to open/close History")); + item.tooltip = _u8L("Redo") + " [" + GUI::shortkey_ctrl_prefix() + "Y]\n" + _u8L("Click right mouse button to open/close History"); item.sprite_id = 1; item.left.action_callback = [this]() { post_event(SimpleEvent(EVT_GLCANVAS_REDO)); }; item.right.action_callback = [this]() { m_imgui_undo_redo_hovered_pos = -1; }; @@ -5084,7 +5085,7 @@ bool GLCanvas3D::_init_undoredo_toolbar() if (can_redo) { std::string action; wxGetApp().plater()->undo_redo_topmost_string_getter(false, action); - new_additional_tooltip = (boost::format(_utf8(L("Next Redo action: %1%"))) % action).str(); + new_additional_tooltip = format(_L("Next Redo action: %1%"), action); } if (new_additional_tooltip != curr_additional_tooltip) { diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 076bef54b9..1d4a53fd9a 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -5,7 +5,15 @@ #include "GUI_ObjectManipulation.hpp" #include "GUI_Factories.hpp" #include "format.hpp" -#include "I18N.hpp" + +// Localization headers: include libslic3r version first so everything in this file +// uses the slic3r/GUI version (the macros will take precedence over the functions). +// Also, there is a check that the former is not included from slic3r module. +// This is the only place where we want to allow that, so define an override macro. +#define SLIC3R_ALLOW_LIBSLIC3R_I18N_IN_SLIC3R +#include "libslic3r/I18N.hpp" +#undef SLIC3R_ALLOW_LIBSLIC3R_I18N_IN_SLIC3R +#include "slic3r/GUI/I18N.hpp" #include #include @@ -44,7 +52,6 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/Model.hpp" -#include "libslic3r/I18N.hpp" #include "libslic3r/PresetBundle.hpp" #include "libslic3r/Color.hpp" @@ -1981,7 +1988,7 @@ void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const void GUI_App::import_zip(wxWindow* parent, wxString& input_file) const { wxFileDialog dialog(parent ? parent : GetTopWindow(), - _L("Choose ZIP file:"), + _L("Choose ZIP file") + ":", from_u8(app_config->get_last_dir()), "", file_wildcards(FT_ZIP), wxFD_OPEN | wxFD_FILE_MUST_EXIST); @@ -2381,8 +2388,8 @@ void GUI_App::add_config_menu(wxMenuBar *menu) auto local_menu = new wxMenu(); wxWindowID config_id_base = wxWindow::NewControlId(int(ConfigMenuCnt)); - const auto config_wizard_name = _(ConfigWizard::name(true)); - const auto config_wizard_tooltip = from_u8((boost::format(_utf8(L("Run %s"))) % config_wizard_name).str()); + const wxString config_wizard_name = _(ConfigWizard::name(true)); + const wxString config_wizard_tooltip = from_u8((boost::format(_u8L("Run %s")) % config_wizard_name).str()); // Cmd+, is standard on OS X - what about other operating systems? if (is_editor()) { local_menu->Append(config_id_base + ConfigMenuWizard, config_wizard_name + dots, config_wizard_tooltip); @@ -2409,7 +2416,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu) mode_menu = new wxMenu(); mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeSimple, _L("Simple"), _L("Simple View Mode")); // mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeAdvanced, _L("Advanced"), _L("Advanced View Mode")); - mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeAdvanced, _CTX(L_CONTEXT("Advanced", "Mode"), "Mode"), _L("Advanced View Mode")); + mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeAdvanced, _CTX("Advanced", "Mode"), _L("Advanced View Mode")); mode_menu->AppendRadioItem(config_id_base + ConfigMenuModeExpert, _L("Expert"), _L("Expert View Mode")); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { if (get_mode() == comSimple) evt.Check(true); }, config_id_base + ConfigMenuModeSimple); Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { if (get_mode() == comAdvanced) evt.Check(true); }, config_id_base + ConfigMenuModeAdvanced); @@ -3433,7 +3440,7 @@ void GUI_App::app_updater(bool from_user) } app_data.target_path =dwnld_dlg.get_download_path(); // start download - this->plater_->get_notification_manager()->push_download_progress_notification(GUI::format(_utf8("Downloading %1%"), app_data.target_path.filename().string()), std::bind(&AppUpdater::cancel_callback, this->m_app_updater.get())); + this->plater_->get_notification_manager()->push_download_progress_notification(GUI::format(_L("Downloading %1%"), app_data.target_path.filename().string()), std::bind(&AppUpdater::cancel_callback, this->m_app_updater.get())); app_data.start_after = dwnld_dlg.run_after_download(); m_app_updater->set_app_data(std::move(app_data)); m_app_updater->sync_download(); @@ -3461,7 +3468,7 @@ void GUI_App::start_download(std::string url) //lets always init so if the download dest folder was changed, new dest is used boost::filesystem::path dest_folder(app_config->get("url_downloader_dest")); if (dest_folder.empty() || !boost::filesystem::is_directory(dest_folder)) { - std::string msg = _utf8("Could not start URL download. Destination folder is not set. Please choose destination folder in Configuration Wizard."); + std::string msg = _u8L("Could not start URL download. Destination folder is not set. Please choose destination folder in Configuration Wizard."); BOOST_LOG_TRIVIAL(error) << msg; show_error(nullptr, msg); return; diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index df8ace79a3..60049c865e 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -411,7 +411,7 @@ static void create_freq_settings_popupmenu(wxMenu* menu, const bool is_object_se if (is_improper_category(category.first, extruders_cnt)) continue; - append_menu_item(menu, wxID_ANY, from_u8((boost::format(_utf8(L("Quick Add Settings (%s)"))) % _(it.first)).str()), "", + append_menu_item(menu, wxID_ANY, format_wxstr(_L("Quick Add Settings (%s)"), _(it.first)), "", [menu, item, is_object_settings, bundle](wxCommandEvent& event) { wxString category_name = menu->GetLabel(event.GetId()); std::vector options; @@ -622,13 +622,13 @@ wxMenuItem* MenuFactory::append_menu_item_settings(wxMenu* menu_) #if 0 for (auto& it : m_freq_settings_fff) { - settings_id = menu->FindItem(from_u8((boost::format(_utf8(L("Quick Add Settings (%s)"))) % _(it.first)).str())); + settings_id = menu->FindItem(format_wxstr(_L("Quick Add Settings (%s)"), _(it.first))); if (settings_id != wxNOT_FOUND) menu->Destroy(settings_id); } for (auto& it : m_freq_settings_sla) { - settings_id = menu->FindItem(from_u8((boost::format(_utf8(L("Quick Add Settings (%s)"))) % _(it.first)).str())); + settings_id = menu->FindItem(format_wxstr(_L("Quick Add Settings (%s)"), _(it.first))); if (settings_id != wxNOT_FOUND) menu->Destroy(settings_id); } @@ -1000,7 +1000,7 @@ void MenuFactory::append_menu_item_edit_text(wxMenu *menu) std::string icon = ""; append_menu_item( menu, wxID_ANY, name, description, - [can_edit_text](wxCommandEvent &) { + [](wxCommandEvent &) { plater()->canvas3D()->get_gizmos_manager().open_gizmo(GLGizmosManager::Emboss); }, icon, nullptr, can_edit_text, m_parent); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index ae0e54b456..ad2758f9e8 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -420,7 +420,7 @@ MeshErrorsInfo ObjectList::get_mesh_errors_info(const int obj_idx, const int vol const ModelObject* object = (*m_objects)[obj_idx]; if (vol_idx != -1 && vol_idx >= int(object->volumes.size())) { if (sidebar_info) - *sidebar_info = _L("Wrong volume index "); + *sidebar_info = _L("Wrong volume index") + " "; return { {}, {} }; // hide tooltip } @@ -2063,9 +2063,8 @@ bool ObjectList::del_from_cut_object(bool is_cut_connector, bool is_model_part/* InfoDialog dialog(wxGetApp().plater(), title, _L("This action will break a cut information.\n" - "After that PrusaSlicer can't guarantee model consistency.\n" - "\n" - "To manipulate with solid parts or negative volumes you have to invalidate cut infornation first." + msg_end ), + "After that PrusaSlicer can't guarantee model consistency.") + "\n\n" + + _L("To manipulate with solid parts or negative volumes you have to invalidate cut infornation first." + msg_end ), false, buttons_style | wxCANCEL_DEFAULT | wxICON_WARNING); dialog.SetButtonLabel(wxID_YES, _L("Invalidate cut info")); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 415f008fba..7d9a87b588 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -272,11 +272,10 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : // We will add a button to toggle mirroring to each axis: auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW); #if ENABLE_WORLD_COORDINATE - btn->SetToolTip(_L("Mirror along") + wxString::Format(_L(" %c "), (int)label) + _L("axis")); - + btn->SetToolTip(format_wxstr(_L("Mirror along %1% axis"), label)); m_mirror_buttons[axis_idx] = btn; #else - btn->SetToolTip(wxString::Format(_L("Toggle %c axis mirroring"), (int)label)); + btn->SetToolTip(format_wxstr(_L("Toggle %1% axis mirroring"), label)); btn->SetBitmapDisabled_(m_mirror_bitmap_hidden); m_mirror_buttons[axis_idx].first = btn; diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 97eb5f10d9..41cad87921 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -102,7 +102,7 @@ bool ObjectSettings::update_settings_list() btn->SetBitmapCurrent(m_bmp_delete_focus.bmp()); btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) { - wxGetApp().plater()->take_snapshot(from_u8((boost::format(_utf8(L("Delete Option %s"))) % opt_key).str())); + wxGetApp().plater()->take_snapshot(format_wxstr(_L("Delete Option %s"), opt_key)); config->erase(opt_key); wxGetApp().obj_list()->changed_object(); wxTheApp->CallAfter([this]() { @@ -151,7 +151,7 @@ bool ObjectSettings::update_settings_list() for (auto& opt : cat.second) optgroup->get_field(opt)->m_on_change = [optgroup](const std::string& opt_id, const boost::any& value) { // first of all take a snapshot and then change value in configuration - wxGetApp().plater()->take_snapshot(from_u8((boost::format(_utf8(L("Change Option %s"))) % opt_id).str())); + wxGetApp().plater()->take_snapshot(format_wxstr(_L("Change Option %s"), opt_id)); optgroup->on_change_OG(opt_id, value); }; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index a884a0589d..770c3ac41c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp @@ -149,15 +149,21 @@ void GLGizmoBase::Grabber::render(float size, const ColorRGBA& render_color) GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id) : m_parent(parent) - , m_group_id(-1) - , m_state(Off) - , m_shortcut_key(NO_SHORTCUT_KEY_VALUE) + , m_group_id(-1) + , m_state(Off) + , m_shortcut_key(NO_SHORTCUT_KEY_VALUE) , m_icon_filename(icon_filename) , m_sprite_id(sprite_id) , m_imgui(wxGetApp().imgui()) { } + +std::string GLGizmoBase::get_action_snapshot_name() const +{ + return _u8L("Gizmo action"); +} + void GLGizmoBase::set_hover_id(int id) { // do not change hover id during dragging @@ -351,12 +357,12 @@ void GLGizmoBase::render_input_window(float x, float y, float bottom_limit) std::string GLGizmoBase::get_name(bool include_shortcut) const { - std::string out = on_get_name(); - if (!include_shortcut) return out; - + std::string out = on_get_name(); + if (!include_shortcut) return out; + int key = get_shortcut_key(); - assert(key==NO_SHORTCUT_KEY_VALUE || (key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z)); - out += std::string(" [") + char(int('A') + key - int(WXK_CONTROL_A)) + "]"; + assert(key==NO_SHORTCUT_KEY_VALUE || (key >= WXK_CONTROL_A && key <= WXK_CONTROL_Z)); + out += std::string(" [") + char(int('A') + key - int(WXK_CONTROL_A)) + "]"; return out; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp index 108b869da5..9ed34b011f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoBase.hpp @@ -4,7 +4,6 @@ #include "libslic3r/Point.hpp" #include "libslic3r/Color.hpp" -#include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GLModel.hpp" #include "slic3r/GUI/MeshUtils.hpp" #include "slic3r/GUI/SceneRaycaster.hpp" @@ -150,7 +149,7 @@ public: virtual bool wants_enter_leave_snapshots() const { return false; } virtual std::string get_gizmo_entering_text() const { assert(false); return ""; } virtual std::string get_gizmo_leaving_text() const { assert(false); return ""; } - virtual std::string get_action_snapshot_name() { return _u8L("Gizmo action"); } + virtual std::string get_action_snapshot_name() const; void set_common_data_pool(CommonGizmosDataPool* ptr) { m_c = ptr; } unsigned int get_sprite_id() const { return m_sprite_id; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index 5c18e9e968..c65f4fad07 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -1,4 +1,3 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoCut.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" @@ -183,9 +182,9 @@ GLGizmoCut3D::GLGizmoCut3D(GLCanvas3D& parent, const std::string& icon_filename, , m_connector_style (size_t(CutConnectorStyle::Prism)) , m_connector_shape_id (size_t(CutConnectorShape::Circle)) { - m_modes = { _u8L("Planar")//, _u8L("Grid") +// m_modes = { _u8L("Planar"), _u8L("Grid") // , _u8L("Radial"), _u8L("Modular") - }; +// }; m_connector_modes = { _u8L("Auto"), _u8L("Manual") }; @@ -232,7 +231,7 @@ std::string GLGizmoCut3D::get_tooltip() const std::string tooltip; if (m_hover_id == Z || (m_dragging && m_hover_id == CutPlane)) { double koef = m_imperial_units ? ObjectManipulation::mm_to_in : 1.0; - std::string unit_str = " " + (m_imperial_units ? _u8L("inch") : _u8L("mm")); + std::string unit_str = " " + (m_imperial_units ? _u8L("in") : _u8L("mm")); const BoundingBoxf3& tbb = m_transformed_bounding_box; const std::string name = m_keep_as_parts ? _u8L("Part") : _u8L("Object"); @@ -1682,7 +1681,7 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) render_build_size(); ImGui::AlignTextToFramePadding(); - ImGuiWrapper::text(_L("Cut position: ")); + ImGuiWrapper::text(_L("Cut position") + ": "); ImGui::SameLine(); render_move_center_input(Z); ImGui::SameLine(); @@ -1789,9 +1788,11 @@ void GLGizmoCut3D::render_cut_plane_input_window(CutConnectors &connectors) ImGuiWrapper::text(_L("Cut to") + ":"); add_horizontal_scaled_interval(1.2f); + // TRN CutGizmo: RadioButton Cut to ... if (m_imgui->radio_button(_L("Objects"), !m_keep_as_parts)) m_keep_as_parts = false; ImGui::SameLine(); + // TRN CutGizmo: RadioButton Cut to ... if (m_imgui->radio_button(_L("Parts"), m_keep_as_parts)) m_keep_as_parts = true; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 794d0d3391..ee804686e1 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -4,6 +4,7 @@ #include "GLGizmoBase.hpp" #include "slic3r/GUI/GLSelectionRectangle.hpp" #include "slic3r/GUI/GLModel.hpp" +#include "slic3r/GUI/I18N.hpp" #include "libslic3r/TriangleMesh.hpp" #include "libslic3r/Model.hpp" #include "imgui/imgui.h" @@ -150,7 +151,7 @@ class GLGizmoCut3D : public GLGizmoBase , Manual }; - std::vector m_modes; +// std::vector m_modes; size_t m_mode{ size_t(CutMode::cutPlanar) }; std::vector m_connector_modes; @@ -253,7 +254,7 @@ protected: bool wants_enter_leave_snapshots() const override { return true; } std::string get_gizmo_entering_text() const override { return _u8L("Entering Cut gizmo"); } std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Cut gizmo"); } - std::string get_action_snapshot_name() override { return _u8L("Cut gizmo editing"); } + std::string get_action_snapshot_name() const override { return _u8L("Cut gizmo editing"); } void data_changed() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index 2155174706..a5a3014683 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp @@ -1329,6 +1329,7 @@ void GLGizmoEmboss::draw_text_input() warning_tool_tip += "\n"; warning_tool_tip += t; }; + if (priv::is_text_empty(m_text)) append_warning(_u8L("Embossed text can NOT contain only white spaces.")); if (m_text_contain_unknown_glyph) @@ -1650,9 +1651,9 @@ void GLGizmoEmboss::draw_font_preview(FaceName& face, bool is_visible) // Not finished preview if (is_visible) { // when not canceled still loading - state_text = (face.cancel->load())? - _u8L(" No symbol"): - _u8L(" ... Loading"); + state_text = std::string(" ") + (face.cancel->load() ? + _u8L("No symbol") : + (dots.ToStdString() + _u8L("Loading"))); } else { // not finished and not visible cancel job face.is_created = nullptr; @@ -1702,7 +1703,7 @@ void GLGizmoEmboss::draw_font_preview(FaceName& face, bool is_visible) queue_job(worker, std::move(job)); } else { // cant start new thread at this moment so wait in queue - state_text = _u8L(" ... In queue"); + state_text = " " + dots.ToStdString() + " " + _u8L("Queue"); } if (!state_text.empty()) { @@ -1936,7 +1937,7 @@ void GLGizmoEmboss::draw_font_list() process(); } } else if (ImGui::IsItemHovered()) - ImGui::SetTooltip("%s", _u8L("add file with font(.ttf, .ttc)").c_str()); + ImGui::SetTooltip("Add file with font(.ttf, .ttc)"); #endif // ALLOW_ADD_FONT_BY_FILE #ifdef ALLOW_ADD_FONT_BY_OS_SELECTOR @@ -1946,7 +1947,7 @@ void GLGizmoEmboss::draw_font_list() process(); } } else if (ImGui::IsItemHovered()) - ImGui::SetTooltip("%s", _u8L("Open dialog for choose from fonts.").c_str()); + ImGui::SetTooltip("Open dialog for choose from fonts."); #endif // ALLOW_ADD_FONT_BY_OS_SELECTOR } @@ -2031,7 +2032,7 @@ void GLGizmoEmboss::draw_model_type() void GLGizmoEmboss::draw_style_rename_popup() { std::string& new_name = m_style_manager.get_style().name; const std::string &old_name = m_style_manager.get_stored_style()->name; - std::string text_in_popup = GUI::format(_L("Rename style(%1%) for embossing text: "), old_name); + std::string text_in_popup = GUI::format(_L("Rename style(%1%) for embossing text"), old_name) + ": "; ImGui::Text("%s", text_in_popup.c_str()); bool is_unique = true; @@ -2054,9 +2055,9 @@ void GLGizmoEmboss::draw_style_rename_popup() { bool store = false; ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue; if (ImGui::InputText("##rename style", &new_name, flags) && allow_change) store = true; - if (m_imgui->button(_L("ok"), ImVec2(0.f, 0.f), allow_change)) store = true; + if (m_imgui->button(_L("OK"), ImVec2(0.f, 0.f), allow_change)) store = true; ImGui::SameLine(); - if (ImGui::Button(_u8L("cancel").c_str())) { + if (ImGui::Button(_u8L("Cancel").c_str())) { new_name = old_name; ImGui::CloseCurrentPopup(); } @@ -2117,7 +2118,7 @@ void GLGizmoEmboss::draw_style_save_button(bool is_modified) } void GLGizmoEmboss::draw_style_save_as_popup() { - ImGui::Text("%s", _u8L("New name of style: ").c_str()); + ImGui::Text("%s", (_u8L("New name of style") +": ").c_str()); // use name inside of volume configuration as temporary new name std::string &new_name = m_volume->text_configuration->style.name; @@ -2141,11 +2142,11 @@ void GLGizmoEmboss::draw_style_save_as_popup() { if (ImGui::InputText("##save as style", &new_name, flags)) save_style = true; - if (m_imgui->button(_L("ok"), ImVec2(0.f, 0.f), allow_change)) + if (m_imgui->button(_L("OK"), ImVec2(0.f, 0.f), allow_change)) save_style = true; ImGui::SameLine(); - if (ImGui::Button(_u8L("cancel").c_str())){ + if (ImGui::Button(_u8L("Cancel").c_str())){ // write original name to volume TextConfiguration new_name = m_style_manager.get_style().name; ImGui::CloseCurrentPopup(); @@ -2388,7 +2389,7 @@ void GLGizmoEmboss::draw_style_list() { process(); } else { wxString title = _L("Not valid style."); - wxString message = GUI::format_wxstr(_L("Style '%1%' can't be used and will be removed from list."), style.name); + wxString message = GUI::format_wxstr(_L("Style '%1%' can't be used and will be removed from a list."), style.name); MessageDialog not_loaded_style_message(nullptr, message, title, wxOK); not_loaded_style_message.ShowModal(); m_style_manager.erase(*selected_style_index); @@ -2840,7 +2841,7 @@ void GLGizmoEmboss::draw_advanced() process(); } m_imgui->disabled_end(); // !can_use_surface - + // TRN EmbossGizmo: font units std::string units = _u8L("font points"); std::string units_fmt = "%.0f " + units; @@ -3111,9 +3112,9 @@ bool GLGizmoEmboss::choose_font_by_wxdialog() (!use_deserialized_font && !m_style_manager.load_style(emboss_style, wx_font))) { m_style_manager.erase(font_index); wxString message = GUI::format_wxstr( - _L("Font '%1%' can't be used. Please select another."), + "Font '%1%' can't be used. Please select another.", emboss_style.name); - wxString title = _L("Selected font is NOT True-type."); + wxString title = "Selected font is NOT True-type."; MessageDialog not_loaded_font_message(nullptr, message, title, wxOK); not_loaded_font_message.ShowModal(); return choose_font_by_wxdialog(); @@ -3150,7 +3151,7 @@ bool GLGizmoEmboss::choose_true_type_file() wxArrayString input_files; wxString fontDir = wxEmptyString; wxString selectedFile = wxEmptyString; - wxFileDialog dialog(nullptr, _L("Choose one or more files (TTF, TTC):"), + wxFileDialog dialog(nullptr, "Choose one or more files (TTF, TTC):", fontDir, selectedFile, file_wildcards(FT_FONTS), wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (dialog.ShowModal() == wxID_OK) dialog.GetPaths(input_files); @@ -3178,7 +3179,7 @@ bool GLGizmoEmboss::choose_svg_file() wxArrayString input_files; wxString fontDir = wxEmptyString; wxString selectedFile = wxEmptyString; - wxFileDialog dialog(nullptr, _L("Choose SVG file:"), fontDir, + wxFileDialog dialog(nullptr, _L("Choose SVG file")+":", fontDir, selectedFile, file_wildcards(FT_SVG), wxFD_OPEN | wxFD_FILE_MUST_EXIST); if (dialog.ShowModal() == wxID_OK) dialog.GetPaths(input_files); @@ -3226,7 +3227,7 @@ void GLGizmoEmboss::create_notification_not_valid_font( } const std::string &face_name = face_name_opt.value_or(face_name_by_wx.value_or(es.path)); std::string text = - GUI::format(_L("Can't load exactly same font(\"%1%\"), " + GUI::format(_L("Can't load exactly same font(\"%1%\"). " "Aplication selected a similar one(\"%2%\"). " "You have to specify font for enable edit text."), face_name_3mf, face_name); diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index ebbdf616cc..a57def86e5 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp @@ -1,12 +1,11 @@ #ifndef slic3r_GLGizmoEmboss_hpp_ #define slic3r_GLGizmoEmboss_hpp_ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, -// which overrides our localization "L" macro. #include "GLGizmoBase.hpp" #include "GLGizmoRotate.hpp" #include "slic3r/GUI/IconManager.hpp" #include "slic3r/GUI/SurfaceDrag.hpp" +#include "slic3r/GUI/I18N.hpp" #include "slic3r/Utils/RaycastManager.hpp" #include "slic3r/Utils/EmbossStyleManager.hpp" @@ -76,7 +75,7 @@ protected: bool wants_enter_leave_snapshots() const override { return true; } std::string get_gizmo_entering_text() const override { return _u8L("Enter emboss gizmo"); } std::string get_gizmo_leaving_text() const override { return _u8L("Leave emboss gizmo"); } - std::string get_action_snapshot_name() override { return _u8L("Embossing actions"); } + std::string get_action_snapshot_name() const override { return _u8L("Embossing actions"); } private: static EmbossStyles create_default_styles(); // localized default text diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 0c89d7620f..d5520403c8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -44,7 +44,8 @@ bool GLGizmoFdmSupports::on_init() m_shortcut_key = WXK_CONTROL_L; m_desc["autopaint"] = _L("Automatic painting"); - m_desc["painting"] = _L("painting..."); + // TRN GizmoFdmSupports : message line during the waiting for autogenerated supports + m_desc["painting"] = _L("painting") + dots; m_desc["clipping_of_view"] = _L("Clipping of view") + ": "; m_desc["reset_direction"] = _L("Reset direction"); m_desc["cursor_size"] = _L("Brush size") + ": "; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index b79e1dda7e..aee669199f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp @@ -3,6 +3,8 @@ #include "GLGizmoPainterBase.hpp" +#include "slic3r/GUI/I18N.hpp" + namespace Slic3r::GUI { class GLGizmoFdmSupports : public GLGizmoPainterBase @@ -21,7 +23,7 @@ protected: std::string get_gizmo_entering_text() const override { return _u8L("Entering Paint-on supports"); } std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Paint-on supports"); } - std::string get_action_snapshot_name() override { return _u8L("Paint-on supports editing"); } + std::string get_action_snapshot_name() const override { return _u8L("Paint-on supports editing"); } private: diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp index 947ef2df8e..6cbec08915 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp @@ -1,4 +1,3 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoFlatten.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index 80520651da..e8f6ad4afe 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1,4 +1,3 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoMeasure.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" @@ -1538,7 +1537,7 @@ void GLGizmoMeasure::render_dimensioning() m_imgui->set_next_window_pos(label_position_ss.x(), viewport[3] - label_position_ss.y(), ImGuiCond_Always, 0.0f, 1.0f); m_imgui->set_next_window_bg_alpha(0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - m_imgui->begin(_L("##angle"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); + m_imgui->begin(wxString("##angle"), ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); ImGui::AlignTextToFramePadding(); ImDrawList* draw_list = ImGui::GetWindowDrawList(); @@ -1737,7 +1736,7 @@ void GLGizmoMeasure::render_debug_dialog() add_strings_row_to_table(*m_imgui, "m_pt3", ImGuiWrapper::COL_ORANGE_LIGHT, format_vec3(*extra_point), ImGui::GetStyleColorVec4(ImGuiCol_Text)); }; - m_imgui->begin(_L("Measure tool debug"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + m_imgui->begin("Measure tool debug", ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); if (ImGui::BeginTable("Mode", 2)) { std::string txt; switch (m_mode) diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 4652a171b7..cc43b068ef 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp @@ -5,6 +5,7 @@ #include "slic3r/GUI/GLModel.hpp" #include "slic3r/GUI/GUI_Utils.hpp" #include "slic3r/GUI/MeshUtils.hpp" +#include "slic3r/GUI/I18N.hpp" #include "libslic3r/Measure.hpp" #include "libslic3r/Model.hpp" @@ -162,7 +163,7 @@ public: bool wants_enter_leave_snapshots() const override { return true; } std::string get_gizmo_entering_text() const override { return _u8L("Entering Measure gizmo"); } std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Measure gizmo"); } - std::string get_action_snapshot_name() override { return _u8L("Measure gizmo editing"); } + std::string get_action_snapshot_name() const override { return _u8L("Measure gizmo editing"); } protected: bool on_init() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp index 67eccd8e8e..ee32c45963 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.hpp @@ -3,6 +3,8 @@ #include "GLGizmoPainterBase.hpp" +#include "slic3r/GUI/I18N.hpp" + namespace Slic3r::GUI { class GLMmSegmentationGizmo3DScene @@ -117,7 +119,7 @@ protected: std::string get_gizmo_entering_text() const override { return _u8L("Entering Multimaterial painting"); } std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Multimaterial painting"); } - std::string get_action_snapshot_name() override { return _u8L("Multimaterial painting editing"); } + std::string get_action_snapshot_name() const override { return _u8L("Multimaterial painting editing"); } size_t m_first_selected_extruder_idx = 0; size_t m_second_selected_extruder_idx = 1; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp index 98f183b74e..73615b4635 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMove.cpp @@ -1,4 +1,3 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoMove.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" diff --git a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp index 3d88ad500f..aa3d56ef93 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp @@ -1,4 +1,3 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoPainterBase.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/Gizmos/GLGizmosCommon.hpp" diff --git a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp index 345d733afd..75b80d8f5b 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp @@ -1,4 +1,3 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoRotate.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/ImGuiWrapper.hpp" diff --git a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp index 9e5191f65f..063dce7217 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoScale.cpp @@ -1,4 +1,3 @@ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoScale.hpp" #include "slic3r/GUI/GLCanvas3D.hpp" #include "slic3r/GUI/GUI_App.hpp" diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp index 533683237d..c1a6d7dfac 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp @@ -3,6 +3,8 @@ #include "GLGizmoPainterBase.hpp" +#include "slic3r/GUI/I18N.hpp" + namespace Slic3r::GUI { class GLGizmoSeam : public GLGizmoPainterBase @@ -22,7 +24,7 @@ protected: std::string get_gizmo_entering_text() const override { return _u8L("Entering Seam painting"); } std::string get_gizmo_leaving_text() const override { return _u8L("Leaving Seam painting"); } - std::string get_action_snapshot_name() override { return _u8L("Paint-on seam editing"); } + std::string get_action_snapshot_name() const override { return _u8L("Paint-on seam editing"); } private: bool on_init() override; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 90552c0a5d..d60784758f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -318,6 +318,7 @@ void GLGizmoSimplify::on_render_input_window(float x, float y, float bottom_limi m_configuration.use_count = !m_configuration.use_count; start_process = true; } else if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) && is_multipart) + // TRN %1% = "Detail level", %2% = "Decimate ratio" ImGui::SetTooltip("%s", GUI::format(_L( "Multipart object can be simplified only by %1%. " "If you want specify %2% process it separately."), @@ -539,7 +540,8 @@ void GLGizmoSimplify::apply_simplify() { const Selection& selection = m_parent.get_selection(); auto plater = wxGetApp().plater(); - plater->take_snapshot(_u8L("Simplify ") + create_volumes_name(m_volume_ids, selection)); + // TRN %1% = volumes name + plater->take_snapshot(Slic3r::format(_u8L("Simplify %1%"), create_volumes_name(m_volume_ids, selection))); plater->clear_before_change_mesh(selection.get_object_idx(), _u8L("Custom supports, seams and multimaterial painting were " "removed after simplifying the mesh.")); // After removing custom supports, seams, and multimaterial painting, we have to update info about the object to remove information about diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index f95aad4953..1a56b77913 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp @@ -1,10 +1,9 @@ #ifndef slic3r_GLGizmoSimplify_hpp_ #define slic3r_GLGizmoSimplify_hpp_ -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, -// which overrides our localization "L" macro. #include "GLGizmoBase.hpp" #include "slic3r/GUI/3DScene.hpp" +#include "slic3r/GUI/I18N.hpp" #include "admesh/stl.h" // indexed_triangle_set #include #include diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp index 073d3fa293..fe7e1b4eae 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp @@ -1,5 +1,4 @@ #include "libslic3r/libslic3r.h" -// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro. #include "GLGizmoSlaSupports.hpp" #include "slic3r/GUI/MainFrame.hpp" #include "slic3r/Utils/UndoRedo.hpp" diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp index 578858b5bd..bb0513682c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp @@ -3,6 +3,7 @@ #include "GLGizmoSlaBase.hpp" #include "slic3r/GUI/GLSelectionRectangle.hpp" +#include "slic3r/GUI/I18N.hpp" #include "libslic3r/SLA/SupportPoint.hpp" #include "libslic3r/ObjectID.hpp" diff --git a/src/slic3r/GUI/HintNotification.cpp b/src/slic3r/GUI/HintNotification.cpp index 1f3d224919..95583a3cdd 100644 --- a/src/slic3r/GUI/HintNotification.cpp +++ b/src/slic3r/GUI/HintNotification.cpp @@ -344,7 +344,7 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) bool was_displayed = is_used(id_string); //unescape text1 unescape_string_cstyle(dict["text"], fulltext); - fulltext = _utf8(fulltext); + fulltext = into_u8(_(fulltext)); #ifdef __APPLE__ boost::replace_all(fulltext, "Ctrl+", "⌘"); #endif //__APPLE__ @@ -370,19 +370,19 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path) fulltext.erase(hypertext_start, HYPERTEXT_MARKER_START.size()); if (fulltext.find(HYPERTEXT_MARKER_START) != std::string::npos) { // This must not happen - only 1 hypertext allowed - BOOST_LOG_TRIVIAL(error) << "Hint notification with multiple hypertexts: " << _utf8(dict["text"]); + BOOST_LOG_TRIVIAL(error) << "Hint notification with multiple hypertexts: " << dict["text"]; continue; } size_t hypertext_end = fulltext.find(HYPERTEXT_MARKER_END); if (hypertext_end == std::string::npos) { // hypertext was not correctly ended - BOOST_LOG_TRIVIAL(error) << "Hint notification without hypertext end marker: " << _utf8(dict["text"]); + BOOST_LOG_TRIVIAL(error) << "Hint notification without hypertext end marker: " << dict["text"]; continue; } fulltext.erase(hypertext_end, HYPERTEXT_MARKER_END.size()); if (fulltext.find(HYPERTEXT_MARKER_END) != std::string::npos) { // This must not happen - only 1 hypertext end allowed - BOOST_LOG_TRIVIAL(error) << "Hint notification with multiple hypertext end markers: " << _utf8(dict["text"]); + BOOST_LOG_TRIVIAL(error) << "Hint notification with multiple hypertext end markers: " << dict["text"]; continue; } diff --git a/src/slic3r/GUI/I18N.hpp b/src/slic3r/GUI/I18N.hpp index 7bad6880e9..8616628eaf 100644 --- a/src/slic3r/GUI/I18N.hpp +++ b/src/slic3r/GUI/I18N.hpp @@ -1,7 +1,6 @@ #ifndef _ #define _(s) Slic3r::GUI::I18N::translate((s)) #define _L(s) Slic3r::GUI::I18N::translate((s)) -#define _utf8(s) Slic3r::GUI::I18N::translate_utf8((s)) #define _u8L(s) Slic3r::GUI::I18N::translate_utf8((s)) #endif /* _ */ diff --git a/src/slic3r/GUI/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index f5c315b30e..208cb2c0bd 100644 --- a/src/slic3r/GUI/Jobs/EmbossJob.cpp +++ b/src/slic3r/GUI/Jobs/EmbossJob.cpp @@ -145,7 +145,7 @@ void CreateVolumeJob::finalize(bool canceled, std::exception_ptr &eptr) { if (!priv::finalize(canceled, eptr, m_input)) return; if (m_result.its.empty()) - return priv::create_message(_u8L("Can't create empty volume.")); + return priv::create_message("Can't create empty volume."); priv::create_volume(std::move(m_result), m_input.object_id, m_input.volume_type, m_input.trmat, m_input); } @@ -198,7 +198,7 @@ void CreateObjectJob::finalize(bool canceled, std::exception_ptr &eptr) // only for sure if (m_result.empty()) - return priv::create_message(_u8L("Can't create empty object.")); + return priv::create_message("Can't create empty object."); GUI_App &app = wxGetApp(); Plater *plater = app.plater(); @@ -462,8 +462,8 @@ TriangleMesh priv::create_mesh(DataBase &input, Fnc was_canceled, Job::Ctl& ctl) if (was_canceled()) return {}; // only info ctl.call_on_main_thread([]() { - create_message(_u8L("It is used default volume for embossed " - "text, try to change text or font to fix it.")); + create_message("It is used default volume for embossed " + "text, try to change text or font to fix it."); }); } @@ -593,10 +593,10 @@ void priv::create_volume( // Parent object for text volume was propably removed. // Assumption: User know what he does, so text volume is no more needed. if (obj == nullptr) - return priv::create_message(_u8L("Bad object to create volume.")); + return priv::create_message("Bad object to create volume."); if (mesh.its.empty()) - return priv::create_message(_u8L("Can't create empty volume.")); + return priv::create_message("Can't create empty volume."); plater->take_snapshot(_L("Add Emboss text Volume")); @@ -823,10 +823,6 @@ bool priv::finalize(bool canceled, std::exception_ptr &eptr, const DataBase &inp return !process(eptr); } - -#include - void priv::create_message(const std::string &message) { - wxMessageBox(wxString(message), _L("Issue during embossing the text."), - wxOK | wxICON_WARNING); + show_error(nullptr, message.c_str()); } diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp index 0980326d31..d33bee1a8d 100644 --- a/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp +++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp @@ -124,4 +124,14 @@ void RotoptimizeJob::finalize(bool canceled, std::exception_ptr &eptr) m_plater->update(); } +std::string RotoptimizeJob::get_method_name(size_t i) +{ + return into_u8(_(Methods[i].name)); +} + +std::string RotoptimizeJob::get_method_description(size_t i) +{ + return into_u8(_(Methods[i].descr)); +} + }} diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp index 71a28deb7c..02aafb551e 100644 --- a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp +++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp @@ -58,15 +58,9 @@ public: static constexpr size_t get_methods_count() { return std::size(Methods); } - static std::string get_method_name(size_t i) - { - return _utf8(Methods[i].name); - } + static std::string get_method_name(size_t i); - static std::string get_method_description(size_t i) - { - return _utf8(Methods[i].descr); - } + static std::string get_method_description(size_t i); }; }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Jobs/SLAImportDialog.hpp b/src/slic3r/GUI/Jobs/SLAImportDialog.hpp index 5477e51e7f..fed84600c2 100644 --- a/src/slic3r/GUI/Jobs/SLAImportDialog.hpp +++ b/src/slic3r/GUI/Jobs/SLAImportDialog.hpp @@ -30,7 +30,7 @@ std::string get_readers_wildcard() std::string ret; for (const char *archtype : SLAArchiveReader::registered_archives()) { - ret += _utf8(SLAArchiveReader::get_description(archtype)); + ret += into_u8(_(SLAArchiveReader::get_description(archtype))); ret += " ("; auto extensions = SLAArchiveReader::get_extensions(archtype); for (const char * ext : extensions) { diff --git a/src/slic3r/GUI/Jobs/SLAImportJob.cpp b/src/slic3r/GUI/Jobs/SLAImportJob.cpp index 2da3ad5b5b..0b3c4cb285 100644 --- a/src/slic3r/GUI/Jobs/SLAImportJob.cpp +++ b/src/slic3r/GUI/Jobs/SLAImportJob.cpp @@ -163,7 +163,7 @@ void SLAImportJob::finalize(bool canceled, std::exception_ptr &eptr) p->plater->get_notification_manager()->push_notification( NotificationType::CustomNotification, NotificationManager::NotificationLevel::WarningNotificationLevel, - _u8L("The profile in the imported archive is corrupt and will not be loaded.")); + _u8L("The profile in the imported archive is corrupted and will not be loaded.")); } } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index eccd96e201..0c7805db80 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -314,9 +314,9 @@ void MainFrame::bind_diff_dialog() process(diff_dlg_type); }; - diff_dialog.Bind(EVT_DIFF_DIALOG_TRANSFER, [this, process_options, transfer](SimpleEvent&) { process_options(transfer); }); + diff_dialog.Bind(EVT_DIFF_DIALOG_TRANSFER, [process_options, transfer](SimpleEvent&) { process_options(transfer); }); - diff_dialog.Bind(EVT_DIFF_DIALOG_UPDATE_PRESETS,[this, process_options, update_presets](SimpleEvent&) { process_options(update_presets); }); + diff_dialog.Bind(EVT_DIFF_DIALOG_UPDATE_PRESETS,[process_options, update_presets](SimpleEvent&) { process_options(update_presets); }); } @@ -1198,10 +1198,10 @@ static void add_common_view_menu_items(wxMenu* view_menu, MainFrame* mainFrame, append_menu_item(view_menu, wxID_ANY, _L("Iso") + sep + "&0", _L("Iso View"), [mainFrame](wxCommandEvent&) { mainFrame->select_view("iso"); }, "", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame); view_menu->AppendSeparator(); - //TRN To be shown in the main menu View->Top + //TRN Main menu: View->Top append_menu_item(view_menu, wxID_ANY, _L("Top") + sep + "&1", _L("Top View"), [mainFrame](wxCommandEvent&) { mainFrame->select_view("top"); }, "", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame); - //TRN To be shown in the main menu View->Bottom + //TRN Main menu: View->Bottom append_menu_item(view_menu, wxID_ANY, _L("Bottom") + sep + "&2", _L("Bottom View"), [mainFrame](wxCommandEvent&) { mainFrame->select_view("bottom"); }, "", nullptr, [can_change_view]() { return can_change_view(); }, mainFrame); append_menu_item(view_menu, wxID_ANY, _L("Front") + sep + "&3", _L("Front View"), [mainFrame](wxCommandEvent&) { mainFrame->select_view("front"); }, @@ -1638,7 +1638,7 @@ void MainFrame::init_menubar_as_gcodeviewer() viewMenu = new wxMenu(); add_common_view_menu_items(viewMenu, this, std::bind(&MainFrame::can_change_view, this)); viewMenu->AppendSeparator(); - append_menu_check_item(viewMenu, wxID_ANY, _L("Show legen&d") + sep + "L", _L("Show legend"), + append_menu_check_item(viewMenu, wxID_ANY, _L("Show Legen&d") + sep + "L", _L("Show legend"), [this](wxCommandEvent&) { m_plater->show_legend(!m_plater->is_legend_shown()); }, this, [this]() { return m_plater->is_preview_shown(); }, [this]() { return m_plater->is_legend_shown(); }, this); } @@ -1755,7 +1755,7 @@ void MainFrame::quick_slice(const int qs) } else if (qs & qsSaveAs) { // The following line may die if the output_filename_format template substitution fails. - wxFileDialog dlg(this, from_u8((boost::format(_utf8(L("Save %s file as:"))) % ((qs & qsExportSVG) ? _L("SVG") : _L("G-code"))).str()), + wxFileDialog dlg(this, format_wxstr(_L("Save %s file as:"), ((qs & qsExportSVG) ? _L("SVG") : _L("G-code"))), wxGetApp().app_config->get_last_output_dir(get_dir_name(output_file)), get_base_name(input_file), qs & qsExportSVG ? file_wildcards(FT_SVG) : file_wildcards(FT_GCODE), wxFD_SAVE | wxFD_OVERWRITE_PROMPT); @@ -1777,8 +1777,8 @@ void MainFrame::quick_slice(const int qs) // show processbar dialog m_progress_dialog = new wxProgressDialog(_L("Slicing") + dots, - // TRN "Processing input_file_basename" - from_u8((boost::format(_utf8(L("Processing %s"))) % (input_file_basename + dots)).str()), + // TRN ProgressDialog on reslicing: "input file basename" + format_wxstr(_L("Processing %s"), (input_file_basename + dots)), 100, nullptr, wxPD_AUTO_HIDE); m_progress_dialog->Pulse(); { diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index ab465a577e..3f7e58b7ef 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -866,7 +866,7 @@ bool NotificationManager::ExportFinishedNotification::on_text_click() } void NotificationManager::ExportFinishedNotification::on_eject_click() { - NotificationData data{ get_data().type, get_data().level , 0, _utf8("Ejecting.") }; + NotificationData data{ get_data().type, get_data().level , 0, _u8L("Ejecting.") }; m_eject_pending = true; m_multiline = false; update(data); @@ -2447,7 +2447,7 @@ void NotificationManager::push_download_URL_progress_notification(size_t id, con } } // push new one - NotificationData data{ NotificationType::URLDownload, NotificationLevel::ProgressBarNotificationLevel, 5, _utf8("Download:") + " " + text }; + NotificationData data{ NotificationType::URLDownload, NotificationLevel::ProgressBarNotificationLevel, 5, _u8L("Download") + ": " + text }; push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, id, user_action_callback), 0); } diff --git a/src/slic3r/GUI/OG_CustomCtrl.cpp b/src/slic3r/GUI/OG_CustomCtrl.cpp index d18df6bb2d..a3cb345b42 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.cpp +++ b/src/slic3r/GUI/OG_CustomCtrl.cpp @@ -173,8 +173,8 @@ wxPoint OG_CustomCtrl::get_pos(const Line& line, Field* field_in/* = nullptr*/) ConfigOptionDef option = opt.opt; // add label if any if (is_multioption_line && !option.label.empty()) { - //! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1 - label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ? + // those two parameter names require localization with context + label = (option.label == "Top" || option.label == "Bottom") ? _CTX(option.label, "Layers") : _(option.label); label += ":"; @@ -622,9 +622,9 @@ void OG_CustomCtrl::CtrlLine::render(wxDC& dc, wxCoord v_pos) ConfigOptionDef option = opt.opt; // add label if any if (is_multioption_line && !option.label.empty()) { - //! To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1 - label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ? - _CTX(option.label, "Layers") : _(option.label); + // those two parameter names require localization with context + label = (option.label == "Top" || option.label == "Bottom") ? + _CTX(option.label, "Layers") : _(option.label); label += ":"; if (is_url_string) diff --git a/src/slic3r/GUI/OG_CustomCtrl.hpp b/src/slic3r/GUI/OG_CustomCtrl.hpp index 0308322f7f..269f847a22 100644 --- a/src/slic3r/GUI/OG_CustomCtrl.hpp +++ b/src/slic3r/GUI/OG_CustomCtrl.hpp @@ -11,7 +11,6 @@ #include "libslic3r/PrintConfig.hpp" #include "OptionsGroup.hpp" -#include "I18N.hpp" // Translate the ifdef #ifdef __WXOSX__ diff --git a/src/slic3r/GUI/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp index ecf0c57909..6960d0a756 100644 --- a/src/slic3r/GUI/OpenGLManager.cpp +++ b/src/slic3r/GUI/OpenGLManager.cpp @@ -371,16 +371,16 @@ bool OpenGLManager::init_gl() if (!valid_version) { // Complain about the OpenGL version. - wxString message = from_u8((boost::format( + wxString message = format_wxstr( #if ENABLE_OPENGL_ES - _utf8(L("PrusaSlicer requires OpenGL ES 2.0 capable graphics driver to run correctly, \n" - "while OpenGL version %s, render %s, vendor %s was detected."))) % s_gl_info.get_version_string() % s_gl_info.get_renderer() % s_gl_info.get_vendor()).str()); + _L("PrusaSlicer requires OpenGL ES 2.0 capable graphics driver to run correctly, \n" + "while OpenGL version %s, render %s, vendor %s was detected."), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor()); #elif ENABLE_GL_CORE_PROFILE - _utf8(L("PrusaSlicer requires OpenGL %s capable graphics driver to run correctly, \n" - "while OpenGL version %s, render %s, vendor %s was detected."))) % (s_gl_info.is_core_profile() ? "3.3" : "2.0") % s_gl_info.get_version_string() % s_gl_info.get_renderer() % s_gl_info.get_vendor()).str()); + _L("PrusaSlicer requires OpenGL %s capable graphics driver to run correctly, \n" + "while OpenGL version %s, render %s, vendor %s was detected."), (s_gl_info.is_core_profile() ? "3.3" : "2.0"), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor()); #else - _utf8(L("PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n" - "while OpenGL version %s, render %s, vendor %s was detected."))) % s_gl_info.get_version_string() % s_gl_info.get_renderer() % s_gl_info.get_vendor()).str()); + _L("PrusaSlicer requires OpenGL 2.0 capable graphics driver to run correctly, \n" + "while OpenGL version %s, render %s, vendor %s was detected."), s_gl_info.get_version_string(), s_gl_info.get_renderer(), s_gl_info.get_vendor()); #endif // ENABLE_OPENGL_ES message += "\n"; message += _L("You may need to update your graphics card driver."); @@ -395,8 +395,7 @@ bool OpenGLManager::init_gl() // load shaders auto [result, error] = m_shaders_manager.init(); if (!result) { - wxString message = from_u8((boost::format( - _utf8(L("Unable to load the following shaders:\n%s"))) % error).str()); + wxString message = format_wxstr(_L("Unable to load the following shaders:\n%s"), error); wxMessageBox(message, wxString("PrusaSlicer - ") + _L("Error loading shaders"), wxOK | wxICON_ERROR); } #if ENABLE_OPENGL_DEBUG_OPTION diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index e567ac7c66..614fda9130 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -384,8 +384,8 @@ void OptionsGroup::activate_line(Line& line) ConfigOptionDef option = opt.opt; // add label if any if ((option_set.size() > 1 || line.label.IsEmpty()) && !option.label.empty()) { - // To correct translation by context have to use wxGETTEXT_IN_CONTEXT macro from wxWidget 3.1.1 - wxString str_label = (option.label == L_CONTEXT("Top", "Layers") || option.label == L_CONTEXT("Bottom", "Layers")) ? + // those two parameter names require localization with context + wxString str_label = (option.label == "Top" || option.label == "Bottom") ? _CTX(option.label, "Layers") : _(option.label); label = new wxStaticText(this->ctrl_parent(), wxID_ANY, str_label + ": ", wxDefaultPosition, //wxDefaultSize); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index a64de49eec..3595276af6 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -830,6 +830,7 @@ Sidebar::Sidebar(Plater *parent) wxRIGHT, margin_5); #else wxBOTTOM, 1); + (void)margin_5; // supress unused capture warning #endif // __WXGTK3__ } else { sizer_filaments->Add(combo_and_btn_sizer, 0, wxEXPAND | @@ -1376,7 +1377,7 @@ void Sidebar::update_sliced_info_sizer() 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->plater->get_notification_manager()->set_slicing_complete_print_time(_utf8("Estimated printing time: ") + boost::nowide::narrow(t_est), p->plater->is_sidebar_collapsed()); + p->plater->get_notification_manager()->set_slicing_complete_print_time(_u8L("Estimated printing time") + ": " + boost::nowide::narrow(t_est), p->plater->is_sidebar_collapsed()); // Hide non-SLA sliced info parameters p->sliced_info->SetTextAndShow(siFilament_m, "N/A"); @@ -1466,7 +1467,7 @@ void Sidebar::update_sliced_info_sizer() new_label += format_wxstr("\n - %1%", _L("normal mode")); info_text += format_wxstr("\n%1%", short_time(ps.estimated_normal_print_time)); - p->plater->get_notification_manager()->set_slicing_complete_print_time(_utf8("Estimated printing time: ") + ps.estimated_normal_print_time, p->plater->is_sidebar_collapsed()); + p->plater->get_notification_manager()->set_slicing_complete_print_time(_u8L("Estimated printing time") + ": " + ps.estimated_normal_print_time, p->plater->is_sidebar_collapsed()); } if (ps.estimated_silent_print_time != "N/A") { @@ -2016,7 +2017,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) , config(Slic3r::DynamicPrintConfig::new_from_defaults_keys({ "bed_shape", "bed_custom_texture", "bed_custom_model", "complete_objects", "duplicate_distance", "extruder_clearance_radius", "skirts", "skirt_distance", "brim_width", "brim_separation", "brim_type", "variable_layer_height", "nozzle_diameter", "single_extruder_multi_material", - "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", + "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_brim_width", "wipe_tower_cone_angle", "wipe_tower_extra_spacing", "extruder_colour", "filament_colour", "material_colour", "max_print_height", "printer_model", "printer_technology", // These values are necessary to construct SlicingParameters by the Canvas3D variable layer height editor. "layer_height", "first_layer_height", "min_layer_height", "max_layer_height", @@ -2251,7 +2252,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->q->load_files(input_files); }); - this->q->Bind(EVT_START_DOWNLOAD_OTHER_INSTANCE, [this](StartDownloadOtherInstanceEvent& evt) { + this->q->Bind(EVT_START_DOWNLOAD_OTHER_INSTANCE, [](StartDownloadOtherInstanceEvent& evt) { BOOST_LOG_TRIVIAL(trace) << "Received url from other instance event."; wxGetApp().mainframe->Raise(); for (size_t i = 0; i < evt.data.size(); ++i) { @@ -2343,8 +2344,8 @@ void Plater::priv::collapse_sidebar(bool collapse) // Now update the tooltip in the toolbar. std::string new_tooltip = collapse - ? _utf8(L("Expand sidebar")) - : _utf8(L("Collapse sidebar")); + ? _u8L("Expand sidebar") + : _u8L("Collapse sidebar"); new_tooltip += " [Shift+Tab]"; int id = collapse_toolbar.get_item_id("collapse_sidebar"); collapse_toolbar.set_tooltip(id, new_tooltip); @@ -3033,8 +3034,8 @@ bool Plater::priv::delete_object_from_model(size_t obj_idx) ModelObject* obj = model.objects[obj_idx]; if (obj->is_cut()) { InfoDialog dialog(q, _L("Delete object which is a part of cut object"), - _L("You try to delete an object which is a part of a cut object.\n" - "This action will break a cut correspondence.\n" + _L("You try to delete an object which is a part of a cut object.") + "\n" + + _L("This action will break a cut information.\n" "After that PrusaSlicer can't guarantee model consistency"), false, wxYES | wxCANCEL | wxCANCEL_DEFAULT | wxICON_WARNING); dialog.SetButtonLabel(wxID_YES, _L("Delete object")); @@ -4251,7 +4252,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt) } if (evt.cancelled()) { // this->statusbar()->set_status_text(_L("Cancelled")); - this->notification_manager->set_slicing_progress_canceled(_utf8("Slicing Cancelled.")); + this->notification_manager->set_slicing_progress_canceled(_u8L("Slicing Cancelled.")); } this->sidebar->show_sliced_info_sizer(evt.success()); @@ -4558,7 +4559,7 @@ bool Plater::priv::init_view_toolbar() item.name = "3D"; item.icon_filename = "editor.svg"; - item.tooltip = _utf8(L("3D editor view")) + " [" + GUI::shortkey_ctrl_prefix() + "5]"; + item.tooltip = _u8L("3D editor view") + " [" + GUI::shortkey_ctrl_prefix() + "5]"; item.sprite_id = 0; item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); }; if (!view_toolbar.add_item(item)) @@ -4566,7 +4567,7 @@ bool Plater::priv::init_view_toolbar() item.name = "Preview"; item.icon_filename = "preview.svg"; - item.tooltip = _utf8(L("Preview")) + " [" + GUI::shortkey_ctrl_prefix() + "6]"; + item.tooltip = _u8L("Preview") + " [" + GUI::shortkey_ctrl_prefix() + "6]"; item.sprite_id = 1; item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); }; if (!view_toolbar.add_item(item)) @@ -4779,7 +4780,7 @@ bool Plater::priv::can_increase_instances() const if (q->canvas3D()->get_gizmos_manager().get_current_type() == GLGizmosManager::Emboss) return false; const auto obj_idxs = get_selection().get_object_idxs(); - return !obj_idxs.empty() && !sidebar->obj_list()->has_selected_cut_object(); + return !obj_idxs.empty() && !get_selection().is_wipe_tower() && !sidebar->obj_list()->has_selected_cut_object(); } bool Plater::priv::can_decrease_instances(int obj_idx /*= -1*/) const @@ -5437,7 +5438,7 @@ protected: LoadProjectsDialog::LoadProjectsDialog(const std::vector& paths) : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, - from_u8((boost::format(_utf8(L("%s - Multiple projects file"))) % SLIC3R_APP_NAME).str()), wxDefaultPosition, + format_wxstr(_L("%1% - Multiple projects file"), SLIC3R_APP_NAME), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) { SetFont(wxGetApp().normal_font()); @@ -5557,7 +5558,7 @@ bool Plater::preview_zip_archive(const boost::filesystem::path& archive_path) mz_zip_zero_struct(&archive); if (!open_zip_reader(&archive, archive_path.string())) { - std::string err_msg = GUI::format(_utf8("Loading of a zip archive on path %1% has failed."), archive_path.string()); + std::string err_msg = GUI::format(_u8L("Loading of a zip archive on path %1% has failed."), archive_path.string()); throw Slic3r::FileIOError(err_msg); } mz_uint num_entries = mz_zip_reader_get_num_files(&archive); @@ -5826,9 +5827,7 @@ protected: ProjectDropDialog::ProjectDropDialog(const std::string& filename) : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, -// #ysFIXME_delete_after_test_of_6377 -// from_u8((boost::format(_utf8(L("%s - Drop project file"))) % SLIC3R_APP_NAME).str()), wxDefaultPosition, - from_u8((boost::format(_utf8(L("%s - Load project file"))) % SLIC3R_APP_NAME).str()), wxDefaultPosition, + format_wxstr("%1% - %2%", SLIC3R_APP_NAME, _L("Load project file")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) { SetFont(wxGetApp().normal_font()); @@ -5936,7 +5935,7 @@ bool Plater::load_files(const wxArrayString& filenames, bool delete_after_load/* std::string filename = (*it).filename().string(); if (boost::algorithm::iends_with(filename, ".3mf") || boost::algorithm::iends_with(filename, ".amf")) { ProjectDropDialog::LoadType load_type = ProjectDropDialog::LoadType::Unknown; -// if (!model().objects.empty()) { // #ysFIXME_delete_after_test_of_6377 + { if ((boost::algorithm::iends_with(filename, ".3mf") && !is_project_3mf(it->string())) || (boost::algorithm::iends_with(filename, ".amf") && !boost::algorithm::iends_with(filename, ".zip.amf"))) load_type = ProjectDropDialog::LoadType::LoadGeometry; @@ -5953,11 +5952,7 @@ bool Plater::load_files(const wxArrayString& filenames, bool delete_after_load/* load_type = static_cast(std::clamp(std::stoi(wxGetApp().app_config->get("drop_project_action")), static_cast(ProjectDropDialog::LoadType::OpenProject), static_cast(ProjectDropDialog::LoadType::LoadConfig))); } -/* // #ysFIXME_delete_after_test_of_6377 } - else - load_type = ProjectDropDialog::LoadType::OpenProject; -*/ if (load_type == ProjectDropDialog::LoadType::Unknown) return false; diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 0d5bf0f8c5..492e3fc37b 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -308,14 +308,9 @@ void PreferencesDialog::build() m_optgroup_general->append_separator(); append_bool_option(m_optgroup_general, "show_drop_project_dialog", -#if 1 // #ysFIXME_delete_after_test_of_6377 L("Show load project dialog"), L("When checked, whenever dragging and dropping a project file on the application or open it from a browser, " "shows a dialog asking to select the action to take on the file to load."), -#else - L("Show drop project dialog"), - L("When checked, whenever dragging and dropping a project file on the application, shows a dialog asking to select the action to take on the file to load."), -#endif app_config->get_bool("show_drop_project_dialog")); append_bool_option(m_optgroup_general, "single_instance", @@ -471,7 +466,7 @@ void PreferencesDialog::build() append_bool_option(m_optgroup_gui, "seq_top_layer_only", L("Sequential slider applied only to top layer"), - L("If enabled, changes made using the sequential slider, in preview, apply only to gcode top layer." + L("If enabled, changes made using the sequential slider, in preview, apply only to gcode top layer. " "If disabled, changes made using the sequential slider, in preview, apply to the whole gcode."), app_config->get_bool("seq_top_layer_only")); @@ -627,7 +622,7 @@ void PreferencesDialog::build() append_bool_option(m_optgroup_dark_mode, "sys_menu_enabled", L("Use system menu for application"), L("If enabled, application will use the standard Windows system menu,\n" - "but on some combination od display scales it can look ugly. If disabled, old UI will be used."), + "but on some combination of display scales it can look ugly. If disabled, old UI will be used."), app_config->get_bool("sys_menu_enabled")); } diff --git a/src/slic3r/GUI/PresetHints.cpp b/src/slic3r/GUI/PresetHints.cpp index ce709d9eb8..15017ba930 100644 --- a/src/slic3r/GUI/PresetHints.cpp +++ b/src/slic3r/GUI/PresetHints.cpp @@ -163,7 +163,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle double volumetric_flow = flow.mm3_per_mm() * (bridging ? bridge_speed : limit_by_first_layer_speed(speed, max_print_speed)); if (max_flow < volumetric_flow) { max_flow = volumetric_flow; - max_flow_extrusion_type = _utf8(err_msg); + max_flow_extrusion_type = GUI::into_u8(_(err_msg)); } }; if (perimeter_extruder_active) { @@ -184,17 +184,17 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle //FIXME handle gap_fill_speed if (! out.empty()) out += "\n"; - out += (first_layer ? _utf8(L("First layer volumetric")) : (bridging ? _utf8(L("Bridging volumetric")) : _utf8(L("Volumetric")))); - out += " " + _utf8(L("flow rate is maximized")) + " "; + out += (first_layer ? _u8L("First layer volumetric") : (bridging ? _u8L("Bridging volumetric") : _u8L("Volumetric"))); + out += " " + _u8L("flow rate is maximized") + " "; bool limited_by_max_volumetric_speed = max_volumetric_speed > 0 && max_volumetric_speed < max_flow; out += (limited_by_max_volumetric_speed ? - _utf8(L("by the print profile maximum")) : - (_utf8(L("when printing"))+ " " + max_flow_extrusion_type)) - + " " + _utf8(L("with a volumetric rate"))+ " "; + _u8L("by the print profile maximum") : + (_u8L("when printing")+ " " + max_flow_extrusion_type)) + + " " + _u8L("with a volumetric rate")+ " "; if (limited_by_max_volumetric_speed) max_flow = max_volumetric_speed; - out += (boost::format(_utf8(L("%3.2f mm³/s at filament speed %3.2f mm/s."))) % max_flow % (max_flow / filament_crossection)).str(); + out += format(_u8L("%3.2f mm³/s at filament speed %3.2f mm/s."), max_flow, (max_flow / filament_crossection)); } return out; @@ -212,13 +212,13 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre std::string out; if (layer_height <= 0.f) { - out += _utf8(L("Recommended object thin wall thickness: Not available due to invalid layer height.")); + out += _u8L("Recommended object thin wall thickness: Not available due to invalid layer height."); return out; } if (num_perimeters > 0) { int num_lines = std::min(num_perimeters * 2, 10); - out += (boost::format(_utf8(L("Recommended object thin wall thickness for layer height %.2f and"))) % layer_height).str() + " "; + out += (boost::format(_u8L("Recommended object thin wall thickness for layer height %.2f and")) % layer_height).str() + " "; // Start with the width of two closely spaced try { Flow external_perimeter_flow = Flow::new_from_config_width( @@ -233,11 +233,11 @@ std::string PresetHints::recommended_thin_wall_thickness(const PresetBundle &pre for (int i = 2; i <= num_lines; thin_walls ? ++ i : i += 2) { if (i > 2) out += ", "; - out += (boost::format(_utf8(L("%d lines: %.2f mm"))) % i % width).str() + " "; + out += (boost::format(_u8L("%d lines: %.2f mm")) % i % width).str() + " "; width += perimeter_flow.spacing() * (thin_walls ? 1.f : 2.f); } } catch (const FlowErrorNegativeSpacing &) { - out = _utf8(L("Recommended object thin wall thickness: Not available due to excessively small extrusion width.")); + out = _u8L("Recommended object thin wall thickness: Not available due to excessively small extrusion width."); } } return out; @@ -266,7 +266,7 @@ std::string PresetHints::top_bottom_shell_thickness_explanation(const PresetBund double min_layer_height = variable_layer_height ? Slicing::min_layer_height_from_nozzle(printer_config, 1) : layer_height; if (layer_height <= 0.f) { - out += _utf8(L("Top / bottom shell thickness hint: Not available due to invalid layer height.")); + out += _u8L("Top / bottom shell thickness hint: Not available due to invalid layer height."); return out; } @@ -279,13 +279,13 @@ std::string PresetHints::top_bottom_shell_thickness_explanation(const PresetBund top_shell_thickness = n * layer_height; } double top_shell_thickness_minimum = std::max(top_solid_min_thickness, top_solid_layers * min_layer_height); - out += (boost::format(_utf8(L("Top shell is %1% mm thick for layer height %2% mm."))) % top_shell_thickness % layer_height).str(); + out += (boost::format(_u8L("Top shell is %1% mm thick for layer height %2% mm.")) % top_shell_thickness % layer_height).str(); if (variable_layer_height && top_shell_thickness_minimum < top_shell_thickness) { out += " "; - out += (boost::format(_utf8(L("Minimum top shell thickness is %1% mm."))) % top_shell_thickness_minimum).str(); + out += (boost::format(_u8L("Minimum top shell thickness is %1% mm.")) % top_shell_thickness_minimum).str(); } } else - out += _utf8(L("Top is open.")); + out += _u8L("Top is open."); out += "\n"; @@ -298,13 +298,13 @@ std::string PresetHints::top_bottom_shell_thickness_explanation(const PresetBund bottom_shell_thickness = n * layer_height; } double bottom_shell_thickness_minimum = std::max(bottom_solid_min_thickness, bottom_solid_layers * min_layer_height); - out += (boost::format(_utf8(L("Bottom shell is %1% mm thick for layer height %2% mm."))) % bottom_shell_thickness % layer_height).str(); + out += (boost::format(_u8L("Bottom shell is %1% mm thick for layer height %2% mm.")) % bottom_shell_thickness % layer_height).str(); if (variable_layer_height && bottom_shell_thickness_minimum < bottom_shell_thickness) { out += " "; - out += (boost::format(_utf8(L("Minimum bottom shell thickness is %1% mm."))) % bottom_shell_thickness_minimum).str(); + out += (boost::format(_u8L("Minimum bottom shell thickness is %1% mm.")) % bottom_shell_thickness_minimum).str(); } } else - out += _utf8(L("Bottom is open.")); + out += _u8L("Bottom is open."); return out; } diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index f986a15522..74bbe2ada2 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -71,7 +71,7 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUplo if (combo_storage != nullptr) { // PrusaLink specific: User needs to choose a storage - auto* label_group = new wxStaticText(this, wxID_ANY, _L("Upload to storage:")); + auto* label_group = new wxStaticText(this, wxID_ANY, _L("Upload to storage") + ":"); content_sizer->Add(label_group); content_sizer->Add(combo_storage, 0, wxBOTTOM, 2 * VERT_SPACING); combo_storage->SetValue(storage_names.front()); @@ -80,7 +80,7 @@ PrintHostSendDialog::PrintHostSendDialog(const fs::path &path, PrintHostPostUplo combo_storage->SetValue(recent_storage); } else if (storage_names.GetCount() == 1){ // PrusaLink specific: Show which storage has been detected. - auto* label_group = new wxStaticText(this, wxID_ANY, _L("Upload to storage: ") + storage_names.front()); + auto* label_group = new wxStaticText(this, wxID_ANY, _L("Upload to storage") + ": " + storage_names.front()); content_sizer->Add(label_group); m_preselected_storage = storage_paths.front(); } @@ -473,7 +473,7 @@ void PrintHostQueueDialog::on_error(Event &evt) set_state(evt.job_id, ST_ERROR); - auto errormsg = from_u8((boost::format("%1%\n%2%") % _utf8(L("Error uploading to print host:")) % std::string(evt.status.ToUTF8())).str()); + auto errormsg = format_wxstr("%1%\n%2%", _L("Error uploading to print host") + ":", evt.status); job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS); job_list->SetValue(wxVariant(errormsg), evt.job_id, COL_ERRORMSG); // Stashes the error message into a hidden column for later diff --git a/src/slic3r/GUI/SavePresetDialog.cpp b/src/slic3r/GUI/SavePresetDialog.cpp index d4c2ba58ca..33f41b9c4e 100644 --- a/src/slic3r/GUI/SavePresetDialog.cpp +++ b/src/slic3r/GUI/SavePresetDialog.cpp @@ -87,9 +87,13 @@ void SavePresetDialog::Item::init_input_name_ctrl(wxBoxSizer *input_name_sizer, wxString SavePresetDialog::Item::get_top_label_text() const { - const std::string label_str = m_use_text_ctrl ?_u8L("Rename %s to:") : _u8L("Save %s as:"); + const std::string label_str = m_use_text_ctrl ? + // TRN %1% = "Preset" + L("Rename %1% to") : + // TRN %1% = "Preset" + L("Save %1% as"); Tab* tab = wxGetApp().get_tab(m_type); - return from_u8((boost::format(label_str) % into_u8(tab->title())).str()); + return format_wxstr(_(label_str) + ":", tab->title()); } SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBoxSizer* sizer, SavePresetDialog* parent): @@ -324,6 +328,7 @@ void SavePresetDialog::build(std::vector types, std::string suffix #endif // __WXMSW__ if (suffix.empty()) + // TRN Suffix for the preset name. Have to be a noun. suffix = _CTX_utf8(L_CONTEXT("Copy", "PresetName"), "PresetName"); wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL); diff --git a/src/slic3r/GUI/SurfaceDrag.cpp b/src/slic3r/GUI/SurfaceDrag.cpp index ecee0a4e06..a202ae5de4 100644 --- a/src/slic3r/GUI/SurfaceDrag.cpp +++ b/src/slic3r/GUI/SurfaceDrag.cpp @@ -5,6 +5,7 @@ #include "slic3r/Utils/RaycastManager.hpp" #include "slic3r/GUI/Camera.hpp" #include "slic3r/GUI/CameraUtils.hpp" +#include "slic3r/GUI/I18N.hpp" #include "libslic3r/Emboss.hpp" namespace Slic3r::GUI { diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 41a015e9f0..6382fb0aed 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -163,9 +163,10 @@ void Tab::create_preset_tab() add_scaled_button(panel, &m_btn_hide_incompatible_presets, "flag_green"); m_btn_compare_preset->SetToolTip(_L("Compare this preset with some another")); - // TRN "Save current Settings" - m_btn_save_preset->SetToolTip(from_u8((boost::format(_utf8(L("Save current %s"))) % m_title).str())); - m_btn_rename_preset->SetToolTip(from_u8((boost::format(_utf8(L("Rename current %s"))) % m_title).str())); + // TRN Settings Tabs: Tooltip for save button: "Settings" + m_btn_save_preset->SetToolTip(format_wxstr(_L("Save current %s"), m_title)); + // TRN Settings Tabs: Tooltip for rename button: "Settings" + m_btn_rename_preset->SetToolTip(format_wxstr(_L("Rename current %1%"), m_title)); m_btn_rename_preset->Hide(); m_btn_delete_preset->SetToolTip(_(L("Delete this preset"))); m_btn_delete_preset->Hide(); @@ -1602,6 +1603,8 @@ void TabPrint::build() optgroup->append_single_option_line("wipe_tower_rotation_angle"); optgroup->append_single_option_line("wipe_tower_brim_width"); optgroup->append_single_option_line("wipe_tower_bridging"); + optgroup->append_single_option_line("wipe_tower_cone_angle"); + optgroup->append_single_option_line("wipe_tower_extra_spacing"); optgroup->append_single_option_line("wipe_tower_no_sparse_layers"); optgroup->append_single_option_line("single_extruder_multi_material_priming"); @@ -3922,8 +3925,7 @@ void Tab::delete_preset() { auto current_preset = m_presets->get_selected_preset(); // Don't let the user delete the ' - default - ' configuration. - std::string action = current_preset.is_external ? _utf8(L("remove")) : _utf8(L("delete")); - // TRN remove/delete + wxString action = current_preset.is_external ? _L("remove") : _L("delete"); PhysicalPrinterCollection& physical_printers = m_preset_bundle->physical_printers; wxString msg; @@ -3967,13 +3969,14 @@ void Tab::delete_preset() "Note, that these printers will be deleted after deleting the selected preset.", ph_printers_only.size()) + "\n\n"; } } - + + // TRN "remove/delete" msg += from_u8((boost::format(_u8L("Are you sure you want to %1% the selected preset?")) % action).str()); } - action = current_preset.is_external ? _utf8(L("Remove")) : _utf8(L("Delete")); - // TRN Remove/Delete - wxString title = from_u8((boost::format(_utf8(L("%1% Preset"))) % action).str()); //action + _(L(" Preset")); + action = current_preset.is_external ? _L("Remove") : _L("Delete"); + // TRN Settings Tabs: Button in toolbar: "Remove/Delete" + wxString title = format_wxstr(_L("%1% Preset"), action); if (current_preset.is_default || //wxID_YES != wxMessageDialog(parent(), msg, title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal()) wxID_YES != MessageDialog(parent(), msg, title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal()) @@ -4059,7 +4062,7 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep deps.checkbox = new wxCheckBox(parent, wxID_ANY, _(L("All"))); deps.checkbox->SetFont(Slic3r::GUI::wxGetApp().normal_font()); wxGetApp().UpdateDarkUI(deps.checkbox, false, true); - deps.btn = new ScalableButton(parent, wxID_ANY, "printer", from_u8((boost::format(" %s %s") % _utf8(L("Set")) % std::string(dots.ToUTF8())).str()), + deps.btn = new ScalableButton(parent, wxID_ANY, "printer", format_wxstr(" %s %s", _L("Set"), dots), wxDefaultSize, wxDefaultPosition, wxBU_LEFT | wxBU_EXACTFIT); deps.btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); deps.btn->SetSize(deps.btn->GetBestSize()); @@ -5022,9 +5025,9 @@ void TabSLAPrint::update_description_lines() { bool elev = !m_config->opt_bool("pad_enable") || !m_config->opt_bool("pad_around_object"); m_support_object_elevation_description_line->SetText(elev ? "" : - from_u8((boost::format(_u8L("\"%1%\" is disabled because \"%2%\" is on in \"%3%\" category.\n" - "To enable \"%1%\", please switch off \"%2%\"")) - % _L("Object elevation") % _L("Pad around object") % _L("Pad")).str())); + format_wxstr(_L("\"%1%\" is disabled because \"%2%\" is on in \"%3%\" category.\n" + "To enable \"%1%\", please switch off \"%2%\"") + , _L("Object elevation"), _L("Pad around object"), _L("Pad"))); } } } diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index 8e3fa7874d..d7d4798c20 100644 --- a/src/slic3r/GUI/UnsavedChangesDialog.cpp +++ b/src/slic3r/GUI/UnsavedChangesDialog.cpp @@ -1591,7 +1591,7 @@ void DiffPresetDialog::create_buttons() } evt.Enable(enable); }); - m_transfer_btn->Bind(wxEVT_ENTER_WINDOW, [this, show_in_bottom_info](wxMouseEvent& e) { + m_transfer_btn->Bind(wxEVT_ENTER_WINDOW, [show_in_bottom_info](wxMouseEvent& e) { show_in_bottom_info(_L("Transfer the selected options from left preset to the right.\n" "Note: New modified presets will be selected in settings tabs after close this dialog."), e); }); @@ -1599,7 +1599,7 @@ void DiffPresetDialog::create_buttons() m_save_btn = new ScalableButton(this, wxID_ANY, "save", _L("Save"), wxDefaultSize, wxDefaultPosition, wxBORDER_DEFAULT, 24); m_save_btn->Bind(wxEVT_BUTTON, [this](wxEvent&) { button_event(Action::Save); }); m_save_btn->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_tree->has_selection()); }); - m_save_btn->Bind(wxEVT_ENTER_WINDOW, [this, show_in_bottom_info](wxMouseEvent& e) { + m_save_btn->Bind(wxEVT_ENTER_WINDOW, [show_in_bottom_info](wxMouseEvent& e) { show_in_bottom_info(_L("Save the selected options from left preset to the right."), e); }); // Cancel diff --git a/src/slic3r/GUI/UpdateDialogs.cpp b/src/slic3r/GUI/UpdateDialogs.cpp index 2b473ae0c6..dea01eb8f6 100644 --- a/src/slic3r/GUI/UpdateDialogs.cpp +++ b/src/slic3r/GUI/UpdateDialogs.cpp @@ -135,10 +135,10 @@ bool AppUpdateAvailableDialog::disable_version_check() const // AppUpdateDownloadDialog AppUpdateDownloadDialog::AppUpdateDownloadDialog( const Semver& ver_online, boost::filesystem::path& path) - : MsgDialog(nullptr, _(L("App Update download")), wxString::Format(_(L("New version of %s is available.")), SLIC3R_APP_NAME)) + : MsgDialog(nullptr, _L("App Update download"), format_wxstr(_L("New version of %1% is available."), SLIC3R_APP_NAME)) { auto* versions = new wxFlexGridSizer(2, 0, VERT_SPACING); - versions->Add(new wxStaticText(this, wxID_ANY, _(L("New version:")))); + versions->Add(new wxStaticText(this, wxID_ANY, _L("New version") + ":")); versions->Add(new wxStaticText(this, wxID_ANY, ver_online.to_string())); content_sizer->Add(versions); content_sizer->AddSpacer(VERT_SPACING); @@ -148,7 +148,7 @@ AppUpdateDownloadDialog::AppUpdateDownloadDialog( const Semver& ver_online, boos #endif content_sizer->AddSpacer(VERT_SPACING); content_sizer->AddSpacer(VERT_SPACING); - content_sizer->Add(new wxStaticText(this, wxID_ANY, _(L("Target directory:")))); + content_sizer->Add(new wxStaticText(this, wxID_ANY, _L("Target directory") + ":")); content_sizer->AddSpacer(VERT_SPACING); txtctrl_path = new wxTextCtrl(this, wxID_ANY, GUI::format_wxstr(path.parent_path().string())); filename = GUI::format_wxstr(path.filename().string()); @@ -173,7 +173,7 @@ AppUpdateDownloadDialog::AppUpdateDownloadDialog( const Semver& ver_online, boos dir = GUI::format(txtctrl_path->GetValue()); wxDirDialog save_dlg( this - , _L("Select directory:") + , _L("Select directory") + ":" , GUI::format_wxstr(dir.string()) /* , filename //boost::nowide::widen(AppUpdater::get_filename_from_url(txtctrl_path->GetValue().ToUTF8().data())) @@ -436,8 +436,7 @@ MsgDataIncompatible::~MsgDataIncompatible() {} MsgDataLegacy::MsgDataLegacy() : MsgDialog(nullptr, _(L("Configuration update")), _(L("Configuration update"))) { - auto *text = new wxStaticText(this, wxID_ANY, from_u8((boost::format( - _utf8(L( + auto *text = new wxStaticText(this, wxID_ANY, format_wxstr( _L( "%s now uses an updated configuration structure.\n\n" "So called 'System presets' have been introduced, which hold the built-in default settings for various " @@ -447,10 +446,8 @@ MsgDataLegacy::MsgDataLegacy() : "Please proceed with the %s that follows to set up the new presets " "and to choose whether to enable automatic preset updates." - ))) - % SLIC3R_APP_NAME - % _utf8(ConfigWizard::name())).str() - )); + ) + , SLIC3R_APP_NAME, ConfigWizard::name())); text->Wrap(CONTENT_WIDTH * wxGetApp().em_unit()); content_sizer->Add(text); content_sizer->AddSpacer(VERT_SPACING); @@ -458,7 +455,7 @@ MsgDataLegacy::MsgDataLegacy() : auto *text2 = new wxStaticText(this, wxID_ANY, _(L("For more information please visit our wiki page:"))); static const wxString url("https://github.com/prusa3d/PrusaSlicer/wiki/Slic3r-PE-1.40-configuration-update"); // The wiki page name is intentionally not localized: - auto *link = new wxHyperlinkCtrl(this, wxID_ANY, wxString::Format("%s 1.40 configuration update", SLIC3R_APP_NAME), CONFIG_UPDATE_WIKI_URL); + auto *link = new wxHyperlinkCtrl(this, wxID_ANY, format_wxstr(_L("%s 1.40 configuration update"), SLIC3R_APP_NAME), CONFIG_UPDATE_WIKI_URL); content_sizer->Add(text2); content_sizer->Add(link); content_sizer->AddSpacer(VERT_SPACING); diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index d4bd27c056..f67ad287ae 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -630,9 +630,8 @@ ModeButton::ModeButton( wxWindow* parent, void ModeButton::Init(const wxString &mode) { - std::string mode_str = std::string(mode.ToUTF8()); - m_tt_focused = Slic3r::GUI::from_u8((boost::format(_utf8(L("Switch to the %s mode"))) % mode_str).str()); - m_tt_selected = Slic3r::GUI::from_u8((boost::format(_utf8(L("Current mode is %s"))) % mode_str).str()); + m_tt_focused = Slic3r::GUI::format_wxstr(_L("Switch to the %s mode"), mode); + m_tt_selected = Slic3r::GUI::format_wxstr(_L("Current mode is %s"), mode); SetBitmapMargins(3, 0); diff --git a/src/slic3r/Utils/AppUpdater.cpp b/src/slic3r/Utils/AppUpdater.cpp index 9eb0128271..4c60f018eb 100644 --- a/src/slic3r/Utils/AppUpdater.cpp +++ b/src/slic3r/Utils/AppUpdater.cpp @@ -39,7 +39,7 @@ namespace { std::string msg; bool res = GUI::create_process(path, std::wstring(), msg); if (!res) { - std::string full_message = GUI::format(_utf8("Running downloaded instaler of %1% has failed:\n%2%"), SLIC3R_APP_NAME, msg); + std::string full_message = GUI::format(_u8L("Running downloaded instaler of %1% has failed:\n%2%"), SLIC3R_APP_NAME, msg); BOOST_LOG_TRIVIAL(error) << full_message; // lm: maybe UI error msg? // dk: bellow. (maybe some general show error evt would be better?) wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_APP_DOWNLOAD_FAILED); evt->SetString(full_message); @@ -174,9 +174,7 @@ bool AppUpdater::priv::http_get_file(const std::string& url, size_t size_limit, cancel = (m_cancel ? true : !progress_fn(std::move(progress))); if (cancel) { // Lets keep error_message empty here - if there is need to show error dialog, the message will be probably shown by whatever caused the cancel. - /* - error_message = GUI::format(_utf8("Error getting: `%1%`: Download was canceled."), url); - */ + //error_message = GUI::format(_u8L("Error getting: `%1%`: Download was canceled."), url); BOOST_LOG_TRIVIAL(debug) << "AppUpdater::priv::http_get_file message: "<< error_message; } }) @@ -205,8 +203,8 @@ boost::filesystem::path AppUpdater::priv::download_file(const DownloadAppData& d assert(!dest_path.empty()); if (dest_path.empty()) { - std::string line1 = GUI::format(_utf8("Internal download error for url %1%:"), data.url); - std::string line2 = _utf8("Destination path is empty."); + std::string line1 = GUI::format(_u8L("Internal download error for url %1%:"), data.url); + std::string line2 = _u8L("Destination path is empty."); std::string message = GUI::format("%1%\n%2%", line1, line2); BOOST_LOG_TRIVIAL(error) << message; wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_APP_DOWNLOAD_FAILED); @@ -222,8 +220,8 @@ boost::filesystem::path AppUpdater::priv::download_file(const DownloadAppData& d file = fopen(temp_path_wstring.c_str(), "wb"); assert(file != NULL); if (file == NULL) { - std::string line1 = GUI::format(_utf8("Download from %1% couldn't start:"), data.url); - std::string line2 = GUI::format(_utf8("Can't create file at %1%."), tmp_path.string()); + std::string line1 = GUI::format(_u8L("Download from %1% couldn't start:"), data.url); + std::string line2 = GUI::format(_u8L("Can't create file at %1%."), tmp_path.string()); std::string message = GUI::format("%1%\n%2%", line1, line2); BOOST_LOG_TRIVIAL(error) << message; wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_APP_DOWNLOAD_FAILED); @@ -264,11 +262,11 @@ boost::filesystem::path AppUpdater::priv::download_file(const DownloadAppData& d // Size check. Does always 1 char == 1 byte? size_t body_size = body.size(); if (body_size != expected_size) { - error_message = GUI::format(_utf8("Downloaded file has wrong size. Expected size: %1% Downloaded size: %2%"), expected_size, body_size); + error_message = GUI::format(_u8L("Downloaded file has wrong size. Expected size: %1% Downloaded size: %2%"), expected_size, body_size); return false; } if (file == NULL) { - error_message = GUI::format(_utf8("Can't create file at %1%."), tmp_path.string()); + error_message = GUI::format(_u8L("Can't create file at %1%."), tmp_path.string()); return false; } try @@ -279,7 +277,7 @@ boost::filesystem::path AppUpdater::priv::download_file(const DownloadAppData& d } catch (const std::exception& e) { - error_message = GUI::format(_utf8("Failed to write to file or to move %1% to %2%:\n%3%"), tmp_path, dest_path, e.what()); + error_message = GUI::format(_u8L("Failed to write to file or to move %1% to %2%:\n%3%"), tmp_path, dest_path, e.what()); return false; } return true; @@ -295,7 +293,7 @@ boost::filesystem::path AppUpdater::priv::download_file(const DownloadAppData& d } else { std::string message = (error_message.empty() ? std::string() - : GUI::format(_utf8("Downloading new %1% has failed:\n%2%"), SLIC3R_APP_NAME, error_message)); + : GUI::format(_u8L("Downloading new %1% has failed:\n%2%"), SLIC3R_APP_NAME, error_message)); wxCommandEvent* evt = new wxCommandEvent(EVT_SLIC3R_APP_DOWNLOAD_FAILED); if (!message.empty()) { BOOST_LOG_TRIVIAL(error) << message; diff --git a/src/slic3r/Utils/AstroBox.cpp b/src/slic3r/Utils/AstroBox.cpp index a2b5bca04d..e7044ad20c 100644 --- a/src/slic3r/Utils/AstroBox.cpp +++ b/src/slic3r/Utils/AstroBox.cpp @@ -66,7 +66,7 @@ bool AstroBox::test(wxString &msg) const const auto text = ptree.get_optional("text"); res = validate_version_text(text); if (! res) { - msg = GUI::from_u8((boost::format(_utf8(L("Mismatched type of print host: %s"))) % (text ? *text : "AstroBox")).str()); + msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : "AstroBox")); } } catch (const std::exception &) { @@ -86,10 +86,10 @@ wxString AstroBox::get_test_ok_msg () const wxString AstroBox::get_test_failed_msg (wxString &msg) const { - return GUI::from_u8((boost::format("%s: %s\n\n%s") - % _utf8(L("Could not connect to AstroBox")) - % std::string(msg.ToUTF8()) - % _utf8(L("Note: AstroBox version at least 1.1.0 is required."))).str()); + return GUI::format_wxstr("%s: %s\n\n%s" + , _L("Could not connect to AstroBox") + , msg + , _L("Note: AstroBox version at least 1.1.0 is required.")); } bool AstroBox::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const diff --git a/src/slic3r/Utils/Duet.cpp b/src/slic3r/Utils/Duet.cpp index 229d0c950e..74bf080cd8 100644 --- a/src/slic3r/Utils/Duet.cpp +++ b/src/slic3r/Utils/Duet.cpp @@ -49,9 +49,7 @@ wxString Duet::get_test_ok_msg () const wxString Duet::get_test_failed_msg (wxString &msg) const { - return GUI::from_u8((boost::format("%s: %s") - % _utf8(L("Could not connect to Duet")) - % std::string(msg.ToUTF8())).str()); + return GUI::format_wxstr("%s: %s", _L("Could not connect to Duet"), msg); } bool Duet::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const diff --git a/src/slic3r/Utils/FlashAir.cpp b/src/slic3r/Utils/FlashAir.cpp index e54dca58fe..157d9623fc 100644 --- a/src/slic3r/Utils/FlashAir.cpp +++ b/src/slic3r/Utils/FlashAir.cpp @@ -70,10 +70,10 @@ wxString FlashAir::get_test_ok_msg () const wxString FlashAir::get_test_failed_msg (wxString &msg) const { - return GUI::from_u8((boost::format("%s: %s\n%s") - % _utf8(L("Could not connect to FlashAir")) - % std::string(msg.ToUTF8()) - % _utf8(L("Note: FlashAir with firmware 2.00.02 or newer and activated upload function is required."))).str()); + return GUI::format_wxstr("%s: %s\n%s" + , _u8L("Could not connect to FlashAir") + , msg + , _u8L("Note: FlashAir with firmware 2.00.02 or newer and activated upload function is required.")); } bool FlashAir::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const diff --git a/src/slic3r/Utils/MKS.cpp b/src/slic3r/Utils/MKS.cpp index 109283fc66..cce212631d 100644 --- a/src/slic3r/Utils/MKS.cpp +++ b/src/slic3r/Utils/MKS.cpp @@ -57,9 +57,7 @@ wxString MKS::get_test_ok_msg() const wxString MKS::get_test_failed_msg(wxString& msg) const { - return GUI::from_u8((boost::format("%s: %s") - % _utf8(L("Could not connect to MKS")) - % std::string(msg.ToUTF8())).str()); + return GUI::format_wxstr("%s: %s", _L("Could not connect to MKS"), msg); } bool MKS::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index 413a3445ae..540852af89 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -203,7 +203,7 @@ bool OctoPrint::test_with_resolved_ip(wxString &msg) const const auto text = ptree.get_optional("text"); res = validate_version_text(text); if (!res) { - msg = GUI::from_u8((boost::format(_utf8(L("Mismatched type of print host: %s"))) % (text ? *text : "OctoPrint")).str()); + msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : "OctoPrint")); } } catch (const std::exception&) { @@ -252,7 +252,7 @@ bool OctoPrint::test(wxString& msg) const const auto text = ptree.get_optional("text"); res = validate_version_text(text); if (! res) { - msg = GUI::from_u8((boost::format(_utf8(L("Mismatched type of print host: %s"))) % (text ? *text : "OctoPrint")).str()); + msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : "OctoPrint")); } } catch (const std::exception &) { @@ -280,10 +280,10 @@ wxString OctoPrint::get_test_ok_msg () const wxString OctoPrint::get_test_failed_msg (wxString &msg) const { - return GUI::from_u8((boost::format("%s: %s\n\n%s") - % _utf8(L("Could not connect to OctoPrint")) - % std::string(msg.ToUTF8()) - % _utf8(L("Note: OctoPrint version at least 1.1.0 is required."))).str()); + return GUI::format_wxstr("%s: %s\n\n%s" + , _L("Could not connect to OctoPrint") + , msg + , _L("Note: OctoPrint version at least 1.1.0 is required.")); } bool OctoPrint::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const @@ -530,9 +530,7 @@ wxString SL1Host::get_test_ok_msg () const wxString SL1Host::get_test_failed_msg (wxString &msg) const { - return GUI::from_u8((boost::format("%s: %s") - % _utf8(L("Could not connect to Prusa SLA")) - % std::string(msg.ToUTF8())).str()); + return GUI::format_wxstr("%s: %s", _L("Could not connect to Prusa SLA"), msg); } bool SL1Host::validate_version_text(const boost::optional &version_text) const @@ -575,9 +573,7 @@ wxString PrusaLink::get_test_ok_msg() const wxString PrusaLink::get_test_failed_msg(wxString& msg) const { - return GUI::from_u8((boost::format("%s: %s") - % _utf8(L("Could not connect to PrusaLink")) - % std::string(msg.ToUTF8())).str()); + return GUI::format_wxstr("%s: %s", _L("Could not connect to PrusaLink"), msg); } bool PrusaLink::validate_version_text(const boost::optional& version_text) const @@ -663,7 +659,7 @@ bool PrusaLink::test(wxString& msg) const const auto text = ptree.get_optional("text"); res = validate_version_text(text); if (!res) { - msg = GUI::from_u8((boost::format(_utf8(L("Mismatched type of print host: %s"))) % (text ? *text : "OctoPrint")).str()); + msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : "OctoPrint")); } } catch (const std::exception&) { @@ -773,12 +769,17 @@ bool PrusaLink::get_storage(wxArrayString& storage_path, wxArrayString& storage_ if (res && storage_path.empty()) { if (!storage.empty()) { // otherwise error_msg is already filled - error_msg = L"\n\n" + _L("Storages found:") + L" \n"; + error_msg = L"\n\n" + _L("Storages found") + L": \n"; for (const auto& si : storage) { - error_msg += si.path + L" : " + (si.read_only ? _L("read only") : _L("no free space")) + L"\n"; + error_msg += GUI::format_wxstr(si.read_only ? + // TRN %1% = storage path + _L("%1% : read only") : + // TRN %1% = storage path + _L("%1% : no free space"), si.path) + L"\n"; } } - std::string message = GUI::format(_L("Upload has failed. There is no suitable storage found at %1%.%2%"), m_host, error_msg); + // TRN %1% = host + std::string message = GUI::format(_L("Upload has failed. There is no suitable storage found at %1%."), m_host) + GUI::into_u8(error_msg); BOOST_LOG_TRIVIAL(error) << message; throw Slic3r::IOError(message); } @@ -821,7 +822,7 @@ bool PrusaLink::test_with_method_check(wxString& msg, bool& use_put) const const auto text = ptree.get_optional("text"); res = validate_version_text(text); if (!res) { - msg = GUI::from_u8((boost::format(_utf8(L("Mismatched type of print host: %s"))) % (text ? *text : "OctoPrint")).str()); + msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : "OctoPrint")); use_put = false; return; } @@ -894,7 +895,7 @@ bool PrusaLink::test_with_resolved_ip_and_method_check(wxString& msg, bool& use_ const auto text = ptree.get_optional("text"); res = validate_version_text(text); if (!res) { - msg = GUI::from_u8((boost::format(_utf8(L("Mismatched type of print host: %s"))) % (text ? *text : "OctoPrint")).str()); + msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (text ? *text : "OctoPrint")); use_put = false; return; } @@ -1142,9 +1143,7 @@ wxString PrusaConnect::get_test_ok_msg() const wxString PrusaConnect::get_test_failed_msg(wxString& msg) const { - return GUI::from_u8((boost::format("%s: %s") - % _utf8(L("Could not connect to PrusaConnect")) - % std::string(msg.ToUTF8())).str()); + return GUI::format_wxstr("%s: %s", _L("Could not connect to PrusaConnect"), msg); } } diff --git a/src/slic3r/Utils/Repetier.cpp b/src/slic3r/Utils/Repetier.cpp index e266be1f82..274ea4351e 100644 --- a/src/slic3r/Utils/Repetier.cpp +++ b/src/slic3r/Utils/Repetier.cpp @@ -85,7 +85,7 @@ bool Repetier::test(wxString &msg) const const auto soft = ptree.get_optional("software"); res = validate_repetier(text, soft); if (! res) { - msg = GUI::from_u8((boost::format(_utf8(L("Mismatched type of print host: %s"))) % (soft ? *soft : (text ? *text : "Repetier"))).str()); + msg = GUI::format_wxstr(_L("Mismatched type of print host: %s"), (soft ? *soft : (text ? *text : "Repetier"))); } } catch (const std::exception &) { @@ -105,10 +105,10 @@ wxString Repetier::get_test_ok_msg () const wxString Repetier::get_test_failed_msg (wxString &msg) const { - return GUI::from_u8((boost::format("%s: %s\n\n%s") - % _utf8(L("Could not connect to Repetier")) - % std::string(msg.ToUTF8()) - % _utf8(L("Note: Repetier version at least 0.90.0 is required."))).str()); + return GUI::format_wxstr("%s: %s\n\n%s" + , _L("Could not connect to Repetier") + , msg + , _L("Note: Repetier version at least 0.90.0 is required.")); } bool Repetier::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, ErrorFn error_fn, InfoFn info_fn) const @@ -142,7 +142,7 @@ bool Repetier::upload(PrintHostUpload upload_data, ProgressFn prorgess_fn, Error auto http = Http::post(std::move(url)); set_auth(http); - if (! upload_data.group.empty() && upload_data.group != _utf8(L("Default"))) { + if (! upload_data.group.empty() && upload_data.group != _u8L("Default")) { http.form_add("group", upload_data.group); } @@ -223,7 +223,7 @@ bool Repetier::get_groups(wxArrayString& groups) const BOOST_FOREACH(boost::property_tree::ptree::value_type &v, ptree.get_child("groupNames.")) { if (v.second.data() == "#") { - groups.push_back(_utf8(L("Default"))); + groups.push_back(_L("Default")); } else { // Is it safe to assume that the data are utf-8 encoded? groups.push_back(GUI::from_u8(v.second.data())); diff --git a/tests/libslic3r/test_placeholder_parser.cpp b/tests/libslic3r/test_placeholder_parser.cpp index ee1461baf8..b29ca0f8e5 100644 --- a/tests/libslic3r/test_placeholder_parser.cpp +++ b/tests/libslic3r/test_placeholder_parser.cpp @@ -186,12 +186,12 @@ SCENARIO("Placeholder parser variables", "[PlaceholderParser]") { SECTION("create a string global variable and redefine it") { REQUIRE(parser.process("{global mystr = \"mine\" + \"only\" + \"mine\"}{global mystr = \"yours\"}{mystr}", 0, nullptr, nullptr, &context_with_global_dict) == "yours"); } SECTION("create a bool global variable and redefine it") { REQUIRE(parser.process("{global mybool = 1 + 1 == 2}{global mybool = false}{mybool}", 0, nullptr, nullptr, &context_with_global_dict) == "false"); } - SECTION("create an ints local variable with array()") { REQUIRE(parser.process("{local myint = array(2*3, 4*6)}{myint[5]}", 0, nullptr, nullptr, nullptr) == "24"); } - SECTION("create a strings local variable array()") { REQUIRE(parser.process("{local mystr = array(2*3, \"mine\" + \"only\" + \"mine\")}{mystr[5]}", 0, nullptr, nullptr, nullptr) == "mineonlymine"); } - SECTION("create a bools local variable array()") { REQUIRE(parser.process("{local mybool = array(5, 1 + 1 == 2)}{mybool[4]}", 0, nullptr, nullptr, nullptr) == "true"); } - SECTION("create an ints global variable array()") { REQUIRE(parser.process("{global myint = array(2*3, 4*6)}{myint[5]}", 0, nullptr, nullptr, &context_with_global_dict) == "24"); } - SECTION("create a strings global variable array()") { REQUIRE(parser.process("{global mystr = array(2*3, \"mine\" + \"only\" + \"mine\")}{mystr[5]}", 0, nullptr, nullptr, &context_with_global_dict) == "mineonlymine"); } - SECTION("create a bools global variable array()") { REQUIRE(parser.process("{global mybool = array(5, 1 + 1 == 2)}{mybool[4]}", 0, nullptr, nullptr, &context_with_global_dict) == "true"); } + SECTION("create an ints local variable with repeat()") { REQUIRE(parser.process("{local myint = repeat(2*3, 4*6)}{myint[5]}", 0, nullptr, nullptr, nullptr) == "24"); } + SECTION("create a strings local variable with repeat()") { REQUIRE(parser.process("{local mystr = repeat(2*3, \"mine\" + \"only\" + \"mine\")}{mystr[5]}", 0, nullptr, nullptr, nullptr) == "mineonlymine"); } + SECTION("create a bools local variable with repeat()") { REQUIRE(parser.process("{local mybool = repeat(5, 1 + 1 == 2)}{mybool[4]}", 0, nullptr, nullptr, nullptr) == "true"); } + SECTION("create an ints global variable with repeat()") { REQUIRE(parser.process("{global myint = repeat(2*3, 4*6)}{myint[5]}", 0, nullptr, nullptr, &context_with_global_dict) == "24"); } + SECTION("create a strings global variable with repeat()") { REQUIRE(parser.process("{global mystr = repeat(2*3, \"mine\" + \"only\" + \"mine\")}{mystr[5]}", 0, nullptr, nullptr, &context_with_global_dict) == "mineonlymine"); } + SECTION("create a bools global variable with repeat()") { REQUIRE(parser.process("{global mybool = repeat(5, 1 + 1 == 2)}{mybool[4]}", 0, nullptr, nullptr, &context_with_global_dict) == "true"); } SECTION("create an ints local variable with initializer list") { REQUIRE(parser.process("{local myint = (2*3, 4*6, 5*5)}{myint[1]}", 0, nullptr, nullptr, nullptr) == "24"); } SECTION("create a strings local variable with initializer list") { REQUIRE(parser.process("{local mystr = (2*3, \"mine\" + \"only\" + \"mine\", 8)}{mystr[1]}", 0, nullptr, nullptr, nullptr) == "mineonlymine"); } @@ -208,18 +208,23 @@ SCENARIO("Placeholder parser variables", "[PlaceholderParser]") { SECTION("create a bools global variable by a copy") { REQUIRE(parser.process("{global mybool = enable_dynamic_fan_speeds}{mybool[0]}", 0, &config, nullptr, &context_with_global_dict) == "true"); } SECTION("create an ints local variable by a copy and overwrite it") { - REQUIRE(parser.process("{local myint = temperature}{myint = array(2*3, 4*6)}{myint[5]}", 0, &config, nullptr, nullptr) == "24"); + REQUIRE(parser.process("{local myint = temperature}{myint = repeat(2*3, 4*6)}{myint[5]}", 0, &config, nullptr, nullptr) == "24"); REQUIRE(parser.process("{local myint = temperature}{myint = (2*3, 4*6)}{myint[1]}", 0, &config, nullptr, nullptr) == "24"); REQUIRE(parser.process("{local myint = temperature}{myint = (1)}{myint = temperature}{myint[0]}", 0, &config, nullptr, nullptr) == "357"); } SECTION("create a strings local variable by a copy and overwrite it") { - REQUIRE(parser.process("{local mystr = filament_notes}{mystr = array(2*3, \"mine\" + \"only\" + \"mine\")}{mystr[5]}", 0, &config, nullptr, nullptr) == "mineonlymine"); + REQUIRE(parser.process("{local mystr = filament_notes}{mystr = repeat(2*3, \"mine\" + \"only\" + \"mine\")}{mystr[5]}", 0, &config, nullptr, nullptr) == "mineonlymine"); REQUIRE(parser.process("{local mystr = filament_notes}{mystr = (2*3, \"mine\" + \"only\" + \"mine\")}{mystr[1]}", 0, &config, nullptr, nullptr) == "mineonlymine"); REQUIRE(parser.process("{local mystr = filament_notes}{mystr = (2*3, \"mine\" + \"only\" + \"mine\")}{mystr = filament_notes}{mystr[0]}", 0, &config, nullptr, nullptr) == "testnotes"); } SECTION("create a bools local variable by a copy and overwrite it") { - REQUIRE(parser.process("{local mybool = enable_dynamic_fan_speeds}{mybool = array(2*3, true)}{mybool[5]}", 0, &config, nullptr, nullptr) == "true"); + REQUIRE(parser.process("{local mybool = enable_dynamic_fan_speeds}{mybool = repeat(2*3, true)}{mybool[5]}", 0, &config, nullptr, nullptr) == "true"); REQUIRE(parser.process("{local mybool = enable_dynamic_fan_speeds}{mybool = (false, true)}{mybool[1]}", 0, &config, nullptr, nullptr) == "true"); REQUIRE(parser.process("{local mybool = enable_dynamic_fan_speeds}{mybool = (false, false)}{mybool = enable_dynamic_fan_speeds}{mybool[0]}", 0, &config, nullptr, nullptr) == "true"); } + + SECTION("size() of a non-empty vector returns the right size") { REQUIRE(parser.process("{local myint = (0, 1, 2, 3)}{size(myint)}", 0, nullptr, nullptr, nullptr) == "4"); } + SECTION("size() of a an empty vector returns the right size") { REQUIRE(parser.process("{local myint = (0);myint=();size(myint)}", 0, nullptr, nullptr, nullptr) == "0"); } + SECTION("empty() of a non-empty vector returns false") { REQUIRE(parser.process("{local myint = (0, 1, 2, 3)}{empty(myint)}", 0, nullptr, nullptr, nullptr) == "false"); } + SECTION("empty() of a an empty vector returns true") { REQUIRE(parser.process("{local myint = (0);myint=();empty(myint)}", 0, nullptr, nullptr, nullptr) == "true"); } }