diff --git a/resources/icons/cog.svg b/resources/icons/cog.svg
new file mode 100644
index 000000000..07adb6610
--- /dev/null
+++ b/resources/icons/cog.svg
@@ -0,0 +1,17 @@
+
+
+
diff --git a/resources/icons/cooling.svg b/resources/icons/cooling.svg
new file mode 100644
index 000000000..b5d80e434
--- /dev/null
+++ b/resources/icons/cooling.svg
@@ -0,0 +1,25 @@
+
+
+
diff --git a/resources/icons/funnel.svg b/resources/icons/funnel.svg
new file mode 100644
index 000000000..8877722e3
--- /dev/null
+++ b/resources/icons/funnel.svg
@@ -0,0 +1,15 @@
+
+
+
diff --git a/resources/icons/infill.svg b/resources/icons/infill.svg
new file mode 100644
index 000000000..fcb1f99c9
--- /dev/null
+++ b/resources/icons/infill.svg
@@ -0,0 +1,33 @@
+
+
+
diff --git a/resources/icons/layers.svg b/resources/icons/layers.svg
index 7718a8cbd..da5dec21d 100644
--- a/resources/icons/layers.svg
+++ b/resources/icons/layers.svg
@@ -1,25 +1,27 @@
-
+
diff --git a/resources/icons/note.svg b/resources/icons/note.svg
new file mode 100644
index 000000000..c14214201
--- /dev/null
+++ b/resources/icons/note.svg
@@ -0,0 +1,25 @@
+
+
+
diff --git a/resources/icons/output+page_white.svg b/resources/icons/output+page_white.svg
new file mode 100644
index 000000000..ec1518f25
--- /dev/null
+++ b/resources/icons/output+page_white.svg
@@ -0,0 +1,21 @@
+
+
+
diff --git a/resources/icons/printer.svg b/resources/icons/printer.svg
new file mode 100644
index 000000000..91e103ec7
--- /dev/null
+++ b/resources/icons/printer.svg
@@ -0,0 +1,14 @@
+
+
+
diff --git a/resources/icons/skirt+brim.svg b/resources/icons/skirt+brim.svg
new file mode 100644
index 000000000..9242761b6
--- /dev/null
+++ b/resources/icons/skirt+brim.svg
@@ -0,0 +1,19 @@
+
+
+
diff --git a/resources/icons/spool.svg b/resources/icons/spool.svg
new file mode 100644
index 000000000..840365938
--- /dev/null
+++ b/resources/icons/spool.svg
@@ -0,0 +1,21 @@
+
+
+
diff --git a/resources/icons/support.svg b/resources/icons/support.svg
new file mode 100644
index 000000000..65c7592c8
--- /dev/null
+++ b/resources/icons/support.svg
@@ -0,0 +1,25 @@
+
+
+
diff --git a/resources/icons/time.svg b/resources/icons/time.svg
new file mode 100644
index 000000000..5d8f23cfc
--- /dev/null
+++ b/resources/icons/time.svg
@@ -0,0 +1,16 @@
+
+
+
diff --git a/resources/icons/wrench.svg b/resources/icons/wrench.svg
new file mode 100644
index 000000000..7966da8d8
--- /dev/null
+++ b/resources/icons/wrench.svg
@@ -0,0 +1,24 @@
+
+
+
diff --git a/src/libslic3r/ClipperUtils.cpp b/src/libslic3r/ClipperUtils.cpp
index f00e908ce..4c6e542f4 100644
--- a/src/libslic3r/ClipperUtils.cpp
+++ b/src/libslic3r/ClipperUtils.cpp
@@ -120,7 +120,7 @@ Slic3r::Polygon ClipperPath_to_Slic3rPolygon(const ClipperLib::Path &input)
{
Polygon retval;
for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit)
- retval.points.push_back(Point( (*pit).X, (*pit).Y ));
+ retval.points.emplace_back(pit->X, pit->Y);
return retval;
}
@@ -128,7 +128,7 @@ Slic3r::Polyline ClipperPath_to_Slic3rPolyline(const ClipperLib::Path &input)
{
Polyline retval;
for (ClipperLib::Path::const_iterator pit = input.begin(); pit != input.end(); ++pit)
- retval.points.push_back(Point( (*pit).X, (*pit).Y ));
+ retval.points.emplace_back(pit->X, pit->Y);
return retval;
}
@@ -137,7 +137,7 @@ Slic3r::Polygons ClipperPaths_to_Slic3rPolygons(const ClipperLib::Paths &input)
Slic3r::Polygons retval;
retval.reserve(input.size());
for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it)
- retval.push_back(ClipperPath_to_Slic3rPolygon(*it));
+ retval.emplace_back(ClipperPath_to_Slic3rPolygon(*it));
return retval;
}
@@ -146,7 +146,7 @@ Slic3r::Polylines ClipperPaths_to_Slic3rPolylines(const ClipperLib::Paths &input
Slic3r::Polylines retval;
retval.reserve(input.size());
for (ClipperLib::Paths::const_iterator it = input.begin(); it != input.end(); ++it)
- retval.push_back(ClipperPath_to_Slic3rPolyline(*it));
+ retval.emplace_back(ClipperPath_to_Slic3rPolyline(*it));
return retval;
}
@@ -171,7 +171,7 @@ Slic3rMultiPoint_to_ClipperPath(const MultiPoint &input)
{
ClipperLib::Path retval;
for (Points::const_iterator pit = input.points.begin(); pit != input.points.end(); ++pit)
- retval.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) ));
+ retval.emplace_back((*pit)(0), (*pit)(1));
return retval;
}
@@ -181,7 +181,7 @@ Slic3rMultiPoint_to_ClipperPath_reversed(const Slic3r::MultiPoint &input)
ClipperLib::Path output;
output.reserve(input.points.size());
for (Slic3r::Points::const_reverse_iterator pit = input.points.rbegin(); pit != input.points.rend(); ++pit)
- output.push_back(ClipperLib::IntPoint( (*pit)(0), (*pit)(1) ));
+ output.emplace_back((*pit)(0), (*pit)(1));
return output;
}
@@ -189,7 +189,7 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polygons &input)
{
ClipperLib::Paths retval;
for (Polygons::const_iterator it = input.begin(); it != input.end(); ++it)
- retval.push_back(Slic3rMultiPoint_to_ClipperPath(*it));
+ retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it));
return retval;
}
@@ -197,7 +197,7 @@ ClipperLib::Paths Slic3rMultiPoints_to_ClipperPaths(const Polylines &input)
{
ClipperLib::Paths retval;
for (Polylines::const_iterator it = input.begin(); it != input.end(); ++it)
- retval.push_back(Slic3rMultiPoint_to_ClipperPath(*it));
+ retval.emplace_back(Slic3rMultiPoint_to_ClipperPath(*it));
return retval;
}
@@ -226,7 +226,7 @@ ClipperLib::Paths _offset(ClipperLib::Paths &&input, ClipperLib::EndType endType
ClipperLib::Paths _offset(ClipperLib::Path &&input, ClipperLib::EndType endType, const float delta, ClipperLib::JoinType joinType, double miterLimit)
{
ClipperLib::Paths paths;
- paths.push_back(std::move(input));
+ paths.emplace_back(std::move(input));
return _offset(std::move(paths), endType, delta, joinType, miterLimit);
}
@@ -585,7 +585,7 @@ Polylines _clipper_pl(ClipperLib::ClipType clipType, const Polygons &subject, co
Polylines polylines;
polylines.reserve(subject.size());
for (Polygons::const_iterator polygon = subject.begin(); polygon != subject.end(); ++polygon)
- polylines.push_back(*polygon); // implicit call to split_at_first_point()
+ polylines.emplace_back(polygon->operator Polyline()); // implicit call to split_at_first_point()
// perform clipping
Polylines retval = _clipper_pl(clipType, polylines, clip, safety_offset_);
@@ -643,7 +643,7 @@ _clipper_ln(ClipperLib::ClipType clipType, const Lines &subject, const Polygons
// convert Polylines to Lines
Lines retval;
for (Polylines::const_iterator polyline = polylines.begin(); polyline != polylines.end(); ++polyline)
- retval.push_back(*polyline);
+ retval.emplace_back(polyline->operator Line());
return retval;
}
@@ -673,7 +673,7 @@ void traverse_pt(ClipperLib::PolyNodes &nodes, Polygons* retval)
ordering_points.reserve(nodes.size());
for (ClipperLib::PolyNodes::const_iterator it = nodes.begin(); it != nodes.end(); ++it) {
Point p((*it)->Contour.front().X, (*it)->Contour.front().Y);
- ordering_points.push_back(p);
+ ordering_points.emplace_back(p);
}
// perform the ordering
@@ -684,7 +684,7 @@ void traverse_pt(ClipperLib::PolyNodes &nodes, Polygons* retval)
for (ClipperLib::PolyNodes::iterator it = ordered_nodes.begin(); it != ordered_nodes.end(); ++it) {
// traverse the next depth
traverse_pt((*it)->Childs, retval);
- retval->push_back(ClipperPath_to_Slic3rPolygon((*it)->Contour));
+ retval->emplace_back(ClipperPath_to_Slic3rPolygon((*it)->Contour));
if ((*it)->IsHole()) retval->back().reverse(); // ccw
}
}
@@ -791,8 +791,8 @@ Polygons top_level_islands(const Slic3r::Polygons &polygons)
Polygons out;
out.reserve(polytree.ChildCount());
for (int i = 0; i < polytree.ChildCount(); ++i)
- out.push_back(ClipperPath_to_Slic3rPolygon(polytree.Childs[i]->Contour));
+ out.emplace_back(ClipperPath_to_Slic3rPolygon(polytree.Childs[i]->Contour));
return out;
}
-}
\ No newline at end of file
+}
diff --git a/src/libslic3r/GCode/Analyzer.cpp b/src/libslic3r/GCode/Analyzer.cpp
index d1ad4f575..321d9a342 100644
--- a/src/libslic3r/GCode/Analyzer.cpp
+++ b/src/libslic3r/GCode/Analyzer.cpp
@@ -776,6 +776,9 @@ void GCodeAnalyzer::_calc_gcode_preview_extrusion_layers(GCodePreviewData& previ
preview_data.ranges.width.update_from(width_range);
preview_data.ranges.feedrate.update_from(feedrate_range);
preview_data.ranges.volumetric_rate.update_from(volumetric_rate_range);
+
+ // we need to sort the layers by their z as they can be shuffled in case of sequential prints
+ std::sort(preview_data.extrusion.layers.begin(), preview_data.extrusion.layers.end(), [](const GCodePreviewData::Extrusion::Layer& l1, const GCodePreviewData::Extrusion::Layer& l2)->bool { return l1.z < l2.z; });
}
void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, std::function cancel_callback)
@@ -855,6 +858,11 @@ void GCodeAnalyzer::_calc_gcode_preview_travel(GCodePreviewData& preview_data, s
preview_data.ranges.height.update_from(height_range);
preview_data.ranges.width.update_from(width_range);
preview_data.ranges.feedrate.update_from(feedrate_range);
+
+ // we need to sort the polylines by their min z as they can be shuffled in case of sequential prints
+ std::sort(preview_data.travel.polylines.begin(), preview_data.travel.polylines.end(),
+ [](const GCodePreviewData::Travel::Polyline& p1, const GCodePreviewData::Travel::Polyline& p2)->bool
+ { return unscale(p1.polyline.bounding_box().min(2)) < unscale(p2.polyline.bounding_box().min(2)); });
}
void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_data, std::function cancel_callback)
@@ -877,6 +885,11 @@ void GCodeAnalyzer::_calc_gcode_preview_retractions(GCodePreviewData& preview_da
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
preview_data.retraction.positions.emplace_back(position, move.data.width, move.data.height);
}
+
+ // we need to sort the positions by their z as they can be shuffled in case of sequential prints
+ std::sort(preview_data.retraction.positions.begin(), preview_data.retraction.positions.end(),
+ [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2)->bool
+ { return unscale(p1.position(2)) < unscale(p2.position(2)); });
}
void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_data, std::function cancel_callback)
@@ -899,6 +912,11 @@ void GCodeAnalyzer::_calc_gcode_preview_unretractions(GCodePreviewData& preview_
Vec3crd position(scale_(move.start_position.x()), scale_(move.start_position.y()), scale_(move.start_position.z()));
preview_data.unretraction.positions.emplace_back(position, move.data.width, move.data.height);
}
+
+ // we need to sort the positions by their z as they can be shuffled in case of sequential prints
+ std::sort(preview_data.unretraction.positions.begin(), preview_data.unretraction.positions.end(),
+ [](const GCodePreviewData::Retraction::Position& p1, const GCodePreviewData::Retraction::Position& p2)->bool
+ { return unscale(p1.position(2)) < unscale(p2.position(2)); });
}
// Return an estimate of the memory consumed by the time estimator.
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index b5b9a008d..e634dd138 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -556,19 +556,9 @@ std::string Model::propose_export_file_name_and_path() const
for (const ModelObject *model_object : this->objects)
for (ModelInstance *model_instance : model_object->instances)
if (model_instance->is_printable()) {
- input_file = model_object->input_file;
- if (! model_object->name.empty()) {
- if (input_file.empty())
- // model_object->input_file was empty, just use model_object->name
- input_file = model_object->name;
- else {
- // Replace file name in input_file with model_object->name, but keep the path and file extension.
- input_file = (boost::filesystem::path(model_object->name).parent_path().empty()) ?
- (boost::filesystem::path(input_file).parent_path() / model_object->name).make_preferred().string() :
- model_object->name;
- }
- }
- if (! input_file.empty())
+ input_file = model_object->get_export_filename();
+
+ if (!input_file.empty())
goto end;
// Other instances will produce the same name, skip them.
break;
@@ -1187,8 +1177,9 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
else {
TriangleMesh upper_mesh, lower_mesh;
- // Transform the mesh by the combined transformation matrix
- volume->mesh.transform(instance_matrix * volume_matrix);
+ // Transform the mesh by the combined transformation matrix.
+ // Flip the triangles in case the composite transformation is left handed.
+ volume->mesh.transform(instance_matrix * volume_matrix, true);
// Perform cut
TriangleMeshSlicer tms(&volume->mesh);
@@ -1432,6 +1423,26 @@ void ModelObject::print_info() const
cout << "volume = " << mesh.volume() << endl;
}
+std::string ModelObject::get_export_filename() const
+{
+ std::string ret = input_file;
+
+ if (!name.empty())
+ {
+ if (ret.empty())
+ // input_file was empty, just use name
+ ret = name;
+ else
+ {
+ // Replace file name in input_file with name, but keep the path and file extension.
+ ret = (boost::filesystem::path(name).parent_path().empty()) ?
+ (boost::filesystem::path(ret).parent_path() / name).make_preferred().string() : name;
+ }
+ }
+
+ return ret;
+}
+
void ModelVolume::set_material_id(t_model_material_id material_id)
{
m_material_id = material_id;
diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index 5cf7f49ca..951401243 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -275,6 +275,8 @@ public:
// Print object statistics to console.
void print_info() const;
+ std::string get_export_filename() const;
+
protected:
friend class Print;
friend class SLAPrint;
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 794390133..c13f0bc2a 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -10,7 +10,7 @@
#include "GCode/WipeTowerPrusaMM.hpp"
#include "Utils.hpp"
-#include "PrintExport.hpp"
+//#include "PrintExport.hpp"
#include
#include
diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp
index 04b993a52..ce62f7cb0 100644
--- a/src/libslic3r/PrintExport.hpp
+++ b/src/libslic3r/PrintExport.hpp
@@ -7,6 +7,7 @@
#include
#include
+#include
#include "Rasterizer/Rasterizer.hpp"
//#include
@@ -72,7 +73,8 @@ public:
void finish_layer();
// Save all the layers into the file (or dir) specified in the path argument
- void save(const std::string& path);
+ // An optional project name can be added to be used for the layer file names
+ void save(const std::string& path, const std::string& projectname = "");
// Save only the selected layer to the file specified in path argument.
void save_layer(unsigned lyr, const std::string& path);
@@ -86,7 +88,8 @@ template struct VeryFalse { static const bool value = false; };
template class LayerWriter {
public:
- LayerWriter(const std::string& /*zipfile_path*/) {
+ LayerWriter(const std::string& /*zipfile_path*/)
+ {
static_assert(VeryFalse::value,
"No layer writer implementation provided!");
}
@@ -99,10 +102,6 @@ public:
void binary_entry(const std::string& /*fname*/,
const std::uint8_t* buf, size_t len);
- // Get the name of the archive but only the name part without the path or
- // the extension.
- std::string get_name() { return ""; }
-
// Test whether the object can still be used for writing.
bool is_ok() { return false; }
@@ -253,12 +252,14 @@ public:
}
template
- inline void save(const std::string& path) {
+ inline void save(const std::string& fpath, const std::string& prjname = "")
+ {
try {
- LayerWriter writer(path);
+ LayerWriter writer(fpath);
if(!writer.is_ok()) return;
- std::string project = writer.get_name();
+ std::string project = prjname.empty()?
+ boost::filesystem::path(fpath).stem().string() : prjname;
writer.next_entry("config.ini");
if(!writer.is_ok()) return;
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index 6c04c7781..42c6fbf75 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -1790,15 +1790,16 @@ std::vector PrintObject::_slice_volumes(const std::vector &z,
if (! volumes.empty()) {
// Compose mesh.
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
- TriangleMesh mesh;
- for (const ModelVolume *v : volumes)
- {
- TriangleMesh vol_mesh(v->mesh);
- vol_mesh.transform(v->get_matrix());
+ TriangleMesh mesh(volumes.front()->mesh);
+ mesh.transform(volumes.front()->get_matrix(), true);
+ for (size_t idx_volume = 1; idx_volume < volumes.size(); ++ idx_volume) {
+ const ModelVolume &model_volume = *volumes[idx_volume];
+ TriangleMesh vol_mesh(model_volume.mesh);
+ vol_mesh.transform(model_volume.get_matrix(), true);
mesh.merge(vol_mesh);
}
if (mesh.stl.stats.number_of_facets > 0) {
- mesh.transform(m_trafo);
+ mesh.transform(m_trafo, true);
// apply XY shift
mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0);
// perform actual slicing
@@ -1819,9 +1820,9 @@ std::vector PrintObject::_slice_volume(const std::vector &z,
// Compose mesh.
//FIXME better to perform slicing over each volume separately and then to use a Boolean operation to merge them.
TriangleMesh mesh(volume.mesh);
- mesh.transform(volume.get_matrix());
+ mesh.transform(volume.get_matrix(), true);
if (mesh.stl.stats.number_of_facets > 0) {
- mesh.transform(m_trafo);
+ mesh.transform(m_trafo, true);
// apply XY shift
mesh.translate(- unscale(m_copies_shift(0)), - unscale(m_copies_shift(1)), 0);
// perform actual slicing
diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index 7dc920517..809b32d90 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -1041,31 +1041,37 @@ void SLAPrint::process()
{
ClipperPolygon poly;
+ // We need to reverse if flpXY OR is_lefthanded is true but
+ // not if both are true which is a logical inequality (XOR)
+ bool needreverse = flpXY != is_lefthanded;
+
// should be a move
poly.Contour.reserve(polygon.contour.size() + 1);
- for(auto& p : polygon.contour.points)
- poly.Contour.emplace_back(p.x(), p.y());
-
- auto pfirst = poly.Contour.front();
- poly.Contour.emplace_back(pfirst);
+ auto& cntr = polygon.contour.points;
+ if(needreverse)
+ for(auto it = cntr.rbegin(); it != cntr.rend(); ++it)
+ poly.Contour.emplace_back(it->x(), it->y());
+ else
+ for(auto& p : cntr)
+ poly.Contour.emplace_back(p.x(), p.y());
for(auto& h : polygon.holes) {
poly.Holes.emplace_back();
auto& hole = poly.Holes.back();
hole.reserve(h.points.size() + 1);
- for(auto& p : h.points) hole.emplace_back(p.x(), p.y());
- auto pfirst = hole.front(); hole.emplace_back(pfirst);
+ if(needreverse)
+ for(auto& p : h.points)
+ hole.emplace_back(p.x(), p.y());
+ else
+ for(auto it = h.points.rbegin(); it != h.points.rend(); ++it)
+ hole.emplace_back(it->x(), it->y());
}
if(is_lefthanded) {
for(auto& p : poly.Contour) p.X = -p.X;
- std::reverse(poly.Contour.begin(), poly.Contour.end());
- for(auto& h : poly.Holes) {
- for(auto& p : h) p.X = -p.X;
- std::reverse(h.begin(), h.end());
- }
+ for(auto& h : poly.Holes) for(auto& p : h) p.X = -p.X;
}
sl::rotate(poly, double(instances[i].rotation));
@@ -1074,12 +1080,7 @@ void SLAPrint::process()
if (flpXY) {
for(auto& p : poly.Contour) std::swap(p.X, p.Y);
- std::reverse(poly.Contour.begin(), poly.Contour.end());
-
- for(auto& h : poly.Holes) {
- for(auto& p : h) std::swap(p.X, p.Y);
- std::reverse(h.begin(), h.end());
- }
+ for(auto& h : poly.Holes) for(auto& p : h) std::swap(p.X, p.Y);
}
polygons.emplace_back(std::move(poly));
diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp
index a1e382acb..d4443d915 100644
--- a/src/libslic3r/SLAPrint.hpp
+++ b/src/libslic3r/SLAPrint.hpp
@@ -320,10 +320,8 @@ struct SLAPrintStatistics
}
};
-struct SLAminzZipper {};
-
// The implementation of creating zipped archives with wxWidgets
-template<> class LayerWriter {
+template<> class LayerWriter {
Zipper m_zip;
public:
@@ -332,16 +330,12 @@ public:
void next_entry(const std::string& fname) { m_zip.add_entry(fname); }
void binary_entry(const std::string& fname,
- const std::uint8_t* buf,
- size_t l)
+ const std::uint8_t* buf,
+ size_t l)
{
m_zip.add_entry(fname, buf, l);
}
- std::string get_name() const {
- return m_zip.get_name();
- }
-
template inline LayerWriter& operator<<(T&& arg) {
m_zip << std::forward(arg); return *this;
}
@@ -389,9 +383,11 @@ public:
// Returns true if the last step was finished with success.
bool finished() const override { return this->is_step_done(slaposSliceSupports) && this->Inherited::is_step_done(slapsRasterize); }
- template
- void export_raster(const std::string& fname) {
- if(m_printer) m_printer->save(fname);
+ template
+ inline void export_raster(const std::string& fpath,
+ const std::string& projectname = "")
+ {
+ if(m_printer) m_printer->save(fpath, projectname);
}
const PrintObjects& objects() const { return m_objects; }
diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp
index c145380c9..0d9a79978 100644
--- a/src/libslic3r/TriangleMesh.cpp
+++ b/src/libslic3r/TriangleMesh.cpp
@@ -314,10 +314,15 @@ void TriangleMesh::mirror(const Axis &axis)
stl_invalidate_shared_vertices(&this->stl);
}
-void TriangleMesh::transform(const Transform3d& t)
+void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed)
{
stl_transform(&stl, t);
stl_invalidate_shared_vertices(&stl);
+ if (fix_left_handed && t.matrix().block(0, 0, 3, 3).determinant() < 0.) {
+ // Left handed transformation is being applied. It is a good idea to flip the faces and their normals.
+ this->repair();
+ stl_reverse_all_facets(&stl);
+ }
}
void TriangleMesh::align_to_origin()
diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp
index a65a4be75..527846f9d 100644
--- a/src/libslic3r/TriangleMesh.hpp
+++ b/src/libslic3r/TriangleMesh.hpp
@@ -49,7 +49,7 @@ public:
void mirror_x() { this->mirror(X); }
void mirror_y() { this->mirror(Y); }
void mirror_z() { this->mirror(Z); }
- void transform(const Transform3d& t);
+ void transform(const Transform3d& t, bool fix_left_handed = false);
void align_to_origin();
void rotate(double angle, Point* center);
TriangleMeshPtrs split() const;
diff --git a/src/libslic3r/Zipper.cpp b/src/libslic3r/Zipper.cpp
index 6b7faaddc..4466f1b04 100644
--- a/src/libslic3r/Zipper.cpp
+++ b/src/libslic3r/Zipper.cpp
@@ -4,7 +4,6 @@
#include "Zipper.hpp"
#include "miniz/miniz_zip.h"
-#include
#include
#include "I18N.hpp"
@@ -213,10 +212,6 @@ void Zipper::finish_entry()
m_entry.clear();
}
-std::string Zipper::get_name() const {
- return boost::filesystem::path(m_impl->m_zipname).stem().string();
-}
-
void Zipper::finalize()
{
finish_entry();
diff --git a/src/libslic3r/Zipper.hpp b/src/libslic3r/Zipper.hpp
index 6566dad42..7d95ffdac 100644
--- a/src/libslic3r/Zipper.hpp
+++ b/src/libslic3r/Zipper.hpp
@@ -81,9 +81,6 @@ public:
/// file is up to minz after the erroneous write.
void finish_entry();
- /// Gets the name of the archive without the path or extension.
- std::string get_name() const;
-
void finalize();
};
diff --git a/src/slic3r.cpp b/src/slic3r.cpp
index 958b66305..780efea7b 100644
--- a/src/slic3r.cpp
+++ b/src/slic3r.cpp
@@ -397,8 +397,9 @@ int CLI::run(int argc, char **argv)
outfile_final = fff_print.print_statistics().finalize_output_path(outfile);
} else {
outfile = sla_print.output_filepath(outfile);
- sla_print.export_raster(outfile);
- outfile_final = sla_print.print_statistics().finalize_output_path(outfile);
+ // We need to finalize the filename beforehand because the export function sets the filename inside the zip metadata
+ outfile_final = sla_print.print_statistics().finalize_output_path(outfile);
+ sla_print.export_raster(outfile_final);
}
if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final) != 0) {
boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl;
diff --git a/src/slic3r/GUI/BackgroundSlicingProcess.cpp b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
index 2601842ef..c6a73864d 100644
--- a/src/slic3r/GUI/BackgroundSlicingProcess.cpp
+++ b/src/slic3r/GUI/BackgroundSlicingProcess.cpp
@@ -98,8 +98,9 @@ void BackgroundSlicingProcess::process_sla()
m_print->process();
if (this->set_step_started(bspsGCodeFinalize)) {
if (! m_export_path.empty()) {
- m_sla_print->export_raster(m_export_path);
- m_print->set_status(100, "Masked SLA file exported to " + m_export_path);
+ const std::string export_path = m_sla_print->print_statistics().finalize_output_path(m_export_path);
+ m_sla_print->export_raster(export_path);
+ m_print->set_status(100, "Masked SLA file exported to " + export_path);
} else if (! m_upload_job.empty()) {
prepare_upload();
} else {
@@ -389,7 +390,7 @@ void BackgroundSlicingProcess::prepare_upload()
// Generate a unique temp path to which the gcode/zip file is copied/exported
boost::filesystem::path source_path = boost::filesystem::temp_directory_path()
- / boost::filesystem::unique_path(".printhost.%%%%-%%%%-%%%%-%%%%.gcode");
+ / boost::filesystem::unique_path(".Slic3rPE.upload.%%%%-%%%%-%%%%-%%%%");
if (m_print == m_fff_print) {
m_print->set_status(95, "Running post-processing scripts");
@@ -399,8 +400,8 @@ void BackgroundSlicingProcess::prepare_upload()
run_post_process_scripts(source_path.string(), m_fff_print->config());
m_upload_job.upload_data.upload_path = m_fff_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
} else {
- m_sla_print->export_raster(source_path.string());
- // TODO: Also finalize upload path like with FFF when there are statistics for SLA print
+ m_upload_job.upload_data.upload_path = m_sla_print->print_statistics().finalize_output_path(m_upload_job.upload_data.upload_path.string());
+ m_sla_print->export_raster(source_path.string(), m_upload_job.upload_data.upload_path.string());
}
m_print->set_status(100, (boost::format("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue") % m_upload_job.printhost->get_host()).str());
diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp
index 16baa1629..4c7f999ff 100644
--- a/src/slic3r/GUI/BitmapCache.cpp
+++ b/src/slic3r/GUI/BitmapCache.cpp
@@ -1,5 +1,7 @@
#include "BitmapCache.hpp"
+#include "libslic3r/Utils.hpp"
+
#if ! defined(WIN32) && ! defined(__APPLE__)
#define BROKEN_ALPHA
#endif
@@ -9,6 +11,11 @@
#include
#endif /* BROKEN_ALPHA */
+#define NANOSVG_IMPLEMENTATION
+#include "nanosvg/nanosvg.h"
+#define NANOSVGRAST_IMPLEMENTATION
+#include "nanosvg/nanosvgrast.h"
+
namespace Slic3r { namespace GUI {
void BitmapCache::clear()
@@ -155,6 +162,72 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg
#endif
}
+wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data)
+{
+ wxImage image(width, height);
+ image.InitAlpha();
+ unsigned char *rgb = image.GetData();
+ unsigned char *alpha = image.GetAlpha();
+ unsigned int pixels = width * height;
+ for (unsigned int i = 0; i < pixels; ++ i) {
+ *rgb ++ = *raw_data ++;
+ *rgb ++ = *raw_data ++;
+ *rgb ++ = *raw_data ++;
+ *alpha ++ = *raw_data ++;
+ }
+ return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image)));
+}
+
+wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned int height)
+{
+ std::string bitmap_key = bitmap_name + "-h" + std::to_string(height);
+ auto it = m_map.find(bitmap_key);
+ if (it != m_map.end())
+ return it->second;
+
+ wxImage image;
+ if (! image.LoadFile(Slic3r::GUI::from_u8(Slic3r::var(bitmap_name + ".png")), wxBITMAP_TYPE_PNG) ||
+ image.GetWidth() == 0 || image.GetHeight() == 0)
+ return nullptr;
+ if (image.GetHeight() != height)
+ image.Rescale(int(0.5f + float(image.GetWidth()) * height / image.GetHeight()), height, wxIMAGE_QUALITY_BILINEAR);
+ return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image)));
+}
+
+wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned int target_height)
+{
+ std::string bitmap_key = bitmap_name + "-h" + std::to_string(target_height);
+ auto it = m_map.find(bitmap_key);
+ if (it != m_map.end())
+ return it->second;
+
+ NSVGimage *image = ::nsvgParseFromFile(Slic3r::var(bitmap_name + ".svg").c_str(), "px", 96.0f);
+ if (image == nullptr)
+ return nullptr;
+
+ float scale = (float)target_height / image->height;
+ int width = (int)(scale * image->width + 0.5f);
+ int height = (int)(scale * image->height + 0.5f);
+ int n_pixels = width * height;
+ if (n_pixels <= 0) {
+ ::nsvgDelete(image);
+ return nullptr;
+ }
+
+ NSVGrasterizer *rast = ::nsvgCreateRasterizer();
+ if (rast == nullptr) {
+ ::nsvgDelete(image);
+ return nullptr;
+ }
+
+ std::vector data(n_pixels * 4, 0);
+ ::nsvgRasterize(rast, image, 0, 0, scale, data.data(), width, height, width * 4);
+ ::nsvgDeleteRasterizer(rast);
+ ::nsvgDelete(image);
+
+ return this->insert_raw_rgba(bitmap_key, width, height, data.data());
+}
+
wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency)
{
wxImage image(width, height);
diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp
index 0cb70d28b..ce5eb3c77 100644
--- a/src/slic3r/GUI/BitmapCache.hpp
+++ b/src/slic3r/GUI/BitmapCache.hpp
@@ -29,6 +29,12 @@ public:
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3);
wxBitmap* insert(const std::string &name, const std::vector &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); }
wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end);
+ wxBitmap* insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data);
+
+ // Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height if nonzero.
+ wxBitmap* load_png(const std::string &bitmap_key, unsigned int height = 0);
+ // Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height.
+ wxBitmap* load_svg(const std::string &bitmap_key, unsigned int height);
static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency);
static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }
diff --git a/src/slic3r/GUI/GLTexture.cpp b/src/slic3r/GUI/GLTexture.cpp
index b48ca2044..68369d9d0 100644
--- a/src/slic3r/GUI/GLTexture.cpp
+++ b/src/slic3r/GUI/GLTexture.cpp
@@ -11,15 +11,11 @@
#include
#include
-#define NANOSVG_IMPLEMENTATION
#include "nanosvg/nanosvg.h"
-#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvg/nanosvgrast.h"
#include "libslic3r/Utils.hpp"
-#include "libslic3r/Utils.hpp"
-
namespace Slic3r {
namespace GUI {
@@ -378,6 +374,7 @@ bool GLTexture::load_from_svg(const std::string& filename, bool use_mipmaps, uns
if (n_pixels <= 0)
{
reset();
+ nsvgDelete(image);
return false;
}
diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp
index f495e168a..6fbcbea37 100644
--- a/src/slic3r/GUI/GUI_ObjectList.cpp
+++ b/src/slic3r/GUI/GUI_ObjectList.cpp
@@ -525,7 +525,6 @@ void ObjectList::key_event(wxKeyEvent& event)
|| event.GetKeyCode() == WXK_BACK
#endif //__WXOSX__
) {
- printf("WXK_BACK\n");
remove();
}
else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))
diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index 637596591..48bb1f690 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -181,7 +181,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
changed_box = true;
}
if (changed_box || !m_cache.instance.matches_instance(instance_idx) || !m_cache.scale.isApprox(100.0 * m_new_scale))
- m_new_size = volume->get_instance_transformation().get_matrix(true, true) * m_cache.instance.box_size;
+ m_new_size = (volume->get_instance_transformation().get_matrix(true, true) * m_cache.instance.box_size).cwiseAbs();
}
else
// this should never happen
@@ -211,7 +211,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
m_new_position = volume->get_volume_offset();
m_new_rotation = volume->get_volume_rotation();
m_new_scale = volume->get_volume_scaling_factor();
- m_new_size = volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size();
+ m_new_size = (volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size()).cwiseAbs();
m_new_enabled = true;
}
else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot))
diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp
index 4c0879ad3..cd995bc09 100644
--- a/src/slic3r/GUI/GUI_ObjectSettings.cpp
+++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp
@@ -85,7 +85,8 @@ void ObjectSettings::update_settings_list()
#endif // __WXMSW__
btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) {
config->erase(opt_key);
- wxTheApp->CallAfter([this]() {
+ wxGetApp().obj_list()->part_settings_changed();
+ wxTheApp->CallAfter([this]() {
wxWindowUpdateLocker noUpdates(m_parent);
update_settings_list();
m_parent->Layout();
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
index 02d663e93..5eb0d0583 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoCut.cpp
@@ -15,12 +15,6 @@ namespace Slic3r {
namespace GUI {
-
-
-
-
-// GLGizmoCut
-
class GLGizmoCutPanel : public wxPanel
{
public:
@@ -192,7 +186,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, co
m_imgui->set_next_window_bg_alpha(0.5f);
m_imgui->begin(_(L("Cut")), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
- ImGui::PushItemWidth(100.0f);
+ ImGui::PushItemWidth(m_imgui->scaled(5.0f));
bool _value_changed = ImGui::InputDouble("Z", &m_cut_z, 0.0f, 0.0f, "%.2f");
m_imgui->checkbox(_(L("Keep upper part")), m_keep_upper);
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index 75f13cdcf..2264c541e 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -330,8 +330,12 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
m_canvas_width = m_parent.get_canvas_size().get_width();
m_canvas_height = m_parent.get_canvas_size().get_height();
}
- else
- select_point(m_hover_id);
+ else {
+ if (m_editing_mode_cache[m_hover_id].selected)
+ unselect_point(m_hover_id);
+ else
+ select_point(m_hover_id);
+ }
return true;
}
@@ -565,12 +569,12 @@ void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_l
RENDER_AGAIN:
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
- const ImVec2 window_size(m_imgui->scaled(15.f, 16.5f));
+ const ImVec2 window_size(m_imgui->scaled(17.f, 18.f));
ImGui::SetNextWindowPos(ImVec2(x, y - std::max(0.f, y+window_size.y-bottom_limit) ));
ImGui::SetNextWindowSize(ImVec2(window_size));
m_imgui->set_next_window_bg_alpha(0.5f);
- m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
+ m_imgui->begin(on_get_name(), ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoCollapse);
ImGui::PushItemWidth(100.0f);
@@ -791,6 +795,19 @@ void GLGizmoSlaSupports::select_point(int i)
}
+void GLGizmoSlaSupports::unselect_point(int i)
+{
+ m_editing_mode_cache[i].selected = false;
+ m_selection_empty = true;
+ for (const CacheEntry& ce : m_editing_mode_cache) {
+ if (ce.selected) {
+ m_selection_empty = false;
+ break;
+ }
+ }
+}
+
+
void GLGizmoSlaSupports::editing_mode_discard_changes()
{
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
index 7e8113774..bb3cf06ce 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.hpp
@@ -93,6 +93,7 @@ private:
NoPoints,
};
void select_point(int i);
+ void unselect_point(int i);
void editing_mode_apply_changes();
void editing_mode_discard_changes();
void editing_mode_reload_cache();
diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp
index 1b4d4edf9..8a6a71b1b 100644
--- a/src/slic3r/GUI/ImGuiWrapper.cpp
+++ b/src/slic3r/GUI/ImGuiWrapper.cpp
@@ -340,13 +340,11 @@ bool ImGuiWrapper::want_any_input() const
void ImGuiWrapper::init_font()
{
- const float font_size = m_font_size * m_style_scaling;
-
destroy_font();
ImGuiIO& io = ImGui::GetIO();
io.Fonts->Clear();
- ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), font_size, nullptr, m_glyph_ranges);
+ ImFont* font = io.Fonts->AddFontFromFileTTF((Slic3r::resources_dir() + "/fonts/NotoSans-Regular.ttf").c_str(), m_font_size, nullptr, m_glyph_ranges);
if (font == nullptr) {
font = io.Fonts->AddFontDefault();
if (font == nullptr) {
diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp
index c1bf491e1..b593054c4 100644
--- a/src/slic3r/GUI/ImGuiWrapper.hpp
+++ b/src/slic3r/GUI/ImGuiWrapper.hpp
@@ -45,8 +45,8 @@ public:
void new_frame();
void render();
- float scaled(float x) const { return x * m_font_size * m_style_scaling; }
- ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size * m_style_scaling, y * m_font_size * m_style_scaling); }
+ float scaled(float x) const { return x * m_font_size; }
+ ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size, y * m_font_size); }
ImVec2 calc_text_size(const wxString &text);
void set_next_window_pos(float x, float y, int flag);
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 435d9548f..53d999283 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -1199,7 +1199,7 @@ struct Plater::priv
BoundingBox scaled_bed_shape_bb() const;
std::vector load_files(const std::vector& input_files, bool load_model, bool load_config);
std::vector load_model_objects(const ModelObjectPtrs &model_objects);
- std::unique_ptr get_export_file(GUI::FileType file_type);
+ wxString get_export_file(GUI::FileType file_type);
const Selection& get_selection() const;
Selection& get_selection();
@@ -1617,6 +1617,45 @@ std::vector Plater::priv::load_files(const std::vector& input_
}
#if ENABLE_VOLUMES_CENTERING_FIXES
}
+ else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf))
+ {
+ bool advanced = false;
+ for (const ModelObject* model_object : model.objects)
+ {
+ // is there more than one instance ?
+ if (model_object->instances.size() > 1)
+ {
+ advanced = true;
+ break;
+ }
+
+ // is there any modifier ?
+ for (const ModelVolume* model_volume : model_object->volumes)
+ {
+ if (!model_volume->is_model_part())
+ {
+ advanced = true;
+ break;
+ }
+ }
+
+ if (advanced)
+ break;
+ }
+
+ if (advanced)
+ {
+ wxMessageDialog dlg(q, _(L("This file cannot be loaded in simple mode. Do you want to switch to expert mode?\n")),
+ _(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO);
+ if (dlg.ShowModal() == wxID_YES)
+ {
+ Slic3r::GUI::wxGetApp().save_mode(comExpert);
+ view3D->set_as_dirty();
+ }
+ else
+ return obj_idxs;
+ }
+ }
#endif // ENABLE_VOLUMES_CENTERING_FIXES
#if !ENABLE_VOLUMES_CENTERING_FIXES
@@ -1642,7 +1681,7 @@ std::vector Plater::priv::load_files(const std::vector& input_
Slic3r::GUI::show_error(nullptr,
wxString::Format(_(L("You can't to add the object(s) from %s because of one or some of them is(are) multi-part")),
from_path(filename)));
- return std::vector();
+ return obj_idxs;
}
}
@@ -1784,7 +1823,7 @@ std::vector Plater::priv::load_model_objects(const ModelObjectPtrs &mode
return obj_idxs;
}
-std::unique_ptr Plater::priv::get_export_file(GUI::FileType file_type)
+wxString Plater::priv::get_export_file(GUI::FileType file_type)
{
wxString wildcard;
switch (file_type) {
@@ -1801,34 +1840,56 @@ std::unique_ptr Plater::priv::get_export_file(GUI::FileType
// Update printbility state of each of the ModelInstances.
this->update_print_volume_state();
- // Find the file name of the first printable object.
- fs::path output_file = this->model.propose_export_file_name_and_path();
+ const Selection& selection = get_selection();
+ int obj_idx = selection.get_object_idx();
+
+ fs::path output_file;
+ // first try to get the file name from the current selection
+ if ((0 <= obj_idx) && (obj_idx < (int)this->model.objects.size()))
+ output_file = this->model.objects[obj_idx]->get_export_filename();
+
+ if (output_file.empty())
+ // Find the file name of the first printable object.
+ output_file = this->model.propose_export_file_name_and_path();
+
+ wxString dlg_title;
switch (file_type) {
- case FT_STL: output_file.replace_extension("stl"); break;
- case FT_AMF: output_file.replace_extension("zip.amf"); break; // XXX: Problem on OS X with double extension?
- case FT_3MF: output_file.replace_extension("3mf"); break;
+ case FT_STL:
+ {
+ output_file.replace_extension("stl");
+ dlg_title = _(L("Export STL file:"));
+ break;
+ }
+ case FT_AMF:
+ {
+ // XXX: Problem on OS X with double extension?
+ output_file.replace_extension("zip.amf");
+ dlg_title = _(L("Export AMF file:"));
+ break;
+ }
+ case FT_3MF:
+ {
+ output_file.replace_extension("3mf");
+ dlg_title = _(L("Save file as:"));
+ break;
+ }
default: break;
}
- auto dlg = Slic3r::make_unique(q,
- ((file_type == FT_AMF) || (file_type == FT_3MF)) ? _(L("Export print config")) : "",
- true,
- _(L("Save file as:")),
- from_path(output_file.parent_path()),
- from_path(output_file.filename()),
- wildcard,
- wxFD_SAVE | wxFD_OVERWRITE_PROMPT
- );
+ wxFileDialog* dlg = new wxFileDialog(q, dlg_title,
+ from_path(output_file.parent_path()), from_path(output_file.filename()),
+ wildcard, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (dlg->ShowModal() != wxID_OK) {
- return nullptr;
+ return wxEmptyString;
}
- fs::path path(into_path(dlg->GetPath()));
+ wxString out_path = dlg->GetPath();
+ fs::path path(into_path(out_path));
wxGetApp().app_config->update_last_output_dir(path.parent_path().string());
- return dlg;
+ return out_path;
}
const Selection& Plater::priv::get_selection() const
@@ -3243,11 +3304,8 @@ void Plater::export_stl(bool selection_only)
{
if (p->model.objects.empty()) { return; }
- auto dialog = p->get_export_file(FT_STL);
- if (! dialog) { return; }
-
- // Store a binary STL
- const wxString path = dialog->GetPath();
+ wxString path = p->get_export_file(FT_STL);
+ if (path.empty()) { return; }
const std::string path_u8 = into_u8(path);
wxBusyCursor wait;
@@ -3272,15 +3330,14 @@ void Plater::export_amf()
{
if (p->model.objects.empty()) { return; }
- auto dialog = p->get_export_file(FT_AMF);
- if (! dialog) { return; }
-
- const wxString path = dialog->GetPath();
+ wxString path = p->get_export_file(FT_AMF);
+ if (path.empty()) { return; }
const std::string path_u8 = into_u8(path);
- DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure();
wxBusyCursor wait;
- if (Slic3r::store_amf(path_u8.c_str(), &p->model, dialog->get_checkbox_value() ? &cfg : nullptr)) {
+ bool export_config = true;
+ DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config_secure();
+ if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr)) {
// Success
p->statusbar()->set_status_text(wxString::Format(_(L("AMF file exported to %s")), path));
} else {
@@ -3297,10 +3354,8 @@ void Plater::export_3mf(const boost::filesystem::path& output_path)
bool export_config = true;
if (output_path.empty())
{
- auto dialog = p->get_export_file(FT_3MF);
- if (!dialog) { return; }
- path = dialog->GetPath();
- export_config = dialog->get_checkbox_value();
+ path = p->get_export_file(FT_3MF);
+ if (path.empty()) { return; }
}
else
path = from_path(output_path);
diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp
index 7103ca12d..db25e6332 100644
--- a/src/slic3r/GUI/Selection.cpp
+++ b/src/slic3r/GUI/Selection.cpp
@@ -108,21 +108,26 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection)
if (is_wipe_tower() && volume->is_wipe_tower)
return;
+ bool keep_instance_mode = (m_mode == Instance) && !as_single_selection && (is_single_full_instance() || is_multiple_full_instance());
+
// resets the current list if needed
bool needs_reset = as_single_selection;
needs_reset |= volume->is_wipe_tower;
needs_reset |= is_wipe_tower() && !volume->is_wipe_tower;
- needs_reset |= !is_modifier() && volume->is_modifier;
+ needs_reset |= !keep_instance_mode && !is_modifier() && volume->is_modifier;
needs_reset |= is_modifier() && !volume->is_modifier;
if (needs_reset)
clear();
if (!contains_volume(volume_idx))
- m_mode = volume->is_modifier ? Volume : Instance;
+ {
+ if (!keep_instance_mode)
+ m_mode = volume->is_modifier ? Volume : Instance;
+ }
else
- // keep current mode
- return;
+ // keep current mode
+ return;
switch (m_mode)
{
@@ -1142,16 +1147,12 @@ void Selection::_update_type()
}
if (modifiers_count == 0)
- {
m_type = MultipleVolume;
- requires_disable = true;
- }
else if (modifiers_count == (unsigned int)m_list.size())
- {
m_type = MultipleModifier;
- requires_disable = true;
- }
}
+
+ requires_disable = true;
}
else if ((selected_instances_count > 1) && (selected_instances_count * volumes_count == (unsigned int)m_list.size()))
{
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 631050f29..a91dae026 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -1446,7 +1446,7 @@ void TabFilament::build()
line.append_option(optgroup->get_option("bed_temperature"));
optgroup->append_line(line);
- page = add_options_page(_(L("Cooling")), "hourglass.png");
+ page = add_options_page(_(L("Cooling")), "cooling");
optgroup = page->new_optgroup(_(L("Enable")));
optgroup->append_single_option_line("fan_always_on");
optgroup->append_single_option_line("cooling");
diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp
index 77d9a4a10..0671bb62c 100644
--- a/src/slic3r/GUI/wxExtensions.cpp
+++ b/src/slic3r/GUI/wxExtensions.cpp
@@ -8,6 +8,8 @@
#include
#include
+#include
+
#include "BitmapCache.hpp"
#include "GUI.hpp"
#include "GUI_App.hpp"
@@ -421,19 +423,16 @@ void PrusaCollapsiblePaneMSW::Collapse(bool collapse)
// PrusaObjectDataViewModelNode
// ----------------------------------------------------------------------------
-wxBitmap create_scaled_bitmap(const std::string& bmp_name)
+wxBitmap create_scaled_bitmap(const std::string& bmp_name_in)
{
- const double scale_f = Slic3r::GUI::wxGetApp().em_unit()* 0.1;//GetContentScaleFactor();
- if (scale_f == 1.0)
- return wxBitmap(Slic3r::GUI::from_u8(Slic3r::var(bmp_name)), wxBITMAP_TYPE_PNG);
-// else if (scale_f == 2.0) // use biger icon
-// return wxBitmap(Slic3r::GUI::from_u8(Slic3r::var(bmp_name_X2)), wxBITMAP_TYPE_PNG);
-
- wxImage img = wxImage(Slic3r::GUI::from_u8(Slic3r::var(bmp_name)), wxBITMAP_TYPE_PNG);
- const int sz_w = int(img.GetWidth()*scale_f);
- const int sz_h = int(img.GetHeight()*scale_f);
- img.Rescale(sz_w, sz_h, wxIMAGE_QUALITY_BILINEAR);
- return wxBitmap(img);
+ static Slic3r::GUI::BitmapCache cache;
+ const auto height = (unsigned int)(Slic3r::GUI::wxGetApp().em_unit() * 1.6f + 0.5f);
+ std::string bmp_name = bmp_name_in;
+ boost::replace_last(bmp_name, ".png", "");
+ wxBitmap *bmp = cache.load_svg(bmp_name, height);
+ if (bmp == nullptr)
+ bmp = cache.load_png(bmp_name, height);
+ return *bmp;
}
void PrusaObjectDataViewModelNode::set_object_action_icon() {