From 929a0eba2cfe6603f036e13083d5f349a0ccb0b7 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 23 Mar 2023 17:08:56 +0100 Subject: [PATCH 01/25] PlaceholderParser: replaced the new "array" operator with "repeat", simplified the parser a bit more. --- src/libslic3r/PlaceholderParser.cpp | 127 +++++++++----------- tests/libslic3r/test_placeholder_parser.cpp | 18 +-- 2 files changed, 68 insertions(+), 77 deletions(-) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index a26841082..29d35ac2f 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -1263,15 +1263,24 @@ namespace client 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"); }; - 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: @@ -1304,11 +1313,11 @@ namespace client { if (lhs.opt) { // Assign to an existing vector variable. - if (lhs.opt->is_scalar()) - ctx->throw_exception("Cannot assign a vector value to a scalar variable.", lhs.it_range); 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; @@ -1344,6 +1353,17 @@ namespace client } } + template + static bool is_vector_variable_reference(const OptWithPos &var) { + 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 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, @@ -1351,9 +1371,9 @@ namespace client const OptWithPos &rhs) { check_writable(ctx, lhs); - assert(rhs.opt->is_vector()); - if (! lhs.opt->is_vector()) - ctx->throw_exception("Cannot assign vector to a scalar", lhs.it_range); + 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()) { @@ -1372,11 +1392,6 @@ namespace client const_cast(lhs.opt)->set(rhs.opt); } - template - static bool is_vector_variable_reference(const OptWithPos &var) { - return ! var.has_index() && var.opt->is_vector(); - } - template static bool vector_variable_new_from_copy( const MyContext *ctx, @@ -1384,43 +1399,26 @@ namespace client NewOldVariable &lhs, const OptWithPos &rhs) { - if (is_vector_variable_reference(rhs)) { - if (lhs.opt) { - OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true }; - copy_vector_variable_to_vector_variable(ctx, lhs_opt, rhs); - } else { - // 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; + 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 { - // Skip parsing this branch, bactrack. - return false; - } - } - - template - static bool vector_variable_assign_copy( - const MyContext *ctx, - OptWithPos &lhs, - const OptWithPos &rhs) - { - if (is_vector_variable_reference(rhs)) { - copy_vector_variable_to_vector_variable(ctx, lhs, rhs); - // Continue parsing. - return true; - } else { - // Skip parsing this branch, bactrack. - return false; + 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 @@ -1572,12 +1570,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" }, @@ -1594,7 +1592,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."} }; @@ -1846,37 +1843,35 @@ 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) > ')') + (lit('(') > 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::vector_variable_assign_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::scalar_variable_assign_scalar_expression, _r1, _a, _1)] - | (kw["array"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")") + | (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) > ')') + (lit('(') > 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::vector_variable_new_from_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::scalar_variable_new_from_scalar_expression, _r1, _a, _b, _1)] - | (kw["array"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")") + | (kw["repeat"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")") [px::bind(&MyContext::vector_variable_new_from_array, _r1, _a, _b, _1, _2)] ); - new_variable_initializer_list = - conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append, _val, _1)] >> - *(lit(',') > conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append, _val, _1)]); + initializer_list = *(lit(',') > conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append, _val, _1)]); struct FactorActions { static void set_start_pos(Iterator &start_pos, expr &out) @@ -1920,7 +1915,7 @@ 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["interpolate_table"] > '(' > interpolate_table(_r1) > ')') [ _val = _1 ] | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ] @@ -1961,9 +1956,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] >> ( @@ -1981,7 +1973,6 @@ namespace client keywords.add ("and") - ("array") ("digits") ("zdigits") ("if") @@ -1998,6 +1989,7 @@ namespace client ("min") ("max") ("random") + ("repeat") ("round") ("not") ("one_of") @@ -2030,7 +2022,6 @@ namespace client debug(optional_parameter); debug(variable_reference); debug(variable); - debug(is_nil_test); debug(regular_expression); } } @@ -2089,7 +2080,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/tests/libslic3r/test_placeholder_parser.cpp b/tests/libslic3r/test_placeholder_parser.cpp index ee1461baf..48fe43117 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,17 +208,17 @@ 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"); } From 9cb50e6586c1f339b84c29fbe078b3521a0405b9 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 23 Mar 2023 17:51:37 +0100 Subject: [PATCH 02/25] PlaceholderParser: added size() and empty() functions over vector variables. --- src/libslic3r/PlaceholderParser.cpp | 42 ++++++++++++++++++--- tests/libslic3r/test_placeholder_parser.cpp | 5 +++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 29d35ac2f..94a1259b6 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -1427,6 +1427,30 @@ namespace client 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 @@ -1843,8 +1867,7 @@ 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('(') > initializer_list(_r1) > ')') - [px::bind(&MyContext::vector_variable_assign_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. | eps(px::bind(&MyContext::is_vector_variable_reference, _a)) >> @@ -1859,8 +1882,7 @@ namespace client 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('(') > initializer_list(_r1) > ')') - [px::bind(&MyContext::vector_variable_new_from_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. | eps(px::bind(&MyContext::could_be_vector_variable_reference, _b)) >> @@ -1871,7 +1893,13 @@ namespace client | (kw["repeat"] > "(" > additive_expression(_r1) > "," > conditional_expression(_r1) > ")") [px::bind(&MyContext::vector_variable_new_from_array, _r1, _a, _b, _1, _2)] ); - initializer_list = *(lit(',') > conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append, _val, _1)]); + 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(')') + ) + ); struct FactorActions { static void set_start_pos(Iterator &start_pos, expr &out) @@ -1917,6 +1945,8 @@ namespace client | (kw["round"] > '(' > conditional_expression(_r1) > ')') [ px::bind(&FactorActions::round, _1, _val) ] | (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) ] @@ -1975,6 +2005,7 @@ namespace client ("and") ("digits") ("zdigits") + ("empty") ("if") ("int") ("is_nil") @@ -1994,6 +2025,7 @@ namespace client ("not") ("one_of") ("or") + ("size") ("true"); if (0) { diff --git a/tests/libslic3r/test_placeholder_parser.cpp b/tests/libslic3r/test_placeholder_parser.cpp index 48fe43117..b29ca0f8e 100644 --- a/tests/libslic3r/test_placeholder_parser.cpp +++ b/tests/libslic3r/test_placeholder_parser.cpp @@ -222,4 +222,9 @@ SCENARIO("Placeholder parser variables", "[PlaceholderParser]") { 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"); } } From 19f2a1d9e988175e5673ef17e0b55ae7e5ea349b Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 20 Mar 2023 10:38:34 +0100 Subject: [PATCH 03/25] Unified usage of localization macros in slic3r/libslic3r --- src/libslic3r/ExtrusionRole.cpp | 1 - src/libslic3r/Flow.cpp | 5 +- src/libslic3r/Format/3mf.cpp | 15 +-- src/libslic3r/Format/AMF.cpp | 6 +- src/libslic3r/Format/SLAArchiveReader.cpp | 1 - src/libslic3r/GCode.cpp | 55 +++++------ src/libslic3r/GCode/PostProcessor.cpp | 9 +- src/libslic3r/I18N.hpp | 7 ++ src/libslic3r/Preset.cpp | 9 -- src/libslic3r/Print.cpp | 96 +++++++++---------- src/libslic3r/PrintBase.cpp | 6 +- src/libslic3r/PrintConfig.cpp | 5 - src/libslic3r/PrintObject.cpp | 16 ++-- src/libslic3r/PrintObjectSlice.cpp | 8 +- src/libslic3r/SLA/Hollowing.cpp | 12 +-- src/libslic3r/SLA/Pad.cpp | 5 +- src/libslic3r/SLA/SupportTree.cpp | 4 - src/libslic3r/SLAPrint.cpp | 14 +-- src/libslic3r/SLAPrintSteps.cpp | 47 +++++---- src/libslic3r/Zipper.cpp | 4 +- src/libslic3r/miniz_extension.cpp | 68 +++++++------ src/slic3r/GUI/BedShapeDialog.cpp | 3 + src/slic3r/GUI/BedShapeDialog.hpp | 4 +- src/slic3r/GUI/ConfigWizard.cpp | 1 + src/slic3r/GUI/GUI_App.cpp | 13 ++- src/slic3r/GUI/Gizmos/GLGizmoBase.cpp | 22 +++-- src/slic3r/GUI/Gizmos/GLGizmoBase.hpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp | 5 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp | 3 +- .../GUI/Gizmos/GLGizmoMmuSegmentation.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoPainterBase.cpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoSeam.hpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | 1 - src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp | 1 + src/slic3r/GUI/OG_CustomCtrl.hpp | 1 - 44 files changed, 211 insertions(+), 264 deletions(-) diff --git a/src/libslic3r/ExtrusionRole.cpp b/src/libslic3r/ExtrusionRole.cpp index 1e91df204..01ec73ed1 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 9f4730261..1084e6f10 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 34594240f..5a608cb05 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 a38960324..c72855c88 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 09c157059..f80b9a2ba 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 65549d2e8..2fca25c96 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 de1807dbb..c434aa560 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/I18N.hpp b/src/libslic3r/I18N.hpp index db4fd22df..3bf286b19 100644 --- a/src/libslic3r/I18N.hpp +++ b/src/libslic3r/I18N.hpp @@ -15,4 +15,11 @@ namespace I18N { } // namespace Slic3r +namespace { + const char* L(const char* s) { return s; } + std::string _u8L(const char* s) { return Slic3r::I18N::translate(s); } + std::string _utf8(const char* s) { return Slic3r::I18N::translate(s); } + std::string _utf8(const std::string& s) { return Slic3r::I18N::translate(s); } +} + #endif /* slic3r_I18N_hpp_ */ diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index b36427175..3598d36ae 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 diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index f2143857a..0dd20ea93 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 { @@ -474,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) { @@ -496,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: @@ -524,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."); } } @@ -541,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()) { @@ -554,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(); @@ -578,14 +576,14 @@ 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); @@ -610,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; } } @@ -634,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 { @@ -647,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; @@ -661,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."); } @@ -669,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)."); } } @@ -709,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; @@ -735,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(); @@ -881,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) @@ -898,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. @@ -909,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(); @@ -957,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. @@ -1181,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; @@ -1312,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); diff --git a/src/libslic3r/PrintBase.cpp b/src/libslic3r/PrintBase.cpp index d9b3e9cda..01c0ecfaa 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 3255c015b..d52f38866 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; diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index aa1216a0f..eefedd143 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,7 @@ void PrintObject::infill() this->prepare_infill(); if (this->set_started(posInfill)) { - m_print->set_status(45, L("making infill")); + 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 +446,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 +471,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 +492,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 4cc5adff0..6f6080cb8 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 634cde469..56cecdccd 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 ec9e216f5..34a1b5dd3 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 3de05261a..d066e02bf 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 202da5e00..6dc4a4620 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 338130454..94ddcec72 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,14 @@ 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"); + 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 +73,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 +249,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 +264,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 +273,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 +283,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 +504,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 +685,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 +734,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 +743,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 +773,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 +781,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 +902,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 cebafa633..29ca264ca 100644 --- a/src/libslic3r/Zipper.cpp +++ b/src/libslic3r/Zipper.cpp @@ -8,7 +8,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) #if defined(_MSC_VER) && _MSC_VER <= 1800 || __cplusplus < 201103L #define SLIC3R_NORETURN @@ -24,7 +24,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 76b4cb4e5..b0eccbeb3 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/GUI/BedShapeDialog.cpp b/src/slic3r/GUI/BedShapeDialog.cpp index aadf605a1..759b17644 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 2f308a507..2c828a58f 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/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index b8956b948..65d08f195 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 diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 076bef54b..5d3b65632 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -5,7 +5,11 @@ #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). +#include "libslic3r/I18N.hpp" +#include "slic3r/GUI/I18N.hpp" #include #include @@ -44,7 +48,6 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/Model.hpp" -#include "libslic3r/I18N.hpp" #include "libslic3r/PresetBundle.hpp" #include "libslic3r/Color.hpp" @@ -2381,8 +2384,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); @@ -3461,7 +3464,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/Gizmos/GLGizmoBase.cpp b/src/slic3r/GUI/Gizmos/GLGizmoBase.cpp index a884a0589..770c3ac41 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 108b869da..9ed34b011 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 e9b6fa694..e4a7e9613 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" diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp index 794d0d339..02ed8d5b6 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" @@ -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.hpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.hpp index ebbdf616c..a57def86e 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.hpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.hpp index b79e1dda7..aee669199 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 947ef2df8..6cbec0891 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 80520651d..a3184371e 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" diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.hpp index 4652a171b..cc43b068e 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 67eccd8e8..ee32c4596 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 98f183b74..73615b463 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 3d88ad500..aa3d56ef9 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 345d733af..75b80d8f5 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 9e5191f65..063dce721 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 533683237..c1a6d7dfa 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.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.hpp index f95aad495..1a56b7791 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 4d76dfb04..18613cd8f 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 578858b5b..bb0513682 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/OG_CustomCtrl.hpp b/src/slic3r/GUI/OG_CustomCtrl.hpp index 0308322f7..269f847a2 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__ From 73857703b8df3fcccd9dad28f0734d1cd9dec38b Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 15 Mar 2023 09:21:12 +0100 Subject: [PATCH 04/25] Added a check that libslic3r/I18N.hpp is not included on the frontend by mistake, also added a check that L macro is not defined when including libslic3r/I18N.hpp --- src/libslic3r/I18N.hpp | 25 +++++++++++++++++++------ src/slic3r/CMakeLists.txt | 3 +++ src/slic3r/GUI/GUI_App.cpp | 4 ++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/libslic3r/I18N.hpp b/src/libslic3r/I18N.hpp index 3bf286b19..51d41a3ea 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,11 +21,18 @@ namespace I18N { } // namespace Slic3r -namespace { - const char* L(const char* s) { return s; } - std::string _u8L(const char* s) { return Slic3r::I18N::translate(s); } - std::string _utf8(const char* s) { return Slic3r::I18N::translate(s); } - std::string _utf8(const std::string& s) { return Slic3r::I18N::translate(s); } -} +// 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; } + std::string _u8L(const char* s) { return Slic3r::I18N::translate(s); } + std::string _utf8(const char* s) { return Slic3r::I18N::translate(s); } + std::string _utf8(const std::string& s) { return Slic3r::I18N::translate(s); } + } +#endif #endif /* slic3r_I18N_hpp_ */ diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 2ca1998e3..db8cefa99 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/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 5d3b65632..4be6de6e1 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -8,7 +8,11 @@ // 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 From 472090a54df9a6a5880805bcbe00d59813976503 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 15 Mar 2023 09:37:12 +0100 Subject: [PATCH 05/25] Fix: file containing localization was missing in list.txt --- resources/localization/list.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/localization/list.txt b/resources/localization/list.txt index 1c67fb49f..b239c8d9a 100644 --- a/resources/localization/list.txt +++ b/resources/localization/list.txt @@ -113,3 +113,4 @@ src/libslic3r/PrintBase.cpp src/libslic3r/PrintConfig.cpp src/libslic3r/Zipper.cpp src/libslic3r/PrintObject.cpp +src/libslic3r/PrintObjectSlice.cpp From f9de995f9e6b8d64efde122563abee67148a1fb7 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 17 Mar 2023 09:28:13 +0100 Subject: [PATCH 06/25] Remove '_utf8' makro. (Initially, it was used because of using of boost::format for localized lines. But now It's better to use format and formal_wxstr functions) + Fixed missed marks for localization + Added missed filed to localization to the list.txt --- resources/localization/list.txt | 2 ++ src/libslic3r/AppConfig.cpp | 6 ---- src/libslic3r/I18N.hpp | 2 -- src/libslic3r/Zipper.cpp | 4 --- src/slic3r/GUI/AboutDialog.cpp | 33 +++++++++--------- src/slic3r/GUI/BackgroundSlicingProcess.cpp | 36 +++++++++---------- src/slic3r/GUI/BonjourDialog.cpp | 6 ++-- src/slic3r/GUI/ConfigSnapshotDialog.cpp | 4 +-- src/slic3r/GUI/ConfigWizard.cpp | 20 +++++------ src/slic3r/GUI/DoubleSlider.cpp | 2 +- src/slic3r/GUI/Field.cpp | 11 +++--- src/slic3r/GUI/GLCanvas3D.cpp | 38 ++++++++++----------- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/GUI_Factories.cpp | 6 ++-- src/slic3r/GUI/GUI_ObjectSettings.cpp | 4 +-- src/slic3r/GUI/HintNotification.cpp | 8 ++--- src/slic3r/GUI/I18N.hpp | 1 - src/slic3r/GUI/Jobs/RotoptimizeJob.cpp | 10 ++++++ src/slic3r/GUI/Jobs/RotoptimizeJob.hpp | 10 ++---- src/slic3r/GUI/Jobs/SLAImportDialog.hpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 4 +-- src/slic3r/GUI/NotificationManager.cpp | 4 +-- src/slic3r/GUI/OpenGLManager.cpp | 17 +++++---- src/slic3r/GUI/Plater.cpp | 22 ++++++------ src/slic3r/GUI/PresetHints.cpp | 36 +++++++++---------- src/slic3r/GUI/PrintHostDialogs.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 18 +++++----- src/slic3r/GUI/UpdateDialogs.cpp | 11 +++--- src/slic3r/GUI/wxExtensions.cpp | 5 ++- src/slic3r/Utils/AppUpdater.cpp | 22 ++++++------ src/slic3r/Utils/AstroBox.cpp | 10 +++--- src/slic3r/Utils/Duet.cpp | 4 +-- src/slic3r/Utils/FlashAir.cpp | 8 ++--- src/slic3r/Utils/MKS.cpp | 4 +-- src/slic3r/Utils/OctoPrint.cpp | 26 ++++++-------- src/slic3r/Utils/Repetier.cpp | 14 ++++---- 36 files changed, 195 insertions(+), 219 deletions(-) diff --git a/resources/localization/list.txt b/resources/localization/list.txt index b239c8d9a..875e92721 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 diff --git a/src/libslic3r/AppConfig.cpp b/src/libslic3r/AppConfig.cpp index be16a2015..f88b80c92 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/I18N.hpp b/src/libslic3r/I18N.hpp index 51d41a3ea..ee39df2e1 100644 --- a/src/libslic3r/I18N.hpp +++ b/src/libslic3r/I18N.hpp @@ -30,8 +30,6 @@ namespace I18N { namespace { const char* L(const char* s) { return s; } std::string _u8L(const char* s) { return Slic3r::I18N::translate(s); } - std::string _utf8(const char* s) { return Slic3r::I18N::translate(s); } - std::string _utf8(const std::string& s) { return Slic3r::I18N::translate(s); } } #endif diff --git a/src/libslic3r/Zipper.cpp b/src/libslic3r/Zipper.cpp index 29ca264ca..53c39c3a7 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 _u8L(s) Slic3r::I18N::translate(s) - #if defined(_MSC_VER) && _MSC_VER <= 1800 || __cplusplus < 201103L #define SLIC3R_NORETURN #elif __cplusplus >= 201103L diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index 823a315b7..132159ff5 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()); @@ -211,7 +211,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 +267,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")); + const wxString copyright_str = _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 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 +287,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 234825508..9ee6946c6 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/BonjourDialog.cpp b/src/slic3r/GUI/BonjourDialog.cpp index 9298aa615..060643c1f 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/ConfigSnapshotDialog.cpp b/src/slic3r/GUI/ConfigSnapshotDialog.cpp index e2bea55d1..c1817a3ba 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 65d08f195..aa2de94af 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -289,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) { @@ -509,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)")) @@ -577,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) { diff --git a/src/slic3r/GUI/DoubleSlider.cpp b/src/slic3r/GUI/DoubleSlider.cpp index 99b8d73d5..a0816c22f 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/Field.cpp b/src/slic3r/GUI/Field.cpp index c6ffa46ec..74ad028d3 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/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6924667e6..dcc85dc65 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); } } @@ -4711,7 +4711,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)) @@ -4719,7 +4719,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(); }; @@ -4728,7 +4728,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(); }; @@ -4737,7 +4737,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(); }; @@ -4757,7 +4757,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(); }; @@ -4766,7 +4766,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(); }; @@ -4778,7 +4778,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; }; @@ -4789,7 +4789,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; }; @@ -4802,7 +4802,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; @@ -4812,7 +4812,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; }; @@ -4826,8 +4826,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") || @@ -4843,7 +4843,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) { @@ -4865,7 +4865,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 { @@ -4918,7 +4918,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; @@ -4940,7 +4940,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) { @@ -4955,7 +4955,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; }; @@ -4976,7 +4976,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 4be6de6e1..fe1fd2012 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -3440,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(); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index df8ace79a..4887d3dcf 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); } diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 97eb5f10d..41cad8792 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/HintNotification.cpp b/src/slic3r/GUI/HintNotification.cpp index 1f3d22491..95583a3cd 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 7bad6880e..8616628ea 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/RotoptimizeJob.cpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.cpp index 0980326d3..d33bee1a8 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 71a28deb7..02aafb551 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 5477e51e7..fed84600c 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/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index eccd96e20..071260ac2 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -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); @@ -1778,7 +1778,7 @@ 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()), + 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 ab465a577..c96ed4dbc 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/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp index ecf0c5790..6960d0a75 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/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 6a17c4ee5..08067c568 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1376,7 +1376,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 +1466,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") { @@ -2343,8 +2343,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); @@ -4251,7 +4251,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 +4558,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 +4566,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)) @@ -5437,7 +5437,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("%s - Multiple projects file"), SLIC3R_APP_NAME), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) { SetFont(wxGetApp().normal_font()); @@ -5557,7 +5557,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 +5826,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(_L("%s - Load project file"), SLIC3R_APP_NAME), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) { SetFont(wxGetApp().normal_font()); diff --git a/src/slic3r/GUI/PresetHints.cpp b/src/slic3r/GUI/PresetHints.cpp index ce709d9eb..15017ba93 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 f986a1552..b381024aa 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -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/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 6e4f64a99..3cdd84662 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -164,8 +164,8 @@ void Tab::create_preset_tab() 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())); + m_btn_save_preset->SetToolTip(format_wxstr(_L("Save current %s"), m_title)); + m_btn_rename_preset->SetToolTip(format_wxstr(_L("Rename current %s"), m_title)); m_btn_rename_preset->Hide(); m_btn_delete_preset->SetToolTip(_(L("Delete this preset"))); m_btn_delete_preset->Hide(); @@ -3924,7 +3924,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")); + wxString action = current_preset.is_external ? _L("remove") : _L("delete"); // TRN remove/delete PhysicalPrinterCollection& physical_printers = m_preset_bundle->physical_printers; @@ -3973,9 +3973,9 @@ void Tab::delete_preset() 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")); + action = current_preset.is_external ? _L("Remove") : _L("Delete"); // TRN Remove/Delete - wxString title = from_u8((boost::format(_utf8(L("%1% Preset"))) % action).str()); //action + _(L(" Preset")); + 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()) @@ -4061,7 +4061,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()); @@ -5024,9 +5024,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/UpdateDialogs.cpp b/src/slic3r/GUI/UpdateDialogs.cpp index 2b473ae0c..0d4dc576d 100644 --- a/src/slic3r/GUI/UpdateDialogs.cpp +++ b/src/slic3r/GUI/UpdateDialogs.cpp @@ -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 d4bd27c05..f67ad287a 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 9eb012827..4c60f018e 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 a2b5bca04..e7044ad20 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 229d0c950..74bf080cd 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 e54dca58f..157d9623f 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 109283fc6..cce212631 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 413a3445a..d8d977c05 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&) { @@ -821,7 +817,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 +890,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; } diff --git a/src/slic3r/Utils/Repetier.cpp b/src/slic3r/Utils/Repetier.cpp index e266be1f8..274ea4351 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())); From 18e56c3d532d02662bb8e399cd0fd40578031a0a Mon Sep 17 00:00:00 2001 From: YuSanka Date: Mon, 20 Mar 2023 10:40:42 +0100 Subject: [PATCH 07/25] Localization: Fixes for some phrases + Added/Fixed comments where it's needed --- src/libslic3r/I18N.hpp | 1 + src/libslic3r/PrintConfig.cpp | 42 ++++++++++++++------ src/libslic3r/PrintObject.cpp | 3 +- src/libslic3r/SLAPrintSteps.cpp | 1 + src/slic3r/GUI/AboutDialog.cpp | 3 +- src/slic3r/GUI/ButtonsDescription.cpp | 2 +- src/slic3r/GUI/ConfigWizard.cpp | 25 +++++++----- src/slic3r/GUI/Downloader.cpp | 2 +- src/slic3r/GUI/DownloaderFileGet.cpp | 1 + src/slic3r/GUI/GUI_App.cpp | 4 +- src/slic3r/GUI/GUI_ObjectList.cpp | 7 ++-- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 5 +-- src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | 10 +++-- src/slic3r/GUI/Gizmos/GLGizmoCut.hpp | 2 +- src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp | 39 +++++++++--------- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp | 4 +- src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp | 4 +- src/slic3r/GUI/Jobs/EmbossJob.cpp | 18 ++++----- src/slic3r/GUI/Jobs/SLAImportJob.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 8 ++-- src/slic3r/GUI/NotificationManager.cpp | 2 +- src/slic3r/GUI/OG_CustomCtrl.cpp | 10 ++--- src/slic3r/GUI/OptionsGroup.cpp | 4 +- src/slic3r/GUI/Plater.cpp | 14 +++---- src/slic3r/GUI/Preferences.cpp | 9 +---- src/slic3r/GUI/PrintHostDialogs.cpp | 4 +- src/slic3r/GUI/SavePresetDialog.cpp | 9 ++++- src/slic3r/GUI/SurfaceDrag.cpp | 1 + src/slic3r/GUI/Tab.cpp | 11 ++--- src/slic3r/GUI/UpdateDialogs.cpp | 8 ++-- src/slic3r/Utils/OctoPrint.cpp | 15 ++++--- 32 files changed, 149 insertions(+), 124 deletions(-) diff --git a/src/libslic3r/I18N.hpp b/src/libslic3r/I18N.hpp index ee39df2e1..3cc196b6a 100644 --- a/src/libslic3r/I18N.hpp +++ b/src/libslic3r/I18N.hpp @@ -29,6 +29,7 @@ namespace I18N { #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 diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index d52f38866..22f296456 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -399,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."); @@ -456,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"); @@ -465,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."); @@ -533,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. " @@ -580,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)"); @@ -1961,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)); @@ -2299,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)); @@ -2464,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."); @@ -2641,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" } @@ -2722,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)") }, @@ -2824,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."); @@ -2855,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("°"); @@ -2866,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("°"); @@ -2877,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; @@ -2886,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"); @@ -2894,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."); @@ -2909,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."); @@ -2920,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 " @@ -3008,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"); @@ -3017,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." @@ -3874,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/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index eefedd143..7136617d8 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -399,7 +399,8 @@ void PrintObject::infill() this->prepare_infill(); if (this->set_started(posInfill)) { - m_print->set_status(45, _u8L("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; diff --git a/src/libslic3r/SLAPrintSteps.cpp b/src/libslic3r/SLAPrintSteps.cpp index 94ddcec72..5ef8a2709 100644 --- a/src/libslic3r/SLAPrintSteps.cpp +++ b/src/libslic3r/SLAPrintSteps.cpp @@ -51,6 +51,7 @@ const std::array OBJ_STEP_LEVELS = { std::string OBJ_STEP_LABELS(size_t idx) { switch (idx) { + // 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."); diff --git a/src/slic3r/GUI/AboutDialog.cpp b/src/slic3r/GUI/AboutDialog.cpp index 132159ff5..0d59f4433 100644 --- a/src/slic3r/GUI/AboutDialog.cpp +++ b/src/slic3r/GUI/AboutDialog.cpp @@ -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( @@ -268,7 +267,7 @@ AboutDialog::AboutDialog() m_html->SetFonts(font.GetFaceName(), font.GetFaceName(), size); m_html->SetBorders(2); const wxString copyright_str = _L("Copyright"); - // TRN "Slic3r _is licensed under the_ License" + // 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."); diff --git a/src/slic3r/GUI/ButtonsDescription.cpp b/src/slic3r/GUI/ButtonsDescription.cpp index e225c7db7..e6fd519df 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/ConfigWizard.cpp b/src/slic3r/GUI/ConfigWizard.cpp index aa2de94af..4aa8c9df6 100644 --- a/src/slic3r/GUI/ConfigWizard.cpp +++ b/src/slic3r/GUI/ConfigWizard.cpp @@ -787,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( "" @@ -1369,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()); }); @@ -1421,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( @@ -1456,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; @@ -1753,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)) { @@ -1793,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); @@ -1829,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); @@ -1843,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); @@ -1935,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/Downloader.cpp b/src/slic3r/GUI/Downloader.cpp index 45ea43631..3d2a00106 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 ee407afdd..ee6455259 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/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index fe1fd2012..1d4a53fd9 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1988,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); @@ -2416,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); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index ae0e54b45..ad2758f9e 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 415f008fb..7d9a87b58 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/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp index e4a7e9613..410cf6753 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp @@ -182,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") }; @@ -231,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"); @@ -1671,7 +1671,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(); @@ -1778,9 +1778,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 02ed8d5b6..ee804686e 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.hpp @@ -151,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; diff --git a/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp b/src/slic3r/GUI/Gizmos/GLGizmoEmboss.cpp index dd18cb878..8c4b4ff70 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/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index 0c89d7620..d5520403c 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/GLGizmoMeasure.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp index a3184371e..e8f6ad4af 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMeasure.cpp @@ -1537,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(); @@ -1736,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/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 90552c0a5..d60784758 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/Jobs/EmbossJob.cpp b/src/slic3r/GUI/Jobs/EmbossJob.cpp index f5c315b30..208cb2c0b 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/SLAImportJob.cpp b/src/slic3r/GUI/Jobs/SLAImportJob.cpp index 2da3ad5b5..0b3c4cb28 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 071260ac2..dd2a90ebd 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -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); } @@ -1777,7 +1777,7 @@ void MainFrame::quick_slice(const int qs) // show processbar dialog m_progress_dialog = new wxProgressDialog(_L("Slicing") + dots, - // TRN "Processing input_file_basename" + // 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 c96ed4dbc..3f7e58b7e 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -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, _u8L("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 d18df6bb2..a3cb345b4 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/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index e567ac7c6..614fda913 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 08067c568..8732251e6 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3033,8 +3033,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")); @@ -5437,7 +5437,7 @@ protected: LoadProjectsDialog::LoadProjectsDialog(const std::vector& paths) : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, - format_wxstr(_L("%s - Multiple projects file"), SLIC3R_APP_NAME), wxDefaultPosition, + format_wxstr(_L("%1% - Multiple projects file"), SLIC3R_APP_NAME), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) { SetFont(wxGetApp().normal_font()); @@ -5826,7 +5826,7 @@ protected: ProjectDropDialog::ProjectDropDialog(const std::string& filename) : DPIDialog(static_cast(wxGetApp().mainframe), wxID_ANY, - format_wxstr(_L("%s - Load project file"), SLIC3R_APP_NAME), wxDefaultPosition, + format_wxstr("%1% - %2%", SLIC3R_APP_NAME, _L("Load project file")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE) { SetFont(wxGetApp().normal_font()); @@ -5934,7 +5934,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; @@ -5951,11 +5951,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 0d5bf0f8c..492e3fc37 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/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index b381024aa..74bbe2ada 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(); } diff --git a/src/slic3r/GUI/SavePresetDialog.cpp b/src/slic3r/GUI/SavePresetDialog.cpp index d4c2ba58c..33f41b9c4 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 ecee0a4e0..a202ae5de 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 3cdd84662..6382fb0ae 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" + // TRN Settings Tabs: Tooltip for save button: "Settings" m_btn_save_preset->SetToolTip(format_wxstr(_L("Save current %s"), m_title)); - m_btn_rename_preset->SetToolTip(format_wxstr(_L("Rename 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(); @@ -3925,7 +3926,6 @@ void Tab::delete_preset() auto current_preset = m_presets->get_selected_preset(); // Don't let the user delete the ' - default - ' configuration. wxString action = current_preset.is_external ? _L("remove") : _L("delete"); - // TRN remove/delete PhysicalPrinterCollection& physical_printers = m_preset_bundle->physical_printers; wxString msg; @@ -3969,12 +3969,13 @@ 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 ? _L("Remove") : _L("Delete"); - // TRN Remove/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()) diff --git a/src/slic3r/GUI/UpdateDialogs.cpp b/src/slic3r/GUI/UpdateDialogs.cpp index 0d4dc576d..dea01eb8f 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())) diff --git a/src/slic3r/Utils/OctoPrint.cpp b/src/slic3r/Utils/OctoPrint.cpp index d8d977c05..540852af8 100644 --- a/src/slic3r/Utils/OctoPrint.cpp +++ b/src/slic3r/Utils/OctoPrint.cpp @@ -769,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); } @@ -1138,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); } } From f57de436804a881a4bc45796a23a4dfd0eb5d2a3 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 7 Mar 2023 15:53:39 +0100 Subject: [PATCH 08/25] Fixed several more warnings --- src/libslic3r/Geometry/VoronoiUtilsCgal.cpp | 2 +- src/libslic3r/PrintConfig.cpp | 2 +- src/slic3r/GUI/GUI_Factories.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 4 ++-- src/slic3r/GUI/Plater.cpp | 3 ++- src/slic3r/GUI/UnsavedChangesDialog.cpp | 4 ++-- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/Geometry/VoronoiUtilsCgal.cpp b/src/libslic3r/Geometry/VoronoiUtilsCgal.cpp index c3348110b..832152c5f 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/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 22f296456..ed1a08b57 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -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."); diff --git a/src/slic3r/GUI/GUI_Factories.cpp b/src/slic3r/GUI/GUI_Factories.cpp index 4887d3dcf..60049c865 100644 --- a/src/slic3r/GUI/GUI_Factories.cpp +++ b/src/slic3r/GUI/GUI_Factories.cpp @@ -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/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index dd2a90ebd..0c7805db8 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); }); } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 8732251e6..3595276af 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 | @@ -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) { diff --git a/src/slic3r/GUI/UnsavedChangesDialog.cpp b/src/slic3r/GUI/UnsavedChangesDialog.cpp index 8e3fa7874..d7d4798c2 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 From 5d89e742b41ba5e38f8b3b5dbeb648aceecd6c54 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 24 Mar 2023 09:27:12 +0100 Subject: [PATCH 09/25] Added missed includes of "format.hpp" --- src/slic3r/GUI/ConfigSnapshotDialog.cpp | 1 + src/slic3r/GUI/OpenGLManager.cpp | 1 + src/slic3r/GUI/wxExtensions.cpp | 1 + src/slic3r/Utils/AstroBox.cpp | 1 + src/slic3r/Utils/Duet.cpp | 1 + src/slic3r/Utils/FlashAir.cpp | 1 + src/slic3r/Utils/MKS.cpp | 1 + 7 files changed, 7 insertions(+) diff --git a/src/slic3r/GUI/ConfigSnapshotDialog.cpp b/src/slic3r/GUI/ConfigSnapshotDialog.cpp index c1817a3ba..77193c857 100644 --- a/src/slic3r/GUI/ConfigSnapshotDialog.cpp +++ b/src/slic3r/GUI/ConfigSnapshotDialog.cpp @@ -9,6 +9,7 @@ #include "GUI_App.hpp" #include "MainFrame.hpp" #include "wxExtensions.hpp" +#include "format.hpp" namespace Slic3r { namespace GUI { diff --git a/src/slic3r/GUI/OpenGLManager.cpp b/src/slic3r/GUI/OpenGLManager.cpp index 6960d0a75..447da442e 100644 --- a/src/slic3r/GUI/OpenGLManager.cpp +++ b/src/slic3r/GUI/OpenGLManager.cpp @@ -7,6 +7,7 @@ #endif // ENABLE_GL_CORE_PROFILE #include "I18N.hpp" #include "3DScene.hpp" +#include "format.hpp" #include "libslic3r/Platform.hpp" diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index f67ad287a..a8da90024 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -18,6 +18,7 @@ #include "BitmapComboBox.hpp" #include "libslic3r/Utils.hpp" #include "OG_CustomCtrl.hpp" +#include "format.hpp" #include "libslic3r/Color.hpp" diff --git a/src/slic3r/Utils/AstroBox.cpp b/src/slic3r/Utils/AstroBox.cpp index e7044ad20..46bb69b20 100644 --- a/src/slic3r/Utils/AstroBox.cpp +++ b/src/slic3r/Utils/AstroBox.cpp @@ -14,6 +14,7 @@ #include "libslic3r/PrintConfig.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/GUI.hpp" +#include "slic3r/GUI/format.hpp" #include "Http.hpp" diff --git a/src/slic3r/Utils/Duet.cpp b/src/slic3r/Utils/Duet.cpp index 74bf080cd..e77ebc858 100644 --- a/src/slic3r/Utils/Duet.cpp +++ b/src/slic3r/Utils/Duet.cpp @@ -20,6 +20,7 @@ #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/MsgDialog.hpp" +#include "slic3r/GUI/format.hpp" #include "Http.hpp" namespace fs = boost::filesystem; diff --git a/src/slic3r/Utils/FlashAir.cpp b/src/slic3r/Utils/FlashAir.cpp index 157d9623f..51fd6b904 100644 --- a/src/slic3r/Utils/FlashAir.cpp +++ b/src/slic3r/Utils/FlashAir.cpp @@ -19,6 +19,7 @@ #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/MsgDialog.hpp" +#include "slic3r/GUI/format.hpp" #include "Http.hpp" namespace fs = boost::filesystem; diff --git a/src/slic3r/Utils/MKS.cpp b/src/slic3r/Utils/MKS.cpp index cce212631..826476757 100644 --- a/src/slic3r/Utils/MKS.cpp +++ b/src/slic3r/Utils/MKS.cpp @@ -24,6 +24,7 @@ #include "slic3r/GUI/GUI.hpp" #include "slic3r/GUI/I18N.hpp" #include "slic3r/GUI/MsgDialog.hpp" +#include "slic3r/GUI/format.hpp" #include "Http.hpp" namespace fs = boost::filesystem; From cf226f8eabd513f31ea3dd41631547f1e23567b9 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 8 Mar 2023 19:34:41 +0100 Subject: [PATCH 10/25] Added 'travel_acceleration' configuration option (not used so far) --- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/Print.cpp | 1 + src/libslic3r/PrintConfig.cpp | 10 +++++++++- src/libslic3r/PrintConfig.hpp | 1 + src/slic3r/GUI/ConfigManipulation.cpp | 2 +- src/slic3r/GUI/Tab.cpp | 1 + 6 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 3598d36ae..21b712217 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -434,7 +434,7 @@ static std::vector s_Preset_print_options { "enable_dynamic_overhang_speeds", "overhang_speed_0", "overhang_speed_1", "overhang_speed_2", "overhang_speed_3", "top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed", "bridge_speed", "gap_fill_speed", "gap_fill_enabled", "travel_speed", "travel_speed_z", "first_layer_speed", "first_layer_speed_over_raft", "perimeter_acceleration", "infill_acceleration", - "external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration", + "external_perimeter_acceleration", "top_solid_infill_acceleration", "solid_infill_acceleration", "travel_acceleration", "bridge_acceleration", "first_layer_acceleration", "first_layer_acceleration_over_raft", "default_acceleration", "skirts", "skirt_distance", "skirt_height", "draft_shield", "min_skirt_length", "brim_width", "brim_separation", "brim_type", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers", "raft_layers", "raft_first_layer_density", "raft_first_layer_expansion", "raft_contact_distance", "raft_expansion", diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 0dd20ea93..afc039bdd 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -137,6 +137,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n "start_filament_gcode", "toolchange_gcode", "top_solid_infill_acceleration", + "travel_acceleration", "thumbnails", "thumbnails_format", "use_firmware_retraction", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index ed1a08b57..ce5aa69b5 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1463,7 +1463,15 @@ void PrintConfigDef::init_fff_params() def->min = 0; def->mode = comExpert; def->set_default_value(new ConfigOptionFloat(0)); - + + def = this->add("travel_acceleration", coFloat); + def->label = L("Travel"); + def->tooltip = L("This is the acceleration your printer will use for travel moves. Set zero to disable " + "acceleration control for travel."); + def->sidetext = L("mm/s²"); + def->min = 0; + def->mode = comExpert; + def->set_default_value(new ConfigOptionFloat(0)); def = this->add("infill_every_layers", coInt); def->label = L("Combine infill every"); diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 52924bf91..17f5e501c 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -815,6 +815,7 @@ PRINT_CONFIG_CLASS_DERIVED_DEFINE( ((ConfigOptionPoints, thumbnails)) ((ConfigOptionEnum, thumbnails_format)) ((ConfigOptionFloat, top_solid_infill_acceleration)) + ((ConfigOptionFloat, travel_acceleration)) ((ConfigOptionBools, wipe)) ((ConfigOptionBool, wipe_tower)) ((ConfigOptionFloat, wipe_tower_x)) diff --git a/src/slic3r/GUI/ConfigManipulation.cpp b/src/slic3r/GUI/ConfigManipulation.cpp index 1bc2280d5..4c5b0fd8e 100644 --- a/src/slic3r/GUI/ConfigManipulation.cpp +++ b/src/slic3r/GUI/ConfigManipulation.cpp @@ -256,7 +256,7 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig* config) bool have_default_acceleration = config->opt_float("default_acceleration") > 0; for (auto el : { "perimeter_acceleration", "infill_acceleration", "top_solid_infill_acceleration", - "solid_infill_acceleration", "external_perimeter_acceleration" + "solid_infill_acceleration", "external_perimeter_acceleration", "bridge_acceleration", "first_layer_acceleration" }) toggle_field(el, have_default_acceleration); diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 6382fb0ae..dc3100eb2 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -1573,6 +1573,7 @@ void TabPrint::build() optgroup->append_single_option_line("bridge_acceleration"); optgroup->append_single_option_line("first_layer_acceleration"); optgroup->append_single_option_line("first_layer_acceleration_over_raft"); + optgroup->append_single_option_line("travel_acceleration"); optgroup->append_single_option_line("default_acceleration"); optgroup = page->new_optgroup(L("Autospeed (advanced)")); From 3ff600bed07770d7afc5c59c0cf43061a831dd21 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 9 Mar 2023 09:14:54 +0100 Subject: [PATCH 11/25] Separated travel and print acceleration control --- src/libslic3r/GCode.cpp | 18 ++++++++++++---- src/libslic3r/GCodeWriter.cpp | 39 +++++++++++++++++------------------ src/libslic3r/GCodeWriter.hpp | 15 ++++++++++++-- 3 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 2fca25c96..a9d7da76d 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2547,7 +2547,7 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, const std::string_view descr } // reset acceleration - gcode += m_writer.set_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5)); + gcode += m_writer.set_print_acceleration((unsigned int)(m_config.default_acceleration.value + 0.5)); if (m_wipe.enable) { m_wipe.path = paths.front().polyline; @@ -2633,7 +2633,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, const std::s } } // reset acceleration - gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); + gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); return gcode; } @@ -2659,7 +2659,7 @@ std::string GCode::extrude_path(ExtrusionPath path, std::string_view description m_wipe.path.reverse(); } // reset acceleration - gcode += m_writer.set_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); + gcode += m_writer.set_print_acceleration((unsigned int)floor(m_config.default_acceleration.value + 0.5)); return gcode; } @@ -2802,7 +2802,7 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de } else { acceleration = m_config.default_acceleration.value; } - gcode += m_writer.set_acceleration((unsigned int)floor(acceleration + 0.5)); + gcode += m_writer.set_print_acceleration((unsigned int)floor(acceleration + 0.5)); } // calculate extrusion length per distance unit @@ -3071,8 +3071,18 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string // use G1 because we rely on paths being straight (G0 may make round paths) if (travel.size() >= 2) { + + gcode += m_writer.set_travel_acceleration((unsigned int)(m_config.travel_acceleration.value + 0.5)); + for (size_t i = 1; i < travel.size(); ++ i) gcode += m_writer.travel_to_xy(this->point_to_gcode(travel.points[i]), comment); + + if (! m_writer.supports_PT()) { + // In case that this flavor does not support separate print and travel acceleration, + // reset acceleration to default. + gcode += m_writer.set_travel_acceleration((unsigned int)(m_config.travel_acceleration.value + 0.5)); + } + this->set_last_pos(travel.points.back()); } return gcode; diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index c2caf5766..b323ae8b2 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -15,6 +15,11 @@ namespace Slic3r { +bool GCodeWriter::supports_PT() const +{ + return (FLAVOR_IS(gcfRepetier) || FLAVOR_IS(gcfMarlinFirmware) || FLAVOR_IS(gcfRepRapFirmware)); +} + void GCodeWriter::apply_print_config(const PrintConfig &print_config) { this->config.apply(print_config, true); @@ -154,36 +159,30 @@ std::string GCodeWriter::set_bed_temperature(unsigned int temperature, bool wait return gcode.str(); } -std::string GCodeWriter::set_acceleration(unsigned int acceleration) +std::string GCodeWriter::set_acceleration_internal(Acceleration type, unsigned int acceleration) { // Clamp the acceleration to the allowed maximum. + // TODO: What about max travel acceleration ? Currently it is clamped by the extruding acceleration !!! if (m_max_acceleration > 0 && acceleration > m_max_acceleration) acceleration = m_max_acceleration; - if (acceleration == 0 || acceleration == m_last_acceleration) + // Are we setting travel acceleration for a flavour that supports separate travel and print acc? + bool separate_travel = (type == Acceleration::Travel && supports_PT()); + + auto& last_value = separate_travel ? m_last_travel_acceleration : m_last_acceleration ; + if (acceleration == 0 || acceleration == last_value) return std::string(); - m_last_acceleration = acceleration; + last_value = acceleration; std::ostringstream gcode; - if (FLAVOR_IS(gcfRepetier)) { - // M201: Set max printing acceleration - gcode << "M201 X" << acceleration << " Y" << acceleration; - if (this->config.gcode_comments) gcode << " ; adjust acceleration"; - gcode << "\n"; - // M202: Set max travel acceleration - gcode << "M202 X" << acceleration << " Y" << acceleration; - } else if (FLAVOR_IS(gcfRepRapFirmware)) { - // M204: Set default acceleration - gcode << "M204 P" << acceleration; - } else if (FLAVOR_IS(gcfMarlinFirmware)) { - // This is new MarlinFirmware with separated print/retraction/travel acceleration. - // Use M204 P, we don't want to override travel acc by M204 S (which is deprecated anyway). - gcode << "M204 P" << acceleration; - } else { - // M204: Set default acceleration + if (FLAVOR_IS(gcfRepetier)) + gcode << (separate_travel ? "M202 X" : "M201 X") << acceleration << " Y" << acceleration; + else if (FLAVOR_IS(gcfRepRapFirmware) || FLAVOR_IS(gcfMarlinFirmware)) + gcode << (separate_travel ? "M204 T" : "M204 P") << acceleration; + else gcode << "M204 S" << acceleration; - } + if (this->config.gcode_comments) gcode << " ; adjust acceleration"; gcode << "\n"; diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 6c36c0d3a..2a2a488fa 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -43,7 +43,8 @@ public: std::string postamble() const; std::string set_temperature(unsigned int temperature, bool wait = false, int tool = -1) const; std::string set_bed_temperature(unsigned int temperature, bool wait = false); - std::string set_acceleration(unsigned int acceleration); + std::string set_print_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Print, acceleration); } + std::string set_travel_acceleration(unsigned int acceleration) { return set_acceleration_internal(Acceleration::Travel, acceleration); } std::string reset_e(bool force = false); std::string update_progress(unsigned int num, unsigned int tot, bool allow_100 = false) const; // return false if this extruder was already selected @@ -69,6 +70,9 @@ public: std::string unlift(); Vec3d get_position() const { return m_pos; } + // Returns whether this flavor supports separate print and travel acceleration. + bool supports_PT() const; + // To be called by the CoolingBuffer from another thread. static std::string set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed); // To be called by the main thread. It always emits the G-code, it does not remember the previous state. @@ -81,7 +85,8 @@ private: std::string m_extrusion_axis; bool m_single_extruder_multi_material; Extruder* m_extruder; - unsigned int m_last_acceleration; + unsigned int m_last_acceleration = (unsigned int)(-1); + unsigned int m_last_travel_acceleration = (unsigned int)(-1); // only used for flavors supporting separate print/travel acc // Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware. // If set to zero, the limit is not in action. unsigned int m_max_acceleration; @@ -90,8 +95,14 @@ private: double m_lifted; Vec3d m_pos = Vec3d::Zero(); + enum class Acceleration { + Travel, + Print + }; + std::string _travel_to_z(double z, const std::string &comment); std::string _retract(double length, double restart_extra, const std::string &comment); + std::string set_acceleration_internal(Acceleration type, unsigned int acceleration); }; class GCodeFormatter { From 42f1217f6eb12783f9a0c864e62e6cecb1200527 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 9 Mar 2023 14:05:04 +0100 Subject: [PATCH 12/25] Klipper: Adding the new firmware flavor: - added the new option - allowed machine limits page - added a check for Klipper + 'emit limits to gcode' (Print::validate so far) --- src/libslic3r/Print.cpp | 4 ++++ src/libslic3r/PrintConfig.cpp | 7 +++++-- src/libslic3r/PrintConfig.hpp | 2 +- src/slic3r/GUI/Tab.cpp | 5 +++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index afc039bdd..febc4956d 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -502,6 +502,10 @@ std::string Print::validate(std::string* warning) const return _u8L("The Spiral Vase option can only be used when printing single material objects."); } + if (m_config.machine_limits_usage == MachineLimitsUsage::EmitToGCode && m_config.gcode_flavor == gcfKlipper) + return L("Machine limits cannot be emitted to G-Code when Klipper firmware flavor is used. " + "Change the value of machine_limits_usage."); + // Cache of layer height profiles for checking: // 1) Whether all layers are synchronized if printing with wipe tower and / or unsynchronized supports. // 2) Whether layer height is constant for Organic supports. diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index ce5aa69b5..1adaa5430 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -48,6 +48,7 @@ static const t_config_enum_values s_keys_map_GCodeFlavor { { "makerware", gcfMakerWare }, { "marlin", gcfMarlinLegacy }, { "marlin2", gcfMarlinFirmware }, + { "klipper", gcfKlipper }, { "sailfish", gcfSailfish }, { "smoothie", gcfSmoothie }, { "mach3", gcfMach3 }, @@ -1406,6 +1407,7 @@ void PrintConfigDef::init_fff_params() { "makerware", "MakerWare (MakerBot)" }, { "marlin", "Marlin (legacy)" }, { "marlin2", "Marlin 2" }, + { "klipper", "Klipper" }, { "sailfish", "Sailfish (MakerBot)" }, { "mach3", "Mach3/LinuxCNC" }, { "machinekit", "Machinekit" }, @@ -4421,8 +4423,9 @@ std::string validate(const FullPrintConfig &cfg) cfg.gcode_flavor.value != gcfMarlinLegacy && cfg.gcode_flavor.value != gcfMarlinFirmware && cfg.gcode_flavor.value != gcfMachinekit && - cfg.gcode_flavor.value != gcfRepetier) - return "--use-firmware-retraction is only supported by Marlin, Smoothie, RepRapFirmware, Repetier and Machinekit firmware"; + cfg.gcode_flavor.value != gcfRepetier && + cfg.gcode_flavor.value != gcfKlipper) + return "--use-firmware-retraction is only supported by Marlin, Klipper, Smoothie, RepRapFirmware, Repetier and Machinekit firmware"; if (cfg.use_firmware_retraction.value) for (unsigned char wipe : cfg.wipe.values) diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 17f5e501c..3a602b7ac 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -32,7 +32,7 @@ namespace Slic3r { enum GCodeFlavor : unsigned char { - gcfRepRapSprinter, gcfRepRapFirmware, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlinLegacy, gcfMarlinFirmware, gcfSailfish, gcfMach3, gcfMachinekit, + gcfRepRapSprinter, gcfRepRapFirmware, gcfRepetier, gcfTeacup, gcfMakerWare, gcfMarlinLegacy, gcfMarlinFirmware, gcfKlipper, gcfSailfish, gcfMach3, gcfMachinekit, gcfSmoothie, gcfNoExtrusion, }; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index dc3100eb2..6227fc537 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2866,7 +2866,7 @@ void TabPrinter::build_unregular_pages(bool from_initial_build/* = false*/) { size_t n_before_extruders = 2; // Count of pages before Extruder pages auto flavor = m_config->option>("gcode_flavor")->value; - bool show_mach_limits = (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware); + bool show_mach_limits = (flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware || flavor == gcfKlipper); /* ! Freeze/Thaw in this function is needed to avoid call OnPaint() for erased pages * and be cause of application crash, when try to change Preset in moment, @@ -3102,7 +3102,8 @@ void TabPrinter::toggle_options() if (m_active_page->title() == "Machine limits" && m_machine_limits_description_line) { assert(flavor == gcfMarlinLegacy || flavor == gcfMarlinFirmware - || flavor == gcfRepRapFirmware); + || flavor == gcfRepRapFirmware + || flavor == gcfKlipper); const auto *machine_limits_usage = m_config->option>("machine_limits_usage"); bool enabled = machine_limits_usage->value != MachineLimitsUsage::Ignore; bool silent_mode = m_config->opt_bool("silent_mode"); From b9eb13dff917db302d03aa7278c9cc9801fea0a1 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 9 Mar 2023 15:03:32 +0100 Subject: [PATCH 13/25] Klipper: specific behaviour (GCodeProcessor, WipeTower). GCodeWriter should behave as Marlin(legacy). --- src/libslic3r/GCode/GCodeProcessor.cpp | 17 +++++++++-------- src/libslic3r/GCode/WipeTower.cpp | 11 ++++++++--- src/libslic3r/GCodeWriter.cpp | 1 + src/libslic3r/Print.cpp | 5 +++-- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index 71d723ca3..ead792662 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -568,10 +568,11 @@ void GCodeProcessor::apply_config(const PrintConfig& config) m_result.filament_cost[i] = static_cast(config.filament_cost.get_at(i)); } - if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware) && config.machine_limits_usage.value != MachineLimitsUsage::Ignore) { + if ((m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware || m_flavor == gcfKlipper) + && config.machine_limits_usage.value != MachineLimitsUsage::Ignore) { m_time_processor.machine_limits = reinterpret_cast(config); - if (m_flavor == gcfMarlinLegacy) { - // Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead. + if (m_flavor == gcfMarlinLegacy || m_flavor == gcfKlipper) { + // Legacy Marlin and Klipper don't have separate travel acceleration, they use the 'extruding' value instead. m_time_processor.machine_limits.machine_max_acceleration_travel = m_time_processor.machine_limits.machine_max_acceleration_extruding; } if (m_flavor == gcfRepRapFirmware) { @@ -788,7 +789,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) if (machine_limits_usage != nullptr) use_machine_limits = machine_limits_usage->value != MachineLimitsUsage::Ignore; - if (use_machine_limits && (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware)) { + if (use_machine_limits && (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware || m_flavor == gcfRepRapFirmware || m_flavor == gcfKlipper)) { const ConfigOptionFloats* machine_max_acceleration_x = config.option("machine_max_acceleration_x"); if (machine_max_acceleration_x != nullptr) m_time_processor.machine_limits.machine_max_acceleration_x.values = machine_max_acceleration_x->values; @@ -846,8 +847,8 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) m_time_processor.machine_limits.machine_max_acceleration_retracting.values = machine_max_acceleration_retracting->values; - // Legacy Marlin does not have separate travel acceleration, it uses the 'extruding' value instead. - const ConfigOptionFloats* machine_max_acceleration_travel = config.option(m_flavor == gcfMarlinLegacy + // Legacy Marlin and Klipper don't have separate travel acceleration, they use the 'extruding' value instead. + const ConfigOptionFloats* machine_max_acceleration_travel = config.option((m_flavor == gcfMarlinLegacy || m_flavor == gcfKlipper) ? "machine_max_acceleration_extruding" : "machine_max_acceleration_travel"); if (machine_max_acceleration_travel != nullptr) @@ -885,7 +886,7 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config) m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION; } - if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) { + if (m_flavor == gcfMarlinLegacy || m_flavor == gcfMarlinFirmware) { // No Klipper here, it does not support silent mode. const ConfigOptionBool* silent_mode = config.option("silent_mode"); if (silent_mode != nullptr) { if (silent_mode->value && m_time_processor.machine_limits.machine_max_acceleration_x.values.size() > 1) @@ -3244,7 +3245,7 @@ void GCodeProcessor::process_M205(const GCodeReader::GCodeLine& line) void GCodeProcessor::process_M220(const GCodeReader::GCodeLine& line) { - if (m_flavor != gcfMarlinLegacy && m_flavor != gcfMarlinFirmware) + if (m_flavor != gcfMarlinLegacy && m_flavor != gcfMarlinFirmware && m_flavor != gcfKlipper) return; if (line.has('B')) diff --git a/src/libslic3r/GCode/WipeTower.cpp b/src/libslic3r/GCode/WipeTower.cpp index 58af2da48..7fdbb6915 100644 --- a/src/libslic3r/GCode/WipeTower.cpp +++ b/src/libslic3r/GCode/WipeTower.cpp @@ -93,9 +93,12 @@ public: } WipeTowerWriter& disable_linear_advance() { - m_gcode += (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware - ? (std::string("M572 D") + std::to_string(m_current_tool) + " S0\n") - : std::string("M900 K0\n")); + if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware) + m_gcode += (std::string("M572 D") + std::to_string(m_current_tool) + " S0\n"); + else if (m_gcode_flavor == gcfKlipper) + m_gcode += "SET_PRESSURE_ADVANCE ADVANCE=0\n"; + else + m_gcode += "M900 K0\n"; return *this; } @@ -363,6 +366,8 @@ public: // Set digital trimpot motor WipeTowerWriter& set_extruder_trimpot(int current) { + if (m_gcode_flavor == gcfKlipper) + return *this; if (m_gcode_flavor == gcfRepRapSprinter || m_gcode_flavor == gcfRepRapFirmware) m_gcode += "M906 E"; else diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index b323ae8b2..45176baaa 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -58,6 +58,7 @@ std::string GCodeWriter::preamble() FLAVOR_IS(gcfRepRapFirmware) || FLAVOR_IS(gcfMarlinLegacy) || FLAVOR_IS(gcfMarlinFirmware) || + FLAVOR_IS(gcfKlipper) || FLAVOR_IS(gcfTeacup) || FLAVOR_IS(gcfRepetier) || FLAVOR_IS(gcfSmoothie)) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index febc4956d..2afe02517 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -562,8 +562,9 @@ std::string Print::validate(std::string* warning) const } 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 _u8L("The Wipe Tower is currently only supported for the Marlin, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors."); + m_config.gcode_flavor != gcfRepetier && m_config.gcode_flavor != gcfMarlinLegacy && + m_config.gcode_flavor != gcfMarlinFirmware && m_config.gcode_flavor != gcfKlipper) + return _u8L("The Wipe Tower is currently only supported for the Marlin, Klipper, RepRap/Sprinter, RepRapFirmware and Repetier G-code flavors."); if (! m_config.use_relative_e_distances) 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) From 06bccab711a055d269dbd92df7888722bcce28dc Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 9 Mar 2023 15:54:55 +0100 Subject: [PATCH 14/25] Added Mainsail print host --- src/libslic3r/PrintConfig.cpp | 2 ++ src/libslic3r/PrintConfig.hpp | 2 +- src/slic3r/Utils/OctoPrint.hpp | 10 ++++++++++ src/slic3r/Utils/PrintHost.cpp | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 1adaa5430..62f9a9a2f 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -68,6 +68,7 @@ static const t_config_enum_values s_keys_map_PrintHostType { { "prusalink", htPrusaLink }, { "prusaconnect", htPrusaConnect }, { "octoprint", htOctoPrint }, + { "mainsail", htMainSail }, { "duet", htDuet }, { "flashair", htFlashAir }, { "astrobox", htAstroBox }, @@ -1954,6 +1955,7 @@ void PrintConfigDef::init_fff_params() { "prusalink", "PrusaLink" }, { "prusaconnect", "PrusaConnect" }, { "octoprint", "OctoPrint" }, + { "mainsail", "Mainsail/Fluidd" }, { "duet", "Duet" }, { "flashair", "FlashAir" }, { "astrobox", "AstroBox" }, diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 3a602b7ac..265628d78 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -44,7 +44,7 @@ enum class MachineLimitsUsage { }; enum PrintHostType { - htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS + htPrusaLink, htPrusaConnect, htOctoPrint, htDuet, htFlashAir, htAstroBox, htRepetier, htMKS, htMainSail }; enum AuthorizationType { diff --git a/src/slic3r/Utils/OctoPrint.hpp b/src/slic3r/Utils/OctoPrint.hpp index fd558eb2c..82c07f6f4 100644 --- a/src/slic3r/Utils/OctoPrint.hpp +++ b/src/slic3r/Utils/OctoPrint.hpp @@ -139,6 +139,16 @@ protected: void set_http_post_header_args(Http& http, PrintHostPostUploadAction post_action) const override; }; + +class Mainsail : public OctoPrint +{ +public: + Mainsail(DynamicPrintConfig* config) : OctoPrint(config) {} + ~Mainsail() override = default; + + const char* get_name() const override { return "Mainsail/Fluidd"; } +}; + } #endif diff --git a/src/slic3r/Utils/PrintHost.cpp b/src/slic3r/Utils/PrintHost.cpp index c8f0e34bc..5cb318715 100644 --- a/src/slic3r/Utils/PrintHost.cpp +++ b/src/slic3r/Utils/PrintHost.cpp @@ -54,6 +54,7 @@ PrintHost* PrintHost::get_print_host(DynamicPrintConfig *config) case htPrusaLink: return new PrusaLink(config); case htPrusaConnect: return new PrusaConnect(config); case htMKS: return new MKS(config); + case htMainSail: return new Mainsail(config); default: return nullptr; } } else { From da714c7210d15a259a3d23e22d4810a752f8e1ac Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Tue, 14 Mar 2023 11:29:19 +0100 Subject: [PATCH 15/25] Removed M107 inserted automatically at the start of the G-Code --- src/libslic3r/GCode.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index a9d7da76d..1135220df 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1147,10 +1147,6 @@ void GCode::_do_export(Print& print, GCodeOutputStream &file, ThumbnailsGenerato // Emit machine envelope limits for the Marlin firmware. this->print_machine_envelope(file, print); - // Disable fan. - if (! print.config().cooling.get_at(initial_extruder_id) || print.config().disable_fan_first_layers.get_at(initial_extruder_id)) - file.write(m_writer.set_fan(0)); - // Let the start-up script prime the 1st printing tool. m_placeholder_parser.set("initial_tool", initial_extruder_id); m_placeholder_parser.set("initial_extruder", initial_extruder_id); From 09122fb0d04ae70e2c787ef2523dbb7c9ee7eaaa Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 15 Mar 2023 14:31:05 +0100 Subject: [PATCH 16/25] Added a new config option to disable automatic temperature commands around start gcode (autoemit_temperature_commands) --- src/libslic3r/GCode.cpp | 10 ++++++---- src/libslic3r/Preset.cpp | 2 +- src/libslic3r/Print.cpp | 1 + src/libslic3r/PrintConfig.cpp | 24 +++++++++++++++++------- src/libslic3r/PrintConfig.hpp | 1 + src/slic3r/GUI/Tab.cpp | 3 +++ 6 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 1135220df..fcfd83da0 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1706,17 +1706,18 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print) // M190 - Set Extruder Temperature and Wait void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait) { + bool autoemit = print.config().autoemit_temperature_commands; // Initial bed temperature based on the first extruder. int temp = print.config().first_layer_bed_temperature.get_at(first_printing_extruder_id); // Is the bed temperature set by the provided custom G-code? int temp_by_gcode = -1; bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, false, temp_by_gcode); - if (temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000) + if (autoemit && temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000) temp = temp_by_gcode; // Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if // the custom start G-code emited these. std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait); - if (! temp_set_by_gcode) + if (autoemit && ! temp_set_by_gcode) file.write(set_temp_gcode); } @@ -1727,13 +1728,14 @@ void GCode::_print_first_layer_bed_temperature(GCodeOutputStream &file, Print &p // RepRapFirmware: G10 Sxx void GCode::_print_first_layer_extruder_temperatures(GCodeOutputStream &file, Print &print, const std::string &gcode, unsigned int first_printing_extruder_id, bool wait) { + bool autoemit = print.config().autoemit_temperature_commands; // Is the bed temperature set by the provided custom G-code? int temp_by_gcode = -1; bool include_g10 = print.config().gcode_flavor == gcfRepRapFirmware; - if (custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) { + if (! autoemit || custom_gcode_sets_temperature(gcode, 104, 109, include_g10, temp_by_gcode)) { // Set the extruder temperature at m_writer, but throw away the generated G-code as it will be written with the custom G-code. int temp = print.config().first_layer_temperature.get_at(first_printing_extruder_id); - if (temp_by_gcode >= 0 && temp_by_gcode < 1000) + if (autoemit && temp_by_gcode >= 0 && temp_by_gcode < 1000) temp = temp_by_gcode; m_writer.set_temperature(temp, wait, first_printing_extruder_id); } else { diff --git a/src/libslic3r/Preset.cpp b/src/libslic3r/Preset.cpp index 21b712217..a58492062 100644 --- a/src/libslic3r/Preset.cpp +++ b/src/libslic3r/Preset.cpp @@ -482,7 +482,7 @@ static std::vector s_Preset_machine_limits_options { }; static std::vector s_Preset_printer_options { - "printer_technology", + "printer_technology", "autoemit_temperature_commands", "bed_shape", "bed_custom_texture", "bed_custom_model", "z_offset", "gcode_flavor", "use_relative_e_distances", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height", //FIXME the print host keys are left here just for conversion from the Printer preset to Physical Printer preset. diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 2afe02517..67407e591 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -58,6 +58,7 @@ bool Print::invalidate_state_by_config_options(const ConfigOptionResolver & /* n // Cache the plenty of parameters, which influence the G-code generator only, // or they are only notes not influencing the generated G-code. static std::unordered_set steps_gcode = { + "autoemit_temperature_commands", "avoid_crossing_perimeters", "avoid_crossing_perimeters_max_detour", "bed_shape", diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 62f9a9a2f..8a8b70501 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -2490,15 +2490,25 @@ void PrintConfigDef::init_fff_params() def->mode = comExpert; def->set_default_value(new ConfigOptionInt(-5)); + def = this->add("autoemit_temperature_commands", coBool); + def->label = L("Emit temperature commands automatically"); + def->tooltip = L("When enabled, PrusaSlicer will check whether your Custom Start G-Code contains M104 or M190. " + "If so, the temperatures will not be emitted automatically so you're free to customize " + "the order of heating commands and other custom actions. Note that you can use " + "placeholder variables for all PrusaSlicer settings, so you can put " + "a \"M109 S[first_layer_temperature]\" command wherever you want.\n" + "If your Custom Start G-Code does NOT contain M104 or M190, " + "PrusaSlicer will execute the Start G-Code after bed reached its target temperature " + "and extruder just started heating.\n\n" + "When disabled, PrusaSlicer will NOT emit commands to heat up extruder and bed, " + "leaving both to Custom Start G-Code."); + def->mode = comExpert; + def->set_default_value(new ConfigOptionBool(true)); + def = this->add("start_gcode", coString); def->label = L("Start G-code"); - def->tooltip = L("This start procedure is inserted at the beginning, after bed has reached " - "the target temperature and extruder just started heating, and before extruder " - "has finished heating. If PrusaSlicer detects M104 or M190 in your custom codes, " - "such commands will not be prepended automatically so you're free to customize " - "the order of heating commands and other custom actions. Note that you can use " - "placeholder variables for all PrusaSlicer settings, so you can put " - "a \"M109 S[first_layer_temperature]\" command wherever you want."); + def->tooltip = L("This start procedure is inserted at the beginning, possibly prepended by " + "temperature-changing commands. See 'autoemit_temperature_commands'."); def->multiline = true; def->full_width = true; def->height = 12; diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp index 265628d78..d29afe5e7 100644 --- a/src/libslic3r/PrintConfig.hpp +++ b/src/libslic3r/PrintConfig.hpp @@ -661,6 +661,7 @@ PRINT_CONFIG_CLASS_DEFINE( PRINT_CONFIG_CLASS_DEFINE( GCodeConfig, + ((ConfigOptionBool, autoemit_temperature_commands)) ((ConfigOptionString, before_layer_gcode)) ((ConfigOptionString, between_objects_gcode)) ((ConfigOptionFloats, deretract_speed)) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 6227fc537..22e23d84e 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2411,6 +2411,9 @@ void TabPrinter::build_fff() option.opt.height = 3 * gcode_field_height;//150; optgroup->append_single_option_line(option); + optgroup = page->new_optgroup(L("Start G-Code options")); + optgroup->append_single_option_line("autoemit_temperature_commands"); + optgroup = page->new_optgroup(L("End G-code"), 0); optgroup->m_on_change = [this, &optgroup_title = optgroup->title](const t_config_option_key& opt_key, const boost::any& value) { validate_custom_gcode_cb(this, optgroup_title, opt_key, value); From 4b27210b6e5c248aa59883d222cc078207a77d5e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 15 Mar 2023 22:03:01 +0100 Subject: [PATCH 17/25] Bypass a crash when validating custom gcodes --- src/slic3r/GUI/Tab.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 22e23d84e..51298f175 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -4515,6 +4515,8 @@ bool Tab::validate_custom_gcodes() if (!opt_group->is_activated()) break; std::string key = opt_group->opt_map().begin()->first; + if (key == "autoemit_temperature_commands") + continue; valid &= validate_custom_gcode(opt_group->title, boost::any_cast(opt_group->get_value(key))); if (!valid) break; From dcfbff5ec8cc4ced4dabd90ddb46edf8c6a65b64 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Wed, 22 Mar 2023 15:42:34 +0100 Subject: [PATCH 18/25] Check value of the parameter "How to apply limits", when Klipper is selected + Suppress silent mode for G-code flavor that is different from MarlinFirmware or MarlinLegacy --- src/slic3r/GUI/Tab.cpp | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 51298f175..3dbbcc260 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2377,14 +2377,44 @@ void TabPrinter::build_fff() } } if (opt_key == "gcode_flavor") { - const int flavor = boost::any_cast(value); - bool supports_travel_acceleration = (flavor == int(gcfMarlinFirmware) || flavor == int(gcfRepRapFirmware)); - bool supports_min_feedrates = (flavor == int(gcfMarlinFirmware) || flavor == int(gcfMarlinLegacy)); + const GCodeFlavor flavor = static_cast(boost::any_cast(value)); + bool supports_travel_acceleration = (flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware); + bool supports_min_feedrates = (flavor == gcfMarlinFirmware || flavor == gcfMarlinLegacy); if (supports_travel_acceleration != m_supports_travel_acceleration || supports_min_feedrates != m_supports_min_feedrates) { m_rebuild_kinematics_page = true; m_supports_travel_acceleration = supports_travel_acceleration; m_supports_min_feedrates = supports_min_feedrates; } + + const bool is_silent_mode = m_config->option("silent_mode")->getBool(); + const bool is_emit_to_gcode = m_config->option("machine_limits_usage")->getInt() == static_cast(MachineLimitsUsage::EmitToGCode); + if ((flavor == gcfKlipper && is_emit_to_gcode) || (!m_supports_min_feedrates && is_silent_mode)) { + DynamicPrintConfig new_conf = *m_config; + wxString msg; + + if (flavor == gcfKlipper && is_emit_to_gcode) { + msg = _L("Emitting machine limits to G-code is not supported with Klipper G-code flavor.\n" + "The option was switched to \"Use for time estimate\"."); + + auto machine_limits_usage = static_cast*>(m_config->option("machine_limits_usage")->clone()); + machine_limits_usage->value = MachineLimitsUsage::TimeEstimateOnly; + new_conf.set_key_value("machine_limits_usage", machine_limits_usage); + } + + if (!m_supports_min_feedrates && is_silent_mode) { + if (!msg.IsEmpty()) + msg += "\n\n"; + msg += _L("Stealth mode for machine limits to G-code is not supported with selected G-code flavor.\n" + "The Stealth mode was suppressed."); + + auto silent_mode = static_cast(m_config->option("silent_mode")->clone()); + silent_mode->value = false; + new_conf.set_key_value("silent_mode", silent_mode); + } + + InfoDialog(parent(), _L("G-code flavor is switched"), msg).ShowModal(); + load_config(new_conf); + } } build_unregular_pages(); update_dirty(); From 51129fd4f3317986add877d4c6bc36e32084567f Mon Sep 17 00:00:00 2001 From: YuSanka Date: Thu, 23 Mar 2023 09:16:33 +0100 Subject: [PATCH 19/25] Follow-up https://github.com/Prusa-Development/PrusaSlicerPrivate/commit/87d77f338de5206a3c6110cf3cda4ebab3f414e6 - Added control of a value of changed parameter "How to apply limits", when Klipper is selected --- src/slic3r/GUI/Tab.cpp | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 3dbbcc260..9797e68cd 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -2260,6 +2260,12 @@ void TabPrinter::build_print_host_upload_group(Page* page) optgroup->append_line(line); } +static wxString get_info_klipper_string() +{ + return _L("Emitting machine limits to G-code is not supported with Klipper G-code flavor.\n" + "The option was switched to \"Use for time estimate\"."); +} + void TabPrinter::build_fff() { if (!m_pages.empty()) @@ -2386,22 +2392,20 @@ void TabPrinter::build_fff() m_supports_min_feedrates = supports_min_feedrates; } - const bool is_silent_mode = m_config->option("silent_mode")->getBool(); const bool is_emit_to_gcode = m_config->option("machine_limits_usage")->getInt() == static_cast(MachineLimitsUsage::EmitToGCode); - if ((flavor == gcfKlipper && is_emit_to_gcode) || (!m_supports_min_feedrates && is_silent_mode)) { + if ((flavor == gcfKlipper && is_emit_to_gcode) || (!m_supports_min_feedrates && m_use_silent_mode)) { DynamicPrintConfig new_conf = *m_config; wxString msg; if (flavor == gcfKlipper && is_emit_to_gcode) { - msg = _L("Emitting machine limits to G-code is not supported with Klipper G-code flavor.\n" - "The option was switched to \"Use for time estimate\"."); + msg = get_info_klipper_string(); auto machine_limits_usage = static_cast*>(m_config->option("machine_limits_usage")->clone()); machine_limits_usage->value = MachineLimitsUsage::TimeEstimateOnly; new_conf.set_key_value("machine_limits_usage", machine_limits_usage); } - if (!m_supports_min_feedrates && is_silent_mode) { + if (!m_supports_min_feedrates && m_use_silent_mode) { if (!msg.IsEmpty()) msg += "\n\n"; msg += _L("Stealth mode for machine limits to G-code is not supported with selected G-code flavor.\n" @@ -2663,6 +2667,27 @@ PageShp TabPrinter::build_kinematics_page() optgroup->append_line(line); } + optgroup->m_on_change = [this](const t_config_option_key& opt_key, boost::any value) + { + if (opt_key == "machine_limits_usage" && + static_cast(boost::any_cast(value)) == MachineLimitsUsage::EmitToGCode && + static_cast(m_config->option("gcode_flavor")->getInt()) == gcfKlipper) + { + DynamicPrintConfig new_conf = *m_config; + + auto machine_limits_usage = static_cast*>(m_config->option("machine_limits_usage")->clone()); + machine_limits_usage->value = MachineLimitsUsage::TimeEstimateOnly; + + new_conf.set_key_value("machine_limits_usage", machine_limits_usage); + + InfoDialog(parent(), wxEmptyString, get_info_klipper_string()).ShowModal(); + load_config(new_conf); + } + + update_dirty(); + update(); + }; + if (m_use_silent_mode) { // Legend for OptionsGroups auto optgroup = page->new_optgroup(""); From 847a34c64420688a06cb72465aff120153b84290 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Thu, 23 Mar 2023 15:21:38 +0100 Subject: [PATCH 20/25] Do not clamp travel acceleration when current firmware flavor does not allow separate setting of print and travel acceleration --- src/libslic3r/GCode.cpp | 2 +- src/libslic3r/GCode/GCodeProcessor.cpp | 6 ++++++ src/libslic3r/GCodeWriter.cpp | 14 +++++++++----- src/libslic3r/GCodeWriter.hpp | 4 +++- src/slic3r/GUI/Tab.cpp | 3 ++- 5 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index fcfd83da0..3113560f4 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -3075,7 +3075,7 @@ std::string GCode::travel_to(const Point &point, ExtrusionRole role, std::string for (size_t i = 1; i < travel.size(); ++ i) gcode += m_writer.travel_to_xy(this->point_to_gcode(travel.points[i]), comment); - if (! m_writer.supports_PT()) { + if (! GCodeWriter::supports_separate_travel_acceleration(config().gcode_flavor)) { // In case that this flavor does not support separate print and travel acceleration, // reset acceleration to default. gcode += m_writer.set_travel_acceleration((unsigned int)(m_config.travel_acceleration.value + 0.5)); diff --git a/src/libslic3r/GCode/GCodeProcessor.cpp b/src/libslic3r/GCode/GCodeProcessor.cpp index ead792662..a2c867505 100644 --- a/src/libslic3r/GCode/GCodeProcessor.cpp +++ b/src/libslic3r/GCode/GCodeProcessor.cpp @@ -3,6 +3,7 @@ #include "libslic3r/Print.hpp" #include "libslic3r/LocalesUtils.hpp" #include "libslic3r/format.hpp" +#include "libslic3r/GCodeWriter.hpp" #include "GCodeProcessor.hpp" #include @@ -610,7 +611,12 @@ for (size_t i = 0; i < static_cast(PrintEstimatedStatistics::ETimeMode:: float max_retract_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_retracting, i); m_time_processor.machines[i].max_retract_acceleration = max_retract_acceleration; m_time_processor.machines[i].retract_acceleration = (max_retract_acceleration > 0.0f) ? max_retract_acceleration : DEFAULT_RETRACT_ACCELERATION; + float max_travel_acceleration = get_option_value(m_time_processor.machine_limits.machine_max_acceleration_travel, i); + if ( ! GCodeWriter::supports_separate_travel_acceleration(config.gcode_flavor.value) || config.machine_limits_usage.value != MachineLimitsUsage::EmitToGCode) { + // Only clamp travel acceleration when it is accessible in machine limits. + max_travel_acceleration = 0; + } m_time_processor.machines[i].max_travel_acceleration = max_travel_acceleration; m_time_processor.machines[i].travel_acceleration = (max_travel_acceleration > 0.0f) ? max_travel_acceleration : DEFAULT_TRAVEL_ACCELERATION; } diff --git a/src/libslic3r/GCodeWriter.cpp b/src/libslic3r/GCodeWriter.cpp index 45176baaa..5080fabb4 100644 --- a/src/libslic3r/GCodeWriter.cpp +++ b/src/libslic3r/GCodeWriter.cpp @@ -15,9 +15,10 @@ namespace Slic3r { -bool GCodeWriter::supports_PT() const +// static +bool GCodeWriter::supports_separate_travel_acceleration(GCodeFlavor flavor) { - return (FLAVOR_IS(gcfRepetier) || FLAVOR_IS(gcfMarlinFirmware) || FLAVOR_IS(gcfRepRapFirmware)); + return (flavor == gcfRepetier || flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware); } void GCodeWriter::apply_print_config(const PrintConfig &print_config) @@ -30,6 +31,8 @@ void GCodeWriter::apply_print_config(const PrintConfig &print_config) || print_config.gcode_flavor.value == gcfRepRapFirmware; m_max_acceleration = static_cast(std::round((use_mach_limits && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode) ? print_config.machine_max_acceleration_extruding.values.front() : 0)); + m_max_travel_acceleration = static_cast(std::round((use_mach_limits && print_config.machine_limits_usage.value == MachineLimitsUsage::EmitToGCode && supports_separate_travel_acceleration(print_config.gcode_flavor.value)) ? + print_config.machine_max_acceleration_travel.values.front() : 0)); } void GCodeWriter::set_extruders(std::vector extruder_ids) @@ -163,12 +166,13 @@ std::string GCodeWriter::set_bed_temperature(unsigned int temperature, bool wait std::string GCodeWriter::set_acceleration_internal(Acceleration type, unsigned int acceleration) { // Clamp the acceleration to the allowed maximum. - // TODO: What about max travel acceleration ? Currently it is clamped by the extruding acceleration !!! - if (m_max_acceleration > 0 && acceleration > m_max_acceleration) + if (type == Acceleration::Print && m_max_acceleration > 0 && acceleration > m_max_acceleration) acceleration = m_max_acceleration; + if (type == Acceleration::Travel && m_max_travel_acceleration > 0 && acceleration > m_max_travel_acceleration) + acceleration = m_max_travel_acceleration; // Are we setting travel acceleration for a flavour that supports separate travel and print acc? - bool separate_travel = (type == Acceleration::Travel && supports_PT()); + bool separate_travel = (type == Acceleration::Travel && supports_separate_travel_acceleration(this->config.gcode_flavor)); auto& last_value = separate_travel ? m_last_travel_acceleration : m_last_acceleration ; if (acceleration == 0 || acceleration == last_value) diff --git a/src/libslic3r/GCodeWriter.hpp b/src/libslic3r/GCodeWriter.hpp index 2a2a488fa..9e5fce702 100644 --- a/src/libslic3r/GCodeWriter.hpp +++ b/src/libslic3r/GCodeWriter.hpp @@ -71,7 +71,7 @@ public: Vec3d get_position() const { return m_pos; } // Returns whether this flavor supports separate print and travel acceleration. - bool supports_PT() const; + static bool supports_separate_travel_acceleration(GCodeFlavor flavor); // To be called by the CoolingBuffer from another thread. static std::string set_fan(const GCodeFlavor gcode_flavor, bool gcode_comments, unsigned int speed); @@ -90,6 +90,8 @@ private: // Limit for setting the acceleration, to respect the machine limits set for the Marlin firmware. // If set to zero, the limit is not in action. unsigned int m_max_acceleration; + unsigned int m_max_travel_acceleration; + unsigned int m_last_bed_temperature; bool m_last_bed_temperature_reached; double m_lifted; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 9797e68cd..b095d4ea2 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -7,6 +7,7 @@ #include "libslic3r/Utils.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/GCode/GCodeProcessor.hpp" +#include "libslic3r/GCodeWriter.hpp" #include "slic3r/Utils/Http.hpp" #include "slic3r/Utils/PrintHost.hpp" @@ -2384,7 +2385,7 @@ void TabPrinter::build_fff() } if (opt_key == "gcode_flavor") { const GCodeFlavor flavor = static_cast(boost::any_cast(value)); - bool supports_travel_acceleration = (flavor == gcfMarlinFirmware || flavor == gcfRepRapFirmware); + bool supports_travel_acceleration = GCodeWriter::supports_separate_travel_acceleration(flavor); bool supports_min_feedrates = (flavor == gcfMarlinFirmware || flavor == gcfMarlinLegacy); if (supports_travel_acceleration != m_supports_travel_acceleration || supports_min_feedrates != m_supports_min_feedrates) { m_rebuild_kinematics_page = true; From 0a52ef8da7ea84a30c9615f60938e1332e4da4a4 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 24 Mar 2023 09:22:50 +0100 Subject: [PATCH 21/25] Fix format of M204 emitted from machine limits for various fws --- src/libslic3r/GCode.cpp | 26 ++++++++++++++------------ src/libslic3r/PrintConfig.cpp | 9 ++++----- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 3113560f4..041194435 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1663,23 +1663,25 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print) int(print.config().machine_max_feedrate_e.values.front() * factor + 0.5), factor == 60 ? "mm / min" : "mm / sec"); - // Now M204 - acceleration. This one is quite hairy thanks to how Marlin guys care about - // backwards compatibility: https://github.com/prusa3d/PrusaSlicer/issues/1089 - // Legacy Marlin should export travel acceleration the same as printing acceleration. - // MarlinFirmware has the two separated. - int travel_acc = flavor == gcfMarlinLegacy - ? int(print.config().machine_max_acceleration_extruding.values.front() + 0.5) - : int(print.config().machine_max_acceleration_travel.values.front() + 0.5); - // Retract acceleration not accepted in M204 in RRF + // Now M204 - acceleration. This one is quite hairy... if (flavor == gcfRepRapFirmware) + // Uses M204 P[print] T[travel] file.write_format("M204 P%d T%d ; sets acceleration (P, T), mm/sec^2\n", int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), - travel_acc); - else - file.write_format("M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n", + int(print.config().machine_max_acceleration_travel.values.front() + 0.5)); + else if (flavor == gcfMarlinLegacy) + // Legacy Marlin uses M204 S[print] T[retract] + file.write_format("M204 " + "S%d T%d ; sets acceleration (S) and retract acceleration (R), mm/sec^2\n", + int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), + int(print.config().machine_max_acceleration_retracting.values.front() + 0.5)); + else if (flavor == gcfMarlinFirmware) + // New Marlin uses M204 P[print] R[retract] T[travel] + file.write_format("M204 " + "P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n", int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), int(print.config().machine_max_acceleration_retracting.values.front() + 0.5), - travel_acc); + int(print.config().machine_max_acceleration_travel.values.front() + 0.5)); + else + assert(false); assert(is_decimal_separator_point()); file.write_format(flavor == gcfRepRapFirmware diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp index 8a8b70501..0089ce457 100644 --- a/src/libslic3r/PrintConfig.cpp +++ b/src/libslic3r/PrintConfig.cpp @@ -1803,9 +1803,7 @@ void PrintConfigDef::init_fff_params() def = this->add("machine_max_acceleration_extruding", coFloats); def->full_label = L("Maximum acceleration when extruding"); def->category = L("Machine limits"); - def->tooltip = L("Maximum acceleration when extruding (M204 P)\n\n" - "Marlin (legacy) firmware flavor will use this also " - "as travel acceleration (M204 T)."); + def->tooltip = L("Maximum acceleration when extruding"); def->sidetext = L("mm/s²"); def->min = 0; def->mode = comAdvanced; @@ -1816,7 +1814,8 @@ void PrintConfigDef::init_fff_params() def = this->add("machine_max_acceleration_retracting", coFloats); def->full_label = L("Maximum acceleration when retracting"); def->category = L("Machine limits"); - def->tooltip = L("Maximum acceleration when retracting (M204 R)"); + def->tooltip = L("Maximum acceleration when retracting.\n\n" + "Not used for RepRapFirmware, which does not support it."); def->sidetext = L("mm/s²"); def->min = 0; def->mode = comAdvanced; @@ -1826,7 +1825,7 @@ void PrintConfigDef::init_fff_params() def = this->add("machine_max_acceleration_travel", coFloats); def->full_label = L("Maximum acceleration for travel moves"); def->category = L("Machine limits"); - def->tooltip = L("Maximum acceleration for travel moves (M204 T)"); + def->tooltip = L("Maximum acceleration for travel moves."); def->sidetext = L("mm/s²"); def->min = 0; def->mode = comAdvanced; From c9b15736dac81a2b296ac3501214c726c2b214af Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 24 Mar 2023 09:56:40 +0100 Subject: [PATCH 22/25] Fixed compilation errors and warnings --- src/libslic3r/GCode.cpp | 4 ++-- src/libslic3r/I18N.hpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 041194435..d4278ed74 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1671,12 +1671,12 @@ void GCode::print_machine_envelope(GCodeOutputStream &file, Print &print) int(print.config().machine_max_acceleration_travel.values.front() + 0.5)); else if (flavor == gcfMarlinLegacy) // Legacy Marlin uses M204 S[print] T[retract] - file.write_format("M204 " + "S%d T%d ; sets acceleration (S) and retract acceleration (R), mm/sec^2\n", + file.write_format("M204 S%d T%d ; sets acceleration (S) and retract acceleration (R), mm/sec^2\n", int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), int(print.config().machine_max_acceleration_retracting.values.front() + 0.5)); else if (flavor == gcfMarlinFirmware) // New Marlin uses M204 P[print] R[retract] T[travel] - file.write_format("M204 " + "P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n", + file.write_format("M204 P%d R%d T%d ; sets acceleration (P, T) and retract acceleration (R), mm/sec^2\n", int(print.config().machine_max_acceleration_extruding.values.front() + 0.5), int(print.config().machine_max_acceleration_retracting.values.front() + 0.5), int(print.config().machine_max_acceleration_travel.values.front() + 0.5)); diff --git a/src/libslic3r/I18N.hpp b/src/libslic3r/I18N.hpp index 3cc196b6a..5d2068a3d 100644 --- a/src/libslic3r/I18N.hpp +++ b/src/libslic3r/I18N.hpp @@ -28,9 +28,9 @@ namespace I18N { #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); } + [[maybe_unused]] const char* L(const char* s) { return s; } + [[maybe_unused]] const char* L_CONTEXT(const char* s, const char* context) { return s; } + [[maybe_unused]] std::string _u8L(const char* s) { return Slic3r::I18N::translate(s); } } #endif From a391d4c445a8e5505eeecdfdad1e9bb125905335 Mon Sep 17 00:00:00 2001 From: YuSanka Date: Fri, 24 Mar 2023 10:07:25 +0100 Subject: [PATCH 23/25] Added missed includes of "format.hpp" --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 1 + src/slic3r/GUI/GUI_ObjectSettings.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 7d9a87b58..02ef719f1 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -1,5 +1,6 @@ #include "GUI_ObjectManipulation.hpp" #include "I18N.hpp" +#include "format.hpp" #include "BitmapComboBox.hpp" #include "GLCanvas3D.hpp" diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 41cad8792..a6d85cef7 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -12,6 +12,7 @@ #include #include "I18N.hpp" +#include "format.hpp" #include "ConfigManipulation.hpp" #include From 5b115b79723fb7bf16f303df8bef6d8c6fa766d2 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 24 Mar 2023 13:55:48 +0100 Subject: [PATCH 24/25] PlaceholderParser: Implemented skipping of inactive if / else / endif and ternary operator branches, thus missing variables or addressing outside of the variable range in an inactive branch will not trigger an error. --- src/libslic3r/PlaceholderParser.cpp | 517 +++++++++++++------- tests/libslic3r/test_placeholder_parser.cpp | 32 +- 2 files changed, 370 insertions(+), 179 deletions(-) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 94a1259b6..06a4d3960 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -177,6 +177,7 @@ namespace client int index { -1 }; boost::iterator_range it_range; + bool empty() const { return opt == nullptr; } bool has_index() const { return index != -1; } }; @@ -292,6 +293,9 @@ namespace client { std::string out; switch (this->type()) { + case TYPE_EMPTY: + // Inside an if / else block to be skipped. + break; case TYPE_BOOL: out = this->b() ? "true" : "false"; break; case TYPE_INT: out = std::to_string(this->i()); break; case TYPE_DOUBLE: @@ -321,6 +325,9 @@ namespace client expr unary_minus(const Iterator start_pos) const { switch (this->type()) { + case TYPE_EMPTY: + // Inside an if / else block to be skipped. + return expr(); case TYPE_INT : return expr(- this->i(), start_pos, this->it_range.end()); case TYPE_DOUBLE: @@ -336,6 +343,9 @@ namespace client expr unary_integer(const Iterator start_pos) const { switch (this->type()) { + case TYPE_EMPTY: + // Inside an if / else block to be skipped. + return expr(); case TYPE_INT: return expr(this->i(), start_pos, this->it_range.end()); case TYPE_DOUBLE: @@ -351,6 +361,9 @@ namespace client expr round(const Iterator start_pos) const { switch (this->type()) { + case TYPE_EMPTY: + // Inside an if / else block to be skipped. + return expr(); case TYPE_INT: return expr(this->i(), start_pos, this->it_range.end()); case TYPE_DOUBLE: @@ -366,6 +379,9 @@ namespace client expr unary_not(const Iterator start_pos) const { switch (this->type()) { + case TYPE_EMPTY: + // Inside an if / else block to be skipped. + return expr(); case TYPE_BOOL: return expr(! this->b(), start_pos, this->it_range.end()); default: @@ -378,7 +394,9 @@ namespace client expr &operator+=(const expr &rhs) { - if (this->type() == TYPE_STRING) { + if (this->type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped. + } else if (this->type() == TYPE_STRING) { // Convert the right hand side to string and append. *m_data.s += rhs.to_string(); } else if (rhs.type() == TYPE_STRING) { @@ -399,72 +417,98 @@ namespace client expr &operator-=(const expr &rhs) { - const char *err_msg = "Cannot subtract non-numeric types."; - this->throw_if_not_numeric(err_msg); - rhs.throw_if_not_numeric(err_msg); - if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) - this->set_d_lite(this->as_d() - rhs.as_d()); - else - m_data.i -= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + if (this->type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped. + this->reset(); + } else { + const char *err_msg = "Cannot subtract non-numeric types."; + this->throw_if_not_numeric(err_msg); + rhs.throw_if_not_numeric(err_msg); + if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) + this->set_d_lite(this->as_d() - rhs.as_d()); + else + m_data.i -= rhs.i(); + this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + } return *this; } expr &operator*=(const expr &rhs) { - const char *err_msg = "Cannot multiply with non-numeric type."; - this->throw_if_not_numeric(err_msg); - rhs.throw_if_not_numeric(err_msg); - if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) - this->set_d_lite(this->as_d() * rhs.as_d()); - else - m_data.i *= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + if (this->type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped. + this->reset(); + } else { + const char *err_msg = "Cannot multiply with non-numeric type."; + this->throw_if_not_numeric(err_msg); + rhs.throw_if_not_numeric(err_msg); + if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) + this->set_d_lite(this->as_d() * rhs.as_d()); + else + m_data.i *= rhs.i(); + this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + } return *this; } expr &operator/=(const expr &rhs) { - this->throw_if_not_numeric("Cannot divide a non-numeric type."); - rhs.throw_if_not_numeric("Cannot divide with a non-numeric type."); - if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.)) - rhs.throw_exception("Division by zero"); - if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) - this->set_d_lite(this->as_d() / rhs.as_d()); - else - m_data.i /= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + if (this->type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped. + this->reset(); + } else { + this->throw_if_not_numeric("Cannot divide a non-numeric type."); + rhs.throw_if_not_numeric("Cannot divide with a non-numeric type."); + if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.)) + rhs.throw_exception("Division by zero"); + if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) + this->set_d_lite(this->as_d() / rhs.as_d()); + else + m_data.i /= rhs.i(); + this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + } return *this; } expr &operator%=(const expr &rhs) { - this->throw_if_not_numeric("Cannot divide a non-numeric type."); - rhs.throw_if_not_numeric("Cannot divide with a non-numeric type."); - if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.)) - rhs.throw_exception("Division by zero"); - if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) - this->set_d_lite(std::fmod(this->as_d(), rhs.as_d())); - else - m_data.i %= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + if (this->type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped. + this->reset(); + } else { + this->throw_if_not_numeric("Cannot divide a non-numeric type."); + rhs.throw_if_not_numeric("Cannot divide with a non-numeric type."); + if (rhs.type() == TYPE_INT ? (rhs.i() == 0) : (rhs.d() == 0.)) + rhs.throw_exception("Division by zero"); + if (this->type() == TYPE_DOUBLE || rhs.type() == TYPE_DOUBLE) + this->set_d_lite(std::fmod(this->as_d(), rhs.as_d())); + else + m_data.i %= rhs.i(); + this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + } return *this; } static void to_string2(expr &self, std::string &out) { - out = self.to_string(); + if (self.type() != TYPE_EMPTY) + // Not inside an if / else block to be skipped + out = self.to_string(); } static void evaluate_boolean(expr &self, bool &out) { - if (self.type() != TYPE_BOOL) - self.throw_exception("Not a boolean expression"); - out = self.b(); + if (self.type() != TYPE_EMPTY) { + // Not inside an if / else block to be skipped + if (self.type() != TYPE_BOOL) + self.throw_exception("Not a boolean expression"); + out = self.b(); + } } static void evaluate_boolean_to_string(expr &self, std::string &out) { + assert(self.type() != TYPE_EMPTY); if (self.type() != TYPE_BOOL) self.throw_exception("Not a boolean expression"); out = self.b() ? "true" : "false"; @@ -473,6 +517,9 @@ namespace client // Is lhs==rhs? Store the result into lhs. static void compare_op(expr &lhs, expr &rhs, char op, bool invert) { + if (lhs.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; bool value = false; if (lhs.numeric_type() && rhs.numeric_type()) { // Both types are numeric. @@ -529,6 +576,9 @@ namespace client // Store the result into param1. static void function_2params(expr ¶m1, expr ¶m2, Function2ParamsType fun) { + if (param1.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; throw_if_not_numeric(param1); throw_if_not_numeric(param2); if (param1.type() == TYPE_DOUBLE || param2.type() == TYPE_DOUBLE) { @@ -556,6 +606,9 @@ namespace client // Store the result into param1. static void random(expr ¶m1, expr ¶m2, std::mt19937 &rng) { + if (param1.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; throw_if_not_numeric(param1); throw_if_not_numeric(param2); if (param1.type() == TYPE_DOUBLE || param2.type() == TYPE_DOUBLE) @@ -569,6 +622,9 @@ namespace client template static void digits(expr ¶m1, expr ¶m2, expr ¶m3) { + if (param1.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; throw_if_not_numeric(param1); if (param2.type() != TYPE_INT) param2.throw_exception("digits: second parameter must be integer"); @@ -590,6 +646,9 @@ namespace client static void regex_op(const expr &lhs, boost::iterator_range &rhs, char op, expr &out) { + if (lhs.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; const std::string *subject = nullptr; if (lhs.type() == TYPE_STRING) { // One type is string, the other could be converted to string. @@ -618,6 +677,11 @@ namespace client } template static void one_of_test(const expr &match, const expr &pattern, expr &out) { + if (match.type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped + out.reset(); + return; + } if (! out.b()) { if (match.type() != TYPE_STRING) match.throw_exception("one_of(): First parameter (the string to match against) has to be a string value"); @@ -635,6 +699,11 @@ namespace client } } static void one_of_test_regex(const expr &match, boost::iterator_range &pattern, expr &out) { + if (match.type() == TYPE_EMPTY) { + // Inside an if / else block to be skipped + out.reset(); + return; + } if (! out.b()) { if (match.type() != TYPE_STRING) match.throw_exception("one_of(): First parameter (the string to match against) has to be a string value"); @@ -644,6 +713,9 @@ namespace client static void logical_op(expr &lhs, expr &rhs, char op) { + if (lhs.type() == TYPE_EMPTY) + // Inside an if / else block to be skipped + return; bool value = false; if (lhs.type() == TYPE_BOOL && rhs.type() == TYPE_BOOL) { value = (op == '|') ? (lhs.b() || rhs.b()) : (lhs.b() && rhs.b()); @@ -656,24 +728,6 @@ namespace client static void logical_or (expr &lhs, expr &rhs) { logical_op(lhs, rhs, '|'); } static void logical_and(expr &lhs, expr &rhs) { logical_op(lhs, rhs, '&'); } - static void ternary_op(expr &lhs, expr &rhs1, expr &rhs2) - { - if (lhs.type() != TYPE_BOOL) - lhs.throw_exception("Not a boolean expression"); - if (lhs.b()) - lhs = std::move(rhs1); - else - lhs = std::move(rhs2); - } - - static void set_if(bool &cond, bool ¬_yet_consumed, std::string &str_in, std::string &str_out) - { - if (cond && not_yet_consumed) { - str_out = str_in; - not_yet_consumed = false; - } - } - void throw_exception(const char *message) const { boost::throw_exception(qi::expectation_failure( @@ -745,6 +799,33 @@ namespace client // 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; } + // Entering a conditional block. + static void block_enter(const MyContext *ctx, const bool condition) + { + if (ctx->skipping() || ! condition) + ++ ctx->m_depth_suppressed; + } + // Exiting a conditional block. + static void block_exit(const MyContext *ctx, const bool condition, bool ¬_yet_consumed, std::string &data_in, std::string &data_out) + { + if (ctx->skipping()) + -- ctx->m_depth_suppressed; + else if (condition && not_yet_consumed) { + data_out = std::move(data_in); + not_yet_consumed = false; + } + } + template + static void block_exit_ternary(const MyContext* ctx, const bool condition, DataType &data_in, DataType &data_out) + { + if (ctx->skipping()) + -- ctx->m_depth_suppressed; + else if (condition) + data_out = std::move(data_in); + } + // Inside a block, which is conditionally suppressed? + bool skipping() const { return m_depth_suppressed > 0; } + const ConfigOption* optptr(const t_config_option_key &opt_key) const override { const ConfigOption *opt = nullptr; @@ -758,7 +839,7 @@ namespace client } const ConfigOption* resolve_symbol(const std::string &opt_key) const { return this->optptr(opt_key); } - ConfigOption* resolve_output_symbol(const std::string &opt_key) const { + ConfigOption* resolve_output_symbol(const std::string &opt_key) const { ConfigOption *out = nullptr; if (this->config_outputs) out = this->config_outputs->optptr(opt_key, false); @@ -783,6 +864,9 @@ namespace client boost::iterator_range &opt_key, std::string &output) { + if (ctx->skipping()) + return; + std::string opt_key_str(opt_key.begin(), opt_key.end()); const ConfigOption *opt = ctx->resolve_symbol(opt_key_str); size_t idx = ctx->current_extruder_id; @@ -820,6 +904,9 @@ namespace client boost::iterator_range &opt_vector_index, std::string &output) { + if (ctx->skipping()) + return; + std::string opt_key_str(opt_key.begin(), opt_key.end()); const ConfigOption *opt = ctx->resolve_symbol(opt_key_str); if (opt == nullptr) { @@ -850,15 +937,17 @@ namespace client boost::iterator_range &opt_key, OptWithPos &output) { - 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(key); - if (opt == nullptr) - ctx->throw_exception("Not a variable name", opt_key); - output.writable = true; + if (! ctx->skipping()) { + 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(key); + if (opt == nullptr) + ctx->throw_exception("Not a variable name", opt_key); + output.writable = true; + } + output.opt = opt; } - output.opt = opt; output.it_range = opt_key; } @@ -870,12 +959,15 @@ namespace client Iterator it_end, OptWithPos &output) { - if (! opt.opt->is_vector()) - ctx->throw_exception("Cannot index a scalar variable", opt.it_range); - if (index < 0) - ctx->throw_exception("Referencing a vector variable with a negative index", opt.it_range); - output = opt; - output.index = index; + if (! ctx->skipping()) { + if (! opt.opt->is_vector()) + ctx->throw_exception("Cannot index a scalar variable", opt.it_range); + if (index < 0) + ctx->throw_exception("Referencing a vector variable with a negative index", opt.it_range); + output = opt; + output.index = index; + } else + output = opt; output.it_range.end() = it_end; } @@ -887,6 +979,9 @@ namespace client OptWithPos &opt, expr &output) { + if (ctx->skipping()) + return; + assert(opt.opt->is_scalar()); switch (opt.opt->type()) { @@ -948,6 +1043,9 @@ namespace client OptWithPos &opt, expr &output) { + if (ctx->skipping()) + return; + assert(opt.opt->is_vector()); if (! opt.has_index()) ctx->throw_exception("Referencing a vector variable when scalar is expected", opt.it_range); @@ -1102,10 +1200,12 @@ namespace client OptWithPos &opt, expr &output) { - if (opt.opt->is_vector()) - vector_element_to_expr(ctx, opt, output); - else - scalar_variable_to_expr(ctx, opt, output); + if (! ctx->skipping()) { + 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; } @@ -1117,7 +1217,8 @@ namespace client OptWithPos &opt, expr &output) { - if (opt.opt->is_vector()) { + if (ctx->skipping()) { + } else 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); @@ -1145,26 +1246,26 @@ namespace client const boost::iterator_range &it_range, NewOldVariable &out) { - t_config_option_key key(std::string(it_range.begin(), it_range.end())); - if (const ConfigOption* opt = ctx->resolve_symbol(key); opt) - ctx->throw_exception("Symbol is already defined in read-only system dictionary", it_range); - if (ctx->config_outputs && ctx->config_outputs->optptr(key)) - ctx->throw_exception("Symbol is already defined as system output variable", it_range); - - bool has_global_dictionary = ctx->context_data != nullptr && ctx->context_data->global_config; - if (global_variable) { - if (! has_global_dictionary) - ctx->throw_exception("Global variables are not available in this context", it_range); - if (ctx->config_local.optptr(key)) - ctx->throw_exception("Variable name already defined in local scope", it_range); - out.opt = ctx->context_data->global_config->optptr(key); - } else { - if (has_global_dictionary && ctx->context_data->global_config->optptr(key)) - ctx->throw_exception("Variable name already defined in global scope", it_range); - out.opt = ctx->config_local.optptr(key); + if (! ctx->skipping()) { + t_config_option_key key(std::string(it_range.begin(), it_range.end())); + if (const ConfigOption* opt = ctx->resolve_symbol(key); opt) + ctx->throw_exception("Symbol is already defined in read-only system dictionary", it_range); + if (ctx->config_outputs && ctx->config_outputs->optptr(key)) + ctx->throw_exception("Symbol is already defined as system output variable", it_range); + bool has_global_dictionary = ctx->context_data != nullptr && ctx->context_data->global_config; + if (global_variable) { + if (! has_global_dictionary) + ctx->throw_exception("Global variables are not available in this context", it_range); + if (ctx->config_local.optptr(key)) + ctx->throw_exception("Variable name already defined in local scope", it_range); + out.opt = ctx->context_data->global_config->optptr(key); + } else { + if (has_global_dictionary && ctx->context_data->global_config->optptr(key)) + ctx->throw_exception("Variable name already defined in global scope", it_range); + out.opt = ctx->config_local.optptr(key); + } + out.name = std::move(key); } - - out.name = std::move(key); out.it_range = it_range; } @@ -1175,11 +1276,13 @@ namespace client OptWithPos &opt, const expr ¶m) { - check_writable(ctx, opt); - if (opt.opt->is_vector()) - vector_variable_element_assign_scalar(ctx, opt, param); - else - scalar_variable_assign_scalar(ctx, opt, param); + if (! ctx->skipping()) { + check_writable(ctx, opt); + if (opt.opt->is_vector()) + vector_variable_element_assign_scalar(ctx, opt, param); + else + scalar_variable_assign_scalar(ctx, opt, param); + } } template @@ -1189,7 +1292,8 @@ namespace client NewOldVariable &lhs, const expr &rhs) { - if (lhs.opt) { + if (ctx->skipping()) { + } else 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 }; @@ -1215,7 +1319,8 @@ namespace client const expr &rhs_count, const expr &rhs_value) { - if (lhs.opt) { + if (ctx->skipping()) { + } else 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 }; @@ -1241,10 +1346,12 @@ namespace client const expr &rhs_count, const expr &rhs_value) { - check_writable(ctx, lhs); - if (lhs.opt->is_scalar()) - 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); + if (! ctx->skipping()) { + check_writable(ctx, lhs); + if (lhs.opt->is_scalar()) + 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 @@ -1262,6 +1369,9 @@ namespace client OptWithPos &lhs, const std::vector> &il) { + if (ctx->skipping()) + return; + check_writable(ctx, lhs); if (lhs.opt->is_scalar()) { @@ -1311,6 +1421,9 @@ namespace client NewOldVariable &lhs, const std::vector> &il) { + if (ctx->skipping()) + return; + if (lhs.opt) { // Assign to an existing vector variable. OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true }; @@ -1355,7 +1468,7 @@ namespace client template static bool is_vector_variable_reference(const OptWithPos &var) { - return ! var.has_index() && var.opt->is_vector(); + return ! var.empty() && ! var.has_index() && var.opt->is_vector(); } // Called when checking whether the NewOldVariable could be assigned a vectir right hand side. @@ -1370,6 +1483,9 @@ namespace client OptWithPos &lhs, const OptWithPos &rhs) { + if (ctx->skipping()) + return; + check_writable(ctx, lhs); assert(lhs.opt->is_vector()); if (rhs.has_index() || ! rhs.opt->is_vector()) @@ -1399,6 +1515,10 @@ namespace client NewOldVariable &lhs, const OptWithPos &rhs) { + if (ctx->skipping()) + // Skipping, continue parsing. + return true; + if (lhs.opt) { assert(lhs.opt->is_vector()); OptWithPos lhs_opt{ lhs.opt, lhs.it_range, true }; @@ -1422,9 +1542,11 @@ namespace client } template - static void initializer_list_append(std::vector> &list, expr &expr) + static void initializer_list_append(std::vector> &list, expr ¶m) { - list.emplace_back(std::move(expr)); + if (param.type() != expr::TYPE_EMPTY) + // not skipping + list.emplace_back(std::move(param)); } template @@ -1433,9 +1555,11 @@ namespace client 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); + if (! ctx->skipping()) { + 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; } @@ -1445,9 +1569,11 @@ namespace client 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())); + if (! ctx->skipping()) { + 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; } @@ -1456,14 +1582,19 @@ namespace client template static void evaluate_index(expr &expr_index, int &output) { - if (expr_index.type() != expr::TYPE_INT) - expr_index.throw_exception("Non-integer index is not allowed to address a vector variable."); - output = expr_index.i(); + if (expr_index.type() != expr::TYPE_EMPTY) { + if (expr_index.type() != expr::TYPE_INT) + expr_index.throw_exception("Non-integer index is not allowed to address a vector variable."); + output = expr_index.i(); + } } template static void random(const MyContext *ctx, expr ¶m1, expr ¶m2) { + if (ctx->skipping()) + return; + if (ctx->context_data == nullptr) ctx->throw_exception("Random number generator not available in this context.", boost::iterator_range(param1.it_range.begin(), param2.it_range.end())); @@ -1525,6 +1656,10 @@ namespace client msg += ' '; msg += "^\n"; } + + private: + // For skipping execution of inactive conditional branches. + mutable int m_depth_suppressed{ 0 }; }; template @@ -1537,17 +1672,24 @@ namespace client std::vector table; static void init(const expr &x) { - if (!x.numeric_type()) - x.throw_exception("Interpolation value must be a number."); + if (x.type() != expr::TYPE_EMPTY) { + if (!x.numeric_type()) + x.throw_exception("Interpolation value must be a number."); + } } static void add_pair(const expr &x, const expr &y, InterpolateTableContext &table) { - if (! x.numeric_type()) - x.throw_exception("X value of a table point must be a number."); - if (! y.numeric_type()) - y.throw_exception("Y value of a table point must be a number."); - table.table.push_back({ x.as_d(), x.it_range, y.as_d() }); + if (x.type() != expr::TYPE_EMPTY) { + if (! x.numeric_type()) + x.throw_exception("X value of a table point must be a number."); + if (! y.numeric_type()) + y.throw_exception("Y value of a table point must be a number."); + table.table.push_back({ x.as_d(), x.it_range, y.as_d() }); + } } static void evaluate(const expr &expr_x, const InterpolateTableContext &table, expr &out) { + if (expr_x.type() == expr::TYPE_EMPTY) + return; + // Check whether the table X values are sorted. double x = expr_x.as_d(); bool evaluated = false; @@ -1698,6 +1840,52 @@ namespace client } }; + template + struct FactorActions { + static void set_start_pos(Iterator &start_pos, expr &out) + { out.it_range = boost::iterator_range(start_pos, start_pos); } + static void int_(const MyContext *ctx, int &value, Iterator &end_pos, expr &out) { + if (ctx->skipping()) { + out.reset(); + out.it_range.end() = end_pos; + } else + out = expr(value, out.it_range.begin(), end_pos); + } + static void double_(const MyContext *ctx, double &value, Iterator &end_pos, expr &out) { + if (ctx->skipping()) { + out.reset(); + out.it_range.end() = end_pos; + } else + out = expr(value, out.it_range.begin(), end_pos); + } + static void bool_(const MyContext *ctx, bool &value, Iterator &end_pos, expr &out) { + if (ctx->skipping()) { + out.reset(); + out.it_range.end() = end_pos; + } else + out = expr(value, out.it_range.begin(), end_pos); + } + static void string_(const MyContext *ctx, boost::iterator_range &it_range, expr &out) { + if (ctx->skipping()) { + out.reset(); + out.it_range = it_range; + } else + out = expr(std::string(it_range.begin() + 1, it_range.end() - 1), it_range.begin(), it_range.end()); + } + static void expr_(expr &value, Iterator &end_pos, expr &out) + { auto begin_pos = out.it_range.begin(); out = expr(std::move(value), begin_pos, end_pos); } + static void minus_(expr &value, expr &out) + { out = value.unary_minus(out.it_range.begin()); } + static void not_(expr &value, expr &out) + { out = value.unary_not(out.it_range.begin()); } + static void to_int(expr &value, expr &out) + { out = value.unary_integer(out.it_range.begin()); } + static void round(expr &value, expr &out) + { out = value.round(out.it_range.begin()); } + // For indicating "no optional parameter". + static void noexpr(expr &out) { out.reset(); } + }; + /////////////////////////////////////////////////////////////////////////// // Our macro_processor grammar /////////////////////////////////////////////////////////////////////////// @@ -1771,19 +1959,19 @@ namespace client // | (kw["switch"] > switch_output(_r1) [_val = _1]) | (assignment_statement(_r1) [_val = _1]) | (new_variable_statement(_r1) [_val = _1]) - | (additive_expression(_r1) [ px::bind(&expr::to_string2, _1, _val) ]) + | (conditional_expression(_r1) [ px::bind(&expr::to_string2, _1, _val) ]) ; macro.name("macro"); // An if expression enclosed in {} (the outmost {} are already parsed by the caller). if_else_output = - eps[_b=true] > - bool_expr_eval(_r1)[_a=_1] > '}' > - text_block(_r1)[px::bind(&expr::set_if, _a, _b, _1, _val)] > '{' > - *(kw["elsif"] > bool_expr_eval(_r1)[_a=_1] > '}' > - text_block(_r1)[px::bind(&expr::set_if, _a, _b, _1, _val)] > '{') > - -(kw["else"] > lit('}') > - text_block(_r1)[px::bind(&expr::set_if, _b, _b, _1, _val)] > '{') > + eps[_a=true] > + (bool_expr_eval(_r1)[px::bind(&MyContext::block_enter, _r1, _1)] > '}' > + text_block(_r1))[px::bind(&MyContext::block_exit, _r1, _1, _a, _2, _val)] > '{' > + *((kw["elsif"] > bool_expr_eval(_r1)[px::bind(&MyContext::block_enter, _r1, _1 && _a)] > '}' > + text_block(_r1))[px::bind(&MyContext::block_exit, _r1, _1, _a, _2, _val)] > '{') > + -(kw["else"] > eps[px::bind(&MyContext::block_enter, _r1, _a)] > lit('}') > + text_block(_r1)[px::bind(&MyContext::block_exit, _r1, _a, _a, _1, _val)] > '{') > kw["endif"]; if_else_output.name("if_else_output"); // A switch expression enclosed in {} (the outmost {} are already parsed by the caller). @@ -1811,8 +1999,11 @@ namespace client identifier.name("identifier"); conditional_expression = - logical_or_expression(_r1) [_val = _1] - >> -('?' > conditional_expression(_r1) > ':' > conditional_expression(_r1)) [px::bind(&expr::ternary_op, _val, _1, _2)]; + logical_or_expression(_r1) [_val = _1] + >> -('?' > eps[px::bind(&expr::evaluate_boolean, _val, _a)] > + eps[px::bind(&MyContext::block_enter, _r1, _a)] > conditional_expression(_r1)[px::bind(&MyContext::block_exit_ternary>, _r1, _a, _1, _val)] + > ':' > + eps[px::bind(&MyContext::block_enter, _r1, ! _a)] > conditional_expression(_r1)[px::bind(&MyContext::block_exit_ternary>, _r1, ! _a, _1, _val)]); conditional_expression.name("conditional_expression"); logical_or_expression = @@ -1901,36 +2092,12 @@ namespace client ) ); - struct FactorActions { - static void set_start_pos(Iterator &start_pos, expr &out) - { out.it_range = boost::iterator_range(start_pos, start_pos); } - static void int_(int &value, Iterator &end_pos, expr &out) - { out = expr(value, out.it_range.begin(), end_pos); } - static void double_(double &value, Iterator &end_pos, expr &out) - { out = expr(value, out.it_range.begin(), end_pos); } - static void bool_(bool &value, Iterator &end_pos, expr &out) - { out = expr(value, out.it_range.begin(), end_pos); } - static void string_(boost::iterator_range &it_range, expr &out) - { out = expr(std::string(it_range.begin() + 1, it_range.end() - 1), it_range.begin(), it_range.end()); } - static void expr_(expr &value, Iterator &end_pos, expr &out) - { auto begin_pos = out.it_range.begin(); out = expr(std::move(value), begin_pos, end_pos); } - static void minus_(expr &value, expr &out) - { out = value.unary_minus(out.it_range.begin()); } - static void not_(expr &value, expr &out) - { out = value.unary_not(out.it_range.begin()); } - static void to_int(expr &value, expr &out) - { out = value.unary_integer(out.it_range.begin()); } - static void round(expr &value, expr &out) - { out = value.round(out.it_range.begin()); } - // For indicating "no optional parameter". - static void noexpr(expr &out) { out.reset(); } - }; - unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( + unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( variable_reference(_r1) [px::bind(&MyContext::variable_value, _r1, _1, _val)] - | (lit('(') > conditional_expression(_r1) > ')' > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] - | (lit('-') > unary_expression(_r1) ) [ px::bind(&FactorActions::minus_, _1, _val) ] - | (lit('+') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] - | ((kw["not"] | '!') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::not_, _1, _val) ] + | (lit('(') > conditional_expression(_r1) > ')' > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] + | (lit('-') > unary_expression(_r1) ) [ px::bind(&FactorActions::minus_, _1, _val) ] + | (lit('+') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] + | ((kw["not"] | '!') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::not_, _1, _val) ] | (kw["min"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') [ px::bind(&expr::min, _val, _2) ] | (kw["max"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') @@ -1941,18 +2108,18 @@ namespace client [ px::bind(&expr::template digits, _val, _2, _3) ] | (kw["zdigits"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > optional_parameter(_r1)) [ 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["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"] > '(' > 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) ] - | (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _1, _2, _val) ] + | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _r1, _1, _2, _val) ] + | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _r1, _1, _2, _val) ] + | (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _r1, _1, _2, _val) ] | raw[lexeme['"' > *((utf8char - char_('\\') - char_('"')) | ('\\' > char_)) > '"']] - [ px::bind(&FactorActions::string_, _1, _val) ] + [ px::bind(&FactorActions::string_, _r1, _1, _val) ] ); unary_expression.name("unary_expression"); @@ -1980,8 +2147,8 @@ namespace client [px::bind(&InterpolateTableContext::add_pair, _1, _2, _val)] >> -lit(',')) ); interpolate_table.name("interpolate_table_list"); - optional_parameter = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( - lit(')') [ px::bind(&FactorActions::noexpr, _val) ] + optional_parameter = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( + lit(')') [ px::bind(&FactorActions::noexpr, _val) ] | (lit(',') > conditional_expression(_r1) > ')') [ _val = _1 ] ); optional_parameter.name("optional_parameter"); @@ -2074,7 +2241,7 @@ namespace client // Parsed identifier name. qi::rule(), spirit_encoding::space_type> identifier; // Ternary operator (?:) over logical_or_expression. - RuleExpression conditional_expression; + qi::rule(const MyContext*), qi::locals, spirit_encoding::space_type> conditional_expression; // Logical or over logical_and_expressions. RuleExpression logical_or_expression; // Logical and over relational_expressions. @@ -2108,7 +2275,7 @@ namespace client qi::rule(const MyContext*), qi::locals>, spirit_encoding::space_type> interpolate_table; qi::rule(const MyContext*, const expr ¶m), spirit_encoding::space_type> interpolate_table_list; - qi::rule, spirit_encoding::space_type> if_else_output; + qi::rule, spirit_encoding::space_type> if_else_output; qi::rule>, spirit_encoding::space_type> assignment_statement; // Allocating new local or global variables. qi::rule>, spirit_encoding::space_type> new_variable_statement; diff --git a/tests/libslic3r/test_placeholder_parser.cpp b/tests/libslic3r/test_placeholder_parser.cpp index b29ca0f8e..0e3521a23 100644 --- a/tests/libslic3r/test_placeholder_parser.cpp +++ b/tests/libslic3r/test_placeholder_parser.cpp @@ -75,6 +75,11 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") { SECTION("math: zdigits(5., 15, 8)") { REQUIRE(parser.process("{zdigits(5, 15, 8)}") == "000005.00000000"); } SECTION("math: digits(13.84375892476, 15, 8)") { REQUIRE(parser.process("{digits(13.84375892476, 15, 8)}") == " 13.84375892"); } SECTION("math: zdigits(13.84375892476, 15, 8)") { REQUIRE(parser.process("{zdigits(13.84375892476, 15, 8)}") == "000013.84375892"); } + SECTION("math: ternary1") { REQUIRE(parser.process("{12 == 12 ? 1 - 3 : 2 * 2 * unknown_symbol}") == "-2"); } + SECTION("math: ternary2") { REQUIRE(parser.process("{12 == 21/2 ? 1 - 1 - unknown_symbol : 2 * 2}") == "4"); } + SECTION("math: ternary3") { REQUIRE(parser.process("{12 == 13 ? 1 - 1 * unknown_symbol : 2 * 2}") == "4"); } + SECTION("math: ternary4") { REQUIRE(parser.process("{12 == 2 * 6 ? 1 - 1 : 2 * unknown_symbol}") == "0"); } + SECTION("math: ternary nested") { REQUIRE(parser.process("{12 == 2 * 6 ? 3 - 1 != 2 ? does_not_exist : 0 * 0 - 0 / 1 + 12345 : bull ? 3 - cokoo : 2 * unknown_symbol}") == "12345"); } SECTION("math: interpolate_table(13.84375892476, (0, 0), (20, 20))") { REQUIRE(std::stod(parser.process("{interpolate_table(13.84375892476, (0, 0), (20, 20))}")) == Approx(13.84375892476)); } SECTION("math: interpolate_table(13, (0, 0), (20, 20), (30, 20))") { REQUIRE(std::stod(parser.process("{interpolate_table(13, (0, 0), (20, 20), (30, 20))}")) == Approx(13.)); } SECTION("math: interpolate_table(25, (0, 0), (20, 20), (30, 20))") { REQUIRE(std::stod(parser.process("{interpolate_table(25, (0, 0), (20, 20), (30, 20))}")) == Approx(20.)); } @@ -106,10 +111,10 @@ SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") { SECTION("boolean expression parser: (12 == 12) or (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) or (13 == 14)")); } SECTION("boolean expression parser: (12 == 12) || (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) || (13 == 14)")); } SECTION("boolean expression parser: (12 == 12) and not (13 == 14)") { REQUIRE(boolean_expression("(12 == 12) and not (13 == 14)")); } - SECTION("boolean expression parser: ternary true") { REQUIRE(boolean_expression("(12 == 12) ? (1 - 1 == 0) : (2 * 2 == 3)")); } - SECTION("boolean expression parser: ternary false") { REQUIRE(! boolean_expression("(12 == 21/2) ? (1 - 1 == 0) : (2 * 2 == 3)")); } - SECTION("boolean expression parser: ternary false 2") { REQUIRE(boolean_expression("(12 == 13) ? (1 - 1 == 3) : (2 * 2 == 4)")); } - SECTION("boolean expression parser: ternary true 2") { REQUIRE(! boolean_expression("(12 == 2 * 6) ? (1 - 1 == 3) : (2 * 2 == 4)")); } + SECTION("boolean expression parser: ternary true") { REQUIRE(boolean_expression("(12 == 12) ? (1 - 1 == 0) : (2 * 2 == 3 * unknown_symbol)")); } + SECTION("boolean expression parser: ternary false") { REQUIRE(! boolean_expression("(12 == 21/2) ? (1 - 1 == 0 - unknown_symbol) : (2 * 2 == 3)")); } + SECTION("boolean expression parser: ternary false 2") { REQUIRE(boolean_expression("(12 == 13) ? (1 - 1 == 3 * unknown_symbol) : (2 * 2 == 4)")); } + SECTION("boolean expression parser: ternary true 2") { REQUIRE(! boolean_expression("(12 == 2 * 6) ? (1 - 1 == 3) : (2 * 2 == 4 * unknown_symbol)")); } SECTION("boolean expression parser: lower than - false") { REQUIRE(! boolean_expression("12 < 3")); } SECTION("boolean expression parser: lower than - true") { REQUIRE(boolean_expression("12 < 22")); } SECTION("boolean expression parser: greater than - true") { REQUIRE(boolean_expression("12 > 3")); } @@ -227,4 +232,23 @@ SCENARIO("Placeholder parser variables", "[PlaceholderParser]") { 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"); } + + SECTION("nested if with new variables") { + std::string script = + "{if 1 == 1}{local myints = (5, 4, 3, 2, 1)}{else}{local myfloats = (1., 2., 3., 4., 5., 6., 7.)}{endif}" + "{myints[1]},{size(myints)}"; + REQUIRE(parser.process(script, 0, nullptr, nullptr, nullptr) == "4,5"); + } + SECTION("nested if with new variables 2") { + std::string script = + "{if 1 == 0}{local myints = (5, 4, 3, 2, 1)}{else}{local myfloats = (1., 2., 3., 4., 5., 6., 7.)}{endif}" + "{size(myfloats)}"; + REQUIRE(parser.process(script, 0, nullptr, nullptr, nullptr) == "7"); + } + SECTION("nested if with new variables, two level") { + std::string script = + "{if 1 == 1}{if 2 == 3}{nejaka / haluz}{else}{local myints = (6, 5, 4, 3, 2, 1)}{endif}{else}{if zase * haluz}{else}{local myfloats = (1., 2., 3., 4., 5., 6., 7.)}{endif}{endif}" + "{size(myints)}"; + REQUIRE(parser.process(script, 0, nullptr, nullptr, nullptr) == "6"); + } } From 59d3683a799f342c3ed9217ee3d1d4ceabdcdc17 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Fri, 24 Mar 2023 14:26:25 +0100 Subject: [PATCH 25/25] PlaceholderParser: Refactored, removed all the unncesseary template parameters. --- src/libslic3r/PlaceholderParser.cpp | 566 ++++++++++++---------------- 1 file changed, 237 insertions(+), 329 deletions(-) diff --git a/src/libslic3r/PlaceholderParser.cpp b/src/libslic3r/PlaceholderParser.cpp index 06a4d3960..fb9fdbea0 100644 --- a/src/libslic3r/PlaceholderParser.cpp +++ b/src/libslic3r/PlaceholderParser.cpp @@ -167,28 +167,28 @@ namespace px = boost::phoenix; namespace client { - template + using Iterator = std::string::const_iterator; + using IteratorRange = boost::iterator_range; + struct OptWithPos { OptWithPos() {} - OptWithPos(ConfigOptionConstPtr opt, boost::iterator_range it_range, bool writable = false) : opt(opt), it_range(it_range), writable(writable) {} + OptWithPos(ConfigOptionConstPtr opt, IteratorRange 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. int index { -1 }; - boost::iterator_range it_range; + IteratorRange it_range; bool empty() const { return opt == nullptr; } bool has_index() const { return index != -1; } }; - template - std::ostream& operator<<(std::ostream& os, OptWithPos const& opt) + std::ostream& operator<<(std::ostream& os, OptWithPos const& opt) { os << std::string(opt.it_range.begin(), opt.it_range.end()); return os; } - template struct expr { expr() {} @@ -320,7 +320,7 @@ namespace client // Range of input iterators covering this expression. // Used for throwing parse exceptions. - boost::iterator_range it_range; + IteratorRange it_range; expr unary_minus(const Iterator start_pos) const { @@ -329,9 +329,9 @@ namespace client // Inside an if / else block to be skipped. return expr(); case TYPE_INT : - return expr(- this->i(), start_pos, this->it_range.end()); + return expr(- this->i(), start_pos, this->it_range.end()); case TYPE_DOUBLE: - return expr(- this->d(), start_pos, this->it_range.end()); + return expr(- this->d(), start_pos, this->it_range.end()); default: this->throw_exception("Cannot apply unary minus operator."); } @@ -347,9 +347,9 @@ namespace client // Inside an if / else block to be skipped. return expr(); case TYPE_INT: - return expr(this->i(), start_pos, this->it_range.end()); + return expr(this->i(), start_pos, this->it_range.end()); case TYPE_DOUBLE: - return expr(static_cast(this->d()), start_pos, this->it_range.end()); + return expr(static_cast(this->d()), start_pos, this->it_range.end()); default: this->throw_exception("Cannot convert to integer."); } @@ -365,9 +365,9 @@ namespace client // Inside an if / else block to be skipped. return expr(); case TYPE_INT: - return expr(this->i(), start_pos, this->it_range.end()); + return expr(this->i(), start_pos, this->it_range.end()); case TYPE_DOUBLE: - return expr(static_cast(std::round(this->d())), start_pos, this->it_range.end()); + return expr(static_cast(std::round(this->d())), start_pos, this->it_range.end()); default: this->throw_exception("Cannot round a non-numeric value."); } @@ -383,7 +383,7 @@ namespace client // Inside an if / else block to be skipped. return expr(); case TYPE_BOOL: - return expr(! this->b(), start_pos, this->it_range.end()); + return expr(! this->b(), start_pos, this->it_range.end()); default: this->throw_exception("Cannot apply a not operator."); } @@ -411,7 +411,7 @@ namespace client else m_data.i += rhs.i(); } - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + this->it_range = IteratorRange(this->it_range.begin(), rhs.it_range.end()); return *this; } @@ -428,7 +428,7 @@ namespace client this->set_d_lite(this->as_d() - rhs.as_d()); else m_data.i -= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + this->it_range = IteratorRange(this->it_range.begin(), rhs.it_range.end()); } return *this; } @@ -446,7 +446,7 @@ namespace client this->set_d_lite(this->as_d() * rhs.as_d()); else m_data.i *= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + this->it_range = IteratorRange(this->it_range.begin(), rhs.it_range.end()); } return *this; } @@ -465,7 +465,7 @@ namespace client this->set_d_lite(this->as_d() / rhs.as_d()); else m_data.i /= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + this->it_range = IteratorRange(this->it_range.begin(), rhs.it_range.end()); } return *this; } @@ -484,7 +484,7 @@ namespace client this->set_d_lite(std::fmod(this->as_d(), rhs.as_d())); else m_data.i %= rhs.i(); - this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); + this->it_range = IteratorRange(this->it_range.begin(), rhs.it_range.end()); } return *this; } @@ -644,7 +644,7 @@ namespace client param1.set_s(buf); } - static void regex_op(const expr &lhs, boost::iterator_range &rhs, char op, expr &out) + static void regex_op(const expr &lhs, IteratorRange &rhs, char op, expr &out) { if (lhs.type() == TYPE_EMPTY) // Inside an if / else block to be skipped @@ -669,8 +669,8 @@ namespace client } } - static void regex_matches (expr &lhs, boost::iterator_range &rhs) { return regex_op(lhs, rhs, '=', lhs); } - static void regex_doesnt_match(expr &lhs, boost::iterator_range &rhs) { return regex_op(lhs, rhs, '!', lhs); } + static void regex_matches (expr &lhs, IteratorRange &rhs) { return regex_op(lhs, rhs, '=', lhs); } + static void regex_doesnt_match(expr &lhs, IteratorRange &rhs) { return regex_op(lhs, rhs, '!', lhs); } static void one_of_test_init(expr &out) { out.set_b(false); @@ -698,7 +698,7 @@ namespace client out.set_b(match.s() == pattern.s()); } } - static void one_of_test_regex(const expr &match, boost::iterator_range &pattern, expr &out) { + static void one_of_test_regex(const expr &match, IteratorRange &pattern, expr &out) { if (match.type() == TYPE_EMPTY) { // Inside an if / else block to be skipped out.reset(); @@ -757,10 +757,9 @@ namespace client } m_data; }; - template - std::ostream& operator<<(std::ostream &os, const expr &expression) + std::ostream& operator<<(std::ostream &os, const expr &expression) { - typedef expr Expr; + typedef expr Expr; os << std::string(expression.it_range.begin(), expression.it_range.end()) << " - "; switch (expression.type()) { case Expr::TYPE_EMPTY: os << "empty"; break; @@ -815,8 +814,7 @@ namespace client not_yet_consumed = false; } } - template - static void block_exit_ternary(const MyContext* ctx, const bool condition, DataType &data_in, DataType &data_out) + static void block_exit_ternary(const MyContext* ctx, const bool condition, expr &data_in, expr &data_out) { if (ctx->skipping()) -- ctx->m_depth_suppressed; @@ -858,11 +856,7 @@ namespace client this->config_local.set_key_value(opt_key, opt.release()); } - template - static void legacy_variable_expansion( - const MyContext *ctx, - boost::iterator_range &opt_key, - std::string &output) + static void legacy_variable_expansion(const MyContext *ctx, IteratorRange &opt_key, std::string &output) { if (ctx->skipping()) return; @@ -881,12 +875,12 @@ namespace client char *endptr = nullptr; idx = strtol(opt_key_str.c_str() + idx + 1, &endptr, 10); if (endptr == nullptr || *endptr != 0) - ctx->throw_exception("Invalid vector index", boost::iterator_range(opt_key.begin() + idx + 1, opt_key.end())); + ctx->throw_exception("Invalid vector index", IteratorRange(opt_key.begin() + idx + 1, opt_key.end())); } } } if (opt == nullptr) - ctx->throw_exception("Variable does not exist", boost::iterator_range(opt_key.begin(), opt_key.end())); + ctx->throw_exception("Variable does not exist", IteratorRange(opt_key.begin(), opt_key.end())); if (opt->is_scalar()) output = opt->serialize(); else { @@ -897,12 +891,11 @@ namespace client } } - template static void legacy_variable_expansion2( - const MyContext *ctx, - boost::iterator_range &opt_key, - boost::iterator_range &opt_vector_index, - std::string &output) + const MyContext *ctx, + IteratorRange &opt_key, + IteratorRange &opt_vector_index, + std::string &output) { if (ctx->skipping()) return; @@ -919,7 +912,7 @@ namespace client ctx->throw_exception("Trying to index a scalar variable", opt_key); const ConfigOptionVectorBase *vec = static_cast(opt); if (vec->empty()) - ctx->throw_exception("Indexing an empty vector variable", boost::iterator_range(opt_key.begin(), opt_key.end())); + ctx->throw_exception("Indexing an empty vector variable", IteratorRange(opt_key.begin(), opt_key.end())); const ConfigOption *opt_index = ctx->resolve_symbol(std::string(opt_vector_index.begin(), opt_vector_index.end())); if (opt_index == nullptr) ctx->throw_exception("Variable does not exist", opt_key); @@ -931,11 +924,10 @@ namespace client output = vec->vserialize()[(idx >= (int)vec->size()) ? 0 : idx]; } - template static void resolve_variable( - const MyContext *ctx, - boost::iterator_range &opt_key, - OptWithPos &output) + const MyContext *ctx, + IteratorRange &opt_key, + OptWithPos &output) { if (! ctx->skipping()) { const std::string key{ opt_key.begin(), opt_key.end() }; @@ -951,13 +943,12 @@ namespace client output.it_range = opt_key; } - template static void store_variable_index( - const MyContext *ctx, - OptWithPos &opt, - int index, - Iterator it_end, - OptWithPos &output) + const MyContext *ctx, + OptWithPos &opt, + int index, + Iterator it_end, + OptWithPos &output) { if (! ctx->skipping()) { if (! opt.opt->is_vector()) @@ -973,11 +964,7 @@ namespace client // 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) + static void scalar_variable_to_expr(const MyContext *ctx, OptWithPos &opt, expr &output) { if (ctx->skipping()) return; @@ -1037,11 +1024,7 @@ namespace client // 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) + static void vector_element_to_expr(const MyContext *ctx, OptWithPos &opt, expr &output) { if (ctx->skipping()) return; @@ -1066,21 +1049,18 @@ namespace client } } - template - static void check_writable(const MyContext *ctx, OptWithPos &opt) { + 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) { + 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) + 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) @@ -1088,11 +1068,7 @@ namespace client return size_t(count); }; - template - static void scalar_variable_assign_scalar( - const MyContext *ctx, - OptWithPos &lhs, - const expr &rhs) + static void scalar_variable_assign_scalar(const MyContext *ctx, OptWithPos &lhs, const expr &rhs) { assert(lhs.opt->is_scalar()); check_writable(ctx, lhs); @@ -1114,7 +1090,7 @@ namespace client static_cast(wropt)->value = rhs.as_d(); break; case coBool: - if (rhs.type() != expr::TYPE_BOOL) + 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; @@ -1123,11 +1099,7 @@ namespace client } } - template - static void vector_variable_element_assign_scalar( - const MyContext *ctx, - OptWithPos &lhs, - const expr &rhs) + static void vector_variable_element_assign_scalar(const MyContext *ctx, OptWithPos &lhs, const expr &rhs) { assert(lhs.opt->is_vector()); check_writable(ctx, lhs); @@ -1155,7 +1127,7 @@ namespace client static_cast(vec)->values[lhs.index] = rhs.as_d(); break; case coBools: - if (rhs.type() != expr::TYPE_BOOL) + 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; @@ -1164,12 +1136,7 @@ namespace client } } - template - static void vector_variable_assign_expr_with_count( - const MyContext *ctx, - OptWithPos &lhs, - const expr &rhs_count, - const expr &rhs_value) + 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); @@ -1186,7 +1153,7 @@ namespace client static_cast(opt)->values.assign(count, rhs_value.to_string()); break; case coBools: - if (rhs_value.type() != expr::TYPE_BOOL) + 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; @@ -1194,11 +1161,7 @@ namespace client } } - template - static void variable_value( - const MyContext *ctx, - OptWithPos &opt, - expr &output) + static void variable_value(const MyContext *ctx, OptWithPos &opt, expr &output) { if (! ctx->skipping()) { if (opt.opt->is_vector()) @@ -1211,11 +1174,7 @@ namespace client // Return a boolean value, true if the scalar variable referenced by "opt" is nullable and it has a nil value. // Return a boolean value, true if an element of a vector variable referenced by "opt[index]" is nullable and it has a nil value. - template - static void is_nil_test( - const MyContext *ctx, - OptWithPos &opt, - expr &output) + static void is_nil_test(const MyContext *ctx, OptWithPos &opt, expr &output) { if (ctx->skipping()) { } else if (opt.opt->is_vector()) { @@ -1233,18 +1192,16 @@ namespace client } // Reference to an existing symbol, or a name of a new symbol. - template struct NewOldVariable { - std::string name; - boost::iterator_range it_range; - ConfigOption *opt{ nullptr }; + std::string name; + IteratorRange it_range; + ConfigOption *opt{ nullptr }; }; - template static void new_old_variable( - const MyContext *ctx, - bool global_variable, - const boost::iterator_range &it_range, - NewOldVariable &out) + const MyContext *ctx, + bool global_variable, + const IteratorRange &it_range, + NewOldVariable &out) { if (! ctx->skipping()) { t_config_option_key key(std::string(it_range.begin(), it_range.end())); @@ -1270,11 +1227,7 @@ namespace client } // Decoding a scalar variable symbol "opt", assigning it a value of "param". - template - static void scalar_variable_assign_scalar_expression( - const MyContext *ctx, - OptWithPos &opt, - const expr ¶m) + static void scalar_variable_assign_scalar_expression(const MyContext *ctx, OptWithPos &opt, const expr ¶m) { if (! ctx->skipping()) { check_writable(ctx, opt); @@ -1285,12 +1238,11 @@ namespace client } } - template static void scalar_variable_new_from_scalar_expression( - const MyContext *ctx, - bool global_variable, - NewOldVariable &lhs, - const expr &rhs) + const MyContext *ctx, + bool global_variable, + NewOldVariable &lhs, + const expr &rhs) { if (ctx->skipping()) { } else if (lhs.opt) { @@ -1301,23 +1253,22 @@ namespace client } else { 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; + 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(lhs.name, std::move(opt_new), global_variable); } } - template static void vector_variable_new_from_array( - const MyContext *ctx, - bool global_variable, - NewOldVariable &lhs, - const expr &rhs_count, - const expr &rhs_value) + const MyContext *ctx, + bool global_variable, + NewOldVariable &lhs, + const expr &rhs_count, + const expr &rhs_value) { if (ctx->skipping()) { } else if (lhs.opt) { @@ -1329,22 +1280,21 @@ namespace client 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; + 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 &rhs_count, - const expr &rhs_value) + const MyContext *ctx, + OptWithPos &lhs, + const expr &rhs_count, + const expr &rhs_value) { if (! ctx->skipping()) { check_writable(ctx, lhs); @@ -1354,20 +1304,16 @@ namespace client } } - template - static void fill_vector_from_initializer_list(ConfigOption *opt, const std::vector> &il, RightValueEvaluate rv_eval) { + 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) + 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) + static void vector_variable_assign_initializer_list(const MyContext *ctx, OptWithPos &lhs, const std::vector &il) { if (ctx->skipping()) return; @@ -1385,7 +1331,7 @@ namespace client ctx->throw_exception("Cannot assign a vector value to a scalar variable.", lhs.it_range); } - auto check_numeric_vector = [](const std::vector> &il) { + 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"); @@ -1406,7 +1352,7 @@ namespace client break; case coBools: for (auto &i : il) - if (i.type() != expr::TYPE_BOOL) + 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; @@ -1414,12 +1360,11 @@ namespace client } } - template static void vector_variable_new_from_initializer_list( - const MyContext *ctx, - bool global_variable, - NewOldVariable &lhs, - const std::vector> &il) + const MyContext *ctx, + bool global_variable, + NewOldVariable &lhs, + const std::vector &il) { if (ctx->skipping()) return; @@ -1439,10 +1384,10 @@ namespace client size_t num_string = 0; for (auto &i : il) switch (i.type()) { - case expr::TYPE_BOOL: ++ num_bool; break; - case expr::TYPE_INT: ++ num_int; break; - case expr::TYPE_DOUBLE: ++ num_double; break; - case expr::TYPE_STRING: ++ num_string; break; + case expr::TYPE_BOOL: ++ num_bool; break; + case expr::TYPE_INT: ++ num_int; break; + case expr::TYPE_DOUBLE: ++ num_double; break; + case expr::TYPE_STRING: ++ num_string; break; default: assert(false); } std::unique_ptr opt_new; @@ -1451,7 +1396,7 @@ namespace client 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() }); + ctx->throw_exception("Right side is not valid: Mixing numeric and boolean types.", IteratorRange{ il.front().it_range.begin(), il.back().it_range.end() }); opt_new = std::make_unique(); } else { // Output is numeric. @@ -1466,22 +1411,16 @@ namespace client } } - template - static bool is_vector_variable_reference(const OptWithPos &var) { + static bool is_vector_variable_reference(const OptWithPos &var) { return ! var.empty() && ! var.has_index() && var.opt->is_vector(); } // Called when checking whether the NewOldVariable could be assigned a vectir right hand side. - template - static bool could_be_vector_variable_reference(const NewOldVariable &var) { + 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) + static void copy_vector_variable_to_vector_variable(const MyContext *ctx, OptWithPos &lhs, const OptWithPos &rhs) { if (ctx->skipping()) return; @@ -1508,12 +1447,11 @@ namespace client 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) + const MyContext *ctx, + bool global_variable, + NewOldVariable &lhs, + const OptWithPos &rhs) { if (ctx->skipping()) // Skipping, continue parsing. @@ -1541,19 +1479,14 @@ namespace client return true; } - template - static void initializer_list_append(std::vector> &list, expr ¶m) + static void initializer_list_append(std::vector &list, expr ¶m) { - if (param.type() != expr::TYPE_EMPTY) + if (param.type() != expr::TYPE_EMPTY) // not skipping list.emplace_back(std::move(param)); } - template - static void is_vector_empty( - const MyContext *ctx, - OptWithPos &opt, - expr &out) + static void is_vector_empty(const MyContext *ctx, OptWithPos &opt, expr &out) { if (! ctx->skipping()) { if (opt.has_index() || ! opt.opt->is_vector()) @@ -1563,11 +1496,7 @@ namespace client out.it_range = opt.it_range; } - template - static void vector_size( - const MyContext *ctx, - OptWithPos &opt, - expr &out) + static void vector_size(const MyContext *ctx, OptWithPos &opt, expr &out) { if (! ctx->skipping()) { if (opt.has_index() || ! opt.opt->is_vector()) @@ -1579,37 +1508,33 @@ namespace client // Verify that the expression returns an integer, which may be used // to address a vector. - template - static void evaluate_index(expr &expr_index, int &output) + static void evaluate_index(expr &expr_index, int &output) { - if (expr_index.type() != expr::TYPE_EMPTY) { - if (expr_index.type() != expr::TYPE_INT) + if (expr_index.type() != expr::TYPE_EMPTY) { + if (expr_index.type() != expr::TYPE_INT) expr_index.throw_exception("Non-integer index is not allowed to address a vector variable."); output = expr_index.i(); } } - template - static void random(const MyContext *ctx, expr ¶m1, expr ¶m2) + static void random(const MyContext *ctx, expr ¶m1, expr ¶m2) { if (ctx->skipping()) return; if (ctx->context_data == nullptr) ctx->throw_exception("Random number generator not available in this context.", - boost::iterator_range(param1.it_range.begin(), param2.it_range.end())); - expr::random(param1, param2, ctx->context_data->rng); + IteratorRange(param1.it_range.begin(), param2.it_range.end())); + expr::random(param1, param2, ctx->context_data->rng); } - template - static void throw_exception(const std::string &msg, const boost::iterator_range &it_range) + static void throw_exception(const std::string &msg, const IteratorRange &it_range) { // An asterix is added to the start of the string to differentiate the boost::spirit::info::tag content // between the grammer terminal / non-terminal symbol name and a free-form error message. - boost::throw_exception(qi::expectation_failure(it_range.begin(), it_range.end(), spirit::info(std::string("*") + msg))); + boost::throw_exception(qi::expectation_failure(it_range.begin(), it_range.end(), spirit::info(std::string("*") + msg))); } - template static void process_error_message(const MyContext *context, const boost::spirit::info &info, const Iterator &it_begin, const Iterator &it_end, const Iterator &it_error) { std::string &msg = const_cast(context)->error_message; @@ -1662,23 +1587,22 @@ namespace client mutable int m_depth_suppressed{ 0 }; }; - template struct InterpolateTableContext { struct Item { - double x; - boost::iterator_range it_range_x; - double y; + double x; + IteratorRange it_range_x; + double y; }; std::vector table; - static void init(const expr &x) { - if (x.type() != expr::TYPE_EMPTY) { + static void init(const expr &x) { + if (x.type() != expr::TYPE_EMPTY) { if (!x.numeric_type()) x.throw_exception("Interpolation value must be a number."); } } - static void add_pair(const expr &x, const expr &y, InterpolateTableContext &table) { - if (x.type() != expr::TYPE_EMPTY) { + static void add_pair(const expr &x, const expr &y, InterpolateTableContext &table) { + if (x.type() != expr::TYPE_EMPTY) { if (! x.numeric_type()) x.throw_exception("X value of a table point must be a number."); if (! y.numeric_type()) @@ -1686,8 +1610,8 @@ namespace client table.table.push_back({ x.as_d(), x.it_range, y.as_d() }); } } - static void evaluate(const expr &expr_x, const InterpolateTableContext &table, expr &out) { - if (expr_x.type() == expr::TYPE_EMPTY) + static void evaluate(const expr &expr_x, const InterpolateTableContext &table, expr &out) { + if (expr_x.type() == expr::TYPE_EMPTY) return; // Check whether the table X values are sorted. @@ -1697,7 +1621,7 @@ namespace client double x0 = table.table[i - 1].x; double x1 = table.table[i].x; if (x0 > x1) - boost::throw_exception(qi::expectation_failure( + boost::throw_exception(qi::expectation_failure( table.table[i - 1].it_range_x.begin(), table.table[i].it_range_x.end(), spirit::info("X coordinates of the table must be increasing"))); if (! evaluated && x >= x0 && x <= x1) { double y0 = table.table[i - 1].y; @@ -1726,8 +1650,7 @@ namespace client } }; - template - std::ostream& operator<<(std::ostream &os, const InterpolateTableContext &table_context) + std::ostream& operator<<(std::ostream &os, const InterpolateTableContext &table_context) { for (const auto &item : table_context.table) os << "(" << item.x << "," << item.y << ")"; @@ -1763,8 +1686,7 @@ namespace client }; // For debugging the boost::spirit parsers. Print out the string enclosed in it_range. - template - std::ostream& operator<<(std::ostream& os, const boost::iterator_range &it_range) + std::ostream& operator<<(std::ostream& os, const IteratorRange &it_range) { os << std::string(it_range.begin(), it_range.end()); return os; @@ -1828,7 +1750,7 @@ namespace client first = it; return true; err: - MyContext::throw_exception("Invalid utf8 sequence", boost::iterator_range(first, last)); + MyContext::throw_exception("Invalid utf8 sequence", IteratorRange(first, last)); return false; } @@ -1840,57 +1762,55 @@ namespace client } }; - template struct FactorActions { - static void set_start_pos(Iterator &start_pos, expr &out) - { out.it_range = boost::iterator_range(start_pos, start_pos); } - static void int_(const MyContext *ctx, int &value, Iterator &end_pos, expr &out) { + static void set_start_pos(Iterator &start_pos, expr &out) + { out.it_range = IteratorRange(start_pos, start_pos); } + static void int_(const MyContext *ctx, int &value, Iterator &end_pos, expr &out) { if (ctx->skipping()) { out.reset(); out.it_range.end() = end_pos; } else - out = expr(value, out.it_range.begin(), end_pos); + out = expr(value, out.it_range.begin(), end_pos); } - static void double_(const MyContext *ctx, double &value, Iterator &end_pos, expr &out) { + static void double_(const MyContext *ctx, double &value, Iterator &end_pos, expr &out) { if (ctx->skipping()) { out.reset(); out.it_range.end() = end_pos; } else - out = expr(value, out.it_range.begin(), end_pos); + out = expr(value, out.it_range.begin(), end_pos); } - static void bool_(const MyContext *ctx, bool &value, Iterator &end_pos, expr &out) { + static void bool_(const MyContext *ctx, bool &value, Iterator &end_pos, expr &out) { if (ctx->skipping()) { out.reset(); out.it_range.end() = end_pos; } else - out = expr(value, out.it_range.begin(), end_pos); + out = expr(value, out.it_range.begin(), end_pos); } - static void string_(const MyContext *ctx, boost::iterator_range &it_range, expr &out) { + static void string_(const MyContext *ctx, IteratorRange &it_range, expr &out) { if (ctx->skipping()) { out.reset(); out.it_range = it_range; } else - out = expr(std::string(it_range.begin() + 1, it_range.end() - 1), it_range.begin(), it_range.end()); + out = expr(std::string(it_range.begin() + 1, it_range.end() - 1), it_range.begin(), it_range.end()); } - static void expr_(expr &value, Iterator &end_pos, expr &out) - { auto begin_pos = out.it_range.begin(); out = expr(std::move(value), begin_pos, end_pos); } - static void minus_(expr &value, expr &out) + static void expr_(expr &value, Iterator &end_pos, expr &out) + { auto begin_pos = out.it_range.begin(); out = expr(std::move(value), begin_pos, end_pos); } + static void minus_(expr &value, expr &out) { out = value.unary_minus(out.it_range.begin()); } - static void not_(expr &value, expr &out) + static void not_(expr &value, expr &out) { out = value.unary_not(out.it_range.begin()); } - static void to_int(expr &value, expr &out) + static void to_int(expr &value, expr &out) { out = value.unary_integer(out.it_range.begin()); } - static void round(expr &value, expr &out) + static void round(expr &value, expr &out) { out = value.round(out.it_range.begin()); } // For indicating "no optional parameter". - static void noexpr(expr &out) { out.reset(); } + static void noexpr(expr &out) { out.reset(); } }; /////////////////////////////////////////////////////////////////////////// // Our macro_processor grammar /////////////////////////////////////////////////////////////////////////// // Inspired by the C grammar rules https://www.lysator.liu.se/c/ANSI-C-grammar-y.html - template struct macro_processor : qi::grammar, spirit_encoding::space_type> { macro_processor() : macro_processor::base_type(start) @@ -1932,10 +1852,10 @@ namespace client // could serve both purposes. start = ( (eps(px::bind(&MyContext::evaluate_full_macro, _r1)) > text_block(_r1) [_val=_1]) - | conditional_expression(_r1) [ px::bind(&expr::evaluate_boolean_to_string, _1, _val) ] + | conditional_expression(_r1) [ px::bind(&expr::evaluate_boolean_to_string, _1, _val) ] ) > eoi; start.name("start"); - qi::on_error(start, px::bind(&MyContext::process_error_message, _r1, _4, _1, _2, _3)); + qi::on_error(start, px::bind(&MyContext::process_error_message, _r1, _4, _1, _2, _3)); text_block = *( text [_val+=_1] @@ -1959,7 +1879,7 @@ namespace client // | (kw["switch"] > switch_output(_r1) [_val = _1]) | (assignment_statement(_r1) [_val = _1]) | (new_variable_statement(_r1) [_val = _1]) - | (conditional_expression(_r1) [ px::bind(&expr::to_string2, _1, _val) ]) + | (conditional_expression(_r1) [ px::bind(&expr::to_string2, _1, _val) ]) ; macro.name("macro"); @@ -1978,18 +1898,18 @@ namespace client /* switch_output = eps[_b=true] > - omit[expr(_r1)[_a=_1]] > '}' > text_block(_r1)[px::bind(&expr::set_if_equal, _a, _b, _1, _val)] > '{' > - *("elsif" > omit[bool_expr_eval(_r1)[_a=_1]] > '}' > text_block(_r1)[px::bind(&expr::set_if, _a, _b, _1, _val)]) >> - -("else" > '}' >> text_block(_r1)[px::bind(&expr::set_if, _b, _b, _1, _val)]) > + omit[expr(_r1)[_a=_1]] > '}' > text_block(_r1)[px::bind(&expr::set_if_equal, _a, _b, _1, _val)] > '{' > + *("elsif" > omit[bool_expr_eval(_r1)[_a=_1]] > '}' > text_block(_r1)[px::bind(&expr::set_if, _a, _b, _1, _val)]) >> + -("else" > '}' >> text_block(_r1)[px::bind(&expr::set_if, _b, _b, _1, _val)]) > "endif"; */ // Legacy variable expansion of the original Slic3r, in the form of [scalar_variable] or [vector_variable_index]. legacy_variable_expansion = (identifier >> &lit(']')) - [ px::bind(&MyContext::legacy_variable_expansion, _r1, _1, _val) ] + [ px::bind(&MyContext::legacy_variable_expansion, _r1, _1, _val) ] | (identifier > lit('[') > identifier > ']') - [ px::bind(&MyContext::legacy_variable_expansion2, _r1, _1, _2, _val) ] + [ px::bind(&MyContext::legacy_variable_expansion2, _r1, _1, _2, _val) ] ; legacy_variable_expansion.name("legacy_variable_expansion"); @@ -2000,43 +1920,43 @@ namespace client conditional_expression = logical_or_expression(_r1) [_val = _1] - >> -('?' > eps[px::bind(&expr::evaluate_boolean, _val, _a)] > - eps[px::bind(&MyContext::block_enter, _r1, _a)] > conditional_expression(_r1)[px::bind(&MyContext::block_exit_ternary>, _r1, _a, _1, _val)] + >> -('?' > eps[px::bind(&expr::evaluate_boolean, _val, _a)] > + eps[px::bind(&MyContext::block_enter, _r1, _a)] > conditional_expression(_r1)[px::bind(&MyContext::block_exit_ternary, _r1, _a, _1, _val)] > ':' > - eps[px::bind(&MyContext::block_enter, _r1, ! _a)] > conditional_expression(_r1)[px::bind(&MyContext::block_exit_ternary>, _r1, ! _a, _1, _val)]); + eps[px::bind(&MyContext::block_enter, _r1, ! _a)] > conditional_expression(_r1)[px::bind(&MyContext::block_exit_ternary, _r1, ! _a, _1, _val)]); conditional_expression.name("conditional_expression"); logical_or_expression = logical_and_expression(_r1) [_val = _1] - >> *( ((kw["or"] | "||") > logical_and_expression(_r1) ) [px::bind(&expr::logical_or, _val, _1)] ); + >> *( ((kw["or"] | "||") > logical_and_expression(_r1) ) [px::bind(&expr::logical_or, _val, _1)] ); logical_or_expression.name("logical_or_expression"); logical_and_expression = equality_expression(_r1) [_val = _1] - >> *( ((kw["and"] | "&&") > equality_expression(_r1) ) [px::bind(&expr::logical_and, _val, _1)] ); + >> *( ((kw["and"] | "&&") > equality_expression(_r1) ) [px::bind(&expr::logical_and, _val, _1)] ); logical_and_expression.name("logical_and_expression"); equality_expression = relational_expression(_r1) [_val = _1] - >> *( ("==" > relational_expression(_r1) ) [px::bind(&expr::equal, _val, _1)] - | ("!=" > relational_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] - | ("<>" > relational_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] - | ("=~" > regular_expression ) [px::bind(&expr::regex_matches, _val, _1)] - | ("!~" > regular_expression ) [px::bind(&expr::regex_doesnt_match, _val, _1)] + >> *( ("==" > relational_expression(_r1) ) [px::bind(&expr::equal, _val, _1)] + | ("!=" > relational_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] + | ("<>" > relational_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] + | ("=~" > regular_expression ) [px::bind(&expr::regex_matches, _val, _1)] + | ("!~" > regular_expression ) [px::bind(&expr::regex_doesnt_match, _val, _1)] ); equality_expression.name("bool expression"); // Evaluate a boolean expression stored as expr into a boolean value. // Throw if the equality_expression does not produce a expr of boolean type. - bool_expr_eval = conditional_expression(_r1) [ px::bind(&expr::evaluate_boolean, _1, _val) ]; + bool_expr_eval = conditional_expression(_r1) [ px::bind(&expr::evaluate_boolean, _1, _val) ]; bool_expr_eval.name("bool_expr_eval"); relational_expression = additive_expression(_r1) [_val = _1] - >> *( ("<=" > additive_expression(_r1) ) [px::bind(&expr::leq, _val, _1)] - | (">=" > additive_expression(_r1) ) [px::bind(&expr::geq, _val, _1)] - | (lit('<') > additive_expression(_r1) ) [px::bind(&expr::lower, _val, _1)] - | (lit('>') > additive_expression(_r1) ) [px::bind(&expr::greater, _val, _1)] + >> *( ("<=" > additive_expression(_r1) ) [px::bind(&expr::leq, _val, _1)] + | (">=" > additive_expression(_r1) ) [px::bind(&expr::geq, _val, _1)] + | (lit('<') > additive_expression(_r1) ) [px::bind(&expr::lower, _val, _1)] + | (lit('>') > additive_expression(_r1) ) [px::bind(&expr::greater, _val, _1)] ); relational_expression.name("relational_expression"); @@ -2058,80 +1978,80 @@ 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. - initializer_list(_r1)[px::bind(&MyContext::vector_variable_assign_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. - | eps(px::bind(&MyContext::is_vector_variable_reference, _a)) >> - variable_reference(_r1)[px::bind(&MyContext::copy_vector_variable_to_vector_variable, _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::scalar_variable_assign_scalar_expression, _r1, _a, _1)] + [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)] + [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('=') > + (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. - initializer_list(_r1)[px::bind(&MyContext::vector_variable_new_from_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. - | 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)] + | 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::scalar_variable_new_from_scalar_expression, _r1, _a, _b, _1)] + [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)] + [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)]) > + ( conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append, _val, _1)] > + *(lit(',') > conditional_expression(_r1)[px::bind(&MyContext::initializer_list_append, _val, _1)]) > lit(')') ) ); - unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( - variable_reference(_r1) [px::bind(&MyContext::variable_value, _r1, _1, _val)] - | (lit('(') > conditional_expression(_r1) > ')' > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] - | (lit('-') > unary_expression(_r1) ) [ px::bind(&FactorActions::minus_, _1, _val) ] - | (lit('+') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] - | ((kw["not"] | '!') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::not_, _1, _val) ] + unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( + variable_reference(_r1) [px::bind(&MyContext::variable_value, _r1, _1, _val)] + | (lit('(') > conditional_expression(_r1) > ')' > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] + | (lit('-') > unary_expression(_r1) ) [ px::bind(&FactorActions::minus_, _1, _val) ] + | (lit('+') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] + | ((kw["not"] | '!') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::not_, _1, _val) ] | (kw["min"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') - [ px::bind(&expr::min, _val, _2) ] + [ px::bind(&expr::min, _val, _2) ] | (kw["max"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') - [ px::bind(&expr::max, _val, _2) ] + [ px::bind(&expr::max, _val, _2) ] | (kw["random"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')') - [ px::bind(&MyContext::random, _r1, _val, _2) ] + [ px::bind(&MyContext::random, _r1, _val, _2) ] | (kw["digits"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > optional_parameter(_r1)) - [ px::bind(&expr::template digits, _val, _2, _3) ] + [ px::bind(&expr::digits, _val, _2, _3) ] | (kw["zdigits"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > optional_parameter(_r1)) - [ 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"] > '(' > variable_reference(_r1) > ')') [px::bind(&MyContext::is_nil_test, _r1, _1, _val)] + [ px::bind(&expr::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"] > '(' > 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["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_, _r1, _1, _2, _val) ] - | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _r1, _1, _2, _val) ] - | (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _r1, _1, _2, _val) ] + | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _r1, _1, _2, _val) ] + | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _r1, _1, _2, _val) ] + | (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _r1, _1, _2, _val) ] | raw[lexeme['"' > *((utf8char - char_('\\') - char_('"')) | ('\\' > char_)) > '"']] - [ px::bind(&FactorActions::string_, _r1, _1, _val) ] + [ px::bind(&FactorActions::string_, _r1, _1, _val) ] ); unary_expression.name("unary_expression"); one_of = (unary_expression(_r1)[_a = _1] > one_of_list(_r1, _a))[_val = _2]; one_of.name("one_of"); one_of_list = - eps[px::bind(&expr::one_of_test_init, _val)] > + eps[px::bind(&expr::one_of_test_init, _val)] > ( ( ',' > *( ( - unary_expression(_r1)[px::bind(&expr::template one_of_test, _r2, _1, _val)] - | (lit('~') > unary_expression(_r1))[px::bind(&expr::template one_of_test, _r2, _1, _val)] - | regular_expression[px::bind(&expr::one_of_test_regex, _r2, _1, _val)] + unary_expression(_r1)[px::bind(&expr::one_of_test, _r2, _1, _val)] + | (lit('~') > unary_expression(_r1))[px::bind(&expr::one_of_test, _r2, _1, _val)] + | regular_expression[px::bind(&expr::one_of_test_regex, _r2, _1, _val)] ) >> -lit(',')) ) | eps @@ -2139,16 +2059,16 @@ namespace client one_of_list.name("one_of_list"); interpolate_table = (unary_expression(_r1)[_a = _1] > ',' > interpolate_table_list(_r1, _a)) - [px::bind(&InterpolateTableContext::evaluate, _a, _2, _val)]; + [px::bind(&InterpolateTableContext::evaluate, _a, _2, _val)]; interpolate_table.name("interpolate_table"); interpolate_table_list = - eps[px::bind(&InterpolateTableContext::init, _r2)] > + eps[px::bind(&InterpolateTableContext::init, _r2)] > ( *(( lit('(') > unary_expression(_r1) > ',' > unary_expression(_r1) > ')' ) - [px::bind(&InterpolateTableContext::add_pair, _1, _2, _val)] >> -lit(',')) ); + [px::bind(&InterpolateTableContext::add_pair, _1, _2, _val)] >> -lit(',')) ); interpolate_table.name("interpolate_table_list"); - optional_parameter = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( - lit(')') [ px::bind(&FactorActions::noexpr, _val) ] + optional_parameter = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( + lit(')') [ px::bind(&FactorActions::noexpr, _val) ] | (lit(',') > conditional_expression(_r1) > ')') [ _val = _1 ] ); optional_parameter.name("optional_parameter"); @@ -2156,13 +2076,13 @@ namespace client variable_reference = variable(_r1)[_a=_1] >> ( - ('[' > additive_expression(_r1)[px::bind(&MyContext::evaluate_index, _1, _b)] > ']' > iter_pos) - [px::bind(&MyContext::store_variable_index, _r1, _a, _b, _2, _val)] + ('[' > additive_expression(_r1)[px::bind(&MyContext::evaluate_index, _1, _b)] > ']' > iter_pos) + [px::bind(&MyContext::store_variable_index, _r1, _a, _b, _2, _val)] | eps[_val=_a] ); variable_reference.name("variable reference"); - variable = identifier[ px::bind(&MyContext::resolve_variable, _r1, _1, _val) ]; + variable = identifier[ px::bind(&MyContext::resolve_variable, _r1, _1, _val) ]; variable.name("variable name"); regular_expression = raw[lexeme['/' > *((utf8char - char_('\\') - char_('/')) | ('\\' > char_)) > '/']]; @@ -2225,8 +2145,8 @@ namespace client } } - // Generic expression over expr. - typedef qi::rule(const MyContext*), spirit_encoding::space_type> RuleExpression; + // Generic expression over expr. + typedef qi::rule RuleExpression; // The start of the grammar. qi::rule, spirit_encoding::space_type> start; @@ -2239,9 +2159,9 @@ namespace client // Legacy variable expansion of the original Slic3r, in the form of [scalar_variable] or [vector_variable_index]. qi::rule legacy_variable_expansion; // Parsed identifier name. - qi::rule(), spirit_encoding::space_type> identifier; + qi::rule identifier; // Ternary operator (?:) over logical_or_expression. - qi::rule(const MyContext*), qi::locals, spirit_encoding::space_type> conditional_expression; + qi::rule, spirit_encoding::space_type> conditional_expression; // Logical or over logical_and_expressions. RuleExpression logical_or_expression; // Logical and over relational_expressions. @@ -2259,51 +2179,39 @@ namespace client // Accepting an optional parameter. RuleExpression optional_parameter; // Rule to capture a regular expression enclosed in //. - qi::rule(), spirit_encoding::space_type> regular_expression; + qi::rule regular_expression; // Evaluate boolean expression into bool. qi::rule bool_expr_eval; // Reference of a scalar variable, or reference to a field of a vector variable. - qi::rule(const MyContext*), qi::locals, int>, spirit_encoding::space_type> variable_reference; + qi::rule, spirit_encoding::space_type> variable_reference; // Rule to translate an identifier to a ConfigOption, or to fail. - qi::rule(const MyContext*), spirit_encoding::space_type> variable; + qi::rule variable; // Evaluating whether a nullable variable is nil. - qi::rule(const MyContext*), spirit_encoding::space_type> is_nil_test; + qi::rule is_nil_test; // Evaluating "one of" list of patterns. - qi::rule(const MyContext*), qi::locals>, spirit_encoding::space_type> one_of; - qi::rule(const MyContext*, const expr ¶m), spirit_encoding::space_type> one_of_list; + qi::rule, spirit_encoding::space_type> one_of; + qi::rule one_of_list; // Evaluating the "interpolate_table" expression. - qi::rule(const MyContext*), qi::locals>, spirit_encoding::space_type> interpolate_table; - qi::rule(const MyContext*, const expr ¶m), spirit_encoding::space_type> interpolate_table_list; + qi::rule, spirit_encoding::space_type> interpolate_table; + qi::rule interpolate_table_list; qi::rule, spirit_encoding::space_type> if_else_output; - qi::rule>, spirit_encoding::space_type> assignment_statement; + 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> initializer_list; + qi::rule, spirit_encoding::space_type> new_variable_statement; + qi::rule(const MyContext*), spirit_encoding::space_type> initializer_list; -// qi::rule, bool, std::string>, spirit_encoding::space_type> switch_output; qi::symbols keywords; }; } +static const client::macro_processor g_macro_processor_instance; + static std::string process_macro(const std::string &templ, client::MyContext &context) { - typedef std::string::const_iterator iterator_type; - typedef client::macro_processor macro_processor; - - // Our whitespace skipper. - spirit_encoding::space_type space; - // Our grammar, statically allocated inside the method, meaning it will be allocated the first time - // PlaceholderParser::process() runs. - //FIXME this kind of initialization is not thread safe! - static macro_processor macro_processor_instance; - // Iterators over the source template. - std::string::const_iterator iter = templ.begin(); - std::string::const_iterator end = templ.end(); - // Accumulator for the processed template. - std::string output; - phrase_parse(iter, end, macro_processor_instance(&context), space, output); - if (!context.error_message.empty()) { + std::string output; + phrase_parse(templ.begin(), templ.end(), g_macro_processor_instance(&context), spirit_encoding::space_type{}, output); + if (! context.error_message.empty()) { if (context.error_message.back() != '\n' && context.error_message.back() != '\r') context.error_message += '\n'; throw Slic3r::PlaceholderParserError(context.error_message);