Fixed conflicts after merge with master
This commit is contained in:
commit
cc0688678c
51 changed files with 7369 additions and 6120 deletions
|
@ -229,7 +229,7 @@ if(WIN32)
|
|||
add_definitions(-D_USE_MATH_DEFINES -D_WIN32 -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS)
|
||||
if(MSVC)
|
||||
# BOOST_ALL_NO_LIB: Avoid the automatic linking of Boost libraries on Windows. Rather rely on explicit linking.
|
||||
add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x601 )
|
||||
add_definitions(-DBOOST_ALL_NO_LIB -DBOOST_USE_WINAPI_VERSION=0x601 -DBOOST_SYSTEM_USE_UTF8 )
|
||||
endif(MSVC)
|
||||
endif(WIN32)
|
||||
|
||||
|
|
14
deps/CGAL/cgal/CGALConfigVersion.cmake
vendored
14
deps/CGAL/cgal/CGALConfigVersion.cmake
vendored
|
@ -22,16 +22,4 @@ endif()
|
|||
# if the installed project requested no architecture check, don't perform the check
|
||||
if("FALSE")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it:
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# check that the installed version has the same 32/64bit-ness as the one which is currently searching:
|
||||
if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8")
|
||||
math(EXPR installedBits "8 * 8")
|
||||
set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)")
|
||||
set(PACKAGE_VERSION_UNSUITABLE TRUE)
|
||||
endif()
|
||||
endif()
|
13
deps/GMP/GMP.cmake
vendored
13
deps/GMP/GMP.cmake
vendored
|
@ -19,15 +19,18 @@ if (MSVC)
|
|||
else ()
|
||||
set(_gmp_ccflags "-O2 -DNDEBUG -fPIC -DPIC -Wall -Wmissing-prototypes -Wpointer-arith -pedantic -fomit-frame-pointer -fno-common")
|
||||
set(_gmp_build_tgt "${CMAKE_SYSTEM_PROCESSOR}")
|
||||
if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")
|
||||
set(_gmp_ccflags "${_gmp_ccflags} -march=armv7-a") # Works on RPi-4
|
||||
set(_gmp_build_tgt armv7)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")
|
||||
set(_gmp_build_tgt aarch64)
|
||||
endif()
|
||||
set(_gmp_ccflags "${_gmp_ccflags} -mmacosx-version-min=${DEP_OSX_TARGET}")
|
||||
set(_gmp_build_tgt "--build=${_gmp_build_tgt}-apple-darwin")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")
|
||||
set(_gmp_ccflags "${_gmp_ccflags} -march=armv7-a") # Works on RPi-4
|
||||
set(_gmp_build_tgt armv7)
|
||||
endif()
|
||||
set(_gmp_build_tgt "--build=${_gmp_build_tgt}-pc-linux-gnu")
|
||||
else ()
|
||||
set(_gmp_build_tgt "") # let it guess
|
||||
|
@ -35,7 +38,7 @@ else ()
|
|||
|
||||
ExternalProject_Add(dep_GMP
|
||||
# URL https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2
|
||||
URL https://gmplib.org/download/gmp/gmp-6.2.0.tar.lz
|
||||
URL https://gmplib.org/download/gmp/gmp-6.2.1.tar.bz2
|
||||
BUILD_IN_SOURCE ON
|
||||
CONFIGURE_COMMAND env "CFLAGS=${_gmp_ccflags}" "CXXFLAGS=${_gmp_ccflags}" ./configure --enable-shared=no --enable-cxx=yes --enable-static=yes "--prefix=${DESTDIR}/usr/local" ${_gmp_build_tgt}
|
||||
BUILD_COMMAND make -j
|
||||
|
|
8
deps/PNG/PNG.cmake
vendored
8
deps/PNG/PNG.cmake
vendored
|
@ -1,3 +1,9 @@
|
|||
if (APPLE)
|
||||
# Only disable NEON extension for Apple ARM builds, leave it enabled for Raspberry PI.
|
||||
set(_disable_neon_extension "-DPNG_ARM_NEON=off")
|
||||
else ()
|
||||
set(_disable_neon_extension "")
|
||||
endif ()
|
||||
|
||||
prusaslicer_add_cmake_project(PNG
|
||||
GIT_REPOSITORY https://github.com/glennrp/libpng.git
|
||||
|
@ -8,6 +14,8 @@ prusaslicer_add_cmake_project(PNG
|
|||
-DPNG_STATIC=ON
|
||||
-DPNG_PREFIX=prusaslicer_
|
||||
-DPNG_TESTS=OFF
|
||||
-DDISABLE_DEPENDENCY_TRACKING=OFF
|
||||
${_disable_neon_extension}
|
||||
)
|
||||
|
||||
if (MSVC)
|
||||
|
|
9
deps/wxWidgets/wxWidgets.cmake
vendored
9
deps/wxWidgets/wxWidgets.cmake
vendored
|
@ -1,4 +1,11 @@
|
|||
set(_wx_git_tag v3.1.3-patched)
|
||||
if (APPLE AND ${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm")
|
||||
# The new OSX 11 (Big Sur) is not compatible with wxWidgets 3.1.3.
|
||||
# Let's use patched wxWidgets 3.1.4, even though it is not quite tested.
|
||||
set(_wx_git_tag v3.1.4-patched)
|
||||
else ()
|
||||
# Use the tested patched wxWidgets 3.1.3 everywhere else.
|
||||
set(_wx_git_tag v3.1.3-patched)
|
||||
endif ()
|
||||
|
||||
# set(_patch_command "")
|
||||
set(_wx_toolkit "")
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4902,7 +4902,7 @@ msgstr "%s encontrou um erro"
|
|||
|
||||
#: src/slic3r/GUI/NotificationManager.hpp:317
|
||||
msgid "Exporting finished."
|
||||
msgstr "Falha na exportação."
|
||||
msgstr "Exportação concluída."
|
||||
|
||||
#: src/slic3r/GUI/NotificationManager.hpp:317
|
||||
msgid "Eject drive."
|
||||
|
|
BIN
resources/localization/ru/PrusaSlicer.mo
Normal file
BIN
resources/localization/ru/PrusaSlicer.mo
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load diff
|
@ -167,6 +167,8 @@ struct NfpPConfig {
|
|||
const ItemGroup& // remaining items
|
||||
)> before_packing;
|
||||
|
||||
std::function<void(const ItemGroup &, NfpPConfig &config)> on_preload;
|
||||
|
||||
NfpPConfig(): rotations({0.0, Pi/2.0, Pi, 3*Pi/2}),
|
||||
alignment(Alignment::CENTER), starting_point(Alignment::CENTER) {}
|
||||
};
|
||||
|
@ -577,6 +579,12 @@ public:
|
|||
Base::clearItems();
|
||||
}
|
||||
|
||||
void preload(const ItemGroup& packeditems) {
|
||||
Base::preload(packeditems);
|
||||
if (config_.on_preload)
|
||||
config_.on_preload(packeditems, config_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
using Shapes = TMultiShape<RawShape>;
|
||||
|
@ -663,62 +671,79 @@ private:
|
|||
remlist.insert(remlist.end(), remaining.from, remaining.to);
|
||||
}
|
||||
|
||||
double global_score = std::numeric_limits<double>::max();
|
||||
|
||||
auto initial_tr = item.translation();
|
||||
auto initial_rot = item.rotation();
|
||||
Vertex final_tr = {0, 0};
|
||||
Radians final_rot = initial_rot;
|
||||
Shapes nfps;
|
||||
|
||||
auto& bin = bin_;
|
||||
double norm = norm_;
|
||||
auto pbb = sl::boundingBox(merged_pile_);
|
||||
auto binbb = sl::boundingBox(bin);
|
||||
|
||||
// This is the kernel part of the object function that is
|
||||
// customizable by the library client
|
||||
std::function<double(const Item&)> _objfunc;
|
||||
if(config_.object_function) _objfunc = config_.object_function;
|
||||
else {
|
||||
|
||||
// Inside check has to be strict if no alignment was enabled
|
||||
std::function<double(const Box&)> ins_check;
|
||||
if(config_.alignment == Config::Alignment::DONT_ALIGN)
|
||||
ins_check = [&binbb, norm](const Box& fullbb) {
|
||||
double ret = 0;
|
||||
if(!sl::isInside(fullbb, binbb))
|
||||
ret += norm;
|
||||
return ret;
|
||||
};
|
||||
else
|
||||
ins_check = [&bin](const Box& fullbb) {
|
||||
double miss = overfit(fullbb, bin);
|
||||
miss = miss > 0? miss : 0;
|
||||
return std::pow(miss, 2);
|
||||
};
|
||||
|
||||
_objfunc = [norm, binbb, pbb, ins_check](const Item& item)
|
||||
{
|
||||
auto ibb = item.boundingBox();
|
||||
auto fullbb = sl::boundingBox(pbb, ibb);
|
||||
|
||||
double score = pl::distance(ibb.center(),
|
||||
binbb.center());
|
||||
score /= norm;
|
||||
|
||||
score += ins_check(fullbb);
|
||||
|
||||
return score;
|
||||
};
|
||||
}
|
||||
|
||||
if(items_.empty()) {
|
||||
setInitialPosition(item);
|
||||
auto best_tr = item.translation();
|
||||
auto best_rot = item.rotation();
|
||||
best_overfit = overfit(item.transformedShape(), bin_);
|
||||
can_pack = best_overfit <= 0;
|
||||
} else {
|
||||
|
||||
double global_score = std::numeric_limits<double>::max();
|
||||
|
||||
auto initial_tr = item.translation();
|
||||
auto initial_rot = item.rotation();
|
||||
Vertex final_tr = {0, 0};
|
||||
Radians final_rot = initial_rot;
|
||||
Shapes nfps;
|
||||
|
||||
auto& bin = bin_;
|
||||
double norm = norm_;
|
||||
auto pbb = sl::boundingBox(merged_pile_);
|
||||
auto binbb = sl::boundingBox(bin);
|
||||
|
||||
// This is the kernel part of the object function that is
|
||||
// customizable by the library client
|
||||
std::function<double(const Item&)> _objfunc;
|
||||
if(config_.object_function) _objfunc = config_.object_function;
|
||||
else {
|
||||
|
||||
// Inside check has to be strict if no alignment was enabled
|
||||
std::function<double(const Box&)> ins_check;
|
||||
if(config_.alignment == Config::Alignment::DONT_ALIGN)
|
||||
ins_check = [&binbb, norm](const Box& fullbb) {
|
||||
double ret = 0;
|
||||
if(!sl::isInside(fullbb, binbb))
|
||||
ret += norm;
|
||||
return ret;
|
||||
};
|
||||
else
|
||||
ins_check = [&bin](const Box& fullbb) {
|
||||
double miss = overfit(fullbb, bin);
|
||||
miss = miss > 0? miss : 0;
|
||||
return std::pow(miss, 2);
|
||||
};
|
||||
|
||||
_objfunc = [norm, binbb, pbb, ins_check](const Item& item)
|
||||
{
|
||||
auto ibb = item.boundingBox();
|
||||
auto fullbb = sl::boundingBox(pbb, ibb);
|
||||
|
||||
double score = pl::distance(ibb.center(),
|
||||
binbb.center());
|
||||
score /= norm;
|
||||
|
||||
score += ins_check(fullbb);
|
||||
|
||||
return score;
|
||||
};
|
||||
for(auto rot : config_.rotations) {
|
||||
item.translation(initial_tr);
|
||||
item.rotation(initial_rot + rot);
|
||||
setInitialPosition(item);
|
||||
double of = 0.;
|
||||
if ((of = overfit(item.transformedShape(), bin_)) < best_overfit) {
|
||||
best_overfit = of;
|
||||
best_tr = item.translation();
|
||||
best_rot = item.rotation();
|
||||
}
|
||||
}
|
||||
|
||||
can_pack = best_overfit <= 0;
|
||||
item.rotation(best_rot);
|
||||
item.translation(best_tr);
|
||||
} else {
|
||||
|
||||
Pile merged_pile = merged_pile_;
|
||||
|
||||
for(auto rot : config_.rotations) {
|
||||
|
@ -948,10 +973,9 @@ private:
|
|||
if(items_.empty() ||
|
||||
config_.alignment == Config::Alignment::DONT_ALIGN) return;
|
||||
|
||||
nfp::Shapes<RawShape> m;
|
||||
m.reserve(items_.size());
|
||||
for(Item& item : items_) m.emplace_back(item.transformedShape());
|
||||
auto&& bb = sl::boundingBox(m);
|
||||
Box bb = items_.front().get().boundingBox();
|
||||
for(Item& item : items_)
|
||||
bb = sl::boundingBox(item.boundingBox(), bb);
|
||||
|
||||
Vertex ci, cb;
|
||||
|
||||
|
@ -988,7 +1012,7 @@ private:
|
|||
for(Item& item : items_) item.translate(d);
|
||||
}
|
||||
|
||||
void setInitialPosition(Item& item) {
|
||||
void setInitialPosition(Item& item) {
|
||||
Box bb = item.boundingBox();
|
||||
|
||||
Vertex ci, cb;
|
||||
|
|
|
@ -109,6 +109,7 @@ void fill_config(PConf& pcfg, const ArrangeParams ¶ms) {
|
|||
|
||||
// Apply penalty to object function result. This is used only when alignment
|
||||
// after arrange is explicitly disabled (PConfig::Alignment::DONT_ALIGN)
|
||||
// Also, this will only work well for Box shaped beds.
|
||||
static double fixed_overfit(const std::tuple<double, Box>& result, const Box &binbb)
|
||||
{
|
||||
double score = std::get<0>(result);
|
||||
|
@ -348,6 +349,17 @@ public:
|
|||
|
||||
m_pconf.object_function = get_objfn();
|
||||
|
||||
m_pconf.on_preload = [this](const ItemGroup &items, PConfig &cfg) {
|
||||
if (items.empty()) return;
|
||||
|
||||
cfg.alignment = PConfig::Alignment::DONT_ALIGN;
|
||||
auto bb = sl::boundingBox(m_bin);
|
||||
auto bbcenter = bb.center();
|
||||
cfg.object_function = [this, bb, bbcenter](const Item &item) {
|
||||
return fixed_overfit(objfunc(item, bbcenter), bb);
|
||||
};
|
||||
};
|
||||
|
||||
auto on_packed = params.on_packed;
|
||||
|
||||
if (progressind || on_packed)
|
||||
|
@ -383,22 +395,12 @@ public:
|
|||
PConfig& config() { return m_pconf; }
|
||||
const PConfig& config() const { return m_pconf; }
|
||||
|
||||
inline void preload(std::vector<Item>& fixeditems) {
|
||||
m_pconf.alignment = PConfig::Alignment::DONT_ALIGN;
|
||||
auto bb = sl::boundingBox(m_bin);
|
||||
auto bbcenter = bb.center();
|
||||
m_pconf.object_function = [this, bb, bbcenter](const Item &item) {
|
||||
return fixed_overfit(objfunc(item, bbcenter), bb);
|
||||
};
|
||||
|
||||
// Build the rtree for queries to work
|
||||
|
||||
inline void preload(std::vector<Item>& fixeditems) {
|
||||
for(unsigned idx = 0; idx < fixeditems.size(); ++idx) {
|
||||
Item& itm = fixeditems[idx];
|
||||
itm.markAsFixedInBin(itm.binId());
|
||||
}
|
||||
|
||||
m_pck.configure(m_pconf);
|
||||
m_item_count += fixeditems.size();
|
||||
}
|
||||
};
|
||||
|
@ -412,13 +414,10 @@ template<> std::function<double(const Item&)> AutoArranger<Box>::get_objfn()
|
|||
|
||||
double score = std::get<0>(result);
|
||||
auto& fullbb = std::get<1>(result);
|
||||
|
||||
auto bin = m_bin;
|
||||
sl::offset(bin, -EPSILON * (m_bin.width() + m_bin.height()));
|
||||
|
||||
double miss = Placer::overfit(fullbb, bin);
|
||||
double miss = Placer::overfit(fullbb, m_bin);
|
||||
miss = miss > 0? miss : 0;
|
||||
score += miss*miss;
|
||||
score += miss * miss;
|
||||
|
||||
return score;
|
||||
};
|
||||
|
@ -486,7 +485,7 @@ void _arrange(
|
|||
{
|
||||
// Integer ceiling the min distance from the bed perimeters
|
||||
coord_t md = params.min_obj_distance;
|
||||
md = (md % 2) ? md / 2 + 1 : md / 2;
|
||||
md = md / 2;
|
||||
|
||||
auto corrected_bin = bin;
|
||||
sl::offset(corrected_bin, md);
|
||||
|
@ -573,10 +572,13 @@ static void process_arrangeable(const ArrangePolygon &arrpoly,
|
|||
|
||||
clppr::Polygon clpath(Slic3rMultiPoint_to_ClipperPath(p));
|
||||
|
||||
if (!clpath.Contour.empty()) {
|
||||
auto firstp = clpath.Contour.front();
|
||||
clpath.Contour.emplace_back(firstp);
|
||||
}
|
||||
// This fixes:
|
||||
// https://github.com/prusa3d/PrusaSlicer/issues/2209
|
||||
if (clpath.Contour.size() < 3)
|
||||
return;
|
||||
|
||||
auto firstp = clpath.Contour.front();
|
||||
clpath.Contour.emplace_back(firstp);
|
||||
|
||||
outp.emplace_back(std::move(clpath));
|
||||
outp.back().rotation(rotation);
|
||||
|
|
|
@ -62,6 +62,15 @@ struct ArrangePolygon {
|
|||
|
||||
/// Test if arrange() was called previously and gave a successful result.
|
||||
bool is_arranged() const { return bed_idx != UNARRANGED; }
|
||||
|
||||
inline ExPolygon transformed_poly() const
|
||||
{
|
||||
ExPolygon ret = poly;
|
||||
ret.rotate(rotation);
|
||||
ret.translate(translation.x(), translation.y());
|
||||
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
using ArrangePolygons = std::vector<ArrangePolygon>;
|
||||
|
|
|
@ -53,6 +53,9 @@ public:
|
|||
return point(0) >= this->min(0) && point(0) <= this->max(0)
|
||||
&& point(1) >= this->min(1) && point(1) <= this->max(1);
|
||||
}
|
||||
bool contains(const BoundingBoxBase<PointClass> &other) const {
|
||||
return contains(other.min) && contains(other.max);
|
||||
}
|
||||
bool overlap(const BoundingBoxBase<PointClass> &other) const {
|
||||
return ! (this->max(0) < other.min(0) || this->min(0) > other.max(0) ||
|
||||
this->max(1) < other.min(1) || this->min(1) > other.max(1));
|
||||
|
|
|
@ -20,7 +20,8 @@ SLIC3R_DERIVE_EXCEPTION(OutOfRange, LogicError);
|
|||
SLIC3R_DERIVE_EXCEPTION(IOError, CriticalException);
|
||||
SLIC3R_DERIVE_EXCEPTION(FileIOError, IOError);
|
||||
SLIC3R_DERIVE_EXCEPTION(HostNetworkError, IOError);
|
||||
SLIC3R_DERIVE_EXCEPTION(ExportError, CriticalException);
|
||||
SLIC3R_DERIVE_EXCEPTION(ExportError, CriticalException);
|
||||
SLIC3R_DERIVE_EXCEPTION(PlaceholderParserError, RuntimeError);
|
||||
// Runtime exception produced by Slicer. Such exception cancels the slicing process and it shall be shown in notifications.
|
||||
SLIC3R_DERIVE_EXCEPTION(SlicingError, Exception);
|
||||
#undef SLIC3R_DERIVE_EXCEPTION
|
||||
|
|
|
@ -748,15 +748,17 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessor::Result* re
|
|||
|
||||
if (! m_placeholder_parser_failed_templates.empty()) {
|
||||
// G-code export proceeded, but some of the PlaceholderParser substitutions failed.
|
||||
//FIXME localize!
|
||||
std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n";
|
||||
for (const std::string &name : m_placeholder_parser_failed_templates)
|
||||
msg += std::string("\t") + name + "\n";
|
||||
for (const auto &name_and_error : m_placeholder_parser_failed_templates)
|
||||
msg += name_and_error.first + "\n" + name_and_error.second + "\n";
|
||||
msg += "\nPlease inspect the file ";
|
||||
msg += path_tmp + " for error messages enclosed between\n";
|
||||
msg += " !!!!! Failed to process the custom G-code template ...\n";
|
||||
msg += "and\n";
|
||||
msg += " !!!!! End of an error report for the custom G-code template ...\n";
|
||||
throw Slic3r::RuntimeError(msg);
|
||||
msg += "for all macro processing errors.";
|
||||
throw Slic3r::PlaceholderParserError(msg);
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Start processing gcode, " << log_memory_info();
|
||||
|
@ -1434,7 +1436,11 @@ std::string GCode::placeholder_parser_process(const std::string &name, const std
|
|||
return m_placeholder_parser.process(templ, current_extruder_id, config_override);
|
||||
} catch (std::runtime_error &err) {
|
||||
// Collect the names of failed template substitutions for error reporting.
|
||||
m_placeholder_parser_failed_templates.insert(name);
|
||||
auto it = m_placeholder_parser_failed_templates.find(name);
|
||||
if (it == m_placeholder_parser_failed_templates.end())
|
||||
// Only if there was no error reported for this template, store the first error message into the map to be reported.
|
||||
// We don't want to collect error message for each and every occurence of a single custom G-code section.
|
||||
m_placeholder_parser_failed_templates.insert(it, std::make_pair(name, std::string(err.what())));
|
||||
// Insert the macro error message into the G-code.
|
||||
return
|
||||
std::string("\n!!!!! Failed to process the custom G-code template ") + name + "\n" +
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "GCode/ThumbnailData.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#ifdef HAS_PRESSURE_EQUALIZER
|
||||
|
@ -323,7 +324,7 @@ private:
|
|||
GCodeWriter m_writer;
|
||||
PlaceholderParser m_placeholder_parser;
|
||||
// Collection of templates, on which the placeholder substitution failed.
|
||||
std::set<std::string> m_placeholder_parser_failed_templates;
|
||||
std::map<std::string, std::string> m_placeholder_parser_failed_templates;
|
||||
OozePrevention m_ooze_prevention;
|
||||
Wipe m_wipe;
|
||||
AvoidCrossingPerimeters m_avoid_crossing_perimeters;
|
||||
|
|
|
@ -266,8 +266,9 @@ inline bool liang_barsky_line_clipping(
|
|||
// Clipped successfully.
|
||||
x1 = x0 + interval.second * v;
|
||||
x0 += interval.first * v;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Based on Liang-Barsky function by Daniel White @ http://www.skytopia.com/project/articles/compsci/clipping.html
|
||||
|
|
|
@ -1273,6 +1273,10 @@ void ModelObject::split(ModelObjectPtrs* new_objects)
|
|||
ModelVolume* volume = this->volumes.front();
|
||||
TriangleMeshPtrs meshptrs = volume->mesh().split();
|
||||
for (TriangleMesh *mesh : meshptrs) {
|
||||
|
||||
// FIXME: crashes if not satisfied
|
||||
if (mesh->facets_count() < 3) continue;
|
||||
|
||||
mesh->repair();
|
||||
|
||||
// XXX: this seems to be the only real usage of m_model, maybe refactor this so that it's not needed?
|
||||
|
@ -1846,7 +1850,7 @@ void ModelInstance::transform_polygon(Polygon* polygon) const
|
|||
|
||||
arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
|
||||
{
|
||||
static const double SIMPLIFY_TOLERANCE_MM = 0.1;
|
||||
// static const double SIMPLIFY_TOLERANCE_MM = 0.1;
|
||||
|
||||
Vec3d rotation = get_rotation();
|
||||
rotation.z() = 0.;
|
||||
|
@ -1858,13 +1862,11 @@ arrangement::ArrangePolygon ModelInstance::get_arrange_polygon() const
|
|||
|
||||
assert(!p.points.empty());
|
||||
|
||||
// this may happen for malformed models, see:
|
||||
// https://github.com/prusa3d/PrusaSlicer/issues/2209
|
||||
if (!p.points.empty()) {
|
||||
Polygons pp{p};
|
||||
pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM));
|
||||
if (!pp.empty()) p = pp.front();
|
||||
}
|
||||
// if (!p.points.empty()) {
|
||||
// Polygons pp{p};
|
||||
// pp = p.simplify(scaled<double>(SIMPLIFY_TOLERANCE_MM));
|
||||
// if (!pp.empty()) p = pp.front();
|
||||
// }
|
||||
|
||||
arrangement::ArrangePolygon ret;
|
||||
ret.poly.contour = std::move(p);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <map>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#ifdef _MSC_VER
|
||||
#include <stdlib.h> // provides **_environ
|
||||
#else
|
||||
|
@ -870,7 +871,9 @@ namespace client
|
|||
}
|
||||
}
|
||||
msg += '\n';
|
||||
msg += error_line;
|
||||
// This hack removes all non-UTF8 characters from the source line, so that the upstream wxWidgets conversions
|
||||
// from UTF8 to UTF16 don't bail out.
|
||||
msg += boost::nowide::narrow(boost::nowide::widen(error_line));
|
||||
msg += '\n';
|
||||
for (size_t i = 0; i < error_pos; ++ i)
|
||||
msg += ' ';
|
||||
|
@ -1304,7 +1307,7 @@ static std::string process_macro(const std::string &templ, client::MyContext &co
|
|||
if (!context.error_message.empty()) {
|
||||
if (context.error_message.back() != '\n' && context.error_message.back() != '\r')
|
||||
context.error_message += '\n';
|
||||
throw Slic3r::RuntimeError(context.error_message);
|
||||
throw Slic3r::PlaceholderParserError(context.error_message);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -40,11 +40,11 @@ public:
|
|||
const DynamicConfig* external_config() const { return m_external_config; }
|
||||
|
||||
// Fill in the template using a macro processing language.
|
||||
// Throws Slic3r::RuntimeError on syntax or runtime error.
|
||||
// Throws Slic3r::PlaceholderParserError on syntax or runtime error.
|
||||
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 Slic3r::RuntimeError on syntax or runtime error.
|
||||
// Throws Slic3r::PlaceholderParserError on syntax or runtime error.
|
||||
static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override = nullptr);
|
||||
|
||||
// Update timestamp, year, month, day, hour, minute, second variables at the provided config.
|
||||
|
|
|
@ -69,7 +69,7 @@ std::string PrintBase::output_filename(const std::string &format, const std::str
|
|||
filename = boost::filesystem::change_extension(filename, default_ext);
|
||||
return filename.string();
|
||||
} catch (std::runtime_error &err) {
|
||||
throw Slic3r::RuntimeError(L("Failed processing of the output_filename_format template.") + "\n" + err.what());
|
||||
throw Slic3r::PlaceholderParserError(L("Failed processing of the output_filename_format template.") + "\n" + err.what());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,7 +98,9 @@ void PrintConfigDef::init_common_params()
|
|||
def = this->add("print_host", coString);
|
||||
def->label = L("Hostname, IP or URL");
|
||||
def->tooltip = L("Slic3r can upload G-code files to a printer host. This field should contain "
|
||||
"the hostname, IP address or URL of the printer host instance.");
|
||||
"the hostname, IP address or URL of the printer host instance. "
|
||||
"Print host behind HAProxy with basic auth enabled can be accessed by putting the user name and password into the URL "
|
||||
"in the following format: https://username:password@your-octopi-address/");
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionString(""));
|
||||
|
||||
|
@ -159,8 +161,8 @@ void PrintConfigDef::init_common_params()
|
|||
def->enum_keys_map = &ConfigOptionEnum<AuthorizationType>::get_enum_values();
|
||||
def->enum_values.push_back("key");
|
||||
def->enum_values.push_back("user");
|
||||
def->enum_labels.push_back("API key");
|
||||
def->enum_labels.push_back("HTTP digest");
|
||||
def->enum_labels.push_back(L("API key"));
|
||||
def->enum_labels.push_back(L("HTTP digest"));
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<AuthorizationType>(atKeyPassword));
|
||||
}
|
||||
|
@ -534,7 +536,7 @@ void PrintConfigDef::init_fff_params()
|
|||
def->tooltip = L("The extruder to use (unless more specific extruder settings are specified). "
|
||||
"This value overrides perimeter and infill extruders, but not the support extruders.");
|
||||
def->min = 0; // 0 = inherit defaults
|
||||
def->enum_labels.push_back("default"); // override label for item 0
|
||||
def->enum_labels.push_back(L("default")); // override label for item 0
|
||||
def->enum_labels.push_back("1");
|
||||
def->enum_labels.push_back("2");
|
||||
def->enum_labels.push_back("3");
|
||||
|
@ -1207,9 +1209,9 @@ void PrintConfigDef::init_fff_params()
|
|||
def->enum_values.push_back("top");
|
||||
def->enum_values.push_back("topmost");
|
||||
def->enum_values.push_back("solid");
|
||||
def->enum_labels.push_back("All top surfaces");
|
||||
def->enum_labels.push_back("Topmost surface only");
|
||||
def->enum_labels.push_back("All solid surfaces");
|
||||
def->enum_labels.push_back(L("All top surfaces"));
|
||||
def->enum_labels.push_back(L("Topmost surface only"));
|
||||
def->enum_labels.push_back(L("All solid surfaces"));
|
||||
def->mode = comAdvanced;
|
||||
def->set_default_value(new ConfigOptionEnum<IroningType>(IroningType::TopSurfaces));
|
||||
|
||||
|
|
|
@ -552,6 +552,7 @@ std::string encode_path(const char *src)
|
|||
}
|
||||
|
||||
// Encode an 8-bit string from a local code page to UTF-8.
|
||||
// Multibyte to utf8
|
||||
std::string decode_path(const char *src)
|
||||
{
|
||||
#ifdef WIN32
|
||||
|
|
|
@ -804,6 +804,10 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M
|
|||
BoundingBoxf3 print_volume(Vec3d(unscale<double>(bed_box_2D.min(0)), unscale<double>(bed_box_2D.min(1)), 0.0), Vec3d(unscale<double>(bed_box_2D.max(0)), unscale<double>(bed_box_2D.max(1)), config->opt_float("max_print_height")));
|
||||
// Allow the objects to protrude below the print bed
|
||||
print_volume.min(2) = -1e10;
|
||||
print_volume.min(0) -= BedEpsilon;
|
||||
print_volume.min(1) -= BedEpsilon;
|
||||
print_volume.max(0) += BedEpsilon;
|
||||
print_volume.max(1) += BedEpsilon;
|
||||
|
||||
ModelInstanceEPrintVolumeState state = ModelInstancePVS_Inside;
|
||||
|
||||
|
|
|
@ -611,6 +611,8 @@ struct _3DScene
|
|||
static void point3_to_verts(const Vec3crd& point, double width, double height, GLVolume& volume);
|
||||
};
|
||||
|
||||
static constexpr float BedEpsilon = EPSILON;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -68,9 +68,10 @@ bool SlicingProcessCompletedEvent::invalidate_plater() const
|
|||
return false;
|
||||
}
|
||||
|
||||
std::string SlicingProcessCompletedEvent::format_error_message() const
|
||||
std::pair<std::string, bool> SlicingProcessCompletedEvent::format_error_message() const
|
||||
{
|
||||
std::string error;
|
||||
bool monospace = false;
|
||||
try {
|
||||
this->rethrow_exception();
|
||||
} catch (const std::bad_alloc& ex) {
|
||||
|
@ -78,12 +79,15 @@ std::string SlicingProcessCompletedEvent::format_error_message() const
|
|||
"If you are sure you have enough RAM on your system, this may also be a bug and we would "
|
||||
"be glad if you reported it."))) % SLIC3R_APP_NAME).str());
|
||||
error = std::string(errmsg.ToUTF8()) + "\n\n" + std::string(ex.what());
|
||||
} catch (PlaceholderParserError &ex) {
|
||||
error = ex.what();
|
||||
monospace = true;
|
||||
} catch (std::exception &ex) {
|
||||
error = ex.what();
|
||||
} catch (...) {
|
||||
error = "Unknown C++ exception.";
|
||||
}
|
||||
return error;
|
||||
return std::make_pair(std::move(error), monospace);
|
||||
}
|
||||
|
||||
BackgroundSlicingProcess::BackgroundSlicingProcess()
|
||||
|
@ -149,30 +153,37 @@ void BackgroundSlicingProcess::process_fff()
|
|||
// 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);
|
||||
std::string error_message;
|
||||
int copy_ret_val = copy_file(m_temp_output_path, export_path, error_message, m_export_path_on_removable_media);
|
||||
int copy_ret_val = CopyFileResult::SUCCESS;
|
||||
try
|
||||
{
|
||||
copy_ret_val = copy_file(m_temp_output_path, export_path, error_message, m_export_path_on_removable_media);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code.")));
|
||||
}
|
||||
switch (copy_ret_val) {
|
||||
case SUCCESS: break; // no error
|
||||
case FAIL_COPY_FILE:
|
||||
case CopyFileResult::SUCCESS: break; // no error
|
||||
case CopyFileResult::FAIL_COPY_FILE:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. Maybe the SD card is write locked?\nError message: %1%"))) % error_message).str());
|
||||
break;
|
||||
case FAIL_FILES_DIFFERENT:
|
||||
case CopyFileResult::FAIL_FILES_DIFFERENT:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code to the output G-code failed. There might be problem with target device, please try exporting again or using different device. The corrupted output G-code is at %1%.tmp."))) % export_path).str());
|
||||
break;
|
||||
case FAIL_RENAMING:
|
||||
case CopyFileResult::FAIL_RENAMING:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Renaming of the G-code after copying to the selected destination folder has failed. Current path is %1%.tmp. Please try exporting again."))) % export_path).str());
|
||||
break;
|
||||
case FAIL_CHECK_ORIGIN_NOT_OPENED:
|
||||
case CopyFileResult::FAIL_CHECK_ORIGIN_NOT_OPENED:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the original code at %1% couldn't be opened during copy check. The output G-code is at %2%.tmp."))) % m_temp_output_path % export_path).str());
|
||||
break;
|
||||
case FAIL_CHECK_TARGET_NOT_OPENED:
|
||||
case CopyFileResult::FAIL_CHECK_TARGET_NOT_OPENED:
|
||||
throw Slic3r::ExportError((boost::format(_utf8(L("Copying of the temporary G-code has finished but the exported code couldn't be opened during copy check. The output G-code is at %1%.tmp."))) % export_path).str());
|
||||
break;
|
||||
default:
|
||||
throw Slic3r::RuntimeError(_utf8(L("Unknown error occured during exporting G-code.")));
|
||||
throw Slic3r::ExportError(_utf8(L("Unknown error occured during exporting G-code.")));
|
||||
BOOST_LOG_TRIVIAL(error) << "Unexpected fail code(" << (int)copy_ret_val << ") durring copy_file() to " << export_path << ".";
|
||||
break;
|
||||
}
|
||||
|
||||
m_print->set_status(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());
|
||||
|
|
|
@ -57,7 +57,8 @@ public:
|
|||
// Only valid if error()
|
||||
void rethrow_exception() const { assert(this->error()); assert(m_exception); std::rethrow_exception(m_exception); }
|
||||
// Produce a human readable message to be displayed by a notification or a message box.
|
||||
std::string format_error_message() const;
|
||||
// 2nd parameter defines whether the output should be displayed with a monospace font.
|
||||
std::pair<std::string, bool> format_error_message() const;
|
||||
|
||||
private:
|
||||
StatusType m_status;
|
||||
|
|
|
@ -1095,23 +1095,48 @@ wxDEFINE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
|
|||
|
||||
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
|
||||
|
||||
static GLCanvas3D::ArrangeSettings load_arrange_settings()
|
||||
void GLCanvas3D::load_arrange_settings()
|
||||
{
|
||||
GLCanvas3D::ArrangeSettings settings;
|
||||
std::string dist_fff_str =
|
||||
wxGetApp().app_config->get("arrange", "min_object_distance_fff");
|
||||
|
||||
std::string dist_str =
|
||||
wxGetApp().app_config->get("arrange", "min_object_distance");
|
||||
std::string dist_fff_seq_print_str =
|
||||
wxGetApp().app_config->get("arrange", "min_object_distance_fff_seq_print");
|
||||
|
||||
std::string en_rot_str =
|
||||
wxGetApp().app_config->get("arrange", "enable_rotation");
|
||||
std::string dist_sla_str =
|
||||
wxGetApp().app_config->get("arrange", "min_object_distance_sla");
|
||||
|
||||
if (!dist_str.empty())
|
||||
settings.distance = std::stof(dist_str);
|
||||
std::string en_rot_fff_str =
|
||||
wxGetApp().app_config->get("arrange", "enable_rotation_fff");
|
||||
|
||||
if (!en_rot_str.empty())
|
||||
settings.enable_rotation = (en_rot_str == "1" || en_rot_str == "yes");
|
||||
std::string en_rot_fff_seqp_str =
|
||||
wxGetApp().app_config->get("arrange", "enable_rotation_fff_seq_print");
|
||||
|
||||
return settings;
|
||||
std::string en_rot_sla_str =
|
||||
wxGetApp().app_config->get("arrange", "enable_rotation_sla");
|
||||
|
||||
if (!dist_fff_str.empty())
|
||||
m_arrange_settings_fff.distance = std::stof(dist_fff_str);
|
||||
|
||||
if (!dist_fff_seq_print_str.empty())
|
||||
m_arrange_settings_fff_seq_print.distance = std::stof(dist_fff_seq_print_str);
|
||||
|
||||
if (!dist_sla_str.empty())
|
||||
m_arrange_settings_sla.distance = std::stof(dist_sla_str);
|
||||
|
||||
if (!en_rot_fff_str.empty())
|
||||
m_arrange_settings_fff.enable_rotation = (en_rot_fff_str == "1" || en_rot_fff_str == "yes");
|
||||
|
||||
if (!en_rot_fff_seqp_str.empty())
|
||||
m_arrange_settings_fff_seq_print.enable_rotation = (en_rot_fff_seqp_str == "1" || en_rot_fff_seqp_str == "yes");
|
||||
|
||||
if (!en_rot_sla_str.empty())
|
||||
m_arrange_settings_sla.enable_rotation = (en_rot_sla_str == "1" || en_rot_sla_str == "yes");
|
||||
}
|
||||
|
||||
PrinterTechnology GLCanvas3D::current_printer_technology() const
|
||||
{
|
||||
return m_process->current_printer_technology();
|
||||
}
|
||||
|
||||
GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
|
||||
|
@ -1156,7 +1181,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas)
|
|||
#endif // ENABLE_RETINA_GL
|
||||
}
|
||||
|
||||
m_arrange_settings = load_arrange_settings();
|
||||
load_arrange_settings();
|
||||
|
||||
m_selection.set_volumes(&m_volumes.volumes);
|
||||
}
|
||||
|
@ -2554,7 +2579,13 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
|||
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE));
|
||||
break;
|
||||
case WXK_ESCAPE: { deselect_all(); break; }
|
||||
case WXK_F5: { post_event(SimpleEvent(EVT_GLCANVAS_RELOAD_FROM_DISK)); break; }
|
||||
case WXK_F5:
|
||||
{
|
||||
if ((wxGetApp().is_editor() && !wxGetApp().plater()->model().objects.empty()) ||
|
||||
(wxGetApp().is_gcode_viewer() && !wxGetApp().plater()->get_last_loaded_gcode().empty()))
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_RELOAD_FROM_DISK));
|
||||
break;
|
||||
}
|
||||
case '0': { select_view("iso"); break; }
|
||||
case '1': { select_view("top"); break; }
|
||||
case '2': { select_view("bottom"); break; }
|
||||
|
@ -3921,37 +3952,60 @@ bool GLCanvas3D::_render_arrange_menu(float pos_x)
|
|||
imgui->set_next_window_pos(x, m_main_toolbar.get_height(), ImGuiCond_Always, 0.5f, 0.0f);
|
||||
|
||||
imgui->begin(_L("Arrange options"), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
|
||||
ArrangeSettings settings = m_arrange_settings;
|
||||
|
||||
ArrangeSettings settings = get_arrange_settings();
|
||||
ArrangeSettings &settings_out = get_arrange_settings();
|
||||
|
||||
auto &appcfg = wxGetApp().app_config;
|
||||
PrinterTechnology ptech = m_process->current_printer_technology();
|
||||
|
||||
bool settings_changed = false;
|
||||
float dist_min = 0.f;
|
||||
std::string dist_key = "min_object_distance", rot_key = "enable_rotation";
|
||||
std::string postfix;
|
||||
|
||||
if (ImGui::DragFloat(_L("Gal size").ToUTF8().data(), &settings.distance, .01f, 0.0f, 100.0f, "%5.2f")) {
|
||||
m_arrange_settings.distance = settings.distance;
|
||||
if (ptech == ptSLA) {
|
||||
dist_min = 0.f;
|
||||
postfix = "_sla";
|
||||
} else if (ptech == ptFFF) {
|
||||
auto co_opt = m_config->option<ConfigOptionBool>("complete_objects");
|
||||
if (co_opt && co_opt->value) {
|
||||
dist_min = float(min_object_distance(*m_config));
|
||||
postfix = "_fff_seq_print";
|
||||
} else {
|
||||
dist_min = 0.f;
|
||||
postfix = "_fff";
|
||||
}
|
||||
}
|
||||
|
||||
dist_key += postfix;
|
||||
rot_key += postfix;
|
||||
|
||||
imgui->text(_L("Use CTRL+left mouse key to enter text edit mode:"));
|
||||
|
||||
if (imgui->slider_float(_L("Clearance size"), &settings.distance, dist_min, 100.0f, "%5.2f") || dist_min > settings.distance) {
|
||||
settings.distance = std::max(dist_min, settings.distance);
|
||||
settings_out.distance = settings.distance;
|
||||
appcfg->set("arrange", dist_key.c_str(), std::to_string(settings_out.distance));
|
||||
settings_changed = true;
|
||||
}
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", _L("Use CTRL+Left mouse button to enter text edit mode.\nUse SHIFT key to increase stepping.").ToUTF8().data());
|
||||
|
||||
if (imgui->checkbox(_L("Enable rotations (slow)"), settings.enable_rotation)) {
|
||||
m_arrange_settings.enable_rotation = settings.enable_rotation;
|
||||
settings_out.enable_rotation = settings.enable_rotation;
|
||||
appcfg->set("arrange", rot_key.c_str(), settings_out.enable_rotation? "1" : "0");
|
||||
settings_changed = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (imgui->button(_L("Reset"))) {
|
||||
m_arrange_settings = ArrangeSettings{};
|
||||
settings_out = ArrangeSettings{};
|
||||
settings_out.distance = std::max(dist_min, settings_out.distance);
|
||||
appcfg->set("arrange", dist_key.c_str(), std::to_string(settings_out.distance));
|
||||
appcfg->set("arrange", rot_key.c_str(), settings_out.enable_rotation? "1" : "0");
|
||||
settings_changed = true;
|
||||
}
|
||||
|
||||
if (settings_changed) {
|
||||
appcfg->set("arrange", "min_object_distance", std::to_string(m_arrange_settings.distance));
|
||||
appcfg->set("arrange", "enable_rotation", m_arrange_settings.enable_rotation? "1" : "0");
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (imgui->button(_L("Arrange"))) {
|
||||
|
@ -4943,7 +4997,7 @@ void GLCanvas3D::_render_objects() const
|
|||
|
||||
if (m_config != nullptr) {
|
||||
const BoundingBoxf3& bed_bb = wxGetApp().plater()->get_bed().get_bounding_box(false);
|
||||
m_volumes.set_print_box((float)bed_bb.min(0), (float)bed_bb.min(1), 0.0f, (float)bed_bb.max(0), (float)bed_bb.max(1), (float)m_config->opt_float("max_print_height"));
|
||||
m_volumes.set_print_box((float)bed_bb.min(0) - BedEpsilon, (float)bed_bb.min(1) - BedEpsilon, 0.0f, (float)bed_bb.max(0) + BedEpsilon, (float)bed_bb.max(1) + BedEpsilon, (float)m_config->opt_float("max_print_height"));
|
||||
m_volumes.check_outside_state(m_config, nullptr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -387,9 +387,11 @@ public:
|
|||
|
||||
struct ArrangeSettings
|
||||
{
|
||||
float distance = 6.;
|
||||
float accuracy = 0.65f;
|
||||
bool enable_rotation = false;
|
||||
float distance = 6.;
|
||||
// float distance_seq_print = 6.; // Used when sequential print is ON
|
||||
// float distance_sla = 6.;
|
||||
float accuracy = 0.65f; // Unused currently
|
||||
bool enable_rotation = false;
|
||||
};
|
||||
|
||||
private:
|
||||
|
@ -463,7 +465,35 @@ private:
|
|||
mutable bool m_tooltip_enabled{ true };
|
||||
Slope m_slope;
|
||||
|
||||
ArrangeSettings m_arrange_settings;
|
||||
ArrangeSettings m_arrange_settings_fff, m_arrange_settings_sla,
|
||||
m_arrange_settings_fff_seq_print;
|
||||
|
||||
PrinterTechnology current_printer_technology() const;
|
||||
|
||||
template<class Self>
|
||||
static auto & get_arrange_settings(Self *self)
|
||||
{
|
||||
PrinterTechnology ptech = self->current_printer_technology();
|
||||
|
||||
auto *ptr = &self->m_arrange_settings_fff;
|
||||
|
||||
if (ptech == ptSLA) {
|
||||
ptr = &self->m_arrange_settings_sla;
|
||||
} else if (ptech == ptFFF) {
|
||||
auto co_opt = self->m_config->template option<ConfigOptionBool>("complete_objects");
|
||||
if (co_opt && co_opt->value) {
|
||||
ptr = &self->m_arrange_settings_fff_seq_print;
|
||||
} else {
|
||||
ptr = &self->m_arrange_settings_fff;
|
||||
}
|
||||
}
|
||||
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
ArrangeSettings &get_arrange_settings() { return get_arrange_settings(this); }
|
||||
|
||||
void load_arrange_settings();
|
||||
|
||||
public:
|
||||
explicit GLCanvas3D(wxGLCanvas* canvas);
|
||||
|
@ -684,7 +714,17 @@ public:
|
|||
void use_slope(bool use) { m_slope.use(use); }
|
||||
void set_slope_normal_angle(float angle_in_deg) { m_slope.set_normal_angle(angle_in_deg); }
|
||||
|
||||
const ArrangeSettings& get_arrange_settings() const { return m_arrange_settings; }
|
||||
ArrangeSettings get_arrange_settings() const
|
||||
{
|
||||
const ArrangeSettings &settings = get_arrange_settings(this);
|
||||
ArrangeSettings ret = settings;
|
||||
if (&settings == &m_arrange_settings_fff_seq_print) {
|
||||
ret.distance = std::max(ret.distance,
|
||||
float(min_object_distance(*m_config)));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
bool _is_shown_on_screen() const;
|
||||
|
|
|
@ -221,16 +221,16 @@ void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt
|
|||
}
|
||||
}
|
||||
|
||||
void show_error(wxWindow* parent, const wxString& message)
|
||||
void show_error(wxWindow* parent, const wxString& message, bool monospaced_font)
|
||||
{
|
||||
ErrorDialog msg(parent, message);
|
||||
ErrorDialog msg(parent, message, monospaced_font);
|
||||
msg.ShowModal();
|
||||
}
|
||||
|
||||
void show_error(wxWindow* parent, const char* message)
|
||||
void show_error(wxWindow* parent, const char* message, bool monospaced_font)
|
||||
{
|
||||
assert(message);
|
||||
show_error(parent, wxString::FromUTF8(message));
|
||||
show_error(parent, wxString::FromUTF8(message), monospaced_font);
|
||||
}
|
||||
|
||||
void show_error_id(int id, const std::string& message)
|
||||
|
|
|
@ -39,9 +39,11 @@ extern void add_menus(wxMenuBar *menu, int event_preferences_changed, int event_
|
|||
// Change option value in config
|
||||
void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0);
|
||||
|
||||
void show_error(wxWindow* parent, const wxString& message);
|
||||
void show_error(wxWindow* parent, const char* message);
|
||||
inline void show_error(wxWindow* parent, const std::string& message) { show_error(parent, message.c_str()); }
|
||||
// If monospaced_font is true, the error message is displayed using html <code><pre></pre></code> tags,
|
||||
// so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
|
||||
void show_error(wxWindow* parent, const wxString& message, bool monospaced_font = false);
|
||||
void show_error(wxWindow* parent, const char* message, bool monospaced_font = false);
|
||||
inline void show_error(wxWindow* parent, const std::string& message, bool monospaced_font = false) { show_error(parent, message.c_str(), monospaced_font); }
|
||||
void show_error_id(int id, const std::string& message); // For Perl
|
||||
void show_info(wxWindow* parent, const wxString& message, const wxString& title = wxString());
|
||||
void show_info(wxWindow* parent, const char* message, const char* title = nullptr);
|
||||
|
|
|
@ -1710,11 +1710,12 @@ bool GUI_App::checked_tab(Tab* tab)
|
|||
}
|
||||
|
||||
// Update UI / Tabs to reflect changes in the currently loaded presets
|
||||
void GUI_App::load_current_presets()
|
||||
void GUI_App::load_current_presets(bool check_printer_presets_ /*= true*/)
|
||||
{
|
||||
// check printer_presets for the containing information about "Print Host upload"
|
||||
// and create physical printer from it, if any exists
|
||||
check_printer_presets();
|
||||
if (check_printer_presets_)
|
||||
check_printer_presets();
|
||||
|
||||
PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology();
|
||||
this->plater()->set_printer_technology(printer_technology);
|
||||
|
@ -1872,6 +1873,7 @@ wxString GUI_App::current_language_code_safe() const
|
|||
{ "pl", "pl_PL", },
|
||||
{ "uk", "uk_UA", },
|
||||
{ "zh", "zh_CN", },
|
||||
{ "ru", "ru_RU", },
|
||||
};
|
||||
wxString language_code = this->current_language_code().BeforeFirst('_');
|
||||
auto it = mapping.find(language_code);
|
||||
|
|
|
@ -206,7 +206,7 @@ public:
|
|||
void add_config_menu(wxMenuBar *menu);
|
||||
bool check_unsaved_changes(const wxString &header = wxString());
|
||||
bool checked_tab(Tab* tab);
|
||||
void load_current_presets();
|
||||
void load_current_presets(bool check_printer_presets = true);
|
||||
|
||||
wxString current_language_code() const { return m_wxLocale->GetCanonicalName(); }
|
||||
// Translate the language code to a code, for which Prusa Research maintains translations. Defaults to "en_US".
|
||||
|
|
|
@ -1007,7 +1007,7 @@ ManipulationEditor::ManipulationEditor(ObjectManipulation* parent,
|
|||
const std::string& opt_key,
|
||||
int axis) :
|
||||
wxTextCtrl(parent->parent(), wxID_ANY, wxEmptyString, wxDefaultPosition,
|
||||
wxSize(5*int(wxGetApp().em_unit()), wxDefaultCoord), wxTE_PROCESS_ENTER),
|
||||
wxSize((wxOSX ? 5 : 6)*int(wxGetApp().em_unit()), wxDefaultCoord), wxTE_PROCESS_ENTER),
|
||||
m_opt_key(opt_key),
|
||||
m_axis(axis)
|
||||
{
|
||||
|
|
|
@ -169,27 +169,11 @@ void View3D::render()
|
|||
Preview::Preview(
|
||||
wxWindow* parent, Model* model, DynamicPrintConfig* config,
|
||||
BackgroundSlicingProcess* process, GCodeProcessor::Result* gcode_result, std::function<void()> schedule_background_process_func)
|
||||
: m_canvas_widget(nullptr)
|
||||
, m_canvas(nullptr)
|
||||
, m_left_sizer(nullptr)
|
||||
, m_layers_slider_sizer(nullptr)
|
||||
, m_bottom_toolbar_panel(nullptr)
|
||||
, m_label_view_type(nullptr)
|
||||
, m_choice_view_type(nullptr)
|
||||
, m_label_show(nullptr)
|
||||
, m_combochecklist_features(nullptr)
|
||||
, m_combochecklist_features_pos(0)
|
||||
, m_combochecklist_options(nullptr)
|
||||
, m_config(config)
|
||||
: m_config(config)
|
||||
, m_process(process)
|
||||
, m_gcode_result(gcode_result)
|
||||
, m_number_extruders(1)
|
||||
, m_preferred_color_mode("feature")
|
||||
, m_loaded(false)
|
||||
, m_schedule_background_process(schedule_background_process_func)
|
||||
#ifdef __linux__
|
||||
, m_volumes_cleanup_required(false)
|
||||
#endif // __linux__
|
||||
{
|
||||
if (init(parent, model))
|
||||
load_print();
|
||||
|
|
|
@ -76,17 +76,17 @@ private:
|
|||
|
||||
class Preview : public wxPanel
|
||||
{
|
||||
wxGLCanvas* m_canvas_widget;
|
||||
GLCanvas3D* m_canvas;
|
||||
wxBoxSizer* m_left_sizer;
|
||||
wxBoxSizer* m_layers_slider_sizer;
|
||||
wxPanel* m_bottom_toolbar_panel;
|
||||
wxStaticText* m_label_view_type;
|
||||
wxChoice* m_choice_view_type;
|
||||
wxStaticText* m_label_show;
|
||||
wxComboCtrl* m_combochecklist_features;
|
||||
size_t m_combochecklist_features_pos;
|
||||
wxComboCtrl* m_combochecklist_options;
|
||||
wxGLCanvas* m_canvas_widget { nullptr };
|
||||
GLCanvas3D* m_canvas { nullptr };
|
||||
wxBoxSizer* m_left_sizer { nullptr };
|
||||
wxBoxSizer* m_layers_slider_sizer { nullptr };
|
||||
wxPanel* m_bottom_toolbar_panel { nullptr };
|
||||
wxStaticText* m_label_view_type { nullptr };
|
||||
wxChoice* m_choice_view_type { nullptr };
|
||||
wxStaticText* m_label_show { nullptr };
|
||||
wxComboCtrl* m_combochecklist_features { nullptr };
|
||||
size_t m_combochecklist_features_pos { 0 };
|
||||
wxComboCtrl* m_combochecklist_options { nullptr };
|
||||
|
||||
DynamicPrintConfig* m_config;
|
||||
BackgroundSlicingProcess* m_process;
|
||||
|
@ -95,16 +95,16 @@ class Preview : public wxPanel
|
|||
#ifdef __linux__
|
||||
// We are getting mysterious crashes on Linux in gtk due to OpenGL context activation GH #1874 #1955.
|
||||
// So we are applying a workaround here.
|
||||
bool m_volumes_cleanup_required;
|
||||
bool m_volumes_cleanup_required { false };
|
||||
#endif /* __linux__ */
|
||||
|
||||
// Calling this function object forces Plater::schedule_background_process.
|
||||
std::function<void()> m_schedule_background_process;
|
||||
|
||||
unsigned int m_number_extruders;
|
||||
unsigned int m_number_extruders { 1 };
|
||||
std::string m_preferred_color_mode;
|
||||
|
||||
bool m_loaded;
|
||||
bool m_loaded { false };
|
||||
|
||||
DoubleSlider::Control* m_layers_slider{ nullptr };
|
||||
DoubleSlider::Control* m_moves_slider{ nullptr };
|
||||
|
|
|
@ -624,7 +624,7 @@ static bool selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
|||
}
|
||||
|
||||
// mark a label with a ImGui::ColorMarkerHovered, if item is hovered
|
||||
char* marked_label = new char[255];
|
||||
char* marked_label = new char[512]; //255 symbols is not enough for translated string (e.t. to Russian)
|
||||
if (hovered)
|
||||
sprintf(marked_label, "%c%s", ImGui::ColorMarkerHovered, label);
|
||||
else
|
||||
|
|
|
@ -145,12 +145,13 @@ void ArrangeJob::process()
|
|||
{
|
||||
static const auto arrangestr = _(L("Arranging"));
|
||||
|
||||
GLCanvas3D::ArrangeSettings settings =
|
||||
m_plater->canvas3D()->get_arrange_settings();
|
||||
|
||||
const GLCanvas3D::ArrangeSettings &settings =
|
||||
static_cast<const GLCanvas3D*>(m_plater->canvas3D())->get_arrange_settings();
|
||||
|
||||
arrangement::ArrangeParams params;
|
||||
params.min_obj_distance = scaled(settings.distance);
|
||||
params.allow_rotations = settings.enable_rotation;
|
||||
params.min_obj_distance = scaled(settings.distance);
|
||||
|
||||
|
||||
auto count = unsigned(m_selected.size() + m_unprintable.size());
|
||||
Points bedpts = get_bed_shape(*m_plater->config());
|
||||
|
|
|
@ -29,7 +29,9 @@ void FillBedJob::prepare()
|
|||
for (ModelInstance *inst : model_object->instances)
|
||||
if (inst->printable) {
|
||||
ArrangePolygon ap = get_arrange_poly(PtrWrapper{inst}, m_plater);
|
||||
++ap.priority; // need to be included in the result
|
||||
// Existing objects need to be included in the result. Only
|
||||
// the needed amount of object will be added, no more.
|
||||
++ap.priority;
|
||||
m_selected.emplace_back(ap);
|
||||
}
|
||||
|
||||
|
@ -38,11 +40,18 @@ void FillBedJob::prepare()
|
|||
m_bedpts = get_bed_shape(*m_plater->config());
|
||||
|
||||
auto &objects = m_plater->model().objects;
|
||||
BoundingBox bedbb = get_extents(m_bedpts);
|
||||
|
||||
for (size_t idx = 0; idx < objects.size(); ++idx)
|
||||
if (int(idx) != m_object_idx)
|
||||
for (ModelInstance *mi : objects[idx]->instances) {
|
||||
m_unselected.emplace_back(get_arrange_poly(PtrWrapper{mi}, m_plater));
|
||||
m_unselected.back().bed_idx = 0;
|
||||
ArrangePolygon ap = get_arrange_poly(PtrWrapper{mi}, m_plater);
|
||||
auto ap_bb = ap.transformed_poly().contour.bounding_box();
|
||||
|
||||
if (ap.bed_idx == 0 && !bedbb.contains(ap_bb))
|
||||
ap.bed_idx = arrangement::UNARRANGED;
|
||||
|
||||
m_unselected.emplace_back(ap);
|
||||
}
|
||||
|
||||
if (auto wt = get_wipe_tower_arrangepoly(*m_plater))
|
||||
|
@ -55,18 +64,17 @@ void FillBedJob::prepare()
|
|||
double unsel_area = std::accumulate(m_unselected.begin(),
|
||||
m_unselected.end(), 0.,
|
||||
[](double s, const auto &ap) {
|
||||
return s + ap.poly.area();
|
||||
return s + (ap.bed_idx == 0) * ap.poly.area();
|
||||
}) / sc;
|
||||
|
||||
double fixed_area = unsel_area + m_selected.size() * poly_area;
|
||||
double bed_area = Polygon{m_bedpts}.area() / sc;
|
||||
|
||||
// This is the maximum range, the real number will always be close but less.
|
||||
double bed_area = Polygon{m_bedpts}.area() / sc;
|
||||
|
||||
m_status_range = (bed_area - fixed_area) / poly_area;
|
||||
// This is the maximum number of items, the real number will always be close but less.
|
||||
int needed_items = (bed_area - fixed_area) / poly_area;
|
||||
|
||||
ModelInstance *mi = model_object->instances[0];
|
||||
for (int i = 0; i < m_status_range; ++i) {
|
||||
for (int i = 0; i < needed_items; ++i) {
|
||||
ArrangePolygon ap;
|
||||
ap.poly = m_selected.front().poly;
|
||||
ap.bed_idx = arrangement::UNARRANGED;
|
||||
|
@ -77,18 +85,28 @@ void FillBedJob::prepare()
|
|||
};
|
||||
m_selected.emplace_back(ap);
|
||||
}
|
||||
|
||||
m_status_range = m_selected.size();
|
||||
|
||||
// The strides have to be removed from the fixed items. For the
|
||||
// arrangeable (selected) items bed_idx is ignored and the
|
||||
// translation is irrelevant.
|
||||
double stride = bed_stride(m_plater);
|
||||
for (auto &p : m_unselected)
|
||||
if (p.bed_idx > 0)
|
||||
p.translation(X) -= p.bed_idx * stride;
|
||||
}
|
||||
|
||||
void FillBedJob::process()
|
||||
{
|
||||
if (m_object_idx == -1 || m_selected.empty()) return;
|
||||
|
||||
GLCanvas3D::ArrangeSettings settings =
|
||||
m_plater->canvas3D()->get_arrange_settings();
|
||||
const GLCanvas3D::ArrangeSettings &settings =
|
||||
static_cast<const GLCanvas3D*>(m_plater->canvas3D())->get_arrange_settings();
|
||||
|
||||
arrangement::ArrangeParams params;
|
||||
params.min_obj_distance = scaled(settings.distance);
|
||||
params.allow_rotations = settings.enable_rotation;
|
||||
params.min_obj_distance = scaled(settings.distance);
|
||||
|
||||
bool do_stop = false;
|
||||
params.stopcondition = [this, &do_stop]() {
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
#include "format.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <string_view>
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -84,6 +86,31 @@ public:
|
|||
};
|
||||
#endif // __APPLE__
|
||||
|
||||
// Load the icon either from the exe, or from the ico file.
|
||||
static wxIcon main_frame_icon(GUI_App::EAppMode app_mode)
|
||||
{
|
||||
#if _WIN32
|
||||
std::wstring path(size_t(MAX_PATH), wchar_t(0));
|
||||
int len = int(::GetModuleFileName(nullptr, path.data(), MAX_PATH));
|
||||
if (len > 0 && len < MAX_PATH) {
|
||||
path.erase(path.begin() + len, path.end());
|
||||
if (app_mode == GUI_App::EAppMode::GCodeViewer) {
|
||||
// Only in case the slicer was started with --gcodeviewer parameter try to load the icon from prusa-gcodeviewer.exe
|
||||
// Otherwise load it from the exe.
|
||||
for (const std::wstring_view exe_name : { std::wstring_view(L"prusa-slicer.exe"), std::wstring_view(L"prusa-slicer-console.exe") })
|
||||
if (boost::iends_with(path, exe_name)) {
|
||||
path.erase(path.end() - exe_name.size(), path.end());
|
||||
path += L"prusa-gcodeviewer.exe";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return wxIcon(path, wxBITMAP_TYPE_ICO);
|
||||
#else // _WIN32
|
||||
return wxIcon(Slic3r::var(app_mode == GUI_App::EAppMode::Editor ? "PrusaSlicer_128px.png" : "PrusaSlicer-gcodeviewer_128px.png"), wxBITMAP_TYPE_PNG);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
MainFrame::MainFrame() :
|
||||
DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "mainframe"),
|
||||
m_printhost_queue_dlg(new PrintHostQueueDialog(this))
|
||||
|
@ -115,35 +142,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
|||
#endif // __APPLE__
|
||||
|
||||
// Load the icon either from the exe, or from the ico file.
|
||||
#if _WIN32
|
||||
{
|
||||
wxString src_path;
|
||||
wxFileName::SplitPath(wxStandardPaths::Get().GetExecutablePath(), &src_path, nullptr, nullptr, wxPATH_NATIVE);
|
||||
switch (wxGetApp().get_app_mode()) {
|
||||
default:
|
||||
case GUI_App::EAppMode::Editor: { src_path += "\\prusa-slicer.exe"; break; }
|
||||
case GUI_App::EAppMode::GCodeViewer: { src_path += "\\prusa-gcodeviewer.exe"; break; }
|
||||
}
|
||||
wxIconLocation icon_location;
|
||||
icon_location.SetFileName(src_path);
|
||||
SetIcon(icon_location);
|
||||
}
|
||||
#else
|
||||
switch (wxGetApp().get_app_mode())
|
||||
{
|
||||
default:
|
||||
case GUI_App::EAppMode::Editor:
|
||||
{
|
||||
SetIcon(wxIcon(Slic3r::var("PrusaSlicer_128px.png"), wxBITMAP_TYPE_PNG));
|
||||
break;
|
||||
}
|
||||
case GUI_App::EAppMode::GCodeViewer:
|
||||
{
|
||||
SetIcon(wxIcon(Slic3r::var("PrusaSlicer-gcodeviewer_128px.png"), wxBITMAP_TYPE_PNG));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif // _WIN32
|
||||
SetIcon(main_frame_icon(wxGetApp().get_app_mode()));
|
||||
|
||||
// initialize status bar
|
||||
m_statusbar = std::make_shared<ProgressStatusBar>(this);
|
||||
|
@ -1243,6 +1242,9 @@ void MainFrame::init_menubar_as_gcodeviewer()
|
|||
append_menu_item(fileMenu, wxID_ANY, _L("&Open G-code") + dots + "\tCtrl+O", _L("Open a G-code file"),
|
||||
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->load_gcode(); }, "open", nullptr,
|
||||
[this]() {return m_plater != nullptr; }, this);
|
||||
append_menu_item(fileMenu, wxID_ANY, _L("Re&load from disk") + sep + "F5",
|
||||
_L("Reload the plater from disk"), [this](wxCommandEvent&) { m_plater->reload_gcode_from_disk(); },
|
||||
"", nullptr, [this]() { return !m_plater->get_last_loaded_gcode().empty(); }, this);
|
||||
fileMenu->AppendSeparator();
|
||||
append_menu_item(fileMenu, wxID_ANY, _L("Export &toolpaths as OBJ") + dots, _L("Export toolpaths as OBJ"),
|
||||
[this](wxCommandEvent&) { if (m_plater != nullptr) m_plater->export_toolpaths_to_obj(); }, "export_plater", nullptr,
|
||||
|
|
|
@ -64,12 +64,9 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he
|
|||
SetSizerAndFit(topsizer);
|
||||
}
|
||||
|
||||
MsgDialog::~MsgDialog() {}
|
||||
|
||||
|
||||
// ErrorDialog
|
||||
|
||||
ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
|
||||
ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg, bool monospaced_font)
|
||||
: MsgDialog(parent, wxString::Format(_(L("%s error")), SLIC3R_APP_NAME),
|
||||
wxString::Format(_(L("%s has encountered an error")), SLIC3R_APP_NAME),
|
||||
wxID_NONE)
|
||||
|
@ -78,19 +75,23 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
|
|||
// Text shown as HTML, so that mouse selection and Ctrl-V to copy will work.
|
||||
wxHtmlWindow* html = new wxHtmlWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO);
|
||||
{
|
||||
html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), -1));
|
||||
html->SetMinSize(wxSize(40 * wxGetApp().em_unit(), monospaced_font ? 30 * wxGetApp().em_unit() : -1));
|
||||
wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
|
||||
wxFont monospace = wxSystemSettings::GetFont(wxSYS_ANSI_FIXED_FONT);
|
||||
wxColour text_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
||||
wxColour bgr_clr = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
||||
auto text_clr_str = wxString::Format(wxT("#%02X%02X%02X"), text_clr.Red(), text_clr.Green(), text_clr.Blue());
|
||||
auto bgr_clr_str = wxString::Format(wxT("#%02X%02X%02X"), bgr_clr.Red(), bgr_clr.Green(), bgr_clr.Blue());
|
||||
const int font_size = font.GetPointSize()-1;
|
||||
int size[] = {font_size, font_size, font_size, font_size, font_size, font_size, font_size};
|
||||
html->SetFonts(font.GetFaceName(), font.GetFaceName(), size);
|
||||
html->SetFonts(font.GetFaceName(), monospace.GetFaceName(), size);
|
||||
html->SetBorders(2);
|
||||
std::string msg_escaped = xml_escape(msg.ToUTF8().data());
|
||||
boost::replace_all(msg_escaped, "\r\n", "<br>");
|
||||
boost::replace_all(msg_escaped, "\n", "<br>");
|
||||
if (monospaced_font)
|
||||
// Code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
|
||||
msg_escaped = std::string("<pre><code>") + msg_escaped + "</code></pre>";
|
||||
html->SetPage("<html><body bgcolor=\"" + bgr_clr_str + "\"><font color=\"" + text_clr_str + "\">" + wxString::FromUTF8(msg_escaped.data()) + "</font></body></html>");
|
||||
content_sizer->Add(html, 1, wxEXPAND);
|
||||
}
|
||||
|
@ -99,15 +100,12 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
|
|||
btn_ok->SetFocus();
|
||||
btn_sizer->Add(btn_ok, 0, wxRIGHT, HORIZ_SPACING);
|
||||
|
||||
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, 192));
|
||||
// Use a small bitmap with monospaced font, as the error text will not be wrapped.
|
||||
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, monospaced_font ? 48 : 192));
|
||||
|
||||
SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT*wxGetApp().em_unit()));
|
||||
Fit();
|
||||
}
|
||||
|
||||
ErrorDialog::~ErrorDialog() {}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ struct MsgDialog : wxDialog
|
|||
MsgDialog(const MsgDialog &) = delete;
|
||||
MsgDialog &operator=(MsgDialog &&) = delete;
|
||||
MsgDialog &operator=(const MsgDialog &) = delete;
|
||||
virtual ~MsgDialog();
|
||||
virtual ~MsgDialog() = default;
|
||||
|
||||
// TODO: refactor with CreateStdDialogButtonSizer usage
|
||||
|
||||
|
@ -52,12 +52,14 @@ protected:
|
|||
class ErrorDialog : public MsgDialog
|
||||
{
|
||||
public:
|
||||
ErrorDialog(wxWindow *parent, const wxString &msg);
|
||||
// If monospaced_font is true, the error message is displayed using html <code><pre></pre></code> tags,
|
||||
// so that the code formatting will be preserved. This is useful for reporting errors from the placeholder parser.
|
||||
ErrorDialog(wxWindow *parent, const wxString &msg, bool courier_font);
|
||||
ErrorDialog(ErrorDialog &&) = delete;
|
||||
ErrorDialog(const ErrorDialog &) = delete;
|
||||
ErrorDialog &operator=(ErrorDialog &&) = delete;
|
||||
ErrorDialog &operator=(const ErrorDialog &) = delete;
|
||||
virtual ~ErrorDialog();
|
||||
virtual ~ErrorDialog() = default;
|
||||
|
||||
private:
|
||||
wxString msg;
|
||||
|
|
|
@ -387,7 +387,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent) :
|
|||
|
||||
option = m_og->get_option("fill_density");
|
||||
option.opt.label = L("Infill");
|
||||
option.opt.width = 7/*6*/;
|
||||
option.opt.width = 8;
|
||||
option.opt.sidetext = " ";
|
||||
line.append_option(option);
|
||||
|
||||
|
@ -2002,9 +2002,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
sidebar->Bind(EVT_SCHEDULE_BACKGROUND_PROCESS, [this](SimpleEvent&) { this->schedule_background_process(); });
|
||||
}
|
||||
|
||||
wxGLCanvas* view3D_canvas = view3D->get_wxglcanvas();
|
||||
wxGLCanvas* view3D_canvas = view3D->get_wxglcanvas();
|
||||
|
||||
if (wxGetApp().is_editor()) {
|
||||
if (wxGetApp().is_editor()) {
|
||||
// 3DScene events:
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS, [this](SimpleEvent&) { this->schedule_background_process(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_OBJECT_SELECT, &priv::on_object_select, this);
|
||||
|
@ -2046,8 +2046,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_OBJECTS, &priv::on_action_split_objects, this);
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_SPLIT_VOLUMES, &priv::on_action_split_volumes, this);
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_LAYERSEDITING, &priv::on_action_layersediting, this);
|
||||
}
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [q](SimpleEvent&) { q->set_bed_shape(); });
|
||||
}
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_UPDATE_BED_SHAPE, [q](SimpleEvent&) { q->set_bed_shape(); });
|
||||
|
||||
// Preview events:
|
||||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_QUESTION_MARK, [this](SimpleEvent&) { wxGetApp().keyboard_shortcuts(); });
|
||||
|
@ -2064,6 +2064,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_MOVE_LAYERS_SLIDER, [this](wxKeyEvent& evt) { preview->move_layers_slider(evt); });
|
||||
#endif // ENABLE_ARROW_KEYS_WITH_SLIDERS
|
||||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_EDIT_COLOR_CHANGE, [this](wxKeyEvent& evt) { preview->edit_layers_slider(evt); });
|
||||
if (wxGetApp().is_gcode_viewer())
|
||||
preview->Bind(EVT_GLCANVAS_RELOAD_FROM_DISK, [this](SimpleEvent&) { this->q->reload_gcode_from_disk(); });
|
||||
|
||||
if (wxGetApp().is_editor()) {
|
||||
q->Bind(EVT_SLICING_COMPLETED, &priv::on_slicing_completed, this);
|
||||
|
@ -2363,7 +2365,8 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
wxGetApp().preset_bundle->load_config_model(filename.string(), std::move(config));
|
||||
if (printer_technology == ptFFF)
|
||||
CustomGCode::update_custom_gcode_per_print_z_from_config(model.custom_gcode_per_print_z, &wxGetApp().preset_bundle->project_config);
|
||||
wxGetApp().load_current_presets();
|
||||
// For exporting from the amf/3mf we shouldn't check printer_presets for the containing information about "Print Host upload"
|
||||
wxGetApp().load_current_presets(false);
|
||||
is_project_file = true;
|
||||
}
|
||||
wxGetApp().app_config->update_config_dir(path.parent_path().string());
|
||||
|
@ -3640,19 +3643,20 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
|||
|
||||
// Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
|
||||
this->background_process.reset_export();
|
||||
|
||||
// This bool stops showing export finished notification even when process_completed_with_error is false
|
||||
bool has_error = false;
|
||||
if (evt.error()) {
|
||||
std::string message = evt.format_error_message();
|
||||
std::pair<std::string, bool> message = evt.format_error_message();
|
||||
if (evt.critical_error()) {
|
||||
if (q->m_tracking_popup_menu)
|
||||
// We don't want to pop-up a message box when tracking a pop-up menu.
|
||||
// We postpone the error message instead.
|
||||
q->m_tracking_popup_menu_error_message = message;
|
||||
q->m_tracking_popup_menu_error_message = message.first;
|
||||
else
|
||||
show_error(q, message);
|
||||
show_error(q, message.first, message.second);
|
||||
} else
|
||||
notification_manager->push_slicing_error_notification(message);
|
||||
this->statusbar()->set_status_text(from_u8(message));
|
||||
notification_manager->push_slicing_error_notification(message.first);
|
||||
this->statusbar()->set_status_text(from_u8(message.first));
|
||||
if (evt.invalidate_plater())
|
||||
{
|
||||
const wxString invalid_str = _L("Invalid data");
|
||||
|
@ -3660,7 +3664,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
|||
sidebar->set_btn_label(btn, invalid_str);
|
||||
process_completed_with_error = true;
|
||||
}
|
||||
|
||||
has_error = true;
|
||||
}
|
||||
if (evt.cancelled())
|
||||
this->statusbar()->set_status_text(_L("Cancelled"));
|
||||
|
@ -3695,11 +3699,11 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
|||
show_action_buttons(false);
|
||||
}
|
||||
// If writing to removable drive was scheduled, show notification with eject button
|
||||
if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !this->process_completed_with_error) {
|
||||
if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !has_error) {
|
||||
show_action_buttons(false);
|
||||
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, true);
|
||||
wxGetApp().removable_drive_manager()->set_exporting_finished(true);
|
||||
}else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !this->process_completed_with_error)
|
||||
}else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error)
|
||||
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false);
|
||||
}
|
||||
exporting_status = ExportingStatus::NOT_EXPORTING;
|
||||
|
@ -4805,6 +4809,13 @@ void Plater::load_gcode(const wxString& filename)
|
|||
set_project_filename(filename);
|
||||
}
|
||||
|
||||
void Plater::reload_gcode_from_disk()
|
||||
{
|
||||
wxString filename(m_last_loaded_gcode);
|
||||
m_last_loaded_gcode.clear();
|
||||
load_gcode(filename);
|
||||
}
|
||||
|
||||
void Plater::refresh_print()
|
||||
{
|
||||
p->preview->refresh_print();
|
||||
|
@ -5215,9 +5226,12 @@ void Plater::export_gcode(bool prefer_removable)
|
|||
if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID)
|
||||
return;
|
||||
default_output_file = this->p->background_process.output_filepath_for_project(into_path(get_project_filename(".3mf")));
|
||||
}
|
||||
catch (const std::exception &ex) {
|
||||
show_error(this, ex.what());
|
||||
} catch (const Slic3r::PlaceholderParserError &ex) {
|
||||
// Show the error with monospaced font.
|
||||
show_error(this, ex.what(), true);
|
||||
return;
|
||||
} catch (const std::exception &ex) {
|
||||
show_error(this, ex.what(), false);
|
||||
return;
|
||||
}
|
||||
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
|
||||
|
@ -5575,9 +5589,12 @@ void Plater::send_gcode()
|
|||
if (state & priv::UPDATE_BACKGROUND_PROCESS_INVALID)
|
||||
return;
|
||||
default_output_file = this->p->background_process.output_filepath_for_project(into_path(get_project_filename(".3mf")));
|
||||
}
|
||||
catch (const std::exception &ex) {
|
||||
show_error(this, ex.what());
|
||||
} catch (const Slic3r::PlaceholderParserError& ex) {
|
||||
// Show the error with monospaced font.
|
||||
show_error(this, ex.what(), true);
|
||||
return;
|
||||
} catch (const std::exception& ex) {
|
||||
show_error(this, ex.what(), false);
|
||||
return;
|
||||
}
|
||||
default_output_file = fs::path(Slic3r::fold_utf8_to_ascii(default_output_file.string()));
|
||||
|
|
|
@ -144,6 +144,7 @@ public:
|
|||
void extract_config_from_project();
|
||||
void load_gcode();
|
||||
void load_gcode(const wxString& filename);
|
||||
void reload_gcode_from_disk();
|
||||
void refresh_print();
|
||||
|
||||
std::vector<size_t> load_files(const std::vector<boost::filesystem::path>& input_files, bool load_model = true, bool load_config = true, bool imperial_units = false);
|
||||
|
@ -154,6 +155,8 @@ public:
|
|||
bool load_files(const wxArrayString& filenames);
|
||||
#endif // ENABLE_DRAG_AND_DROP_FIX
|
||||
|
||||
const wxString& get_last_loaded_gcode() const { return m_last_loaded_gcode; }
|
||||
|
||||
void update();
|
||||
void stop_jobs();
|
||||
void select_view(const std::string& direction);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <glob.h>
|
||||
#include <pwd.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
#include <boost/process.hpp>
|
||||
#endif
|
||||
|
@ -187,8 +188,9 @@ namespace search_for_drives_internal
|
|||
//if not same file system - could be removable drive
|
||||
if (! compare_filesystem_id(path, parent_path)) {
|
||||
//free space
|
||||
boost::filesystem::space_info si = boost::filesystem::space(path);
|
||||
if (si.available != 0) {
|
||||
boost::system::error_code ec;
|
||||
boost::filesystem::space_info si = boost::filesystem::space(path, ec);
|
||||
if (!ec && si.available != 0) {
|
||||
//user id
|
||||
struct stat buf;
|
||||
stat(path.c_str(), &buf);
|
||||
|
|
|
@ -133,7 +133,7 @@ void SavePresetDialog::Item::update()
|
|||
if (existing->is_compatible)
|
||||
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists.")) % m_preset_name).str());
|
||||
else
|
||||
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists and is imcopatible with selected printer.")) % m_preset_name).str());
|
||||
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists and is incopatible with selected printer.")) % m_preset_name).str());
|
||||
info_line += "\n" + _L("Note: This preset will be replaced after saving");
|
||||
m_valid_type = Warning;
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ void OptionsSearcher::append_options(DynamicPrintConfig* config, Preset::Type ty
|
|||
options.emplace_back(Option{ boost::nowide::widen(opt_key), type,
|
||||
(label + suffix).ToStdWstring(), (_(label) + suffix_local).ToStdWstring(),
|
||||
gc.group.ToStdWstring(), _(gc.group).ToStdWstring(),
|
||||
gc.category.ToStdWstring(), _(gc.category).ToStdWstring() });
|
||||
gc.category.ToStdWstring(), GUI::Tab::translate_category(gc.category, type).ToStdWstring() });
|
||||
};
|
||||
|
||||
for (std::string opt_key : config->keys())
|
||||
|
|
|
@ -432,6 +432,17 @@ Slic3r::GUI::PageShp Tab::add_options_page(const wxString& title, const std::str
|
|||
return page;
|
||||
}
|
||||
|
||||
// Names of categories is save in English always. We translate them only for UI.
|
||||
// But category "Extruder n" can't be translated regularly (using _()), so
|
||||
// just for this category we should splite the title and translate "Extruder" word separately
|
||||
wxString Tab::translate_category(const wxString& title, Preset::Type preset_type)
|
||||
{
|
||||
if (preset_type == Preset::TYPE_PRINTER && title.Contains("Extruder ")) {
|
||||
return _("Extruder") + title.SubString(8, title.Last());
|
||||
}
|
||||
return _(title);
|
||||
}
|
||||
|
||||
void Tab::OnActivate()
|
||||
{
|
||||
wxWindowUpdateLocker noUpdates(this);
|
||||
|
@ -509,7 +520,7 @@ void Tab::update_labels_colour()
|
|||
auto title = m_treectrl->GetItemText(cur_item);
|
||||
for (auto page : m_pages)
|
||||
{
|
||||
if (_(page->title()) != title)
|
||||
if (translate_category(page->title(), m_type) != title)
|
||||
continue;
|
||||
|
||||
const wxColor *clr = !page->m_is_nonsys_values ? &m_sys_label_clr :
|
||||
|
@ -736,7 +747,7 @@ void Tab::update_changed_tree_ui()
|
|||
auto title = m_treectrl->GetItemText(cur_item);
|
||||
for (auto page : m_pages)
|
||||
{
|
||||
if (_(page->title()) != title)
|
||||
if (translate_category(page->title(), m_type) != title)
|
||||
continue;
|
||||
bool sys_page = true;
|
||||
bool modified_page = false;
|
||||
|
@ -1132,7 +1143,7 @@ void Tab::update_wiping_button_visibility() {
|
|||
|
||||
void Tab::activate_option(const std::string& opt_key, const wxString& category)
|
||||
{
|
||||
wxString page_title = _(category);
|
||||
wxString page_title = translate_category(category, m_type);
|
||||
|
||||
auto cur_item = m_treectrl->GetFirstVisibleItem();
|
||||
if (!cur_item || !m_treectrl->IsVisible(cur_item))
|
||||
|
@ -1803,7 +1814,6 @@ void TabFilament::build()
|
|||
on_value_change(opt_key, value);
|
||||
};
|
||||
|
||||
// optgroup = page->new_optgroup(_(L("Temperature")) + wxString(" °C", wxConvUTF8));
|
||||
optgroup = page->new_optgroup(L("Temperature"));
|
||||
Line line = { L("Nozzle"), "" };
|
||||
line.append_option(optgroup->get_option("first_layer_temperature"));
|
||||
|
@ -2515,7 +2525,7 @@ void TabPrinter::build_unregular_pages()
|
|||
// Build missed extruder pages
|
||||
for (auto extruder_idx = m_extruders_count_old; extruder_idx < m_extruders_count; ++extruder_idx) {
|
||||
//# build page
|
||||
const wxString& page_name = wxString::Format(L("Extruder %d"), int(extruder_idx + 1));
|
||||
const wxString& page_name = wxString::Format("Extruder %d", int(extruder_idx + 1));
|
||||
auto page = add_options_page(page_name, "funnel", true);
|
||||
m_pages.insert(m_pages.begin() + n_before_extruders + extruder_idx, page);
|
||||
|
||||
|
@ -2947,7 +2957,7 @@ void Tab::rebuild_page_tree()
|
|||
{
|
||||
if (!p->get_show())
|
||||
continue;
|
||||
auto itemId = m_treectrl->AppendItem(rootItem, _(p->title()), p->iconID());
|
||||
auto itemId = m_treectrl->AppendItem(rootItem, translate_category(p->title(), m_type), p->iconID());
|
||||
m_treectrl->SetItemTextColour(itemId, p->get_item_colour());
|
||||
if (p->title() == selected)
|
||||
item = itemId;
|
||||
|
@ -3286,7 +3296,7 @@ bool Tab::tree_sel_change_delayed()
|
|||
const auto sel_item = m_treectrl->GetSelection();
|
||||
const auto selection = sel_item ? m_treectrl->GetItemText(sel_item) : "";
|
||||
for (auto p : m_pages)
|
||||
if (_(p->title()) == selection)
|
||||
if (translate_category(p->title(), m_type) == selection)
|
||||
{
|
||||
page = p.get();
|
||||
m_is_nonsys_values = page->m_is_nonsys_values;
|
||||
|
|
|
@ -309,6 +309,7 @@ public:
|
|||
void on_roll_back_value(const bool to_sys = false);
|
||||
|
||||
PageShp add_options_page(const wxString& title, const std::string& icon, bool is_extruder_pages = false);
|
||||
static wxString translate_category(const wxString& title, Preset::Type preset_type);
|
||||
|
||||
virtual void OnActivate();
|
||||
virtual void on_preset_loaded() {}
|
||||
|
|
|
@ -16,7 +16,11 @@
|
|||
#include "Plater.hpp"
|
||||
#include "../Utils/MacDarkMode.hpp"
|
||||
|
||||
#ifndef __WXGTK__// msw_menuitem_bitmaps is used for MSW and OSX
|
||||
#ifdef __linux__
|
||||
#define wxLinux true
|
||||
#else
|
||||
#define wxLinux false
|
||||
// msw_menuitem_bitmaps is used for MSW and OSX
|
||||
static std::map<int, std::string> msw_menuitem_bitmaps;
|
||||
#ifdef __WXMSW__
|
||||
void msw_rescale_menu(wxMenu* menu)
|
||||
|
@ -653,7 +657,7 @@ void ModeButton::focus_button(const bool focus)
|
|||
Slic3r::GUI::wxGetApp().normal_font();
|
||||
|
||||
SetFont(new_font);
|
||||
SetForegroundColour(wxSystemSettings::GetColour(focus ? wxSYS_COLOUR_BTNTEXT : wxSYS_COLOUR_BTNSHADOW));
|
||||
SetForegroundColour(wxSystemSettings::GetColour(focus ? wxSYS_COLOUR_BTNTEXT : wxLinux ? wxSYS_COLOUR_GRAYTEXT : wxSYS_COLOUR_BTNSHADOW));
|
||||
|
||||
Refresh();
|
||||
Update();
|
||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue