Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer
This commit is contained in:
commit
2b93900ac0
2
deps/MPFR/MPFR.cmake
vendored
2
deps/MPFR/MPFR.cmake
vendored
@ -21,7 +21,7 @@ else ()
|
||||
ExternalProject_Add(dep_MPFR
|
||||
URL http://ftp.vim.org/ftp/gnu/mpfr/mpfr-3.1.6.tar.bz2 https://www.mpfr.org/mpfr-3.1.6/mpfr-3.1.6.tar.bz2 # mirrors are allowed
|
||||
BUILD_IN_SOURCE ON
|
||||
CONFIGURE_COMMAND ./configure --prefix=${DESTDIR}/usr/local --with-gmp=${DESTDIR}/usr/local --with-pic
|
||||
CONFIGURE_COMMAND ./configure --prefix=${DESTDIR}/usr/local --enable-shared=no --enable-static=yes --with-gmp=${DESTDIR}/usr/local --with-pic
|
||||
BUILD_COMMAND make -j
|
||||
INSTALL_COMMAND make install
|
||||
DEPENDS dep_GMP
|
||||
|
12
resources/icons/error_tick.svg
Normal file
12
resources/icons/error_tick.svg
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 24.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
|
||||
<g id="error_tick">
|
||||
<path fill="#808080" d="M8,1.85l5.29,3.53V7v3.62L8,14.15l-5.29-3.53V7V5.38L8,1.85 M8,1L2,5v2v4l6,4l6-4V7V5L8,1L8,1z"/>
|
||||
|
||||
<path fill="none" stroke="#ED6B21" stroke-linecap="round" stroke-width="2" d="M8 4 L8 9" />
|
||||
|
||||
<circle fill="#ED6B21" cx="8" cy="12" r="1"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 640 B |
145
resources/icons/export_to_sd.svg
Normal file
145
resources/icons/export_to_sd.svg
Normal file
@ -0,0 +1,145 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg8"
|
||||
version="1.1"
|
||||
viewBox="0 0 210 297"
|
||||
height="297mm"
|
||||
width="210mm">
|
||||
<defs
|
||||
id="defs2">
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath3733">
|
||||
<path
|
||||
d="M 0,800 H 800 V 0 H 0 Z"
|
||||
id="path3731" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1">
|
||||
<g
|
||||
id="g3721"
|
||||
transform="matrix(0.35277777,0,0,-0.35277777,-27.74952,290.88146)">
|
||||
<path
|
||||
d="M 381.663,302.607 H 558.791 V 65.846 H 381.663 Z"
|
||||
style="fill:#d8d8db;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3723" />
|
||||
<path
|
||||
d="m 470.227,302.607 h 95.411 V 65.846 h -95.411 z"
|
||||
style="fill:#f7f7f8;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3725" />
|
||||
<g
|
||||
id="g3727">
|
||||
<g
|
||||
id="g3729"
|
||||
clip-path="url(#clipPath3733)">
|
||||
<g
|
||||
id="g3735"
|
||||
transform="translate(380.7793,225.1963)">
|
||||
<path
|
||||
d="m 0,0 h 174.037 c 39.032,0 70.675,31.643 70.675,70.675 v 372.92 c 0,39.033 -31.643,70.675 -70.675,70.675 H 0 c -39.033,0 -70.675,-31.642 -70.675,-70.675 V 70.675 C -70.675,31.643 -39.033,0 0,0"
|
||||
style="fill:#e96700;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3737" />
|
||||
</g>
|
||||
<g
|
||||
id="g3739"
|
||||
transform="translate(377.0244,168.7666)">
|
||||
<path
|
||||
d="m 0,0 h -237.865 c -8.782,0 -15.902,7.12 -15.902,15.902 v 365.743 c 0,8.782 7.12,15.901 15.902,15.901 H 28.933 c 8.782,0 15.902,-7.119 15.902,-15.901 V 56.43 C 38.907,48.507 9.055,8.503 0,0"
|
||||
style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3741" />
|
||||
</g>
|
||||
<g
|
||||
id="g3743"
|
||||
transform="translate(421.8594,225.1963)">
|
||||
<path
|
||||
d="M 0,0 C -7.399,-10.049 -35.78,-47.927 -44.835,-56.43 H -282.7"
|
||||
style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3745" />
|
||||
</g>
|
||||
<g
|
||||
id="g3747"
|
||||
transform="translate(421.8594,225.1963)">
|
||||
<path
|
||||
d="M 0,0 C -5.876,-7.899 -35.78,-47.927 -44.835,-56.43"
|
||||
style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3749" />
|
||||
</g>
|
||||
<g
|
||||
id="g3751"
|
||||
transform="translate(333.957,198.1406)">
|
||||
<path
|
||||
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 81.276 c 0,2.195 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.781 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
|
||||
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3753" />
|
||||
</g>
|
||||
<g
|
||||
id="g3755"
|
||||
transform="translate(297.957,198.1406)">
|
||||
<path
|
||||
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 81.276 c 0,2.195 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.781 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
|
||||
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3757" />
|
||||
</g>
|
||||
<g
|
||||
id="g3759"
|
||||
transform="translate(261.957,198.1406)">
|
||||
<path
|
||||
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 81.276 c 0,2.195 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.781 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
|
||||
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3761" />
|
||||
</g>
|
||||
<g
|
||||
id="g3763"
|
||||
transform="translate(225.957,198.1406)">
|
||||
<path
|
||||
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 81.276 c 0,2.195 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.781 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
|
||||
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3765" />
|
||||
</g>
|
||||
<g
|
||||
id="g3767"
|
||||
transform="translate(189.957,198.1406)">
|
||||
<path
|
||||
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 81.276 c 0,2.195 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.781 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
|
||||
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3769" />
|
||||
</g>
|
||||
<g
|
||||
id="g3771"
|
||||
transform="translate(369.2207,225.1963)">
|
||||
<path
|
||||
d="m 0,0 h -22.969 c -2.196,0 -3.976,1.78 -3.976,3.976 v 54.22 c 0,2.196 1.78,3.976 3.976,3.976 H 0 c 2.196,0 3.976,-1.78 3.976,-3.976 V 3.976 C 3.976,1.78 2.196,0 0,0"
|
||||
style="fill:#efee86;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3773" />
|
||||
</g>
|
||||
<path
|
||||
d="m 450.019,104.056 h -50.577 v 33.128 h 50.577 z"
|
||||
style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3775" />
|
||||
<path
|
||||
d="m 543.221,104.056 h -50.576 v 33.128 h 50.576 z"
|
||||
style="fill:#666666;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
id="path3777" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 5.8 KiB |
@ -8,7 +8,7 @@ msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-09-09 16:39+0200\n"
|
||||
"PO-Revision-Date: 2019-11-18 16:39-0300\n"
|
||||
"PO-Revision-Date: 2019-12-21 19:55-0300\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -1432,7 +1432,7 @@ msgid ""
|
||||
"You will lose content of the plater."
|
||||
msgstr ""
|
||||
"Alterar a linguagem fará com que o aplicativo reinicie.\n"
|
||||
"Você irá perder conteúdo no prato."
|
||||
"Você irá perder conteúdo na bandeja."
|
||||
|
||||
#: src/slic3r/GUI/GUI_App.cpp:877
|
||||
msgid "Do you want to proceed?"
|
||||
@ -2302,7 +2302,7 @@ msgstr "(Re)fatiar"
|
||||
|
||||
#: src/slic3r/GUI/KBShortcutsDialog.cpp:116
|
||||
msgid "Select Plater Tab"
|
||||
msgstr "Selecione a guia de prato"
|
||||
msgstr "Selecione a guia de bandeja"
|
||||
|
||||
#: src/slic3r/GUI/KBShortcutsDialog.cpp:118
|
||||
msgid "Select Print Settings Tab"
|
||||
@ -2466,7 +2466,7 @@ msgstr "Desmarcar Gizmo/limpar seleção"
|
||||
|
||||
#: src/slic3r/GUI/KBShortcutsDialog.cpp:166
|
||||
msgid "Plater Shortcuts"
|
||||
msgstr "Atalhos do prato"
|
||||
msgstr "Atalhos da bandeja"
|
||||
|
||||
#: src/slic3r/GUI/KBShortcutsDialog.cpp:181
|
||||
#: src/slic3r/GUI/KBShortcutsDialog.cpp:193
|
||||
@ -2546,7 +2546,7 @@ msgstr "baseado no Slic3r"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:189
|
||||
msgid "Plater"
|
||||
msgstr "Prato"
|
||||
msgstr "Bandeja"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:400
|
||||
msgid "&New Project"
|
||||
@ -2635,7 +2635,7 @@ msgstr "Exportar &G-code"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:469
|
||||
msgid "Export current plate as G-code"
|
||||
msgstr "Exporte o prato atual como o G-code"
|
||||
msgstr "Exporte a bandeja atual como o G-code"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:473 src/slic3r/GUI/MainFrame.cpp:720
|
||||
msgid "S&end G-code"
|
||||
@ -2643,31 +2643,31 @@ msgstr "E&nviar G-code"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:473
|
||||
msgid "Send to print current plate as G-code"
|
||||
msgstr "Enviar para imprimir prato atual como G-code"
|
||||
msgstr "Enviar para imprimir a bandeja atual como G-code"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:478
|
||||
msgid "Export plate as &STL"
|
||||
msgstr "Exportar prato como &STL"
|
||||
msgstr "Exportar bandeja como &STL"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:478
|
||||
msgid "Export current plate as STL"
|
||||
msgstr "Exporte o prato atual como STL"
|
||||
msgstr "Exporte a bandeja atual como STL"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:481
|
||||
msgid "Export plate as STL &including supports"
|
||||
msgstr "Exportar prato como STL &incluindo suportes"
|
||||
msgstr "Exportar bandeja como STL &incluindo suportes"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:481
|
||||
msgid "Export current plate as STL including supports"
|
||||
msgstr "Exporte o prato atual como o STL que inclui suportes"
|
||||
msgstr "Exporte a bandeja atual como o STL que inclui suportes"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:484
|
||||
msgid "Export plate as &AMF"
|
||||
msgstr "Exportar prato como &AMF"
|
||||
msgstr "Exportar bandeja como &AMF"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:484
|
||||
msgid "Export current plate as AMF"
|
||||
msgstr "Exporte o prato atual como o AMF"
|
||||
msgstr "Exporte a bandeja atual como o AMF"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:488
|
||||
msgid "Export &toolpaths as OBJ"
|
||||
@ -2804,11 +2804,11 @@ msgstr "Colar área de transferência"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:590
|
||||
msgid "&Plater Tab"
|
||||
msgstr "&Prato"
|
||||
msgstr "&Bandeja"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:590
|
||||
msgid "Show the plater"
|
||||
msgstr "Mostrar o prato"
|
||||
msgstr "Mostrar a bandeja"
|
||||
|
||||
#: src/slic3r/GUI/MainFrame.cpp:597
|
||||
msgid "P&rint Settings Tab"
|
||||
@ -6198,7 +6198,7 @@ msgstr "Distância entre cópias"
|
||||
|
||||
#: src/libslic3r/PrintConfig.cpp:352
|
||||
msgid "Distance used for the auto-arrange feature of the plater."
|
||||
msgstr "Distância usada para o recurso de organizar automaticamente o prato."
|
||||
msgstr "Distância usada para o recurso de organizar automaticamente a bandeja."
|
||||
|
||||
#: src/libslic3r/PrintConfig.cpp:359
|
||||
msgid "Elephant foot compensation"
|
||||
@ -6395,8 +6395,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Defina isso para o raio de folga em torno de sua extrusora. Se a extrusora "
|
||||
"não estiver centralizada, escolha o maior valor para a segurança. Essa "
|
||||
"config. é usada para verificar colisões e exibir a visualização gráfica no "
|
||||
"prato."
|
||||
"config. é usada para verificar colisões e exibir a visualização gráfica na "
|
||||
"bandeja."
|
||||
|
||||
#: src/libslic3r/PrintConfig.cpp:505
|
||||
msgid "Extruder Color"
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <math.h>
|
||||
#include <string_view>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/find.hpp>
|
||||
@ -34,6 +35,8 @@
|
||||
|
||||
#include "miniz_extension.hpp"
|
||||
|
||||
using namespace std::literals::string_view_literals;
|
||||
|
||||
#if 0
|
||||
// Enable debugging and asserts, even in the release build.
|
||||
#define DEBUG
|
||||
@ -2268,8 +2271,20 @@ void GCode::apply_print_config(const PrintConfig &print_config)
|
||||
void GCode::append_full_config(const Print &print, std::string &str)
|
||||
{
|
||||
const DynamicPrintConfig &cfg = print.full_print_config();
|
||||
// Sorted list of config keys, which shall not be stored into the G-code. Initializer list.
|
||||
static constexpr auto banned_keys = {
|
||||
"compatible_printers"sv,
|
||||
"compatible_prints"sv,
|
||||
"print_host"sv,
|
||||
"printhost_apikey"sv,
|
||||
"printhost_cafile"sv
|
||||
};
|
||||
assert(std::is_sorted(banned_keys.begin(), banned_keys.end()));
|
||||
auto is_banned = [](const std::string &key) {
|
||||
return std::binary_search(banned_keys.begin(), banned_keys.end(), key);
|
||||
};
|
||||
for (const std::string &key : cfg.keys())
|
||||
if (key != "compatible_prints" && key != "compatible_printers" && ! cfg.option(key)->is_nil())
|
||||
if (! is_banned(key) && ! cfg.option(key)->is_nil())
|
||||
str += "; " + key + " = " + cfg.opt_serialize(key) + "\n";
|
||||
}
|
||||
|
||||
|
@ -332,6 +332,21 @@ namespace client
|
||||
return expr();
|
||||
}
|
||||
|
||||
expr unary_integer(const Iterator start_pos) const
|
||||
{
|
||||
switch (this->type) {
|
||||
case TYPE_INT :
|
||||
return expr<Iterator>(this->i(), start_pos, this->it_range.end());
|
||||
case TYPE_DOUBLE:
|
||||
return expr<Iterator>((int)(this->d()), start_pos, this->it_range.end());
|
||||
default:
|
||||
this->throw_exception("Cannot convert to integer.");
|
||||
}
|
||||
assert(false);
|
||||
// Suppress compiler warnings.
|
||||
return expr();
|
||||
}
|
||||
|
||||
expr unary_not(const Iterator start_pos) const
|
||||
{
|
||||
switch (this->type) {
|
||||
@ -415,6 +430,22 @@ namespace client
|
||||
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 ((this->type == TYPE_INT) ? (rhs.i() == 0) : (rhs.d() == 0.))
|
||||
rhs.throw_exception("Division by zero");
|
||||
if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) {
|
||||
double d = std::fmod(this->as_d(), rhs.as_d());
|
||||
this->data.d = d;
|
||||
this->type = TYPE_DOUBLE;
|
||||
} else
|
||||
this->data.i %= rhs.i();
|
||||
this->it_range = boost::iterator_range<Iterator>(this->it_range.begin(), rhs.it_range.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
static void to_string2(expr &self, std::string &out)
|
||||
{
|
||||
out = self.to_string();
|
||||
@ -1087,6 +1118,7 @@ namespace client
|
||||
unary_expression(_r1) [_val = _1]
|
||||
>> *( (lit('*') > unary_expression(_r1) ) [_val *= _1]
|
||||
| (lit('/') > unary_expression(_r1) ) [_val /= _1]
|
||||
| (lit('%') > unary_expression(_r1) ) [_val %= _1]
|
||||
);
|
||||
multiplicative_expression.name("multiplicative_expression");
|
||||
|
||||
@ -1107,6 +1139,8 @@ namespace client
|
||||
{ out = value.unary_minus(out.it_range.begin()); }
|
||||
static void not_(expr<Iterator> &value, expr<Iterator> &out)
|
||||
{ out = value.unary_not(out.it_range.begin()); }
|
||||
static void to_int(expr<Iterator> &value, expr<Iterator> &out)
|
||||
{ out = value.unary_integer(out.it_range.begin()); }
|
||||
};
|
||||
unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> (
|
||||
scalar_variable_reference(_r1) [ _val = _1 ]
|
||||
@ -1118,6 +1152,8 @@ namespace client
|
||||
[ px::bind(&expr<Iterator>::min, _val, _2) ]
|
||||
| (kw["max"] > '(' > conditional_expression(_r1) [_val = _1] > ',' > conditional_expression(_r1) > ')')
|
||||
[ px::bind(&expr<Iterator>::max, _val, _2) ]
|
||||
//FIXME this is likley not correct
|
||||
| (kw["int"] > '(' > unary_expression(_r1) /* > ')' */ ) [ px::bind(&FactorActions::to_int, _1, _val) ]
|
||||
| (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) ]
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
|
||||
// Fill in the template using a macro processing language.
|
||||
// Throws std::runtime_error on syntax or runtime error.
|
||||
std::string process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr) const;
|
||||
std::string process(const std::string &templ, unsigned int current_extruder_id = 0, const DynamicConfig *config_override = nullptr) const;
|
||||
|
||||
// Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax.
|
||||
// Throws std::runtime_error on syntax or runtime error.
|
||||
|
@ -449,7 +449,7 @@ int copy_file(const std::string &from, const std::string &to, const bool with_ch
|
||||
ret_val = check_copy(from, to_temp);
|
||||
|
||||
if (ret_val == 0 && rename_file(to_temp, to))
|
||||
ret_val = -1;
|
||||
ret_val = -3;
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
@ -460,11 +460,11 @@ int check_copy(const std::string &origin, const std::string ©)
|
||||
std::ifstream f2(copy, std::ifstream::in | std::ifstream::binary | std::ifstream::ate);
|
||||
|
||||
if (f1.fail() || f2.fail())
|
||||
return -1;
|
||||
return -2;
|
||||
|
||||
std::streampos fsize = f1.tellg();
|
||||
if (fsize != f2.tellg())
|
||||
return -1;
|
||||
return -2;
|
||||
|
||||
f1.seekg(0, std::ifstream::beg);
|
||||
f2.seekg(0, std::ifstream::beg);
|
||||
@ -481,12 +481,12 @@ int check_copy(const std::string &origin, const std::string ©)
|
||||
if (origin_cnt != copy_cnt ||
|
||||
(origin_cnt > 0 && std::memcmp(buffer_origin.data(), buffer_copy.data(), origin_cnt) != 0))
|
||||
// Files are different.
|
||||
return -1;
|
||||
return -2;
|
||||
fsize -= origin_cnt;
|
||||
} while (f1.good() && f2.good());
|
||||
|
||||
// All data has been read and compared equal.
|
||||
return (f1.eof() && f2.eof() && fsize == 0) ? 0 : -1;
|
||||
return (f1.eof() && f2.eof() && fsize == 0) ? 0 : -2;
|
||||
}
|
||||
|
||||
// Ignore system and hidden files, which may be created by the DropBox synchronisation process.
|
||||
|
@ -78,6 +78,9 @@ void AppConfig::set_defaults()
|
||||
if (get("remember_output_path").empty())
|
||||
set("remember_output_path", "1");
|
||||
|
||||
if (get("remember_output_path_removable").empty())
|
||||
set("remember_output_path_removable", "1");
|
||||
|
||||
if (get("use_custom_toolbar_size").empty())
|
||||
set("use_custom_toolbar_size", "0");
|
||||
|
||||
@ -388,7 +391,7 @@ void AppConfig::update_skein_dir(const std::string &dir)
|
||||
{
|
||||
this->set("recent", "skein_directory", dir);
|
||||
}
|
||||
|
||||
/*
|
||||
std::string AppConfig::get_last_output_dir(const std::string &alt) const
|
||||
{
|
||||
|
||||
@ -406,6 +409,26 @@ void AppConfig::update_last_output_dir(const std::string &dir)
|
||||
{
|
||||
this->set("", "last_output_path", dir);
|
||||
}
|
||||
*/
|
||||
std::string AppConfig::get_last_output_dir(const std::string& alt, const bool removable) const
|
||||
{
|
||||
std::string s1 = (removable ? "last_output_path_removable" : "last_output_path");
|
||||
std::string s2 = (removable ? "remember_output_path_removable" : "remember_output_path");
|
||||
const auto it = m_storage.find("");
|
||||
if (it != m_storage.end()) {
|
||||
const auto it2 = it->second.find(s1);
|
||||
const auto it3 = it->second.find(s2);
|
||||
if (it2 != it->second.end() && it3 != it->second.end() && !it2->second.empty() && it3->second == "1")
|
||||
return it2->second;
|
||||
}
|
||||
return alt;
|
||||
}
|
||||
|
||||
void AppConfig::update_last_output_dir(const std::string& dir, const bool removable)
|
||||
{
|
||||
this->set("", (removable ? "last_output_path_removable" : "last_output_path"), dir);
|
||||
}
|
||||
|
||||
|
||||
void AppConfig::reset_selections()
|
||||
{
|
||||
|
@ -102,8 +102,10 @@ public:
|
||||
void update_config_dir(const std::string &dir);
|
||||
void update_skein_dir(const std::string &dir);
|
||||
|
||||
std::string get_last_output_dir(const std::string &alt) const;
|
||||
void update_last_output_dir(const std::string &dir);
|
||||
//std::string get_last_output_dir(const std::string &alt) const;
|
||||
//void update_last_output_dir(const std::string &dir);
|
||||
std::string get_last_output_dir(const std::string& alt, const bool removable = false) const;
|
||||
void update_last_output_dir(const std::string &dir, const bool removable = false);
|
||||
|
||||
// reset the current print / filament / printer selections, so that
|
||||
// the PresetBundle::load_selections(const AppConfig &config) call will select
|
||||
|
@ -100,8 +100,23 @@ void BackgroundSlicingProcess::process_fff()
|
||||
//FIXME localize the messages
|
||||
// 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);
|
||||
if (copy_file(m_temp_output_path, export_path, GUI::RemovableDriveManager::get_instance().is_path_on_removable_drive(export_path)) != 0)
|
||||
GUI::RemovableDriveManager::get_instance().update();
|
||||
bool with_check = GUI::RemovableDriveManager::get_instance().is_path_on_removable_drive(export_path);
|
||||
int copy_ret_val = copy_file(m_temp_output_path, export_path, with_check);
|
||||
if (with_check && copy_ret_val == -2)
|
||||
{
|
||||
std::string err_msg = "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 " + export_path + ".tmp.";
|
||||
throw std::runtime_error(_utf8(L(err_msg)));
|
||||
}
|
||||
else if (copy_ret_val == -3)
|
||||
{
|
||||
std::string err_msg = "Renaming of the G-code after copying to the selected destination folder has failed. Current path is " + export_path + ".tmp. Please try exporting again.";
|
||||
throw std::runtime_error(_utf8(L(err_msg)));
|
||||
}
|
||||
else if ( copy_ret_val != 0)
|
||||
{
|
||||
throw std::runtime_error(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?")));
|
||||
}
|
||||
m_print->set_status(95, _utf8(L("Running post-processing scripts")));
|
||||
run_post_process_scripts(export_path, m_fff_print->config());
|
||||
m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());
|
||||
|
@ -704,6 +704,7 @@ struct Sidebar::priv
|
||||
wxButton *btn_reslice;
|
||||
ScalableButton *btn_send_gcode;
|
||||
ScalableButton *btn_remove_device;
|
||||
ScalableButton* btn_export_gcode_removable; //exports to removable drives (appears only if removable drive is connected)
|
||||
|
||||
priv(Plater *plater) : plater(plater) {}
|
||||
~priv();
|
||||
@ -869,6 +870,7 @@ Sidebar::Sidebar(Plater *parent)
|
||||
|
||||
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _(L("Send to printer")));
|
||||
init_scalable_btn(&p->btn_remove_device, "cross" , _(L("Remove device")));
|
||||
init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _(L("Export to SD card/ USB thumb drive")));
|
||||
|
||||
// regular buttons "Slice now" and "Export G-code"
|
||||
|
||||
@ -889,8 +891,10 @@ Sidebar::Sidebar(Plater *parent)
|
||||
auto* complect_btns_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND);
|
||||
complect_btns_sizer->Add(p->btn_send_gcode);
|
||||
complect_btns_sizer->Add(p->btn_export_gcode_removable);
|
||||
complect_btns_sizer->Add(p->btn_remove_device);
|
||||
|
||||
|
||||
btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5);
|
||||
btns_sizer->Add(complect_btns_sizer, 0, wxEXPAND | wxTOP, margin_5);
|
||||
|
||||
@ -900,7 +904,7 @@ Sidebar::Sidebar(Plater *parent)
|
||||
SetSizer(sizer);
|
||||
|
||||
// Events
|
||||
p->btn_export_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(); });
|
||||
p->btn_export_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(false); });
|
||||
p->btn_reslice->Bind(wxEVT_BUTTON, [this](wxCommandEvent&)
|
||||
{
|
||||
const bool export_gcode_after_slicing = wxGetKeyState(WXK_SHIFT);
|
||||
@ -912,6 +916,7 @@ Sidebar::Sidebar(Plater *parent)
|
||||
});
|
||||
p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); });
|
||||
p->btn_remove_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); });
|
||||
p->btn_export_gcode_removable->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(true); });
|
||||
}
|
||||
|
||||
Sidebar::~Sidebar() {}
|
||||
@ -1059,6 +1064,7 @@ void Sidebar::msw_rescale()
|
||||
|
||||
p->btn_send_gcode->msw_rescale();
|
||||
p->btn_remove_device->msw_rescale();
|
||||
p->btn_export_gcode_removable->msw_rescale();
|
||||
const int scaled_height = p->btn_remove_device->GetBitmap().GetHeight() + 4;
|
||||
p->btn_export_gcode->SetMinSize(wxSize(-1, scaled_height));
|
||||
p->btn_reslice ->SetMinSize(wxSize(-1, scaled_height));
|
||||
@ -1292,12 +1298,14 @@ void Sidebar::enable_buttons(bool enable)
|
||||
p->btn_export_gcode->Enable(enable);
|
||||
p->btn_send_gcode->Enable(enable);
|
||||
p->btn_remove_device->Enable(enable);
|
||||
p->btn_export_gcode_removable->Enable(enable);
|
||||
}
|
||||
|
||||
bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Show(show); }
|
||||
bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); }
|
||||
bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); }
|
||||
bool Sidebar::show_disconnect(bool show)const { return p->btn_remove_device->Show(show); }
|
||||
bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Show(show); }
|
||||
bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); }
|
||||
bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); }
|
||||
bool Sidebar::show_disconnect(bool show) const { return p->btn_remove_device->Show(show); }
|
||||
bool Sidebar::show_export_removable(bool show)const { return p->btn_export_gcode_removable->Show(show); }
|
||||
|
||||
bool Sidebar::is_multifilament()
|
||||
{
|
||||
@ -2200,6 +2208,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||
|
||||
// Initialize the Undo / Redo stack with a first snapshot.
|
||||
this->take_snapshot(_(L("New Project")));
|
||||
|
||||
//void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
||||
RemovableDriveManager::get_instance().set_drive_count_changed_callback(std::bind(&Plater::priv::show_action_buttons, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
Plater::priv::~priv()
|
||||
@ -3684,12 +3695,8 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
||||
|
||||
if(!canceled && RemovableDriveManager::get_instance().get_is_writing())
|
||||
{
|
||||
//if (!RemovableDriveManager::get_instance().is_last_drive_removed())
|
||||
//{
|
||||
RemovableDriveManager::get_instance().set_is_writing(false);
|
||||
show_action_buttons(false);
|
||||
//}
|
||||
|
||||
RemovableDriveManager::get_instance().set_is_writing(false);
|
||||
show_action_buttons(false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4263,18 +4270,21 @@ void Plater::priv::update_object_menu()
|
||||
|
||||
void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
||||
{
|
||||
RemovableDriveManager::get_instance().set_plater_ready_to_slice(is_ready_to_slice);
|
||||
wxWindowUpdateLocker noUpdater(sidebar);
|
||||
const auto prin_host_opt = config->option<ConfigOptionString>("print_host");
|
||||
const bool send_gcode_shown = prin_host_opt != nullptr && !prin_host_opt->value.empty();
|
||||
|
||||
bool disconnect_shown = !RemovableDriveManager::get_instance().is_last_drive_removed() ; // #dk_FIXME
|
||||
bool disconnect_shown = !RemovableDriveManager::get_instance().is_last_drive_removed();
|
||||
bool export_removable_shown = RemovableDriveManager::get_instance().get_drives_count() > 0;
|
||||
// when a background processing is ON, export_btn and/or send_btn are showing
|
||||
if (wxGetApp().app_config->get("background_processing") == "1")
|
||||
{
|
||||
if (sidebar->show_reslice(false) |
|
||||
sidebar->show_export(true) |
|
||||
sidebar->show_send(send_gcode_shown) |
|
||||
sidebar->show_disconnect(disconnect_shown))
|
||||
if (sidebar->show_reslice(false) |
|
||||
sidebar->show_export(true) |
|
||||
sidebar->show_send(send_gcode_shown) |
|
||||
sidebar->show_export_removable(export_removable_shown) |
|
||||
sidebar->show_disconnect(disconnect_shown))
|
||||
sidebar->Layout();
|
||||
}
|
||||
else
|
||||
@ -4282,6 +4292,7 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
||||
if (sidebar->show_reslice(is_ready_to_slice) |
|
||||
sidebar->show_export(!is_ready_to_slice) |
|
||||
sidebar->show_send(send_gcode_shown && !is_ready_to_slice) |
|
||||
sidebar->show_export_removable(export_removable_shown && !is_ready_to_slice) |
|
||||
sidebar->show_disconnect(disconnect_shown && !is_ready_to_slice))
|
||||
sidebar->Layout();
|
||||
}
|
||||
@ -4791,7 +4802,7 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::export_gcode()
|
||||
void Plater::export_gcode(bool prefer_removable)
|
||||
{
|
||||
if (p->model.objects.empty())
|
||||
return;
|
||||
@ -4813,11 +4824,19 @@ void Plater::export_gcode()
|
||||
}
|
||||
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
|
||||
auto start_dir = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string());
|
||||
if (GUI::RemovableDriveManager::get_instance().update())
|
||||
bool removable_drives_connected = GUI::RemovableDriveManager::get_instance().update();
|
||||
if(prefer_removable)
|
||||
{
|
||||
if (!RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir))
|
||||
if(removable_drives_connected)
|
||||
{
|
||||
start_dir = RemovableDriveManager::get_instance().get_drive_path();
|
||||
auto start_dir_removable = wxGetApp().app_config->get_last_output_dir(default_output_file.parent_path().string(), true);
|
||||
if (RemovableDriveManager::get_instance().is_path_on_removable_drive(start_dir_removable))
|
||||
{
|
||||
start_dir = start_dir_removable;
|
||||
}else
|
||||
{
|
||||
start_dir = RemovableDriveManager::get_instance().get_drive_path();
|
||||
}
|
||||
}
|
||||
}
|
||||
wxFileDialog dlg(this, (printer_technology() == ptFFF) ? _(L("Save G-code file as:")) : _(L("Save SL1 file as:")),
|
||||
@ -4830,7 +4849,7 @@ void Plater::export_gcode()
|
||||
fs::path output_path;
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
fs::path path = into_path(dlg.GetPath());
|
||||
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
|
||||
wxGetApp().app_config->update_last_output_dir(path.parent_path().string(), RemovableDriveManager::get_instance().is_path_on_removable_drive(path.parent_path().string()));
|
||||
output_path = std::move(path);
|
||||
}
|
||||
if (! output_path.empty())
|
||||
@ -4846,7 +4865,7 @@ void Plater::export_gcode()
|
||||
{
|
||||
RemovableDriveManager::get_instance().set_is_writing(true);
|
||||
RemovableDriveManager::get_instance().erase_callbacks();
|
||||
RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this));
|
||||
RemovableDriveManager::get_instance().add_remove_callback(std::bind(&Plater::drive_ejected_callback, this));
|
||||
}
|
||||
|
||||
}
|
||||
@ -5148,8 +5167,8 @@ void Plater::send_gcode()
|
||||
void Plater::eject_drive()
|
||||
{
|
||||
RemovableDriveManager::get_instance().update(0, true);
|
||||
//RemovableDriveManager::get_instance().erase_callbacks();
|
||||
//RemovableDriveManager::get_instance().add_callback(std::bind(&Plater::drive_ejected_callback, this));
|
||||
RemovableDriveManager::get_instance().erase_callbacks();
|
||||
RemovableDriveManager::get_instance().add_remove_callback(std::bind(&Plater::drive_ejected_callback, this));
|
||||
RemovableDriveManager::get_instance().eject_drive(RemovableDriveManager::get_instance().get_last_save_path());
|
||||
|
||||
}
|
||||
@ -5158,7 +5177,7 @@ void Plater::drive_ejected_callback()
|
||||
if (RemovableDriveManager::get_instance().get_did_eject())
|
||||
{
|
||||
RemovableDriveManager::get_instance().set_did_eject(false);
|
||||
wxString message = "Unmounting succesesful. The device " + RemovableDriveManager::get_instance().get_last_save_name() + "(" + RemovableDriveManager::get_instance().get_last_save_path() + ")" + " can now be safely removed from the computer.";
|
||||
wxString message = "Unmounting successful. The device " + RemovableDriveManager::get_instance().get_ejected_name() + "(" + RemovableDriveManager::get_instance().get_ejected_path() + ")" + " can now be safely removed from the computer.";
|
||||
wxMessageBox(message);
|
||||
}
|
||||
p->show_action_buttons(false);
|
||||
|
@ -120,6 +120,7 @@ public:
|
||||
bool show_export(bool show) const;
|
||||
bool show_send(bool show) const;
|
||||
bool show_disconnect(bool show)const;
|
||||
bool show_export_removable(bool show) const;
|
||||
bool is_multifilament();
|
||||
void update_mode();
|
||||
|
||||
@ -186,7 +187,7 @@ public:
|
||||
|
||||
void cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false);
|
||||
|
||||
void export_gcode();
|
||||
void export_gcode(bool prefer_removable = true);
|
||||
void export_stl(bool extended = false, bool selection_only = false);
|
||||
void export_amf();
|
||||
void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path());
|
||||
|
@ -109,6 +109,8 @@ void RemovableDriveManager::eject_drive(const std::string &path)
|
||||
CloseHandle(handle);
|
||||
m_did_eject = true;
|
||||
m_current_drives.erase(it);
|
||||
m_ejected_path = m_last_save_path;
|
||||
m_ejected_name = m_last_save_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -239,35 +241,10 @@ void RemovableDriveManager::search_for_drives()
|
||||
//search /media/* folder
|
||||
search_path("/media/*", "/media");
|
||||
|
||||
//search /Volumes/* folder (OSX)
|
||||
//search_path("/Volumes/*", "/Volumes");
|
||||
std::string path(std::getenv("USER"));
|
||||
std::string pp(path);
|
||||
//std::cout << "user: "<< path << "\n";
|
||||
//if program is run with sudo, we have to search for all users
|
||||
// but do we want that?
|
||||
/*
|
||||
if(path == "root"){
|
||||
while (true) {
|
||||
passwd* entry = getpwent();
|
||||
if (!entry) {
|
||||
break;
|
||||
}
|
||||
path = entry->pw_name;
|
||||
pp = path;
|
||||
//search /media/USERNAME/* folder
|
||||
pp = "/media/"+pp;
|
||||
path = "/media/" + path + "/*";
|
||||
search_path(path, pp);
|
||||
|
||||
//search /run/media/USERNAME/* folder
|
||||
path = "/run" + path;
|
||||
pp = "/run"+pp;
|
||||
search_path(path, pp);
|
||||
}
|
||||
endpwent();
|
||||
}else
|
||||
*/
|
||||
{
|
||||
//search /media/USERNAME/* folder
|
||||
pp = "/media/"+pp;
|
||||
@ -310,7 +287,6 @@ void RemovableDriveManager::inspect_file(const std::string &path, const std::str
|
||||
{
|
||||
//free space
|
||||
boost::filesystem::space_info si = boost::filesystem::space(path);
|
||||
//std::cout << "Free space: " << fs_si.free << "Available space: " << fs_si.available << " " << path << '\n';
|
||||
if(si.available != 0)
|
||||
{
|
||||
//user id
|
||||
@ -353,7 +329,7 @@ void RemovableDriveManager::eject_drive(const std::string &path)
|
||||
i++;
|
||||
}
|
||||
}
|
||||
std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n";
|
||||
//std::cout<<"Ejecting "<<(*it).name<<" from "<< correct_path<<"\n";
|
||||
// there is no usable command in c++ so terminal command is used instead
|
||||
// but neither triggers "succesful safe removal messege"
|
||||
std::string command = "";
|
||||
@ -373,7 +349,8 @@ void RemovableDriveManager::eject_drive(const std::string &path)
|
||||
|
||||
m_did_eject = true;
|
||||
m_current_drives.erase(it);
|
||||
|
||||
m_ejected_path = m_last_save_path;
|
||||
m_ejected_name = m_last_save_name;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -385,7 +362,7 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path)
|
||||
if (m_current_drives.empty())
|
||||
return false;
|
||||
std::size_t found = path.find_last_of("/");
|
||||
std::string new_path = path.substr(0,found);
|
||||
std::string new_path = found == path.size() - 1 ? path.substr(0, found) : path;
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
if(compare_filesystem_id(new_path, (*it).path))
|
||||
@ -396,7 +373,7 @@ bool RemovableDriveManager::is_path_on_removable_drive(const std::string &path)
|
||||
std::string RemovableDriveManager::get_drive_from_path(const std::string& path)
|
||||
{
|
||||
std::size_t found = path.find_last_of("/");
|
||||
std::string new_path = path.substr(0, found);
|
||||
std::string new_path = found == path.size() - 1 ? path.substr(0, found) : path;
|
||||
//check if same filesystem
|
||||
for (auto it = m_current_drives.begin(); it != m_current_drives.end(); ++it)
|
||||
{
|
||||
@ -414,7 +391,10 @@ RemovableDriveManager::RemovableDriveManager():
|
||||
m_last_save_name(""),
|
||||
m_last_save_path_verified(false),
|
||||
m_is_writing(false),
|
||||
m_did_eject(false)
|
||||
m_did_eject(false),
|
||||
m_plater_ready_to_slice(true),
|
||||
m_ejected_path(""),
|
||||
m_ejected_name("")
|
||||
#if __APPLE__
|
||||
, m_rdmmm(new RDMMMWrapper())
|
||||
#endif
|
||||
@ -451,7 +431,10 @@ bool RemovableDriveManager::update(const long time,const bool check)
|
||||
search_for_drives();
|
||||
if (m_drives_count != m_current_drives.size())
|
||||
{
|
||||
if (check)check_and_notify();
|
||||
if (check)
|
||||
{
|
||||
check_and_notify();
|
||||
}
|
||||
m_drives_count = m_current_drives.size();
|
||||
}
|
||||
return !m_current_drives.empty();
|
||||
@ -495,7 +478,11 @@ std::vector<DriveData> RemovableDriveManager::get_all_drives()
|
||||
}
|
||||
void RemovableDriveManager::check_and_notify()
|
||||
{
|
||||
if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() && m_last_save_path_verified && !is_drive_mounted(m_last_save_path))
|
||||
if(m_drive_count_changed_callback)
|
||||
{
|
||||
m_drive_count_changed_callback(m_plater_ready_to_slice);
|
||||
}
|
||||
if(m_callbacks.size() != 0 && m_drives_count > m_current_drives.size() /*&& m_last_save_path_verified */&& !is_drive_mounted(m_last_save_path))
|
||||
{
|
||||
for (auto it = m_callbacks.begin(); it != m_callbacks.end(); ++it)
|
||||
{
|
||||
@ -503,18 +490,35 @@ void RemovableDriveManager::check_and_notify()
|
||||
}
|
||||
}
|
||||
}
|
||||
void RemovableDriveManager::add_callback(std::function<void()> callback)
|
||||
void RemovableDriveManager::add_remove_callback(std::function<void()> callback)
|
||||
{
|
||||
m_callbacks.push_back(callback);
|
||||
}
|
||||
void RemovableDriveManager::erase_callbacks()
|
||||
void RemovableDriveManager::erase_callbacks()
|
||||
{
|
||||
m_callbacks.clear();
|
||||
}
|
||||
void RemovableDriveManager::set_drive_count_changed_callback(std::function<void(const bool)> callback)
|
||||
{
|
||||
m_drive_count_changed_callback = callback;
|
||||
}
|
||||
void RemovableDriveManager::set_plater_ready_to_slice(bool b)
|
||||
{
|
||||
m_plater_ready_to_slice = b;
|
||||
}
|
||||
void RemovableDriveManager::set_last_save_path(const std::string& path)
|
||||
{
|
||||
m_last_save_path_verified = false;
|
||||
m_last_save_path = path;
|
||||
if(m_last_save_path_verified)// if old path is on drive
|
||||
{
|
||||
if(get_drive_from_path(path) != "") //and new is too, rewrite the path
|
||||
{
|
||||
m_last_save_path_verified = false;
|
||||
m_last_save_path = path;
|
||||
}//else do nothing
|
||||
}else
|
||||
{
|
||||
m_last_save_path = path;
|
||||
}
|
||||
}
|
||||
void RemovableDriveManager::verify_last_save_path()
|
||||
{
|
||||
@ -544,16 +548,15 @@ std::string RemovableDriveManager::get_drive_name(const std::string& path)
|
||||
}
|
||||
bool RemovableDriveManager::is_last_drive_removed()
|
||||
{
|
||||
//std::cout<<"is last: "<<m_last_save_path;
|
||||
//m_drives_count = m_current_drives.size();
|
||||
if(!m_last_save_path_verified)
|
||||
{
|
||||
//std::cout<<"\n";
|
||||
return true;
|
||||
}
|
||||
bool r = !is_drive_mounted(m_last_save_path);
|
||||
if (r) reset_last_save_path();
|
||||
//std::cout<<" "<< r <<"\n";
|
||||
if (r)
|
||||
{
|
||||
reset_last_save_path();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
bool RemovableDriveManager::is_last_drive_removed_with_update(const long time)
|
||||
@ -587,4 +590,16 @@ void RemovableDriveManager::set_did_eject(const bool b)
|
||||
{
|
||||
m_did_eject = b;
|
||||
}
|
||||
size_t RemovableDriveManager::get_drives_count()
|
||||
{
|
||||
return m_current_drives.size();
|
||||
}
|
||||
std::string RemovableDriveManager::get_ejected_path()
|
||||
{
|
||||
return m_ejected_path;
|
||||
}
|
||||
std::string RemovableDriveManager::get_ejected_name()
|
||||
{
|
||||
return m_ejected_name;
|
||||
}
|
||||
}}//namespace Slicer::Gui
|
||||
|
@ -45,9 +45,13 @@ public:
|
||||
std::vector<DriveData> get_all_drives();
|
||||
bool is_path_on_removable_drive(const std::string &path);
|
||||
// callback will notify only if device with last save path was removed
|
||||
void add_callback(std::function<void()> callback);
|
||||
// erases all callbacks added by add_callback()
|
||||
void add_remove_callback(std::function<void()> callback);
|
||||
// erases all remove callbacks added by add_remove_callback()
|
||||
void erase_callbacks();
|
||||
//drive_count_changed callback is called on every added or removed device
|
||||
void set_drive_count_changed_callback(std::function<void(const bool)> callback);
|
||||
//thi serves to set correct value for drive_count_changed callback
|
||||
void set_plater_ready_to_slice(bool b);
|
||||
// marks one of the eveices in vector as last used
|
||||
void set_last_save_path(const std::string &path);
|
||||
void verify_last_save_path();
|
||||
@ -59,6 +63,9 @@ public:
|
||||
bool get_did_eject();
|
||||
void set_did_eject(const bool b);
|
||||
std::string get_drive_name(const std::string& path);
|
||||
size_t get_drives_count();
|
||||
std::string get_ejected_path();
|
||||
std::string get_ejected_name();
|
||||
private:
|
||||
RemovableDriveManager();
|
||||
void search_for_drives();
|
||||
@ -70,6 +77,7 @@ private:
|
||||
|
||||
std::vector<DriveData> m_current_drives;
|
||||
std::vector<std::function<void()>> m_callbacks;
|
||||
std::function<void(const bool)> m_drive_count_changed_callback;
|
||||
size_t m_drives_count;
|
||||
long m_last_update;
|
||||
std::string m_last_save_path;
|
||||
@ -77,6 +85,9 @@ private:
|
||||
std::string m_last_save_name;
|
||||
bool m_is_writing;//on device
|
||||
bool m_did_eject;
|
||||
bool m_plater_ready_to_slice;
|
||||
std::string m_ejected_path;
|
||||
std::string m_ejected_name;
|
||||
#if _WIN32
|
||||
//registers for notifications by creating invisible window
|
||||
void register_window();
|
||||
|
@ -2325,7 +2325,7 @@ DoubleSlider::DoubleSlider( wxWindow *parent,
|
||||
m_cog_icon_dim = int((float)m_bmp_cog.bmp().GetSize().x / scale_factor);
|
||||
|
||||
m_selection = ssUndef;
|
||||
m_pause_print_msg = _utf8(L("Place bearings in slots and resume"));
|
||||
m_ticks.set_pause_print_msg(_utf8(L("Place bearings in slots and resume")));
|
||||
|
||||
// slider events
|
||||
Bind(wxEVT_PAINT, &DoubleSlider::OnPaint, this);
|
||||
@ -2539,13 +2539,13 @@ Slic3r::Model::CustomGCodeInfo DoubleSlider::GetTicksValues() const
|
||||
|
||||
const int val_size = m_values.size();
|
||||
if (!m_values.empty())
|
||||
for (const TICK_CODE& tick : m_ticks) {
|
||||
for (const TICK_CODE& tick : m_ticks.ticks) {
|
||||
if (tick.tick > val_size)
|
||||
break;
|
||||
values.emplace_back(t_custom_code{m_values[tick.tick], tick.gcode, tick.extruder, tick.color});
|
||||
}
|
||||
|
||||
custom_gcode_per_print_z.mode = m_mode;
|
||||
custom_gcode_per_print_z.mode = m_force_mode_apply ? m_mode : m_ticks.mode;
|
||||
|
||||
return custom_gcode_per_print_z;
|
||||
}
|
||||
@ -2554,13 +2554,13 @@ void DoubleSlider::SetTicksValues(const Slic3r::Model::CustomGCodeInfo& custom_g
|
||||
{
|
||||
if (m_values.empty())
|
||||
{
|
||||
m_ticks_mode = m_mode;
|
||||
m_ticks.mode = m_mode;
|
||||
return;
|
||||
}
|
||||
|
||||
const bool was_empty = m_ticks.empty();
|
||||
|
||||
m_ticks.clear();
|
||||
m_ticks.ticks.clear();
|
||||
const std::vector<t_custom_code>& heights = custom_gcode_per_print_z.gcodes;
|
||||
for (auto h : heights) {
|
||||
auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon());
|
||||
@ -2568,14 +2568,14 @@ void DoubleSlider::SetTicksValues(const Slic3r::Model::CustomGCodeInfo& custom_g
|
||||
if (it == m_values.end())
|
||||
continue;
|
||||
|
||||
m_ticks.emplace(TICK_CODE{int(it-m_values.begin()), h.gcode, h.extruder, h.color});
|
||||
m_ticks.ticks.emplace(TICK_CODE{int(it-m_values.begin()), h.gcode, h.extruder, h.color});
|
||||
}
|
||||
|
||||
if (!was_empty && m_ticks.empty())
|
||||
// Switch to the "Feature type"/"Tool" from the very beginning of a new object slicing after deleting of the old one
|
||||
post_ticks_changed_event();
|
||||
|
||||
m_ticks_mode = custom_gcode_per_print_z.mode;
|
||||
m_ticks.mode = custom_gcode_per_print_z.mode;
|
||||
|
||||
Refresh();
|
||||
Update();
|
||||
@ -2649,7 +2649,7 @@ void DoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoin
|
||||
return;
|
||||
|
||||
wxBitmap* icon = m_is_action_icon_focesed ? &m_bmp_add_tick_off.bmp() : &m_bmp_add_tick_on.bmp();
|
||||
if (m_ticks.find(TICK_CODE{tick}) != m_ticks.end())
|
||||
if (m_ticks.ticks.find(TICK_CODE{tick}) != m_ticks.ticks.end())
|
||||
icon = m_is_action_icon_focesed ? &m_bmp_del_tick_off.bmp() : &m_bmp_del_tick_on.bmp();
|
||||
|
||||
wxCoord x_draw, y_draw;
|
||||
@ -2792,7 +2792,7 @@ void DoubleSlider::draw_ticks(wxDC& dc)
|
||||
int height, width;
|
||||
get_size(&width, &height);
|
||||
const wxCoord mid = is_horizontal() ? 0.5*height : 0.5*width;
|
||||
for (auto tick : m_ticks)
|
||||
for (auto tick : m_ticks.ticks)
|
||||
{
|
||||
const wxCoord pos = get_position_from_value(tick.tick);
|
||||
|
||||
@ -2801,11 +2801,23 @@ void DoubleSlider::draw_ticks(wxDC& dc)
|
||||
is_horizontal() ? dc.DrawLine(pos, mid+14, pos, mid+9) :
|
||||
dc.DrawLine(mid + 14, pos/* - 1*/, mid + 9, pos/* - 1*/);
|
||||
|
||||
wxBitmap icon = wxNullBitmap;
|
||||
|
||||
// Draw icon for "Pause print" or "Custom Gcode"
|
||||
if (tick.gcode != Slic3r::ColorChangeCode && tick.gcode != Slic3r::ToolChangeCode)
|
||||
icon = create_scaled_bitmap(this, tick.gcode == Slic3r::PausePrintCode ? "pause_print" : "edit_gcode");
|
||||
else
|
||||
{
|
||||
wxBitmap icon = create_scaled_bitmap(this, tick.gcode == Slic3r::PausePrintCode ? "pause_print" : "edit_gcode");
|
||||
if ((tick.gcode == Slic3r::ColorChangeCode && (
|
||||
(m_ticks.mode == t_mode::SingleExtruder && m_mode == t_mode::MultiExtruder ) ||
|
||||
(m_ticks.mode == t_mode::MultiExtruder && m_mode == t_mode::SingleExtruder) )) ||
|
||||
(tick.gcode == Slic3r::ToolChangeCode &&
|
||||
(m_ticks.mode == t_mode::MultiAsSingle && m_mode != t_mode::MultiAsSingle ) ))
|
||||
icon = create_scaled_bitmap(this, "error_tick");
|
||||
}
|
||||
|
||||
if (!icon.IsNull())
|
||||
{
|
||||
wxCoord x_draw, y_draw;
|
||||
is_horizontal() ? x_draw = pos - 0.5 * m_tick_icon_dim : y_draw = pos - 0.5 * m_tick_icon_dim;
|
||||
is_horizontal() ? y_draw = mid + 22 : x_draw = mid + m_thumb_size.x + 3;
|
||||
@ -2820,7 +2832,7 @@ std::string DoubleSlider::get_color_for_tool_change_tick(std::set<TICK_CODE>::co
|
||||
const int current_extruder = it->extruder == 0 ? std::max<int>(m_only_extruder, 1) : it->extruder;
|
||||
|
||||
auto it_n = it;
|
||||
while (it_n != m_ticks.begin()) {
|
||||
while (it_n != m_ticks.ticks.begin()) {
|
||||
--it_n;
|
||||
if (it_n->gcode == Slic3r::ColorChangeCode && it_n->extruder == current_extruder)
|
||||
return it_n->color;
|
||||
@ -2834,7 +2846,7 @@ std::string DoubleSlider::get_color_for_color_change_tick(std::set<TICK_CODE>::c
|
||||
const int def_extruder = std::max<int>(1, m_only_extruder);
|
||||
auto it_n = it;
|
||||
bool is_tool_change = false;
|
||||
while (it_n != m_ticks.begin()) {
|
||||
while (it_n != m_ticks.ticks.begin()) {
|
||||
--it_n;
|
||||
if (it_n->gcode == Slic3r::ToolChangeCode) {
|
||||
is_tool_change = true;
|
||||
@ -2881,9 +2893,9 @@ void DoubleSlider::draw_colored_band(wxDC& dc)
|
||||
const int default_color_idx = m_mode==t_mode::MultiAsSingle ? std::max<int>(m_only_extruder - 1, 0) : 0;
|
||||
draw_band(dc, wxColour(Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config()[default_color_idx]), main_band);
|
||||
|
||||
std::set<TICK_CODE>::const_iterator tick_it = m_ticks.begin();
|
||||
std::set<TICK_CODE>::const_iterator tick_it = m_ticks.ticks.begin();
|
||||
|
||||
while (tick_it != m_ticks.end())
|
||||
while (tick_it != m_ticks.ticks.end())
|
||||
{
|
||||
if ( (m_mode == t_mode::SingleExtruder && tick_it->gcode == Slic3r::ColorChangeCode ) ||
|
||||
(m_mode == t_mode::MultiAsSingle && (tick_it->gcode == Slic3r::ToolChangeCode || tick_it->gcode == Slic3r::ColorChangeCode)) )
|
||||
@ -2993,7 +3005,7 @@ bool DoubleSlider::is_point_in_rect(const wxPoint& pt, const wxRect& rect)
|
||||
|
||||
int DoubleSlider::is_point_near_tick(const wxPoint& pt)
|
||||
{
|
||||
for (auto tick : m_ticks) {
|
||||
for (auto tick : m_ticks.ticks) {
|
||||
const wxCoord pos = get_position_from_value(tick.tick);
|
||||
|
||||
if (is_horizontal()) {
|
||||
@ -3030,8 +3042,13 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event)
|
||||
|
||||
wxClientDC dc(this);
|
||||
wxPoint pos = event.GetLogicalPosition(dc);
|
||||
if (is_point_in_rect(pos, m_rect_tick_action) && m_is_enabled_tick_manipulation) {
|
||||
action_tick(taOnIcon);
|
||||
if (is_point_in_rect(pos, m_rect_tick_action) && m_is_enabled_tick_manipulation)
|
||||
{
|
||||
const auto it = m_ticks.ticks.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value });
|
||||
if (it == m_ticks.ticks.end())
|
||||
m_force_add_tick = true;
|
||||
else
|
||||
m_force_delete_tick = true;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3054,12 +3071,13 @@ void DoubleSlider::OnLeftDown(wxMouseEvent& event)
|
||||
m_selection == ssLower ? correct_lower_value() : correct_higher_value();
|
||||
if (!m_selection) m_selection = ssHigher;
|
||||
|
||||
m_ticks.clear();
|
||||
m_ticks.ticks.clear();
|
||||
post_ticks_changed_event();
|
||||
}
|
||||
else if (is_point_in_rect(pos, m_rect_cog_icon) && m_mode == t_mode::MultiExtruder) {
|
||||
// show dialog for set extruder sequence
|
||||
m_edit_extruder_sequence = true;
|
||||
m_force_edit_extruder_sequence = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
detect_selected_slider(pos);
|
||||
@ -3127,8 +3145,8 @@ wxString DoubleSlider::get_tooltip(IconFocus icon_focus)
|
||||
else if (m_is_action_icon_focesed)
|
||||
{
|
||||
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
|
||||
const auto tick_code_it = m_ticks.find(TICK_CODE{tick});
|
||||
tooltip = tick_code_it == m_ticks.end() ? (m_mode == t_mode::MultiAsSingle ?
|
||||
const auto tick_code_it = m_ticks.ticks.find(TICK_CODE{tick});
|
||||
tooltip = tick_code_it == m_ticks.ticks.end() ? (m_mode == t_mode::MultiAsSingle ?
|
||||
_(L("For add change extruder use left mouse button click")) :
|
||||
_(L("For add color change use left mouse button click")) ) + "\n" +
|
||||
_(L("For add another code use right mouse button click")) :
|
||||
@ -3211,10 +3229,8 @@ void DoubleSlider::append_change_extruder_menu_item(wxMenu* menu)
|
||||
|
||||
if (m_mode == t_mode::MultiAsSingle)
|
||||
append_menu_item(change_extruder_menu, wxID_ANY, item_name, "",
|
||||
[this, i](wxCommandEvent&) { change_extruder(i); }, "", menu,
|
||||
[this, i](wxCommandEvent&) { add_code_as_tick(Slic3r::ToolChangeCode, i); }, "", menu,
|
||||
[is_active_extruder]() { return !is_active_extruder; }, Slic3r::GUI::wxGetApp().plater());
|
||||
// append_menu_radio_item(change_extruder_menu, wxID_ANY, item_name, "",
|
||||
// [this, i](wxCommandEvent&) { change_extruder(i); }, menu)->Check(i == initial_extruder);
|
||||
}
|
||||
|
||||
const wxString change_extruder_menu_name = m_mode == t_mode::MultiAsSingle ? _(L("Change extruder")) : _(L("Change extruder (N/A)"));
|
||||
@ -3245,13 +3261,13 @@ void DoubleSlider::append_add_color_change_menu_item(wxMenu* menu)
|
||||
(is_used_extruder ? " (" + _(L("used")) + ")" : "");
|
||||
|
||||
append_menu_item(add_color_change_menu, wxID_ANY, item_name, "",
|
||||
[this, i](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode, i); }, "", menu,
|
||||
[this, i](wxCommandEvent&) { add_code_as_tick(Slic3r::ColorChangeCode, i); }, "", menu,
|
||||
[is_used_extruder]() { return is_used_extruder; }, Slic3r::GUI::wxGetApp().plater());
|
||||
}
|
||||
|
||||
const wxString menu_name = from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % Slic3r::ColorChangeCode).str());
|
||||
wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, "");
|
||||
add_color_change_menu_item->SetBitmap(create_scaled_bitmap(nullptr, "colorchange_add_m"));
|
||||
add_color_change_menu_item->SetBitmap(create_scaled_bitmap(this, "colorchange_add_m"));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3262,28 +3278,21 @@ void DoubleSlider::OnLeftUp(wxMouseEvent& event)
|
||||
this->ReleaseMouse();
|
||||
m_is_left_down = false;
|
||||
|
||||
if (m_show_context_menu)
|
||||
if (m_force_delete_tick)
|
||||
{
|
||||
if (m_mode == t_mode::SingleExtruder)
|
||||
add_code(Slic3r::ColorChangeCode);
|
||||
else
|
||||
{
|
||||
wxMenu menu;
|
||||
|
||||
if (m_mode == t_mode::MultiAsSingle)
|
||||
append_change_extruder_menu_item(&menu);
|
||||
else
|
||||
append_add_color_change_menu_item(&menu);
|
||||
|
||||
Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu);
|
||||
}
|
||||
|
||||
m_show_context_menu = false;
|
||||
delete_current_tick();
|
||||
m_force_delete_tick = false;
|
||||
}
|
||||
|
||||
if (m_edit_extruder_sequence) {
|
||||
else
|
||||
if (m_force_add_tick)
|
||||
{
|
||||
add_current_tick();
|
||||
m_force_add_tick = false;
|
||||
}
|
||||
else
|
||||
if (m_force_edit_extruder_sequence) {
|
||||
edit_extruder_sequence();
|
||||
m_edit_extruder_sequence = false;
|
||||
m_force_edit_extruder_sequence = false;
|
||||
}
|
||||
|
||||
Refresh();
|
||||
@ -3329,45 +3338,6 @@ void DoubleSlider::move_current_thumb(const bool condition)
|
||||
ProcessWindowEvent(e);
|
||||
}
|
||||
|
||||
void DoubleSlider::action_tick(const TicksAction action)
|
||||
{
|
||||
if (m_selection == ssUndef)
|
||||
return;
|
||||
|
||||
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
|
||||
|
||||
const auto it = m_ticks.find(TICK_CODE{tick});
|
||||
|
||||
if (it != m_ticks.end()) // erase this tick
|
||||
{
|
||||
if (action == taAdd)
|
||||
return;
|
||||
m_ticks.erase(TICK_CODE{tick});
|
||||
|
||||
post_ticks_changed_event(it->gcode);
|
||||
Refresh();
|
||||
Update();
|
||||
return;
|
||||
}
|
||||
|
||||
if (action == taDel)
|
||||
return;
|
||||
if (action == taAdd)
|
||||
{
|
||||
// OnChar() is called immediately after OnKeyDown(), which can cause call of add_code() twice.
|
||||
// To avoid this case we should suppress second add_code() call.
|
||||
if (m_suppress_add_code)
|
||||
return;
|
||||
m_suppress_add_code = true;
|
||||
if (m_mode == t_mode::SingleExtruder) // if (m_mode != t_mode::MultiExtruder)
|
||||
add_code(Slic3r::ColorChangeCode);
|
||||
m_suppress_add_code = false;
|
||||
return;
|
||||
}
|
||||
|
||||
m_show_context_menu = true;
|
||||
}
|
||||
|
||||
void DoubleSlider::OnWheel(wxMouseEvent& event)
|
||||
{
|
||||
// Set nearest to the mouse thumb as a selected, if there is not selected thumb
|
||||
@ -3391,10 +3361,18 @@ void DoubleSlider::OnWheel(wxMouseEvent& event)
|
||||
void DoubleSlider::OnKeyDown(wxKeyEvent &event)
|
||||
{
|
||||
const int key = event.GetKeyCode();
|
||||
if (key == WXK_NUMPAD_ADD)
|
||||
action_tick(taAdd);
|
||||
else if (key == 390 || key == WXK_DELETE || key == WXK_BACK)
|
||||
action_tick(taDel);
|
||||
if (key == WXK_NUMPAD_ADD) {
|
||||
// OnChar() is called immediately after OnKeyDown(), which can cause call of add_tick() twice.
|
||||
// To avoid this case we should suppress second add_tick() call.
|
||||
m_ticks.suppress_plus(true);
|
||||
add_current_tick(true);
|
||||
}
|
||||
else if (key == 390 || key == WXK_DELETE || key == WXK_BACK) {
|
||||
// OnChar() is called immediately after OnKeyDown(), which can cause call of delete_tick() twice.
|
||||
// To avoid this case we should suppress second delete_tick() call.
|
||||
m_ticks.suppress_minus(true);
|
||||
delete_current_tick();
|
||||
}
|
||||
else if (is_horizontal())
|
||||
{
|
||||
if (key == WXK_LEFT || key == WXK_RIGHT)
|
||||
@ -3428,10 +3406,14 @@ void DoubleSlider::OnKeyUp(wxKeyEvent &event)
|
||||
void DoubleSlider::OnChar(wxKeyEvent& event)
|
||||
{
|
||||
const int key = event.GetKeyCode();
|
||||
if (key == '+')
|
||||
action_tick(taAdd);
|
||||
else if (key == '-')
|
||||
action_tick(taDel);
|
||||
if (key == '+' && !m_ticks.suppressed_plus()) {
|
||||
add_current_tick(true);
|
||||
m_ticks.suppress_plus(false);
|
||||
}
|
||||
else if (key == '-' && !m_ticks.suppressed_minus()) {
|
||||
delete_current_tick();
|
||||
m_ticks.suppress_minus(false);
|
||||
}
|
||||
}
|
||||
|
||||
void DoubleSlider::OnRightDown(wxMouseEvent& event)
|
||||
@ -3446,8 +3428,8 @@ void DoubleSlider::OnRightDown(wxMouseEvent& event)
|
||||
{
|
||||
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
|
||||
// if on this Z doesn't exist tick
|
||||
auto it = m_ticks.find(TICK_CODE{ tick });
|
||||
if (it == m_ticks.end())
|
||||
auto it = m_ticks.ticks.find(TICK_CODE{ tick });
|
||||
if (it == m_ticks.ticks.end())
|
||||
{
|
||||
// show context menu on OnRightUp()
|
||||
m_show_context_menu = true;
|
||||
@ -3484,8 +3466,8 @@ int DoubleSlider::get_extruder_for_tick(int tick)
|
||||
if (m_ticks.empty())
|
||||
return default_initial_extruder;
|
||||
|
||||
auto it = m_ticks.lower_bound(TICK_CODE{tick});
|
||||
while (it != m_ticks.begin()) {
|
||||
auto it = m_ticks.ticks.lower_bound(TICK_CODE{tick});
|
||||
while (it != m_ticks.ticks.begin()) {
|
||||
--it;
|
||||
if(it->gcode == Slic3r::ToolChangeCode)
|
||||
return it->extruder;
|
||||
@ -3522,16 +3504,17 @@ std::set<int> DoubleSlider::get_used_extruders_for_tick(int tick)
|
||||
return {default_initial_extruder};
|
||||
|
||||
std::set<int> used_extruders;
|
||||
auto it_start = m_ticks.lower_bound(TICK_CODE{tick});
|
||||
const std::set<TICK_CODE>& ticks = m_ticks.ticks;
|
||||
|
||||
auto it_start = ticks.lower_bound(TICK_CODE{tick});
|
||||
auto it = it_start;
|
||||
if (it == m_ticks.begin() && it->gcode == Slic3r::ToolChangeCode) {
|
||||
if (it == ticks.begin() && it->gcode == Slic3r::ToolChangeCode) {
|
||||
used_extruders.emplace(it->extruder);
|
||||
if (tick < it->tick)
|
||||
used_extruders.emplace(default_initial_extruder);
|
||||
}
|
||||
|
||||
while (it != m_ticks.begin()) {
|
||||
while (it != ticks.begin()) {
|
||||
--it;
|
||||
if(it->gcode == Slic3r::ToolChangeCode)
|
||||
{
|
||||
@ -3540,11 +3523,11 @@ std::set<int> DoubleSlider::get_used_extruders_for_tick(int tick)
|
||||
}
|
||||
}
|
||||
|
||||
if (it == m_ticks.begin() && used_extruders.empty())
|
||||
if (it == ticks.begin() && used_extruders.empty())
|
||||
used_extruders.emplace(default_initial_extruder);
|
||||
|
||||
it = it_start;
|
||||
while (it != m_ticks.end()) {
|
||||
while (it != ticks.end()) {
|
||||
if(it->gcode == Slic3r::ToolChangeCode)
|
||||
used_extruders.emplace(it->extruder);
|
||||
++it;
|
||||
@ -3565,7 +3548,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event)
|
||||
|
||||
if (m_mode == t_mode::SingleExtruder)
|
||||
append_menu_item(&menu, wxID_ANY, _(L("Add color change")) + " (M600)", "",
|
||||
[this](wxCommandEvent&) { add_code(Slic3r::ColorChangeCode); }, "colorchange_add_m", &menu,
|
||||
[this](wxCommandEvent&) { add_code_as_tick(Slic3r::ColorChangeCode); }, "colorchange_add_m", &menu,
|
||||
[](){return true;}, this);
|
||||
else
|
||||
{
|
||||
@ -3574,11 +3557,11 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event)
|
||||
}
|
||||
|
||||
append_menu_item(&menu, wxID_ANY, _(L("Add pause print")) + " (M601)", "",
|
||||
[this](wxCommandEvent&) { add_code(Slic3r::PausePrintCode); }, "pause_print", &menu,
|
||||
[this](wxCommandEvent&) { add_code_as_tick(Slic3r::PausePrintCode); }, "pause_print", &menu,
|
||||
[]() {return true; }, this);
|
||||
|
||||
append_menu_item(&menu, wxID_ANY, _(L("Add custom G-code")), "",
|
||||
[this](wxCommandEvent&) { add_code(""); }, "edit_gcode", &menu,
|
||||
[this](wxCommandEvent&) { add_code_as_tick(""); }, "edit_gcode", &menu,
|
||||
[]() {return true; }, this);
|
||||
|
||||
Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu);
|
||||
@ -3588,7 +3571,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event)
|
||||
else if (m_show_edit_menu) {
|
||||
wxMenu menu;
|
||||
|
||||
std::set<TICK_CODE>::iterator it = m_ticks.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value });
|
||||
std::set<TICK_CODE>::iterator it = m_ticks.ticks.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value });
|
||||
const bool is_color_change = it->gcode == Slic3r::ColorChangeCode;
|
||||
|
||||
append_menu_item(&menu, wxID_ANY, it->gcode == Slic3r::ColorChangeCode ? _(L("Edit color")) :
|
||||
@ -3599,7 +3582,7 @@ void DoubleSlider::OnRightUp(wxMouseEvent& event)
|
||||
append_menu_item(&menu, wxID_ANY, it->gcode == Slic3r::ColorChangeCode ? _(L("Delete color change")) :
|
||||
it->gcode == Slic3r::PausePrintCode ? _(L("Delete pause print")) :
|
||||
_(L("Delete custom G-code")), "",
|
||||
[this](wxCommandEvent&) { action_tick(taDel); }, "colorchange_del_f", &menu);
|
||||
[this](wxCommandEvent&) { delete_current_tick();}, "colorchange_del_f", &menu);
|
||||
|
||||
Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu);
|
||||
|
||||
@ -3656,123 +3639,100 @@ static std::string get_pause_print_msg(const std::string& msg_in, double height)
|
||||
return into_u8(dlg.GetValue());
|
||||
}
|
||||
|
||||
void DoubleSlider::add_code(std::string code, int selected_extruder/* = -1*/)
|
||||
void DoubleSlider::add_code_as_tick(std::string code, int selected_extruder/* = -1*/)
|
||||
{
|
||||
if (m_selection == ssUndef)
|
||||
return;
|
||||
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
|
||||
// if on this Z doesn't exist tick
|
||||
auto it = m_ticks.find(TICK_CODE{ tick });
|
||||
if (it != m_ticks.end())
|
||||
|
||||
if (m_ticks.ticks.find(TICK_CODE{ tick }) != m_ticks.ticks.end() || // if on this Z doesn't exist tick
|
||||
!check_ticks_changed_event(code))
|
||||
return;
|
||||
|
||||
std::string color;
|
||||
const int extruder = selected_extruder > 0 ? selected_extruder : std::max<int>(1, m_only_extruder);
|
||||
|
||||
if (code == Slic3r::ColorChangeCode)
|
||||
{
|
||||
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
|
||||
|
||||
if (m_ticks.empty())
|
||||
color = colors[extruder-1];
|
||||
else
|
||||
{
|
||||
auto before_tick_it = std::lower_bound(m_ticks.begin(), m_ticks.end(), TICK_CODE{ tick });
|
||||
while (before_tick_it != m_ticks.begin()) {
|
||||
--before_tick_it;
|
||||
if (before_tick_it->gcode == Slic3r::ColorChangeCode && before_tick_it->extruder == extruder) {
|
||||
color = before_tick_it->color;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (color.empty())
|
||||
color = colors[extruder-1];
|
||||
}
|
||||
|
||||
color = get_new_color(color);
|
||||
if (color.empty())
|
||||
return;
|
||||
}
|
||||
else if (code == Slic3r::PausePrintCode)
|
||||
{
|
||||
/* PausePrintCode doesn't need a color, so
|
||||
* this field is used for save a short message shown on Printer display
|
||||
* */
|
||||
color = get_pause_print_msg(m_pause_print_msg, m_values[tick]);
|
||||
if (color.empty())
|
||||
return;
|
||||
m_pause_print_msg = color;
|
||||
}
|
||||
else if (code.empty())
|
||||
{
|
||||
code = get_custom_code(m_custom_gcode, m_values[tick]);
|
||||
if (code.empty())
|
||||
return;
|
||||
m_custom_gcode = code;
|
||||
}
|
||||
|
||||
m_ticks.emplace(TICK_CODE{tick, code, extruder, color});
|
||||
if (!m_ticks.add_tick(tick, code, extruder, m_values[tick]))
|
||||
return;
|
||||
|
||||
post_ticks_changed_event(code);
|
||||
Refresh();
|
||||
Update();
|
||||
}
|
||||
|
||||
void DoubleSlider::add_current_tick(bool call_from_keyboard /*= false*/)
|
||||
{
|
||||
if (m_selection == ssUndef)
|
||||
return;
|
||||
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
|
||||
auto it = m_ticks.ticks.find(TICK_CODE{ tick });
|
||||
|
||||
if (it != m_ticks.ticks.end() || // this tick is already exist
|
||||
!check_ticks_changed_event(m_mode == t_mode::MultiAsSingle ? Slic3r::ToolChangeCode : Slic3r::ColorChangeCode))
|
||||
return;
|
||||
|
||||
if (m_mode == t_mode::SingleExtruder)
|
||||
add_code_as_tick(Slic3r::ColorChangeCode);
|
||||
else
|
||||
{
|
||||
wxMenu menu;
|
||||
|
||||
if (m_mode == t_mode::MultiAsSingle)
|
||||
append_change_extruder_menu_item(&menu);
|
||||
else
|
||||
append_add_color_change_menu_item(&menu);
|
||||
|
||||
wxPoint pos = wxDefaultPosition;
|
||||
if (call_from_keyboard)
|
||||
{
|
||||
int width, height;
|
||||
get_size(&width, &height);
|
||||
|
||||
const wxCoord coord = 0.75 * (is_horizontal() ? height : width);
|
||||
this->GetPosition(&width, &height);
|
||||
|
||||
pos = is_horizontal() ?
|
||||
wxPoint(get_position_from_value(tick), height + coord) :
|
||||
wxPoint(width + coord, get_position_from_value(tick));
|
||||
}
|
||||
|
||||
Slic3r::GUI::wxGetApp().plater()->PopupMenu(&menu, pos);
|
||||
}
|
||||
}
|
||||
|
||||
void DoubleSlider::delete_current_tick()
|
||||
{
|
||||
if (m_selection == ssUndef)
|
||||
return;
|
||||
auto it = m_ticks.ticks.find(TICK_CODE{ m_selection == ssLower ? m_lower_value : m_higher_value });
|
||||
|
||||
if (it != m_ticks.ticks.end())
|
||||
{
|
||||
if (!check_ticks_changed_event(it->gcode))
|
||||
return;
|
||||
|
||||
const std::string code = it->gcode;
|
||||
m_ticks.ticks.erase(it);
|
||||
post_ticks_changed_event(code);
|
||||
}
|
||||
}
|
||||
|
||||
void DoubleSlider::edit_tick()
|
||||
{
|
||||
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
|
||||
// if on this Z exists tick
|
||||
std::set<TICK_CODE>::iterator it = m_ticks.find(TICK_CODE{ tick });
|
||||
if (it != m_ticks.end())
|
||||
{
|
||||
std::string edited_value;
|
||||
if (it->gcode == Slic3r::ColorChangeCode)
|
||||
edited_value = get_new_color(it->color);
|
||||
else if (it->gcode == Slic3r::PausePrintCode)
|
||||
edited_value = get_pause_print_msg(it->color, m_values[it->tick]);
|
||||
else
|
||||
edited_value = get_custom_code(it->gcode, m_values[it->tick]);
|
||||
const std::set<TICK_CODE>::iterator it = m_ticks.ticks.find(TICK_CODE{ tick });
|
||||
|
||||
if (edited_value.empty())
|
||||
return;
|
||||
if (it == m_ticks.ticks.end() || // if on this Z exists tick
|
||||
!check_ticks_changed_event(it->gcode))
|
||||
return;
|
||||
|
||||
TICK_CODE changed_tick = *it;
|
||||
if (it->gcode == Slic3r::ColorChangeCode || it->gcode == Slic3r::PausePrintCode) {
|
||||
if (it->color == edited_value)
|
||||
return;
|
||||
changed_tick.color = edited_value;
|
||||
}
|
||||
else {
|
||||
if (it->gcode == edited_value)
|
||||
return;
|
||||
changed_tick.gcode = edited_value;
|
||||
}
|
||||
|
||||
m_ticks.erase(it);
|
||||
m_ticks.emplace(changed_tick);
|
||||
|
||||
post_ticks_changed_event(changed_tick.gcode);
|
||||
}
|
||||
}
|
||||
|
||||
void DoubleSlider::change_extruder(int extruder)
|
||||
{
|
||||
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
|
||||
|
||||
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
|
||||
|
||||
// if on this Y doesn't exist tick
|
||||
if (m_ticks.find(TICK_CODE{tick}) == m_ticks.end())
|
||||
{
|
||||
m_ticks.emplace(TICK_CODE{tick, Slic3r::ToolChangeCode, extruder, extruder == 0 ? "" : colors[extruder-1]});
|
||||
|
||||
post_ticks_changed_event(Slic3r::ToolChangeCode);
|
||||
Refresh();
|
||||
Update();
|
||||
}
|
||||
const std::string code = it->gcode;
|
||||
if (m_ticks.edit_tick(it, m_values[it->tick]))
|
||||
post_ticks_changed_event(code);
|
||||
}
|
||||
|
||||
void DoubleSlider::edit_extruder_sequence()
|
||||
{
|
||||
if (!check_ticks_changed_event(Slic3r::ToolChangeCode))
|
||||
return;
|
||||
|
||||
Slic3r::GUI::ExtruderSequenceDialog dlg(m_extruders_sequence);
|
||||
if (dlg.ShowModal() != wxID_OK)
|
||||
return;
|
||||
@ -3783,13 +3743,7 @@ void DoubleSlider::edit_extruder_sequence()
|
||||
|
||||
m_extruders_sequence = from_dlg_val;
|
||||
|
||||
auto it = m_ticks.begin();
|
||||
while (it != m_ticks.end()) {
|
||||
if (it->gcode == Slic3r::ToolChangeCode)
|
||||
it = m_ticks.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
m_ticks.erase_all_ticks_with_code(Slic3r::ToolChangeCode);
|
||||
|
||||
int tick = 0;
|
||||
double value = 0.0;
|
||||
@ -3800,8 +3754,8 @@ void DoubleSlider::edit_extruder_sequence()
|
||||
|
||||
while (tick <= m_max_value)
|
||||
{
|
||||
int cur_extruder = m_extruders_sequence.extruders[extruder];
|
||||
m_ticks.emplace(TICK_CODE{tick, Slic3r::ToolChangeCode, cur_extruder + 1, colors[cur_extruder]});
|
||||
const int cur_extruder = m_extruders_sequence.extruders[extruder];
|
||||
m_ticks.ticks.emplace(TICK_CODE{tick, Slic3r::ToolChangeCode, cur_extruder + 1, colors[cur_extruder]});
|
||||
|
||||
extruder++;
|
||||
if (extruder == extr_cnt)
|
||||
@ -3825,40 +3779,183 @@ void DoubleSlider::edit_extruder_sequence()
|
||||
|
||||
void DoubleSlider::post_ticks_changed_event(const std::string& gcode /*= ""*/)
|
||||
{
|
||||
if ( m_ticks_mode == m_mode ||
|
||||
(gcode != Slic3r::ColorChangeCode && gcode != Slic3r::ToolChangeCode) )
|
||||
{
|
||||
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ticks_mode == t_mode::SingleExtruder && m_mode == t_mode::MultiAsSingle)
|
||||
{
|
||||
}
|
||||
|
||||
if (m_ticks_mode == t_mode::SingleExtruder && m_mode == t_mode::MultiExtruder)
|
||||
{
|
||||
}
|
||||
|
||||
if (m_ticks_mode == t_mode::MultiAsSingle && m_mode == t_mode::SingleExtruder)
|
||||
{
|
||||
}
|
||||
|
||||
if (m_ticks_mode == t_mode::MultiAsSingle && m_mode == t_mode::MultiExtruder)
|
||||
{
|
||||
}
|
||||
|
||||
if (m_ticks_mode == t_mode::MultiExtruder && m_mode == t_mode::SingleExtruder)
|
||||
{
|
||||
}
|
||||
|
||||
if (m_ticks_mode == t_mode::MultiExtruder && m_mode == t_mode::MultiAsSingle)
|
||||
{
|
||||
}
|
||||
m_force_mode_apply = (gcode.empty() || gcode == Slic3r::ColorChangeCode || gcode == Slic3r::ToolChangeCode);
|
||||
|
||||
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
|
||||
}
|
||||
|
||||
bool DoubleSlider::check_ticks_changed_event(const std::string& gcode)
|
||||
{
|
||||
if ( m_ticks.mode == m_mode ||
|
||||
(gcode != Slic3r::ColorChangeCode && gcode != Slic3r::ToolChangeCode) ||
|
||||
(m_ticks.mode == t_mode::SingleExtruder && m_mode == t_mode::MultiAsSingle) || // All ColorChanges will be applied for 1st extruder
|
||||
(m_ticks.mode == t_mode::MultiExtruder && m_mode == t_mode::MultiAsSingle) ) // Just mark ColorChanges for all unused extruders
|
||||
return true;
|
||||
|
||||
if ((m_ticks.mode == t_mode::SingleExtruder && m_mode == t_mode::MultiExtruder ) ||
|
||||
(m_ticks.mode == t_mode::MultiExtruder && m_mode == t_mode::SingleExtruder) )
|
||||
{
|
||||
if (!m_ticks.has_tick_with_code(Slic3r::ColorChangeCode))
|
||||
return true;
|
||||
|
||||
wxString message = (m_ticks.mode == t_mode::SingleExtruder ?
|
||||
_(L("The last color change data was saved for a single extruder printer profile.")) :
|
||||
_(L("The last color change data was saved for a multiple extruder printer profile."))
|
||||
) + "\n" +
|
||||
_(L("Your current changes will cause a deletion of all saved color changes.")) + "\n\n\t" +
|
||||
_(L("Are you sure you want to continue?"));
|
||||
|
||||
wxMessageDialog msg(this, message, _(L("Notice")), wxYES_NO);
|
||||
if (msg.ShowModal() == wxID_YES) {
|
||||
m_ticks.erase_all_ticks_with_code(Slic3r::ColorChangeCode);
|
||||
post_ticks_changed_event(Slic3r::ColorChangeCode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// m_ticks_mode == t_mode::MultiAsSingle
|
||||
if( m_ticks.has_tick_with_code(Slic3r::ToolChangeCode) )
|
||||
{
|
||||
wxString message = m_mode == t_mode::SingleExtruder ? (
|
||||
_(L("The last color change data was saved for a multi extruder printing.")) + "\n\n" +
|
||||
_(L("Select YES if you want to delete all saved tool changes, \n\t"
|
||||
"NO if you want all tool changes switch to color changes, \n\t"
|
||||
"or CANCEL for do nothing")) + "\n\n\t" +
|
||||
_(L("Do you want to delete all saved tool changes?"))
|
||||
) : ( // t_mode::MultiExtruder
|
||||
_(L("The last color change data was saved for a multi extruder printing with tool changes for whole print.")) + "\n\n" +
|
||||
_(L("Your current changes will cause a deletion of all saved tool changes.")) + "\n\n\t" +
|
||||
_(L("Are you sure you want to continue?")) ) ;
|
||||
|
||||
wxMessageDialog msg(this, message, _(L("Notice")), wxYES_NO | (m_mode == t_mode::SingleExtruder ? wxCANCEL : 0));
|
||||
const int answer = msg.ShowModal();
|
||||
if (answer == wxID_YES) {
|
||||
m_ticks.erase_all_ticks_with_code(Slic3r::ToolChangeCode);
|
||||
post_ticks_changed_event(Slic3r::ToolChangeCode);
|
||||
}
|
||||
else if (m_mode == t_mode::SingleExtruder && answer == wxID_NO) {
|
||||
m_ticks.switch_code(Slic3r::ToolChangeCode, Slic3r::ColorChangeCode);
|
||||
post_ticks_changed_event(Slic3r::ColorChangeCode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DoubleSlider::TICK_CODE_INFO::add_tick(const int tick, std::string& code, const int extruder, double print_z)
|
||||
{
|
||||
std::string color;
|
||||
if (code.empty()) // custom Gcode
|
||||
{
|
||||
code = get_custom_code(custom_gcode, print_z);
|
||||
if (code.empty())
|
||||
return false;
|
||||
custom_gcode = code;
|
||||
}
|
||||
else if (code == Slic3r::PausePrintCode)
|
||||
{
|
||||
/* PausePrintCode doesn't need a color, so
|
||||
* this field is used for save a short message shown on Printer display
|
||||
* */
|
||||
color = get_pause_print_msg(pause_print_msg, print_z);
|
||||
if (color.empty())
|
||||
return false;
|
||||
pause_print_msg = color;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string> colors = Slic3r::GUI::wxGetApp().plater()->get_extruder_colors_from_plater_config();
|
||||
color = colors[extruder - 1];
|
||||
|
||||
if (code == Slic3r::ColorChangeCode)
|
||||
{
|
||||
if (!ticks.empty())
|
||||
{
|
||||
auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), TICK_CODE{ tick });
|
||||
while (before_tick_it != ticks.begin()) {
|
||||
--before_tick_it;
|
||||
if (before_tick_it->gcode == Slic3r::ColorChangeCode && before_tick_it->extruder == extruder) {
|
||||
color = before_tick_it->color;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color = get_new_color(color);
|
||||
if (color.empty())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ticks.emplace(TICK_CODE{ tick, code, extruder, color });
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DoubleSlider::TICK_CODE_INFO::edit_tick(std::set<TICK_CODE>::iterator it, double print_z)
|
||||
{
|
||||
std::string edited_value;
|
||||
if (it->gcode == Slic3r::ColorChangeCode)
|
||||
edited_value = get_new_color(it->color);
|
||||
else if (it->gcode == Slic3r::PausePrintCode)
|
||||
edited_value = get_pause_print_msg(it->color, print_z);
|
||||
else
|
||||
edited_value = get_custom_code(it->gcode, print_z);
|
||||
|
||||
if (edited_value.empty())
|
||||
return false;
|
||||
|
||||
TICK_CODE changed_tick = *it;
|
||||
if (it->gcode == Slic3r::ColorChangeCode || it->gcode == Slic3r::PausePrintCode) {
|
||||
if (it->color == edited_value)
|
||||
return false;
|
||||
changed_tick.color = edited_value;
|
||||
}
|
||||
else {
|
||||
if (it->gcode == edited_value)
|
||||
return false;
|
||||
changed_tick.gcode = edited_value;
|
||||
}
|
||||
|
||||
ticks.erase(it);
|
||||
ticks.emplace(changed_tick);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DoubleSlider::TICK_CODE_INFO::switch_code(const std::string& code_from, const std::string& code_to)
|
||||
{
|
||||
for (auto it{ ticks.begin() }, end{ ticks.end() }; it != end; )
|
||||
if (it->gcode == code_from)
|
||||
{
|
||||
TICK_CODE tick = *it;
|
||||
tick.gcode = code_to;
|
||||
tick.extruder = 1;
|
||||
ticks.erase(it);
|
||||
it = ticks.emplace(tick).first;
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
void DoubleSlider::TICK_CODE_INFO::erase_all_ticks_with_code(const std::string& gcode)
|
||||
{
|
||||
for (auto it{ ticks.begin() }, end{ ticks.end() }; it != end; ) {
|
||||
if (it->gcode == gcode)
|
||||
it = ticks.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
bool DoubleSlider::TICK_CODE_INFO::has_tick_with_code(const std::string& gcode)
|
||||
{
|
||||
for (const TICK_CODE& tick : ticks)
|
||||
if (tick.gcode == gcode)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// LockButton
|
||||
|
@ -844,9 +844,13 @@ public:
|
||||
void OnChar(wxKeyEvent &event);
|
||||
void OnRightDown(wxMouseEvent& event);
|
||||
void OnRightUp(wxMouseEvent& event);
|
||||
void add_code(std::string code, int selected_extruder = -1);
|
||||
|
||||
void add_code_as_tick(std::string code, int selected_extruder = -1);
|
||||
// add default action for tick, when press "+"
|
||||
void add_current_tick(bool call_from_keyboard = false);
|
||||
// delete current tick, when press "-"
|
||||
void delete_current_tick();
|
||||
void edit_tick();
|
||||
void change_extruder(int extruder);
|
||||
void edit_extruder_sequence();
|
||||
|
||||
struct TICK_CODE
|
||||
@ -882,7 +886,6 @@ protected:
|
||||
void correct_lower_value();
|
||||
void correct_higher_value();
|
||||
void move_current_thumb(const bool condition);
|
||||
void action_tick(const TicksAction action);
|
||||
void enter_window(wxMouseEvent& event, const bool enter);
|
||||
|
||||
private:
|
||||
@ -906,6 +909,7 @@ private:
|
||||
std::set<int> get_used_extruders_for_tick(int tick);
|
||||
|
||||
void post_ticks_changed_event(const std::string& gcode = "");
|
||||
bool check_ticks_changed_event(const std::string& gcode);
|
||||
void append_change_extruder_menu_item(wxMenu*);
|
||||
void append_add_color_change_menu_item(wxMenu*);
|
||||
|
||||
@ -937,11 +941,11 @@ private:
|
||||
bool m_is_enabled_tick_manipulation = true;
|
||||
bool m_show_context_menu = false;
|
||||
bool m_show_edit_menu = false;
|
||||
bool m_edit_extruder_sequence = false;
|
||||
bool m_suppress_add_code = false;
|
||||
bool m_force_edit_extruder_sequence = false;
|
||||
bool m_force_mode_apply = true;
|
||||
bool m_force_add_tick = false;
|
||||
bool m_force_delete_tick = false;
|
||||
t_mode m_mode = t_mode::SingleExtruder;
|
||||
std::string m_custom_gcode = "";
|
||||
std::string m_pause_print_msg;
|
||||
int m_only_extruder = -1;
|
||||
|
||||
wxRect m_rect_lower_thumb;
|
||||
@ -972,8 +976,34 @@ private:
|
||||
std::vector<wxPen*> m_line_pens;
|
||||
std::vector<wxPen*> m_segm_pens;
|
||||
std::vector<double> m_values;
|
||||
std::set<TICK_CODE> m_ticks;
|
||||
t_mode m_ticks_mode;
|
||||
|
||||
struct TICK_CODE_INFO
|
||||
{
|
||||
std::set<TICK_CODE> ticks;
|
||||
t_mode mode = t_mode::SingleExtruder;
|
||||
|
||||
bool empty() const { return ticks.empty(); }
|
||||
void set_pause_print_msg(const std::string& message) { pause_print_msg = message; }
|
||||
|
||||
bool add_tick (const int tick, std::string &code, int extruder, double print_z);
|
||||
bool edit_tick (std::set<TICK_CODE>::iterator it, double print_z);
|
||||
void switch_code(const std::string& code_from, const std::string& code_to);
|
||||
void erase_all_ticks_with_code (const std::string& gcode);
|
||||
bool has_tick_with_code (const std::string& gcode);
|
||||
|
||||
void suppress_plus (bool suppress) { m_suppress_plus = suppress;}
|
||||
void suppress_minus(bool suppress) { m_suppress_minus = suppress;}
|
||||
bool suppressed_plus () { return m_suppress_plus ; }
|
||||
bool suppressed_minus() { return m_suppress_minus; }
|
||||
|
||||
private:
|
||||
|
||||
std::string custom_gcode = "";
|
||||
std::string pause_print_msg = "";
|
||||
bool m_suppress_plus = false;
|
||||
bool m_suppress_minus = false;
|
||||
}
|
||||
m_ticks;
|
||||
|
||||
public:
|
||||
struct ExtrudersSequence
|
||||
|
@ -1,4 +1,4 @@
|
||||
use Test::More tests => 81;
|
||||
use Test::More tests => 38;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
@ -45,70 +45,6 @@ use Slic3r::Test;
|
||||
|
||||
#==========================================================
|
||||
|
||||
{
|
||||
my $parser = Slic3r::GCode::PlaceholderParser->new;
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('printer_notes', ' PRINTER_VENDOR_PRUSA3D PRINTER_MODEL_MK2 ');
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$parser->apply_config($config);
|
||||
$parser->set('foo' => 0);
|
||||
$parser->set('bar' => 2);
|
||||
$parser->set('num_extruders' => 4);
|
||||
is $parser->process('[temperature_[foo]]'),
|
||||
$config->temperature->[0],
|
||||
"nested config options (legacy syntax)";
|
||||
is $parser->process('{temperature[foo]}'),
|
||||
$config->temperature->[0],
|
||||
"array reference";
|
||||
is $parser->process("test [ temperature_ [foo] ] \n hu"),
|
||||
"test " . $config->temperature->[0] . " \n hu",
|
||||
"whitespaces and newlines are maintained";
|
||||
is $parser->process('{2*3}'), '6', 'math: 2*3';
|
||||
is $parser->process('{2*3/6}'), '1', 'math: 2*3/6';
|
||||
is $parser->process('{2*3/12}'), '0', 'math: 2*3/12';
|
||||
ok abs($parser->process('{2.*3/12}') - 0.5) < 1e-7, 'math: 2.*3/12';
|
||||
is $parser->process('{2*(3-12)}'), '-18', 'math: 2*(3-12)';
|
||||
is $parser->process('{2*foo*(3-12)}'), '0', 'math: 2*foo*(3-12)';
|
||||
is $parser->process('{2*bar*(3-12)}'), '-36', 'math: 2*bar*(3-12)';
|
||||
ok abs($parser->process('{2.5*bar*(3-12)}') - -45) < 1e-7, 'math: 2.5*bar*(3-12)';
|
||||
is $parser->process('{min(12, 14)}'), '12', 'math: min(12, 14)';
|
||||
is $parser->process('{max(12, 14)}'), '14', 'math: max(12, 14)';
|
||||
is $parser->process('{min(13.4, -1238.1)}'), '-1238.1', 'math: min(13.4, -1238.1)';
|
||||
is $parser->process('{max(13.4, -1238.1)}'), '13.4', 'math: max(13.4, -1238.1)';
|
||||
|
||||
# Test the boolean expression parser.
|
||||
is $parser->evaluate_boolean_expression('12 == 12'), 1, 'boolean expression parser: 12 == 12';
|
||||
is $parser->evaluate_boolean_expression('12 != 12'), 0, 'boolean expression parser: 12 != 12';
|
||||
is $parser->evaluate_boolean_expression('"has some PATTERN embedded" =~ /.*PATTERN.*/'), 1, 'boolean expression parser: regex matches';
|
||||
is $parser->evaluate_boolean_expression('"has some PATTERN embedded" =~ /.*PTRN.*/'), 0, 'boolean expression parser: regex does not match';
|
||||
is $parser->evaluate_boolean_expression('foo + 2 == bar'), 1, 'boolean expression parser: accessing variables, equal';
|
||||
is $parser->evaluate_boolean_expression('foo + 3 == bar'), 0, 'boolean expression parser: accessing variables, not equal';
|
||||
|
||||
is $parser->evaluate_boolean_expression('(12 == 12) and (13 != 14)'), 1, 'boolean expression parser: (12 == 12) and (13 != 14)';
|
||||
is $parser->evaluate_boolean_expression('(12 == 12) && (13 != 14)'), 1, 'boolean expression parser: (12 == 12) && (13 != 14)';
|
||||
is $parser->evaluate_boolean_expression('(12 == 12) or (13 == 14)'), 1, 'boolean expression parser: (12 == 12) or (13 == 14)';
|
||||
is $parser->evaluate_boolean_expression('(12 == 12) || (13 == 14)'), 1, 'boolean expression parser: (12 == 12) || (13 == 14)';
|
||||
is $parser->evaluate_boolean_expression('(12 == 12) and not (13 == 14)'), 1, 'boolean expression parser: (12 == 12) and not (13 == 14)';
|
||||
is $parser->evaluate_boolean_expression('(12 == 12) ? (1 - 1 == 0) : (2 * 2 == 3)'), 1, 'boolean expression parser: ternary true';
|
||||
is $parser->evaluate_boolean_expression('(12 == 21/2) ? (1 - 1 == 0) : (2 * 2 == 3)'), 0, 'boolean expression parser: ternary false';
|
||||
is $parser->evaluate_boolean_expression('(12 == 13) ? (1 - 1 == 3) : (2 * 2 == 4)'), 1, 'boolean expression parser: ternary false';
|
||||
is $parser->evaluate_boolean_expression('(12 == 2 * 6) ? (1 - 1 == 3) : (2 * 2 == 4)'), 0, 'boolean expression parser: ternary true';
|
||||
is $parser->evaluate_boolean_expression('12 < 3'), 0, 'boolean expression parser: lower than - false';
|
||||
is $parser->evaluate_boolean_expression('12 < 22'), 1, 'boolean expression parser: lower than - true';
|
||||
is $parser->evaluate_boolean_expression('12 > 3'), 1, 'boolean expression parser: greater than - true';
|
||||
is $parser->evaluate_boolean_expression('12 > 22'), 0, 'boolean expression parser: greater than - false';
|
||||
is $parser->evaluate_boolean_expression('12 <= 3'), 0, 'boolean expression parser: lower than or equal- false';
|
||||
is $parser->evaluate_boolean_expression('12 <= 22'), 1, 'boolean expression parser: lower than or equal - true';
|
||||
is $parser->evaluate_boolean_expression('12 >= 3'), 1, 'boolean expression parser: greater than or equal - true';
|
||||
is $parser->evaluate_boolean_expression('12 >= 22'), 0, 'boolean expression parser: greater than or equal - false';
|
||||
is $parser->evaluate_boolean_expression('12 <= 12'), 1, 'boolean expression parser: lower than or equal (same values) - true';
|
||||
is $parser->evaluate_boolean_expression('12 >= 12'), 1, 'boolean expression parser: greater than or equal (same values) - true';
|
||||
|
||||
is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1'), 1, 'complex expression';
|
||||
is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.6 and num_extruders>1)'), 1, 'complex expression2';
|
||||
is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.3 and num_extruders>1)'), 0, 'complex expression3';
|
||||
}
|
||||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('output_filename_format', 'ts_[travel_speed]_lh_[layer_height].gcode');
|
||||
|
@ -7,6 +7,7 @@ add_executable(${_TEST_NAME}_tests
|
||||
test_config.cpp
|
||||
test_elephant_foot_compensation.cpp
|
||||
test_geometry.cpp
|
||||
test_placeholder_parser.cpp
|
||||
test_polygon.cpp
|
||||
test_stl.cpp
|
||||
)
|
||||
|
@ -26,7 +26,7 @@ SCENARIO("Export+Import geometry to/from 3mf file cycle", "[3mf]") {
|
||||
GIVEN("world vertices coordinates before save") {
|
||||
// load a model from stl file
|
||||
Model src_model;
|
||||
std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/prusa.stl";
|
||||
std::string src_file = std::string(TEST_DATA_DIR) + "/test_3mf/Prusa.stl";
|
||||
load_stl(src_file.c_str(), &src_model);
|
||||
src_model.add_default_instances();
|
||||
|
||||
|
74
tests/libslic3r/test_placeholder_parser.cpp
Normal file
74
tests/libslic3r/test_placeholder_parser.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include "libslic3r/PlaceholderParser.hpp"
|
||||
#include "libslic3r/PrintConfig.hpp"
|
||||
|
||||
using namespace Slic3r;
|
||||
|
||||
SCENARIO("Placeholder parser scripting", "[PlaceholderParser]") {
|
||||
PlaceholderParser parser;
|
||||
auto config = DynamicPrintConfig::full_print_config();
|
||||
|
||||
config.set_deserialize( {
|
||||
{ "printer_notes", " PRINTER_VENDOR_PRUSA3D PRINTER_MODEL_MK2 " },
|
||||
{ "nozzle_diameter", "0.6;0.6;0.6;0.6" },
|
||||
{ "temperature", "357;359;363;378" }
|
||||
});
|
||||
parser.apply_config(config);
|
||||
parser.set("foo", 0);
|
||||
parser.set("bar", 2);
|
||||
parser.set("num_extruders", 4);
|
||||
|
||||
SECTION("nested config options (legacy syntax)") { REQUIRE(parser.process("[temperature_[foo]]") == "357"); }
|
||||
SECTION("array reference") { REQUIRE(parser.process("{temperature[foo]}") == "357"); }
|
||||
SECTION("whitespaces and newlines are maintained") { REQUIRE(parser.process("test [ temperature_ [foo] ] \n hu") == "test 357 \n hu"); }
|
||||
|
||||
// Test the math expressions.
|
||||
SECTION("math: 2*3") { REQUIRE(parser.process("{2*3}") == "6"); }
|
||||
SECTION("math: 2*3/6") { REQUIRE(parser.process("{2*3/6}") == "1"); }
|
||||
SECTION("math: 2*3/12") { REQUIRE(parser.process("{2*3/12}") == "0"); }
|
||||
SECTION("math: 2.*3/12") { REQUIRE(std::stod(parser.process("{2.*3/12}")) == Approx(0.5)); }
|
||||
// SECTION("math: 10 % 2.5") { REQUIRE(parser.process("{10%2.5}") == "0"); }
|
||||
// SECTION("math: 11 / 2.5") { REQUIRE(parser.process("{11/2.5-1}") == "1"); }
|
||||
SECTION("math: 2*(3-12)") { REQUIRE(parser.process("{2*(3-12)}") == "-18"); }
|
||||
SECTION("math: 2*foo*(3-12)") { REQUIRE(parser.process("{2*foo*(3-12)}") == "0"); }
|
||||
SECTION("math: 2*bar*(3-12)") { REQUIRE(parser.process("{2*bar*(3-12)}") == "-36"); }
|
||||
SECTION("math: 2.5*bar*(3-12)") { REQUIRE(std::stod(parser.process("{2.5*bar*(3-12)}")) == Approx(-45)); }
|
||||
SECTION("math: min(12, 14)") { REQUIRE(parser.process("{min(12, 14)}") == "12"); }
|
||||
SECTION("math: max(12, 14)") { REQUIRE(parser.process("{max(12, 14)}") == "14"); }
|
||||
SECTION("math: min(13.4, -1238.1)") { REQUIRE(std::stod(parser.process("{min(13.4, -1238.1)}")) == Approx(-1238.1)); }
|
||||
SECTION("math: max(13.4, -1238.1)") { REQUIRE(std::stod(parser.process("{max(13.4, -1238.1)}")) == Approx(13.4)); }
|
||||
// SECTION("math: int(13.4)") { REQUIRE(parser.process("{int(13.4)}") == "13"); }
|
||||
|
||||
// Test the boolean expression parser.
|
||||
auto boolean_expression = [&parser](const std::string& templ) { return parser.evaluate_boolean_expression(templ, parser.config()); };
|
||||
|
||||
SECTION("boolean expression parser: 12 == 12") { REQUIRE(boolean_expression("12 == 12")); }
|
||||
SECTION("boolean expression parser: 12 != 12") { REQUIRE(! boolean_expression("12 != 12")); }
|
||||
SECTION("boolean expression parser: regex matches") { REQUIRE(boolean_expression("\"has some PATTERN embedded\" =~ /.*PATTERN.*/")); }
|
||||
SECTION("boolean expression parser: regex does not match") { REQUIRE(! boolean_expression("\"has some PATTERN embedded\" =~ /.*PTRN.*/")); }
|
||||
SECTION("boolean expression parser: accessing variables, equal") { REQUIRE(boolean_expression("foo + 2 == bar")); }
|
||||
SECTION("boolean expression parser: accessing variables, not equal") { REQUIRE(! boolean_expression("foo + 3 == bar")); }
|
||||
SECTION("boolean expression parser: (12 == 12) and (13 != 14)") { REQUIRE(boolean_expression("(12 == 12) and (13 != 14)")); }
|
||||
SECTION("boolean expression parser: (12 == 12) && (13 != 14)") { REQUIRE(boolean_expression("(12 == 12) && (13 != 14)")); }
|
||||
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: 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")); }
|
||||
SECTION("boolean expression parser: greater than - false") { REQUIRE(! boolean_expression("12 > 22")); }
|
||||
SECTION("boolean expression parser: lower than or equal- false") { REQUIRE(! boolean_expression("12 <= 3")); }
|
||||
SECTION("boolean expression parser: lower than or equal - true") { REQUIRE(boolean_expression("12 <= 22")); }
|
||||
SECTION("boolean expression parser: greater than or equal - true") { REQUIRE(boolean_expression("12 >= 3")); }
|
||||
SECTION("boolean expression parser: greater than or equal - false") { REQUIRE(! boolean_expression("12 >= 22")); }
|
||||
SECTION("boolean expression parser: lower than or equal (same values) - true") { REQUIRE(boolean_expression("12 <= 12")); }
|
||||
SECTION("boolean expression parser: greater than or equal (same values) - true") { REQUIRE(boolean_expression("12 >= 12")); }
|
||||
SECTION("complex expression") { REQUIRE(boolean_expression("printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1")); }
|
||||
SECTION("complex expression2") { REQUIRE(boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.6 and num_extruders>1)")); }
|
||||
SECTION("complex expression3") { REQUIRE(! boolean_expression("printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.3 and num_extruders>1)")); }
|
||||
}
|
Loading…
Reference in New Issue
Block a user