Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libslic3r/Format/AMF.cpp11
-rw-r--r--src/libslic3r/MTUtils.hpp107
-rw-r--r--src/libslic3r/Model.cpp6
-rw-r--r--src/libslic3r/Model.hpp4
-rw-r--r--src/libslic3r/PrintConfig.cpp1
-rw-r--r--src/libslic3r/SLA/SLASupportTree.cpp12
-rw-r--r--src/libslic3r/SLA/SLASupportTree.hpp2
-rw-r--r--src/libslic3r/SLAPrint.cpp365
-rw-r--r--src/libslic3r/SLAPrint.hpp170
-rw-r--r--src/slic3r/GUI/Field.cpp5
-rw-r--r--src/slic3r/GUI/GLCanvas3D.cpp446
-rw-r--r--src/slic3r/GUI/GLCanvas3D.hpp13
-rw-r--r--src/slic3r/GUI/GLToolbar.cpp32
-rw-r--r--src/slic3r/GUI/GLToolbar.hpp2
-rw-r--r--src/slic3r/GUI/GUI_ObjectManipulation.cpp4
-rw-r--r--src/slic3r/GUI/GUI_ObjectSettings.cpp7
-rw-r--r--src/slic3r/GUI/GUI_Preview.cpp47
-rw-r--r--src/slic3r/GUI/GUI_Preview.hpp4
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp6
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmosManager.cpp340
-rw-r--r--src/slic3r/GUI/Gizmos/GLGizmosManager.hpp37
-rw-r--r--src/slic3r/GUI/Plater.cpp23
-rw-r--r--src/slic3r/GUI/Plater.hpp8
-rw-r--r--src/slic3r/GUI/Preset.cpp86
-rw-r--r--src/slic3r/GUI/Preset.hpp22
-rw-r--r--src/slic3r/GUI/PresetBundle.cpp10
-rw-r--r--src/slic3r/GUI/Tab.cpp101
-rw-r--r--src/slic3r/GUI/Tab.hpp3
28 files changed, 1349 insertions, 525 deletions
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index f5219263d..ff1da37cc 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -175,6 +175,11 @@ struct AMFParserContext
bool mirrory_set;
float mirrorz;
bool mirrorz_set;
+
+ bool anything_set() const { return deltax_set || deltay_set || deltaz_set ||
+ rx_set || ry_set || rz_set ||
+ scalex_set || scaley_set || scalez_set ||
+ mirrorx_set || mirrory_set || mirrorz_set; }
};
struct Object {
@@ -644,11 +649,7 @@ void AMFParserContext::endDocument()
continue;
}
for (const Instance &instance : object.second.instances)
-#if ENABLE_VOLUMES_CENTERING_FIXES
- {
-#else
- if (instance.deltax_set && instance.deltay_set) {
-#endif // ENABLE_VOLUMES_CENTERING_FIXES
+ if (instance.anything_set()) {
ModelInstance *mi = m_model.objects[object.second.idx]->add_instance();
mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0));
mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0));
diff --git a/src/libslic3r/MTUtils.hpp b/src/libslic3r/MTUtils.hpp
index 1e0fb426a..1f6ca1a23 100644
--- a/src/libslic3r/MTUtils.hpp
+++ b/src/libslic3r/MTUtils.hpp
@@ -56,6 +56,113 @@ public:
}
};
+template<class Vector,
+ class Value = typename Vector::value_type>
+class IndexBasedIterator {
+ static const size_t NONE = size_t(-1);
+
+ std::reference_wrapper<Vector> m_index_ref;
+ size_t m_idx = NONE;
+public:
+
+ using value_type = Value;
+ using pointer = Value *;
+ using reference = Value &;
+ using difference_type = long;
+ using iterator_category = std::random_access_iterator_tag;
+
+ inline explicit
+ IndexBasedIterator(Vector& index, size_t idx):
+ m_index_ref(index), m_idx(idx) {}
+
+ // Post increment
+ inline IndexBasedIterator operator++(int) {
+ IndexBasedIterator cpy(*this); ++m_idx; return cpy;
+ }
+
+ inline IndexBasedIterator operator--(int) {
+ IndexBasedIterator cpy(*this); --m_idx; return cpy;
+ }
+
+ inline IndexBasedIterator& operator++() {
+ ++m_idx; return *this;
+ }
+
+ inline IndexBasedIterator& operator--() {
+ --m_idx; return *this;
+ }
+
+ inline IndexBasedIterator& operator+=(difference_type l) {
+ m_idx += size_t(l); return *this;
+ }
+
+ inline IndexBasedIterator operator+(difference_type l) {
+ auto cpy = *this; cpy += l; return cpy;
+ }
+
+ inline IndexBasedIterator& operator-=(difference_type l) {
+ m_idx -= size_t(l); return *this;
+ }
+
+ inline IndexBasedIterator operator-(difference_type l) {
+ auto cpy = *this; cpy -= l; return cpy;
+ }
+
+ operator difference_type() { return difference_type(m_idx); }
+
+ inline bool is_end() const { return m_idx >= m_index_ref.get().size();}
+
+ inline Value & operator*() const {
+ assert(m_idx < m_index_ref.get().size());
+ return m_index_ref.get().operator[](m_idx);
+ }
+
+ inline Value * operator->() const {
+ assert(m_idx < m_index_ref.get().size());
+ return &m_index_ref.get().operator[](m_idx);
+ }
+
+ inline bool operator ==(const IndexBasedIterator& other) {
+ size_t e = m_index_ref.get().size();
+ return m_idx == other.m_idx || (m_idx >= e && other.m_idx >= e);
+ }
+
+ inline bool operator !=(const IndexBasedIterator& other) {
+ return !(*this == other);
+ }
+
+ inline bool operator <=(const IndexBasedIterator& other) {
+ return (m_idx < other.m_idx) || (*this == other);
+ }
+
+ inline bool operator <(const IndexBasedIterator& other) {
+ return m_idx < other.m_idx && (*this != other);
+ }
+
+ inline bool operator >=(const IndexBasedIterator& other) {
+ return m_idx > other.m_idx || *this == other;
+ }
+
+ inline bool operator >(const IndexBasedIterator& other) {
+ return m_idx > other.m_idx && *this != other;
+ }
+};
+
+template<class It> class Range {
+ It from, to;
+public:
+ It begin() const { return from; }
+ It end() const { return to; }
+ using Type = It;
+
+ Range() = default;
+ Range(It &&b, It &&e):
+ from(std::forward<It>(b)), to(std::forward<It>(e)) {}
+
+ inline size_t size() const { return end() - begin(); }
+ inline bool empty() const { return size() == 0; }
+};
+
}
#endif // MTUTILS_HPP
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 68f71c308..f9db9fea0 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -997,12 +997,16 @@ Polygon ModelObject::convex_hull_2d(const Transform3d &trafo_instance)
return hull;
}
+#if ENABLE_VOLUMES_CENTERING_FIXES
+void ModelObject::center_around_origin(bool include_modifiers)
+#else
void ModelObject::center_around_origin()
+#endif // ENABLE_VOLUMES_CENTERING_FIXES
{
// calculate the displacements needed to
// center this object around the origin
#if ENABLE_VOLUMES_CENTERING_FIXES
- BoundingBoxf3 bb = full_raw_mesh_bounding_box();
+ BoundingBoxf3 bb = include_modifiers ? full_raw_mesh_bounding_box() : raw_mesh_bounding_box();
#else
BoundingBoxf3 bb;
for (ModelVolume *v : this->volumes)
diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index 1260500ee..8a48f8ee9 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -236,7 +236,11 @@ public:
// This method is used by the auto arrange function.
Polygon convex_hull_2d(const Transform3d &trafo_instance);
+#if ENABLE_VOLUMES_CENTERING_FIXES
+ void center_around_origin(bool include_modifiers = true);
+#else
void center_around_origin();
+#endif // ENABLE_VOLUMES_CENTERING_FIXES
void ensure_on_bed();
void translate_instances(const Vec3d& vector);
void translate_instance(size_t instance_idx, const Vec3d& vector);
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 8c67cc067..630dbfb5f 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -1375,6 +1375,7 @@ void PrintConfigDef::init_fff_params()
def->sidetext = L("(minimum)");
def->aliases = { "perimeter_offsets" };
def->min = 0;
+ def->max = 10000;
def->default_value = new ConfigOptionInt(3);
def = this->add("post_process", coStrings);
diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp
index df9990822..34dd80cee 100644
--- a/src/libslic3r/SLA/SLASupportTree.cpp
+++ b/src/libslic3r/SLA/SLASupportTree.cpp
@@ -2240,6 +2240,18 @@ SlicedSupports SLASupportTree::slice(float layerh, float init_layerh) const
return ret;
}
+SlicedSupports SLASupportTree::slice(const std::vector<float> &heights,
+ float cr) const
+{
+ TriangleMesh fullmesh = m_impl->merged_mesh();
+ fullmesh.merge(get_pad());
+ TriangleMeshSlicer slicer(&fullmesh);
+ SlicedSupports ret;
+ slicer.slice(heights, cr, &ret, get().ctl().cancelfn);
+
+ return ret;
+}
+
const TriangleMesh &SLASupportTree::add_pad(const SliceLayer& baseplate,
const PoolConfig& pcfg) const
{
diff --git a/src/libslic3r/SLA/SLASupportTree.hpp b/src/libslic3r/SLA/SLASupportTree.hpp
index 74d7da9ca..66677e4d7 100644
--- a/src/libslic3r/SLA/SLASupportTree.hpp
+++ b/src/libslic3r/SLA/SLASupportTree.hpp
@@ -181,6 +181,8 @@ public:
/// Get the sliced 2d layers of the support geometry.
SlicedSupports slice(float layerh, float init_layerh = -1.0) const;
+ SlicedSupports slice(const std::vector<float>&, float closing_radius) const;
+
/// Adding the "pad" (base pool) under the supports
const TriangleMesh& add_pad(const SliceLayer& baseplate,
const PoolConfig& pcfg) const;
diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index 83fa61fdd..79834908f 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -30,7 +30,6 @@ public:
std::vector<sla::SupportPoint> support_points; // all the support points (manual/auto)
SupportTreePtr support_tree_ptr; // the supports
SlicedSupports support_slices; // sliced supports
- std::vector<LevelID> level_ids;
inline SupportData(const TriangleMesh& trmesh): emesh(trmesh) {}
};
@@ -567,6 +566,18 @@ sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) {
return scfg;
}
+sla::PoolConfig make_pool_config(const SLAPrintObjectConfig& c) {
+ sla::PoolConfig pcfg;
+
+ pcfg.min_wall_thickness_mm = c.pad_wall_thickness.getFloat();
+ pcfg.wall_slope = c.pad_wall_slope.getFloat();
+ pcfg.edge_radius_mm = c.pad_edge_radius.getFloat();
+ pcfg.max_merge_distance_mm = c.pad_max_merge_distance.getFloat();
+ pcfg.min_wall_height_mm = c.pad_wall_height.getFloat();
+
+ return pcfg;
+}
+
void swapXY(ExPolygon& expoly) {
for(auto& p : expoly.contour.points) std::swap(p(X), p(Y));
for(auto& h : expoly.holes) for(auto& p : h.points) std::swap(p(X), p(Y));
@@ -591,25 +602,9 @@ std::string SLAPrint::validate() const
return "";
}
-std::vector<float> SLAPrint::calculate_heights(const BoundingBoxf3& bb3d,
- float elevation,
- float initial_layer_height,
- float layer_height) const
-{
- std::vector<float> heights;
- float minZ = float(bb3d.min(Z)) - float(elevation);
- float maxZ = float(bb3d.max(Z));
- auto flh = float(layer_height);
- auto gnd = float(bb3d.min(Z));
-
- for(float h = minZ + initial_layer_height; h < maxZ; h += flh)
- if(h >= gnd) heights.emplace_back(h);
-
- return heights;
-}
-
template<class...Args>
-void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args) {
+void report_status(SLAPrint& p, int st, const std::string& msg, Args&&...args)
+{
BOOST_LOG_TRIVIAL(info) << st << "% " << msg;
p.set_status(st, msg, std::forward<Args>(args)...);
}
@@ -620,12 +615,19 @@ void SLAPrint::process()
using namespace sla;
using ExPolygon = Slic3r::ExPolygon;
+ if(m_objects.empty()) return;
+
// Assumption: at this point the print objects should be populated only with
// the model objects we have to process and the instances are also filtered
// shortcut to initial layer height
double ilhd = m_material_config.initial_layer_height.getFloat();
auto ilh = float(ilhd);
+ double lhd = m_objects.front()->m_config.layer_height.getFloat();
+ float lh = float(lhd);
+
+ auto ilhs = LevelID(ilhd / SCALING_FACTOR);
+ auto lhs = LevelID(lhd / SCALING_FACTOR);
const size_t objcount = m_objects.size();
const unsigned min_objstatus = 0; // where the per object operations start
@@ -646,24 +648,59 @@ void SLAPrint::process()
// Slicing the model object. This method is oversimplified and needs to
// be compared with the fff slicing algorithm for verification
- auto slice_model = [this, ilh](SLAPrintObject& po) {
- double lh = po.m_config.layer_height.getFloat();
-
+ auto slice_model = [this, ilhs, lhs, ilh, lh](SLAPrintObject& po) {
TriangleMesh mesh = po.transformed_mesh();
+
+ // We need to prepare the slice index...
+
+ auto&& bb3d = mesh.bounding_box();
+ double minZ = bb3d.min(Z) - po.get_elevation();
+ double maxZ = bb3d.max(Z);
+
+ auto minZs = LevelID(minZ / SCALING_FACTOR);
+ auto maxZs = LevelID(maxZ / SCALING_FACTOR);
+
+ po.m_slice_index.clear();
+ po.m_slice_index.reserve(size_t(maxZs - (minZs + ilhs) / lhs) + 1);
+ po.m_slice_index.emplace_back(minZs + ilhs, float(minZ) + ilh / 2.f, ilh);
+
+ for(LevelID h = minZs + ilhs + lhs; h <= maxZs; h += lhs) {
+ po.m_slice_index.emplace_back(h, float(h*SCALING_FACTOR) - lh / 2.f, lh);
+ }
+
+ auto slindex_it = po.search_slice_index(float(bb3d.min(Z)));
+
+ if(slindex_it == po.m_slice_index.end())
+ throw std::runtime_error(L("Slicing had to be stopped "
+ "due to an internal error."));
+
+ po.m_model_height_levels.clear();
+ po.m_model_height_levels.reserve(po.m_slice_index.size());
+ for(auto it = slindex_it; it != po.m_slice_index.end(); ++it)
+ {
+ po.m_model_height_levels.emplace_back(it->slice_level());
+ }
+
TriangleMeshSlicer slicer(&mesh);
- // The 1D grid heights
- std::vector<float> heights = calculate_heights(mesh.bounding_box(),
- float(po.get_elevation()),
- ilh, float(lh));
+ po.m_model_slices.clear();
+ slicer.slice(po.m_model_height_levels,
+ float(po.config().slice_closing_radius.value),
+ &po.m_model_slices,
+ [this](){ throw_if_canceled(); });
- auto& layers = po.m_model_slices; layers.clear();
- slicer.slice(heights, float(po.config().slice_closing_radius.value), &layers, [this](){ throw_if_canceled(); });
+ auto mit = slindex_it;
+ for(size_t id = 0;
+ id < po.m_model_slices.size() && mit != po.m_slice_index.end();
+ id++)
+ {
+ mit->set_model_slice_idx(id); ++mit;
+ }
};
// In this step we check the slices, identify island and cover them with
// support points. Then we sprinkle the rest of the mesh.
- auto support_points = [this, ilh](SLAPrintObject& po) {
+ auto support_points = [this](SLAPrintObject& po) {
const ModelObject& mo = *po.m_model_object;
po.m_supportdata.reset(
new SLAPrintObject::SupportData(po.transformed_mesh()) );
@@ -680,12 +717,7 @@ void SLAPrint::process()
if (mo.sla_points_status != sla::PointsStatus::UserModified) {
// calculate heights of slices (slices are calculated already)
- double lh = po.m_config.layer_height.getFloat();
-
- std::vector<float> heights =
- calculate_heights(po.transformed_mesh().bounding_box(),
- float(po.get_elevation()),
- ilh, float(lh));
+ const std::vector<float>& heights = po.m_model_height_levels;
this->throw_if_canceled();
SLAAutoSupports::Config config;
@@ -831,86 +863,34 @@ void SLAPrint::process()
// Slicing the support geometries similarly to the model slicing procedure.
// If the pad had been added previously (see step "base_pool" than it will
// be part of the slices)
- auto slice_supports = [ilh](SLAPrintObject& po) {
+ auto slice_supports = [](SLAPrintObject& po) {
auto& sd = po.m_supportdata;
- if(sd && sd->support_tree_ptr) {
- auto lh = float(po.m_config.layer_height.getFloat());
- sd->support_slices = sd->support_tree_ptr->slice(lh, ilh);
- }
- };
- // We have the layer polygon collection but we need to unite them into
- // an index where the key is the height level in discrete levels (clipper)
- auto index_slices = [this, ilhd](SLAPrintObject& po) {
- po.m_slice_index.clear();
- auto sih = LevelID(scale_(ilhd));
-
- // Establish the slice grid boundaries
- auto bb = po.transformed_mesh().bounding_box();
- double modelgnd = bb.min(Z);
- double elevation = po.get_elevation();
- double lh = po.m_config.layer_height.getFloat();
- double minZ = modelgnd - elevation;
-
- // scaled values:
- auto sminZ = LevelID(scale_(minZ));
- auto smaxZ = LevelID(scale_(bb.max(Z)));
- auto smodelgnd = LevelID(scale_(modelgnd));
- auto slh = LevelID(scale_(lh));
-
- // It is important that the next levels match the levels in
- // model_slice method. Only difference is that here it works with
- // scaled coordinates
- po.m_level_ids.clear();
- for(LevelID h = sminZ + sih; h < smaxZ; h += slh)
- if(h >= smodelgnd) po.m_level_ids.emplace_back(h);
-
- std::vector<ExPolygons>& oslices = po.m_model_slices;
-
- // If everything went well this code should not run at all, but
- // let's be robust...
- // assert(levelids.size() == oslices.size());
- if(po.m_level_ids.size() < oslices.size()) { // extend the levels until...
-
- BOOST_LOG_TRIVIAL(warning)
- << "Height level mismatch at rasterization!\n";
-
- LevelID lastlvl = po.m_level_ids.back();
- while(po.m_level_ids.size() < oslices.size()) {
- lastlvl += slh;
- po.m_level_ids.emplace_back(lastlvl);
- }
- }
-
- for(size_t i = 0; i < oslices.size(); ++i) {
- LevelID h = po.m_level_ids[i];
+ if(sd) sd->support_slices.clear();
- float fh = float(double(h) * SCALING_FACTOR);
-
- // now for the public slice index:
- SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
- // There should be only one slice layer for each print object
- assert(sr.model_slices_idx == SLAPrintObject::SliceRecord::NONE);
- sr.model_slices_idx = i;
- }
+ if(sd && sd->support_tree_ptr) {
- if(po.m_supportdata) { // deal with the support slices if present
- std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices;
- po.m_supportdata->level_ids.clear();
- po.m_supportdata->level_ids.reserve(sslices.size());
+ std::vector<float> heights; heights.reserve(po.m_slice_index.size());
- for(int i = 0; i < int(sslices.size()); ++i) {
- LevelID h = sminZ + sih + i * slh;
- po.m_supportdata->level_ids.emplace_back(h);
+ for(auto& rec : po.m_slice_index) {
+ heights.emplace_back(rec.slice_level());
+ }
- float fh = float(double(h) * SCALING_FACTOR);
+ sd->support_slices = sd->support_tree_ptr->slice(
+ heights, float(po.config().slice_closing_radius.value));
+ }
- SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
- assert(sr.support_slices_idx == SLAPrintObject::SliceRecord::NONE);
- sr.support_slices_idx = SLAPrintObject::SliceRecord::Idx(i);
- }
+ for(size_t i = 0;
+ i < sd->support_slices.size() && i < po.m_slice_index.size();
+ ++i)
+ {
+ po.m_slice_index[i].set_support_slice_idx(i);
}
+ };
+ // We have the layer polygon collection but we need to unite them into
+ // an index where the key is the height level in discrete levels (clipper)
+ auto index_slices = [this/*, ilhd*/](SLAPrintObject& /*po*/) {
// Using RELOAD_SLA_PREVIEW to tell the Plater to pass the update status to the 3D preview to load the SLA slices.
report_status(*this, -2, "", SlicingStatus::RELOAD_SLA_PREVIEW);
};
@@ -923,30 +903,18 @@ void SLAPrint::process()
m_printer_input.clear();
for(SLAPrintObject * o : m_objects) {
- auto& po = *o;
- std::vector<ExPolygons>& oslices = po.m_model_slices;
-
- // We need to adjust the min Z level of the slices to be zero
- LevelID smfirst =
- po.m_supportdata && !po.m_supportdata->level_ids.empty() ?
- po.m_supportdata->level_ids.front() : 0;
- LevelID mfirst = po.m_level_ids.empty()? 0 : po.m_level_ids.front();
- LevelID gndlvl = -(std::min(smfirst, mfirst));
-
- // now merge this object's support and object slices with the rest
- // of the print object slices
-
- for(size_t i = 0; i < oslices.size(); ++i) {
- auto& lyrs = m_printer_input[gndlvl + po.m_level_ids[i]];
- lyrs.emplace_back(oslices[i], po.m_instances);
- }
+ LevelID gndlvl = o->get_slice_index().front().key();
+ for(auto& slicerecord : o->get_slice_index()) {
+ auto& lyrs = m_printer_input[slicerecord.key() - gndlvl];
- if(!po.m_supportdata) continue;
- std::vector<ExPolygons>& sslices = po.m_supportdata->support_slices;
- for(size_t i = 0; i < sslices.size(); ++i) {
- LayerRefs& lyrs =
- m_printer_input[gndlvl + po.m_supportdata->level_ids[i]];
- lyrs.emplace_back(sslices[i], po.m_instances);
+ const ExPolygons& objslices = o->get_slices_from_record(slicerecord, soModel);
+ const ExPolygons& supslices = o->get_slices_from_record(slicerecord, soSupport);
+
+ if(!objslices.empty())
+ lyrs.emplace_back(objslices, o->instances());
+
+ if(!supslices.empty())
+ lyrs.emplace_back(supslices, o->instances());
}
}
@@ -1249,13 +1217,13 @@ void SLAPrint::fill_statistics()
// find highest object
// Which is a better bet? To compare by max_z or by number of layers in the index?
- double max_z = 0.;
+ float max_z = 0.;
size_t max_layers_cnt = 0;
size_t highest_obj_idx = 0;
for (SLAPrintObject *&po : m_objects) {
const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index();
if (! slice_index.empty()) {
- double z = (-- slice_index.end())->first;
+ float z = (-- slice_index.end())->slice_level();
size_t cnt = slice_index.size();
//if (z > max_z) {
if (cnt > max_layers_cnt) {
@@ -1275,7 +1243,7 @@ void SLAPrint::fill_statistics()
int sliced_layer_cnt = 0;
for (const auto& layer : highest_obj_slice_index)
{
- const double l_height = (layer.first == highest_obj_slice_index.begin()->first) ? init_layer_height : layer_height;
+ const double l_height = (layer.key() == highest_obj_slice_index.begin()->key()) ? init_layer_height : layer_height;
// Calculation of the consumed material
@@ -1284,21 +1252,22 @@ void SLAPrint::fill_statistics()
for (SLAPrintObject * po : m_objects)
{
- const SLAPrintObject::SliceRecord *record = nullptr;
+ const SLAPrintObject::_SliceRecord *record = nullptr;
{
const SLAPrintObject::SliceIndex& index = po->get_slice_index();
- auto key = layer.first;
- const SLAPrintObject::SliceIndex::const_iterator it_key = index.lower_bound(key - float(EPSILON));
- if (it_key == index.end() || it_key->first > key + EPSILON)
+ auto it = po->search_slice_index(layer.slice_level() - float(EPSILON));
+ if (it == index.end() || it->slice_level() > layer.slice_level() + float(EPSILON))
continue;
- record = &it_key->second;
+ record = &(*it);
}
- if (record->model_slices_idx != SLAPrintObject::SliceRecord::NONE)
- append(model_polygons, get_all_polygons(po->get_model_slices()[record->model_slices_idx], po->instances()));
-
- if (record->support_slices_idx != SLAPrintObject::SliceRecord::NONE)
- append(supports_polygons, get_all_polygons(po->get_support_slices()[record->support_slices_idx], po->instances()));
+ const ExPolygons &modelslices = po->get_slices_from_record(*record, soModel);
+ if (!modelslices.empty())
+ append(model_polygons, get_all_polygons(modelslices, po->instances()));
+
+ const ExPolygons &supportslices = po->get_slices_from_record(*record, soSupport);
+ if (!supportslices.empty())
+ append(supports_polygons, get_all_polygons(supportslices, po->instances()));
}
model_polygons = union_(model_polygons);
@@ -1394,11 +1363,15 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
for (const t_config_option_key &opt_key : opt_keys) {
if ( opt_key == "layer_height"
|| opt_key == "faded_layers"
+ || opt_key == "pad_enable"
+ || opt_key == "pad_wall_thickness"
+ || opt_key == "supports_enable"
+ || opt_key == "support_object_elevation"
|| opt_key == "slice_closing_radius") {
steps.emplace_back(slaposObjectSlice);
} else if (
- opt_key == "supports_enable"
- || opt_key == "support_points_density_relative"
+
+ opt_key == "support_points_density_relative"
|| opt_key == "support_points_minimal_distance") {
steps.emplace_back(slaposSupportPoints);
} else if (
@@ -1413,12 +1386,10 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf
|| opt_key == "support_critical_angle"
|| opt_key == "support_max_bridge_length"
|| opt_key == "support_max_pillar_link_distance"
- || opt_key == "support_object_elevation") {
+ ) {
steps.emplace_back(slaposSupportTree);
} else if (
- opt_key == "pad_enable"
- || opt_key == "pad_wall_thickness"
- || opt_key == "pad_wall_height"
+ opt_key == "pad_wall_height"
|| opt_key == "pad_max_merge_distance"
|| opt_key == "pad_wall_slope"
|| opt_key == "pad_edge_radius") {
@@ -1474,11 +1445,7 @@ double SLAPrintObject::get_elevation() const {
// its walls but currently it is half of its thickness. Whatever it
// will be in the future, we provide the config to the get_pad_elevation
// method and we will have the correct value
- sla::PoolConfig pcfg;
- pcfg.min_wall_height_mm = m_config.pad_wall_height.getFloat();
- pcfg.min_wall_thickness_mm = m_config.pad_wall_thickness.getFloat();
- pcfg.edge_radius_mm = m_config.pad_edge_radius.getFloat();
- pcfg.max_merge_distance_mm = m_config.pad_max_merge_distance.getFloat();
+ sla::PoolConfig pcfg = make_pool_config(m_config);
ret += sla::get_pad_elevation(pcfg);
}
@@ -1502,6 +1469,7 @@ double SLAPrintObject::get_current_elevation() const
namespace { // dummy empty static containers for return values in some methods
const std::vector<ExPolygons> EMPTY_SLICES;
const TriangleMesh EMPTY_MESH;
+const ExPolygons EMPTY_SLICE;
}
const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const
@@ -1509,6 +1477,72 @@ const std::vector<sla::SupportPoint>& SLAPrintObject::get_support_points() const
return m_supportdata->support_points;
}
+SLAPrintObject::SliceIndex::iterator
+SLAPrintObject::search_slice_index(float slice_level)
+{
+ _SliceRecord query(0, slice_level, 0);
+ auto it = std::lower_bound(m_slice_index.begin(), m_slice_index.end(),
+ query,
+ [](const _SliceRecord& r1, const _SliceRecord& r2)
+ {
+ return r1.slice_level() < r2.slice_level();
+ });
+
+ return it;
+}
+
+SLAPrintObject::SliceIndex::const_iterator
+SLAPrintObject::search_slice_index(float slice_level) const
+{
+ _SliceRecord query(0, slice_level, 0);
+ auto it = std::lower_bound(m_slice_index.cbegin(), m_slice_index.cend(),
+ query,
+ [](const _SliceRecord& r1, const _SliceRecord& r2)
+ {
+ return r1.slice_level() < r2.slice_level();
+ });
+
+ return it;
+}
+
+SLAPrintObject::SliceIndex::iterator
+SLAPrintObject::search_slice_index(SLAPrintObject::_SliceRecord::Key key,
+ bool exact)
+{
+ _SliceRecord query(key, 0.f, 0.f);
+ auto it = std::lower_bound(m_slice_index.begin(), m_slice_index.end(),
+ query,
+ [](const _SliceRecord& r1, const _SliceRecord& r2)
+ {
+ return r1.key() < r2.key();
+ });
+
+ // Return valid iterator only if the keys really match
+ if(exact && it != m_slice_index.end() && it->key() != key)
+ it = m_slice_index.end();
+
+ return it;
+}
+
+SLAPrintObject::SliceIndex::const_iterator
+SLAPrintObject::search_slice_index(SLAPrintObject::_SliceRecord::Key key,
+ bool exact) const
+{
+ _SliceRecord query(key, 0.f, 0.f);
+ auto it = std::lower_bound(m_slice_index.cbegin(), m_slice_index.cend(),
+ query,
+ [](const _SliceRecord& r1, const _SliceRecord& r2)
+ {
+ return r1.key() < r2.key();
+ });
+
+ // Return valid iterator only if the keys really match
+ if(exact && it != m_slice_index.end() && it->key() != key)
+ it = m_slice_index.end();
+
+ return it;
+}
+
const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
{
// assert(is_step_done(slaposSliceSupports));
@@ -1516,7 +1550,30 @@ const std::vector<ExPolygons> &SLAPrintObject::get_support_slices() const
return m_supportdata->support_slices;
}
-const SLAPrintObject::SliceIndex &SLAPrintObject::get_slice_index() const
+const ExPolygons &SLAPrintObject::get_slices_from_record(
+ const _SliceRecord &rec,
+ SliceOrigin o) const
+{
+ size_t idx = o == soModel ? rec.get_model_slice_idx() :
+ rec.get_support_slice_idx();
+
+ const std::vector<ExPolygons>& v = o == soModel? get_model_slices() :
+ get_support_slices();
+
+ if(idx >= v.size()) return EMPTY_SLICE;
+
+ return idx >= v.size() ? EMPTY_SLICE : v[idx];
+}
+
+const ExPolygons &SLAPrintObject::get_slices_from_record(
+ SLAPrintObject::SliceRecordConstIterator it, SliceOrigin o) const
+{
+ if(it.is_end()) return EMPTY_SLICE;
+ return get_slices_from_record(*it, o);
+}
+
+const std::vector<SLAPrintObject::_SliceRecord>&
+SLAPrintObject::get_slice_index() const
{
// assert(is_step_done(slaposIndexSlices));
return m_slice_index;
diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp
index c06e2fc77..fbe2821b2 100644
--- a/src/libslic3r/SLAPrint.hpp
+++ b/src/libslic3r/SLAPrint.hpp
@@ -6,6 +6,7 @@
#include "PrintExport.hpp"
#include "Point.hpp"
#include "MTUtils.hpp"
+#include <iterator>
namespace Slic3r {
@@ -35,12 +36,19 @@ using _SLAPrintObjectBase =
// the printer (rasterizer) in the SLAPrint class.
using LevelID = long long;
+enum SliceOrigin { soSupport, soModel };
+
class SLAPrintObject : public _SLAPrintObjectBase
{
private: // Prevents erroneous use by other classes.
using Inherited = _SLAPrintObjectBase;
public:
+
+ // I refuse to grantee copying (Tamas)
+ SLAPrintObject(const SLAPrintObject&) = delete;
+ SLAPrintObject& operator=(const SLAPrintObject&) = delete;
+
const SLAPrintObjectConfig& config() const { return m_config; }
const Transform3d& trafo() const { return m_trafo; }
@@ -82,40 +90,146 @@ public:
// pad is not, then without the pad, otherwise the full value is returned.
double get_current_elevation() const;
- // These two methods should be callable on the client side (e.g. UI thread)
- // when the appropriate steps slaposObjectSlice and slaposSliceSupports
- // are ready. All the print objects are processed before slapsRasterize so
- // it is safe to call them during and/or after slapsRasterize.
- const std::vector<ExPolygons>& get_model_slices() const;
- const std::vector<ExPolygons>& get_support_slices() const;
-
// This method returns the support points of this SLAPrintObject.
const std::vector<sla::SupportPoint>& get_support_points() const;
+ // The public Slice record structure. It corresponds to one printable layer.
+ // To get the sliced polygons, use SLAPrintObject::get_slices_from_record
+ class SliceRecord {
+ public:
+ using Key = LevelID;
+
+ private:
+ Key m_print_z = 0; // Top of the layer
+ float m_slice_z = 0.f; // Exact level of the slice
+ float m_height = 0.f; // Height of the sliced layer
+
+ protected:
+ SliceRecord(Key key, float slicez, float height):
+ m_print_z(key), m_slice_z(slicez), m_height(height) {}
+
+ public:
+
+ // The key will be the integer height level of the top of the layer.
+ inline Key key() const { return m_print_z; }
+
+ // Returns the exact floating point Z coordinate of the slice
+ inline float slice_level() const { return m_slice_z; }
+
+ // Returns the current layer height
+ inline float layer_height() const { return m_height; }
+ };
+
+private:
+
// An index record referencing the slices
// (get_model_slices(), get_support_slices()) where the keys are the height
// levels of the model in scaled-clipper coordinates. The levels correspond
// to the z coordinate of the object coordinate system.
- struct SliceRecord {
- using Key = float;
-
- using Idx = size_t;
- static const Idx NONE = Idx(-1); // this will be the max limit of size_t
-
- Idx model_slices_idx = NONE;
- Idx support_slices_idx = NONE;
+ class _SliceRecord: public SliceRecord {
+ public:
+ static const size_t NONE = size_t(-1); // this will be the max limit of size_t
+ private:
+ size_t m_model_slices_idx = NONE;
+ size_t m_support_slices_idx = NONE;
+
+ public:
+ _SliceRecord(Key key, float slicez, float height):
+ SliceRecord(key, slicez, height) {}
+
+ // Methods for setting the indices into the slice vectors.
+ void set_model_slice_idx(size_t id) { m_model_slices_idx = id; }
+ void set_support_slice_idx(size_t id) { m_support_slices_idx = id; }
+
+ inline size_t get_model_slice_idx() const { return m_model_slices_idx; }
+ inline size_t get_support_slice_idx() const { return m_support_slices_idx; }
};
- using SliceIndex = std::map<SliceRecord::Key, SliceRecord>;
+ // Slice index will be a plain vector sorted by the integer height levels
+ using SliceIndex = std::vector<_SliceRecord>;
// Retrieve the slice index which is readable only after slaposIndexSlices
// is done.
const SliceIndex& get_slice_index() const;
- // I refuse to grantee copying (Tamas)
- SLAPrintObject(const SLAPrintObject&) = delete;
- SLAPrintObject& operator=(const SLAPrintObject&) = delete;
+ // Search slice index for the closest slice to the given level
+ SliceIndex::iterator search_slice_index(float slice_level);
+ SliceIndex::const_iterator search_slice_index(float slice_level) const;
+
+ // Search the slice index for a particular level in integer coordinates.
+ // If no such layer is present, it will return m_slice_index.end()
+ // This behavior can be suppressed by the second parameter. If it is true
+ // the method will return the closest (non-equal) record
+ SliceIndex::iterator search_slice_index(_SliceRecord::Key key, bool exact = false);
+ SliceIndex::const_iterator search_slice_index(_SliceRecord::Key key, bool = false) const;
+
+ const std::vector<ExPolygons>& get_model_slices() const;
+ const std::vector<ExPolygons>& get_support_slices() const;
+
+public:
+
+ // Should work as a polymorphic bidirectional iterator to the slice records
+ using SliceRecordConstIterator =
+ IndexBasedIterator<const SliceIndex, const _SliceRecord>;
+
+ // /////////////////////////////////////////////////////////////////////////
+ //
+ // These two methods should be callable on the client side (e.g. UI thread)
+ // when the appropriate steps slaposObjectSlice and slaposSliceSupports
+ // are ready. All the print objects are processed before slapsRasterize so
+ // it is safe to call them during and/or after slapsRasterize.
+ //
+ // /////////////////////////////////////////////////////////////////////////
+
+ // Get the slice records from a range of slice levels (inclusive). Floating
+ // point keys are the levels where the model was sliced with the mesh
+ // slicer. Integral keys are the keys of the slice records, which
+ // correspond to the top of each layer.. The end() method of the returned
+ // range points *after* the last valid element. This is for being
+ // consistent with std and makeing range based for loops work. use
+ // std::prev(range.end()) or --range.end() to get the last element.
+ template<class Key> Range<SliceRecordConstIterator>
+ get_slice_records(Key from, Key to = std::numeric_limits<Key>::max()) const
+ {
+ SliceIndex::const_iterator it_from, it_to;
+ if(std::is_integral<Key>::value) {
+ it_from = search_slice_index(SliceRecord::Key(from));
+ it_to = search_slice_index(SliceRecord::Key(to));
+ } else if(std::is_floating_point<Key>::value) {
+ it_from = search_slice_index(float(from));
+ it_to = search_slice_index(float(to));
+ } else return {
+ SliceRecordConstIterator(m_slice_index, _SliceRecord::NONE ),
+ SliceRecordConstIterator(m_slice_index, _SliceRecord::NONE ),
+ };
+
+ auto start = m_slice_index.begin();
+
+ size_t bidx = it_from == m_slice_index.end() ? _SliceRecord::NONE :
+ size_t(it_from - start);
+
+ size_t eidx = it_to == m_slice_index.end() ? _SliceRecord::NONE :
+ size_t(it_to - start) + 1;
+
+ return {
+ SliceRecordConstIterator(m_slice_index, bidx),
+ SliceRecordConstIterator(m_slice_index, eidx),
+ };
+ }
+
+ // Get all the slice records as a range.
+ inline Range<SliceRecordConstIterator> get_slice_records() const {
+ return {
+ SliceRecordConstIterator(m_slice_index, 0),
+ SliceRecordConstIterator(m_slice_index, m_slice_index.size())
+ };
+ }
+ const ExPolygons& get_slices_from_record(SliceRecordConstIterator it,
+ SliceOrigin o) const;
+
+ const ExPolygons& get_slices_from_record(const _SliceRecord& rec,
+ SliceOrigin o) const;
protected:
// to be called from SLAPrint only.
friend class SLAPrint;
@@ -145,8 +259,10 @@ protected:
private:
// Object specific configuration, pulled from the configuration layer.
SLAPrintObjectConfig m_config;
+
// Translation in Z + Rotation by Y and Z + Scaling / Mirroring.
Transform3d m_trafo = Transform3d::Identity();
+
std::vector<Instance> m_instances;
// Individual 2d slice polygons from lower z to higher z levels
@@ -154,11 +270,9 @@ private:
// Exact (float) height levels mapped to the slices. Each record contains
// the index to the model and the support slice vectors.
- SliceIndex m_slice_index;
+ std::vector<_SliceRecord> m_slice_index;
- // The height levels corrected and scaled up in integer values. This will
- // be used at rasterization.
- std::vector<LevelID> m_level_ids;
+ std::vector<float> m_model_height_levels;
// Caching the transformed (m_trafo) raw mesh of the object
mutable CachedObject<TriangleMesh> m_transformed_rmesh;
@@ -236,6 +350,11 @@ public:
}
const PrintObjects& objects() const { return m_objects; }
+ const SLAPrintConfig& print_config() const { return m_print_config; }
+ const SLAPrinterConfig& printer_config() const { return m_printer_config; }
+ const SLAMaterialConfig& material_config() const { return m_material_config; }
+
+
std::string output_filename() const override;
const SLAPrintStatistics& print_statistics() const { return m_print_statistics; }
@@ -249,11 +368,6 @@ private:
// Invalidate steps based on a set of parameters changed.
bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys);
- std::vector<float> calculate_heights(const BoundingBoxf3& bb,
- float elevation,
- float initial_layer_height,
- float layer_height) const;
-
void fill_statistics();
SLAPrintConfig m_print_config;
diff --git a/src/slic3r/GUI/Field.cpp b/src/slic3r/GUI/Field.cpp
index 026b62ab5..9cd933160 100644
--- a/src/slic3r/GUI/Field.cpp
+++ b/src/slic3r/GUI/Field.cpp
@@ -540,7 +540,10 @@ void Choice::BUILD() {
else{
for (auto el : m_opt.enum_labels.empty() ? m_opt.enum_values : m_opt.enum_labels) {
const wxString& str = _(el);//m_opt_id == "support" ? _(el) : el;
- temp->Append(str, create_scaled_bitmap("empty_icon.png"));
+ //FIXME Vojtech: Why is the single column empty icon necessary? It is a workaround of some kind, but what for?
+ // Please document such workarounds by comments!
+ // temp->Append(str, create_scaled_bitmap("empty_icon.png"));
+ temp->Append(str, wxNullBitmap);
}
set_selection();
}
diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp
index bf0e1785a..e4f0f461e 100644
--- a/src/slic3r/GUI/GLCanvas3D.cpp
+++ b/src/slic3r/GUI/GLCanvas3D.cpp
@@ -34,6 +34,7 @@
#include <wx/settings.h>
#include <wx/tooltip.h>
#include <wx/debug.h>
+#include <wx/fontutil.h>
// Print now includes tbb, and tbb includes Windows. This breaks compilation of wxWidgets if included before wx.
#include "libslic3r/Print.hpp"
@@ -728,13 +729,69 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool
_generate(text, canvas, red_colored); // GUI::GLTexture::reset() is called at the beginning of generate(...)
}
-bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanvas3D& canvas, const bool red_colored/* = false*/)
+
+#ifdef __WXMSW__
+static bool is_font_cleartype(const wxFont &font)
+{
+ // Native font description: on MSW, it is a version number plus the content of LOGFONT, separated by semicolon.
+ wxString font_desc = font.GetNativeFontInfoDesc();
+ // Find the quality field.
+ wxString sep(";");
+ size_t startpos = 0;
+ for (size_t i = 0; i < 12; ++ i)
+ startpos = font_desc.find(sep, startpos + 1);
+ ++ startpos;
+ size_t endpos = font_desc.find(sep, startpos);
+ int quality = wxAtoi(font_desc(startpos, endpos - startpos));
+ return quality == CLEARTYPE_QUALITY;
+}
+
+// ClearType produces renders, which are difficult to convert into an alpha blended OpenGL texture.
+// Therefore it is better to disable it, though Vojtech found out, that the font returned with ClearType
+// disabled is signifcantly thicker than the default ClearType font.
+// This function modifies the font provided.
+static void msw_disable_cleartype(wxFont &font)
+{
+ // Native font description: on MSW, it is a version number plus the content of LOGFONT, separated by semicolon.
+ wxString font_desc = font.GetNativeFontInfoDesc();
+ // Find the quality field.
+ wxString sep(";");
+ size_t startpos_weight = 0;
+ for (size_t i = 0; i < 5; ++ i)
+ startpos_weight = font_desc.find(sep, startpos_weight + 1);
+ ++ startpos_weight;
+ size_t endpos_weight = font_desc.find(sep, startpos_weight);
+ // Parse the weight field.
+ unsigned int weight = atoi(font_desc(startpos_weight, endpos_weight - startpos_weight));
+ size_t startpos = endpos_weight;
+ for (size_t i = 0; i < 6; ++ i)
+ startpos = font_desc.find(sep, startpos + 1);
+ ++ startpos;
+ size_t endpos = font_desc.find(sep, startpos);
+ int quality = wxAtoi(font_desc(startpos, endpos - startpos));
+ if (quality == CLEARTYPE_QUALITY) {
+ // Replace the weight with a smaller value to compensate the weight of non ClearType font.
+ wxString sweight = std::to_string(weight * 2 / 4);
+ size_t len_weight = endpos_weight - startpos_weight;
+ wxString squality = std::to_string(ANTIALIASED_QUALITY);
+ font_desc.replace(startpos_weight, len_weight, sweight);
+ font_desc.replace(startpos + sweight.size() - len_weight, endpos - startpos, squality);
+ font.SetNativeFontInfo(font_desc);
+ wxString font_desc2 = font.GetNativeFontInfoDesc();
+ }
+ wxString font_desc2 = font.GetNativeFontInfoDesc();
+}
+#endif /* __WXMSW__ */
+
+bool GLCanvas3D::WarningTexture::_generate(const std::string& msg_utf8, const GLCanvas3D& canvas, const bool red_colored/* = false*/)
{
reset();
- if (msg.empty())
+ if (msg_utf8.empty())
return false;
+ wxString msg = GUI::from_u8(msg_utf8);
+
wxMemoryDC memDC;
// select default font
const float scale = canvas.get_canvas_size().get_scale_factor();
@@ -745,46 +802,47 @@ bool GLCanvas3D::WarningTexture::_generate(const std::string& msg, const GLCanva
// calculates texture size
wxCoord w, h;
-// memDC.GetTextExtent(msg, &w, &h);
memDC.GetMultiLineTextExtent(msg, &w, &h);
- int pow_of_two_size = next_highest_power_of_2(std::max<unsigned int>(w, h));
-
m_original_width = (int)w;
m_original_height = (int)h;
- m_width = pow_of_two_size;
- m_height = pow_of_two_size;
+ m_width = (int)next_highest_power_of_2((uint32_t)w);
+ m_height = (int)next_highest_power_of_2((uint32_t)h);
// generates bitmap
wxBitmap bitmap(m_width, m_height);
memDC.SelectObject(bitmap);
- memDC.SetBackground(wxBrush(wxColour(Background_Color[0], Background_Color[1], Background_Color[2])));
+ memDC.SetBackground(wxBrush(*wxBLACK));
memDC.Clear();
// draw message
- memDC.SetTextForeground(red_colored ? wxColour(255,72,65/*204,204*/) : *wxWHITE);
-// memDC.DrawText(msg, 0, 0);
- memDC.DrawLabel(msg, wxRect(0,0, m_original_width, m_original_height), wxALIGN_CENTER);
+ memDC.SetTextForeground(*wxRED);
+ memDC.DrawLabel(msg, wxRect(0,0, m_original_width, m_original_height), wxALIGN_CENTER);
memDC.SelectObject(wxNullBitmap);
// Convert the bitmap into a linear data ready to be loaded into the GPU.
wxImage image = bitmap.ConvertToImage();
- image.SetMaskColour(Background_Color[0], Background_Color[1], Background_Color[2]);
// prepare buffer
std::vector<unsigned char> data(4 * m_width * m_height, 0);
+ const unsigned char *src = image.GetData();
for (int h = 0; h < m_height; ++h)
{
- int hh = h * m_width;
- unsigned char* px_ptr = data.data() + 4 * hh;
+ unsigned char* dst = data.data() + 4 * h * m_width;
for (int w = 0; w < m_width; ++w)
{
- *px_ptr++ = image.GetRed(w, h);
- *px_ptr++ = image.GetGreen(w, h);
- *px_ptr++ = image.GetBlue(w, h);
- *px_ptr++ = image.IsTransparent(w, h) ? 0 : Opacity;
+ *dst++ = 255;
+ if (red_colored) {
+ *dst++ = 72; // 204
+ *dst++ = 65; // 204
+ } else {
+ *dst++ = 255;
+ *dst++ = 255;
+ }
+ *dst++ = (unsigned char)std::min<int>(255, *src);
+ src += 3;
}
}
@@ -908,7 +966,15 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
const int scaled_border = Px_Border * scale;
// select default font
- const wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale_gl);
+ wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Scale(scale_gl);
+#ifdef __WXMSW__
+ // Disabling ClearType works, but the font returned is very different (much thicker) from the default.
+// msw_disable_cleartype(font);
+ bool cleartype = is_font_cleartype(font);
+#else
+ bool cleartype = false;
+#endif /* __WXMSW__ */
+
memDC.SetFont(font);
mask_memDC.SetFont(font);
@@ -932,10 +998,8 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
if (items_count > 1)
m_original_height += (items_count - 1) * scaled_square_contour;
- int pow_of_two_size = (int)next_highest_power_of_2(std::max<uint32_t>(m_original_width, m_original_height));
-
- m_width = pow_of_two_size;
- m_height = pow_of_two_size;
+ m_width = (int)next_highest_power_of_2((uint32_t)m_original_width);
+ m_height = (int)next_highest_power_of_2((uint32_t)m_original_height);
// generates bitmap
wxBitmap bitmap(m_width, m_height);
@@ -952,16 +1016,13 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
// draw title
memDC.SetTextForeground(*wxWHITE);
- mask_memDC.SetTextForeground(*wxWHITE);
+ mask_memDC.SetTextForeground(*wxRED);
int title_x = scaled_border;
int title_y = scaled_border;
memDC.DrawText(title, title_x, title_y);
mask_memDC.DrawText(title, title_x, title_y);
- mask_memDC.SetPen(wxPen(*wxWHITE));
- mask_memDC.SetBrush(wxBrush(*wxWHITE));
-
// draw icons contours as background
int squares_contour_x = scaled_border;
int squares_contour_y = scaled_border + title_height + scaled_title_offset;
@@ -976,7 +1037,6 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
memDC.SetPen(pen);
memDC.SetBrush(brush);
memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height));
- mask_memDC.DrawRectangle(wxRect(squares_contour_x, squares_contour_y, squares_contour_width, squares_contour_height));
// draw items (colored icon + text)
int icon_x = squares_contour_x + scaled_square_contour;
@@ -1012,7 +1072,6 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
memDC.DrawRectangle(wxRect(icon_x_inner, icon_y + 1, px_inner_square, px_inner_square));
// draw text
- memDC.DrawText(GUI::from_u8(item.text), text_x, icon_y + text_y_offset);
mask_memDC.DrawText(GUI::from_u8(item.text), text_x, icon_y + text_y_offset);
// update y
@@ -1028,17 +1087,34 @@ bool GLCanvas3D::LegendTexture::generate(const GCodePreviewData& preview_data, c
// prepare buffer
std::vector<unsigned char> data(4 * m_width * m_height, 0);
- for (int h = 0; h < m_height; ++h)
+ const unsigned char *src_image = image.GetData();
+ const unsigned char *src_mask = mask_image.GetData();
+ for (int h = 0; h < m_height; ++h)
{
int hh = h * m_width;
unsigned char* px_ptr = data.data() + 4 * hh;
for (int w = 0; w < m_width; ++w)
{
- unsigned char alpha = (mask_image.GetRed(w, h) + mask_image.GetGreen(w, h) + mask_image.GetBlue(w, h)) / 3;
- *px_ptr++ = image.GetRed(w, h);
- *px_ptr++ = image.GetGreen(w, h);
- *px_ptr++ = image.GetBlue(w, h);
- *px_ptr++ = (alpha == 0) ? 128 : 255;
+ if (w >= squares_contour_x && w < squares_contour_x + squares_contour_width &&
+ h >= squares_contour_y && h < squares_contour_y + squares_contour_height) {
+ // Color palette, use the color verbatim.
+ *px_ptr++ = *src_image++;
+ *px_ptr++ = *src_image++;
+ *px_ptr++ = *src_image++;
+ *px_ptr++ = 255;
+ } else {
+ // Text or background
+ unsigned char alpha = *src_mask;
+ // Compensate the white color for the 50% opacity reduction at the character edges.
+ //unsigned char color = (unsigned char)floor(alpha * 255.f / (128.f + 0.5f * alpha));
+ unsigned char color = alpha;
+ *px_ptr++ = color;
+ *px_ptr++ = color; // *src_mask ++;
+ *px_ptr++ = color; // *src_mask ++;
+ *px_ptr++ = 128 + (alpha / 2); // (alpha > 0) ? 255 : 128;
+ src_image += 3;
+ }
+ src_mask += 3;
}
}
@@ -1286,11 +1362,13 @@ int GLCanvas3D::check_volumes_outside_state() const
return (int)state;
}
-void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible)
+void GLCanvas3D::toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo, int instance_idx)
{
for (GLVolume* vol : m_volumes.volumes) {
- if (vol->composite_id.volume_id < 0)
- vol->is_active = visible;
+ if ((mo == nullptr || m_model->objects[vol->composite_id.object_id] == mo)
+ && (instance_idx == -1 || vol->composite_id.instance_id == instance_idx)
+ && vol->composite_id.volume_id < 0)
+ vol->is_active = visible;
}
m_render_sla_auxiliaries = visible;
@@ -1306,7 +1384,7 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject
}
}
if (visible && !mo)
- toggle_sla_auxiliaries_visibility(true);
+ toggle_sla_auxiliaries_visibility(true, mo, instance_idx);
if (!mo && !visible && !m_model->objects.empty() && (m_model->objects.size() > 1 || m_model->objects.front()->instances.size() > 1))
_set_warning_texture(WarningTexture::SomethingNotShown, true);
@@ -1938,7 +2016,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
m_selection.volumes_changed(map_glvolume_old_to_new);
}
- _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ update_gizmos_data();
+// _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// Update the toolbar
post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
@@ -2253,7 +2334,10 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
{
if (m_gizmos.handle_shortcut(keyCode, m_selection))
{
- _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ update_gizmos_data();
+// _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
m_dirty = true;
}
else
@@ -2432,13 +2516,25 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
return;
}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ std::cout << to_string(m_mouse.position) << std::endl;
+
+ if (m_gizmos.on_mouse(evt, *this))
+ {
+ m_mouse.set_start_position_3D_as_invalid();
+ return;
+ }
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
if (m_picking_enabled)
_set_current();
int selected_object_idx = m_selection.get_object_idx();
int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1;
m_layers_editing.select_object(*m_model, layer_editing_object_idx);
- bool gizmos_overlay_contains_mouse = m_gizmos.overlay_contains_mouse(*this, m_mouse.position);
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+// bool gizmos_overlay_contains_mouse = m_gizmos.overlay_contains_mouse(*this, m_mouse.position);
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
if (m_mouse.drag.move_requires_threshold && m_mouse.is_move_start_threshold_position_2D_defined() && m_mouse.is_move_threshold_met(pos))
{
@@ -2508,15 +2604,27 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_dirty = true;
}
}
- else if (!m_selection.is_empty() && gizmos_overlay_contains_mouse)
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+// else if (!m_selection.is_empty() && gizmos_overlay_contains_mouse)
+// {
+// m_gizmos.update_on_off_state(*this, m_mouse.position, m_selection);
+// _update_gizmos_data();
+// m_dirty = true;
+// }
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ else if (evt.LeftDown() && m_gizmos.get_current_type() == GLGizmosManager::SlaSupports && m_gizmos.gizmo_event(SLAGizmoEventType::LeftDown, Vec2d(pos(0), pos(1)), evt.ShiftDown()))
+// else if (evt.LeftDown() && m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.gizmo_event(SLAGizmoEventType::LeftDown, Vec2d(pos(0), pos(1)), evt.ShiftDown()))
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
{
- m_gizmos.update_on_off_state(*this, m_mouse.position, m_selection);
- _update_gizmos_data();
- m_dirty = true;
+ // the gizmo got the event and took some action, there is no need to do anything more
}
else if (evt.LeftDown() && !m_selection.is_empty() && m_gizmos.grabber_contains_mouse())
{
- _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ update_gizmos_data();
+// _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
m_selection.start_dragging();
m_gizmos.start_dragging(m_selection);
@@ -2529,11 +2637,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_dirty = true;
}
- else if (evt.LeftDown() && m_gizmos.get_current_type() == GLGizmosManager::SlaSupports && m_gizmos.gizmo_event(SLAGizmoEventType::LeftDown, Vec2d(pos(0), pos(1)), evt.ShiftDown()))
- {
- // the gizmo got the event and took some action, there is no need to do anything more
- }
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
else if ((selected_object_idx != -1) && evt.RightDown() && m_gizmos.get_current_type() == GLGizmosManager::SlaSupports && m_gizmos.gizmo_event(SLAGizmoEventType::RightDown))
+// else if ((selected_object_idx != -1) && evt.RightDown() && m_gizmos.get_current_type() == Gizmos::SlaSupports && m_gizmos.gizmo_event(SLAGizmoEventType::RightDown))
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
{
// event was taken care of by the SlaSupports gizmo
}
@@ -2569,7 +2676,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
{
m_gizmos.update_on_off_state(m_selection);
- _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ update_gizmos_data();
+// _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
m_dirty = true;
}
@@ -2596,7 +2706,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
}
}
}
- else if (evt.Dragging() && evt.LeftIsDown() && !gizmos_overlay_contains_mouse && (m_layers_editing.state == LayersEditing::Unknown)
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ else if (evt.Dragging() && evt.LeftIsDown() && (m_layers_editing.state == LayersEditing::Unknown)
+// else if (evt.Dragging() && evt.LeftIsDown() && !gizmos_overlay_contains_mouse && (m_layers_editing.state == LayersEditing::Unknown)
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
&& (m_mouse.drag.move_volume_idx != -1) && m_gizmos.get_current_type() != GLGizmosManager::SlaSupports /* don't allow dragging objects with the Sla gizmo on */)
{
if (!m_mouse.drag.move_requires_threshold)
@@ -2695,8 +2808,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// the gizmo got the event and took some action, no need to do anything more here
m_dirty = true;
}
- // do not process dragging if the mouse is into any of the HUD elements
- else if (evt.Dragging() && !gizmos_overlay_contains_mouse)
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ else if (evt.Dragging())
+// // do not process dragging if the mouse is into any of the HUD elements
+// else if (evt.Dragging() && !gizmos_overlay_contains_mouse)
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
{
m_mouse.dragging = true;
@@ -2758,8 +2874,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
// of the scene with the background processing data should be performed.
post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
}
- else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging()
- && !is_layers_editing_enabled())
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !m_gizmos.is_dragging()
+// else if (evt.LeftUp() && !m_mouse.dragging && (m_hover_volume_id == -1) && !gizmos_overlay_contains_mouse && !m_gizmos.is_dragging()
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ && !is_layers_editing_enabled())
{
// deselect and propagate event through callback
if (!evt.ShiftDown() && m_picking_enabled && !m_mouse.ignore_up_event)
@@ -2768,7 +2887,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_selection.set_mode(Selection::Instance);
wxGetApp().obj_manipul()->update_settings_value(m_selection);
m_gizmos.reset_all_states();
- _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ update_gizmos_data();
+// _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
}
m_mouse.ignore_up_event = false;
@@ -2797,7 +2919,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
break;
}
m_gizmos.stop_dragging();
- _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ update_gizmos_data();
+// _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
wxGetApp().obj_manipul()->update_settings_value(m_selection);
// Let the platter know that the dragging finished, so a delayed refresh
@@ -2822,7 +2947,10 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
m_selection.add(m_hover_volume_id);
m_gizmos.update_on_off_state(m_selection);
post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
- _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ update_gizmos_data();
+// _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
wxGetApp().obj_manipul()->update_settings_value(m_selection);
// forces a frame render to update the view before the context menu is shown
render();
@@ -2853,9 +2981,14 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
std::string tooltip = "";
// updates gizmos overlay
- tooltip = m_gizmos.update_hover_state(*this, m_mouse.position, m_selection);
- if (m_selection.is_empty())
- m_gizmos.reset_all_states();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ if (tooltip.empty())
+ tooltip = m_gizmos.get_tooltip();
+
+// tooltip = m_gizmos.update_hover_state(*this, m_mouse.position, m_selection);
+// if (m_selection.is_empty())
+// m_gizmos.reset_all_states();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
if (tooltip.empty())
tooltip = m_toolbar.get_tooltip();
@@ -2865,6 +2998,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
set_tooltip(tooltip);
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ if (m_selection.is_empty())
+ m_gizmos.reset_all_states();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
// Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor hovers over.
if (m_picking_enabled)
m_dirty = true;
@@ -3172,7 +3310,10 @@ void GLCanvas3D::set_camera_zoom(float zoom)
void GLCanvas3D::update_gizmos_on_off_state()
{
set_as_dirty();
- _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ update_gizmos_data();
+// _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
m_gizmos.update_on_off_state(get_selection());
}
@@ -3207,6 +3348,48 @@ void GLCanvas3D::update_ui_from_settings()
#endif
}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+void GLCanvas3D::update_gizmos_data()
+{
+ if (!m_gizmos.is_enabled())
+ return;
+
+ bool enable_move_z = !m_selection.is_wipe_tower();
+ m_gizmos.enable_grabber(GLGizmosManager::Move, 2, enable_move_z);
+ bool enable_scale_xyz = m_selection.is_single_full_instance() || m_selection.is_single_volume() || m_selection.is_single_modifier();
+ for (int i = 0; i < 6; ++i)
+ {
+ m_gizmos.enable_grabber(GLGizmosManager::Scale, i, enable_scale_xyz);
+ }
+
+ if (m_selection.is_single_full_instance())
+ {
+ // all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first
+ const GLVolume* volume = m_volumes.volumes[*m_selection.get_volume_idxs().begin()];
+ m_gizmos.set_scale(volume->get_instance_scaling_factor());
+ m_gizmos.set_rotation(Vec3d::Zero());
+ ModelObject* model_object = m_model->objects[m_selection.get_object_idx()];
+ m_gizmos.set_flattening_data(model_object);
+ m_gizmos.set_sla_support_data(model_object, m_selection);
+ }
+ else if (m_selection.is_single_volume() || m_selection.is_single_modifier())
+ {
+ const GLVolume* volume = m_volumes.volumes[*m_selection.get_volume_idxs().begin()];
+ m_gizmos.set_scale(volume->get_volume_scaling_factor());
+ m_gizmos.set_rotation(Vec3d::Zero());
+ m_gizmos.set_flattening_data(nullptr);
+ m_gizmos.set_sla_support_data(nullptr, m_selection);
+ }
+ else
+ {
+ m_gizmos.set_scale(Vec3d::Ones());
+ m_gizmos.set_rotation(Vec3d::Zero());
+ m_gizmos.set_flattening_data(m_selection.is_from_single_object() ? m_model->objects[m_selection.get_object_idx()] : nullptr);
+ m_gizmos.set_sla_support_data(nullptr, m_selection);
+ }
+}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
bool GLCanvas3D::_is_shown_on_screen() const
{
return (m_canvas != nullptr) ? m_canvas->IsShownOnScreen() : false;
@@ -3964,24 +4147,20 @@ void GLCanvas3D::_render_sla_slices() const
{
const SLAPrintObject* obj = print_objects[i];
- double shift_z = obj->get_current_elevation();
- double min_z = clip_min_z - shift_z;
- double max_z = clip_max_z - shift_z;
-
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_bottom = m_sla_caps[0].triangles.find(i);
SlaCap::ObjectIdToTrianglesMap::iterator it_caps_top = m_sla_caps[1].triangles.find(i);
{
if (it_caps_bottom == m_sla_caps[0].triangles.end())
it_caps_bottom = m_sla_caps[0].triangles.emplace(i, SlaCap::Triangles()).first;
- if (! m_sla_caps[0].matches(min_z)) {
- m_sla_caps[0].z = min_z;
+ if (! m_sla_caps[0].matches(clip_min_z)) {
+ m_sla_caps[0].z = clip_min_z;
it_caps_bottom->second.object.clear();
it_caps_bottom->second.supports.clear();
}
if (it_caps_top == m_sla_caps[1].triangles.end())
it_caps_top = m_sla_caps[1].triangles.emplace(i, SlaCap::Triangles()).first;
- if (! m_sla_caps[1].matches(max_z)) {
- m_sla_caps[1].z = max_z;
+ if (! m_sla_caps[1].matches(clip_max_z)) {
+ m_sla_caps[1].z = clip_max_z;
it_caps_top->second.object.clear();
it_caps_top->second.supports.clear();
}
@@ -4001,36 +4180,39 @@ void GLCanvas3D::_render_sla_slices() const
std::vector<InstanceTransform> instance_transforms;
for (const SLAPrintObject::Instance& inst : instances)
{
- instance_transforms.push_back({ to_3d(unscale(inst.shift), shift_z), Geometry::rad2deg(inst.rotation) });
+ instance_transforms.push_back({ to_3d(unscale(inst.shift), 0.), Geometry::rad2deg(inst.rotation) });
}
if ((bottom_obj_triangles.empty() || bottom_sup_triangles.empty() || top_obj_triangles.empty() || top_sup_triangles.empty()) && obj->is_step_done(slaposIndexSlices))
{
- const std::vector<ExPolygons>& model_slices = obj->get_model_slices();
- const std::vector<ExPolygons>& support_slices = obj->get_support_slices();
-
- const SLAPrintObject::SliceIndex& index = obj->get_slice_index();
- SLAPrintObject::SliceIndex::const_iterator it_min_z = std::find_if(index.begin(), index.end(), [min_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(min_z - id.first) < EPSILON; });
- SLAPrintObject::SliceIndex::const_iterator it_max_z = std::find_if(index.begin(), index.end(), [max_z](const SLAPrintObject::SliceIndex::value_type& id) -> bool { return std::abs(max_z - id.first) < EPSILON; });
-
- if (it_min_z != index.end())
- {
+ double initial_layer_height = print->material_config().initial_layer_height.value;
+ LevelID key_zero = obj->get_slice_records().begin()->key();
+ LevelID key_low = LevelID((clip_min_z - initial_layer_height) / SCALING_FACTOR) + key_zero;
+ LevelID key_high = LevelID((clip_max_z - initial_layer_height) / SCALING_FACTOR) + key_zero;
+ auto slice_range = obj->get_slice_records(key_low - LevelID(SCALED_EPSILON), key_high - LevelID(SCALED_EPSILON));
+ auto it_low = slice_range.begin();
+ auto it_high = std::prev(slice_range.end());
+
+ if (! it_low.is_end() && it_low->key() < key_low + LevelID(SCALED_EPSILON)) {
+ const ExPolygons& obj_bottom = obj->get_slices_from_record(it_low, soModel);
+ const ExPolygons& sup_bottom = obj->get_slices_from_record(it_low, soSupport);
// calculate model bottom cap
- if (bottom_obj_triangles.empty() && (it_min_z->second.model_slices_idx < model_slices.size()))
- bottom_obj_triangles = triangulate_expolygons_3d(model_slices[it_min_z->second.model_slices_idx], min_z, true);
+ if (bottom_obj_triangles.empty() && !obj_bottom.empty())
+ bottom_obj_triangles = triangulate_expolygons_3d(obj_bottom, clip_min_z, true);
// calculate support bottom cap
- if (bottom_sup_triangles.empty() && (it_min_z->second.support_slices_idx < support_slices.size()))
- bottom_sup_triangles = triangulate_expolygons_3d(support_slices[it_min_z->second.support_slices_idx], min_z, true);
+ if (bottom_sup_triangles.empty() && !sup_bottom.empty())
+ bottom_sup_triangles = triangulate_expolygons_3d(sup_bottom, clip_min_z, true);
}
- if (it_max_z != index.end())
- {
+ if (! it_high.is_end() && it_high->key() < key_high + LevelID(SCALED_EPSILON)) {
+ const ExPolygons& obj_top = obj->get_slices_from_record(it_high, soModel);
+ const ExPolygons& sup_top = obj->get_slices_from_record(it_high, soSupport);
// calculate model top cap
- if (top_obj_triangles.empty() && (it_max_z->second.model_slices_idx < model_slices.size()))
- top_obj_triangles = triangulate_expolygons_3d(model_slices[it_max_z->second.model_slices_idx], max_z, false);
+ if (top_obj_triangles.empty() && !obj_top.empty())
+ top_obj_triangles = triangulate_expolygons_3d(obj_top, clip_max_z, false);
// calculate support top cap
- if (top_sup_triangles.empty() && (it_max_z->second.support_slices_idx < support_slices.size()))
- top_sup_triangles = triangulate_expolygons_3d(support_slices[it_max_z->second.support_slices_idx], max_z, false);
+ if (top_sup_triangles.empty() && !sup_top.empty())
+ top_sup_triangles = triangulate_expolygons_3d(sup_top, clip_max_z, false);
}
}
@@ -4122,45 +4304,47 @@ void GLCanvas3D::_update_volumes_hover_state() const
}
}
-void GLCanvas3D::_update_gizmos_data()
-{
- if (!m_gizmos.is_enabled())
- return;
-
- bool enable_move_z = !m_selection.is_wipe_tower();
- m_gizmos.enable_grabber(GLGizmosManager::Move, 2, enable_move_z);
- bool enable_scale_xyz = m_selection.is_single_full_instance() || m_selection.is_single_volume() || m_selection.is_single_modifier();
- for (int i = 0; i < 6; ++i)
- {
- m_gizmos.enable_grabber(GLGizmosManager::Scale, i, enable_scale_xyz);
- }
-
- if (m_selection.is_single_full_instance())
- {
- // all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first
- const GLVolume* volume = m_volumes.volumes[*m_selection.get_volume_idxs().begin()];
- m_gizmos.set_scale(volume->get_instance_scaling_factor());
- m_gizmos.set_rotation(Vec3d::Zero());
- ModelObject* model_object = m_model->objects[m_selection.get_object_idx()];
- m_gizmos.set_flattening_data(model_object);
- m_gizmos.set_sla_support_data(model_object, m_selection);
- }
- else if (m_selection.is_single_volume() || m_selection.is_single_modifier())
- {
- const GLVolume* volume = m_volumes.volumes[*m_selection.get_volume_idxs().begin()];
- m_gizmos.set_scale(volume->get_volume_scaling_factor());
- m_gizmos.set_rotation(Vec3d::Zero());
- m_gizmos.set_flattening_data(nullptr);
- m_gizmos.set_sla_support_data(nullptr, m_selection);
- }
- else
- {
- m_gizmos.set_scale(Vec3d::Ones());
- m_gizmos.set_rotation(Vec3d::Zero());
- m_gizmos.set_flattening_data(m_selection.is_from_single_object() ? m_model->objects[m_selection.get_object_idx()] : nullptr);
- m_gizmos.set_sla_support_data(nullptr, m_selection);
- }
-}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//void GLCanvas3D::_update_gizmos_data()
+//{
+// if (!m_gizmos.is_enabled())
+// return;
+//
+// bool enable_move_z = !m_selection.is_wipe_tower();
+// m_gizmos.enable_grabber(GLGizmosManager::Move, 2, enable_move_z);
+// bool enable_scale_xyz = m_selection.is_single_full_instance() || m_selection.is_single_volume() || m_selection.is_single_modifier();
+// for (int i = 0; i < 6; ++i)
+// {
+// m_gizmos.enable_grabber(GLGizmosManager::Scale, i, enable_scale_xyz);
+// }
+//
+// if (m_selection.is_single_full_instance())
+// {
+// // all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first
+// const GLVolume* volume = m_volumes.volumes[*m_selection.get_volume_idxs().begin()];
+// m_gizmos.set_scale(volume->get_instance_scaling_factor());
+// m_gizmos.set_rotation(Vec3d::Zero());
+// ModelObject* model_object = m_model->objects[m_selection.get_object_idx()];
+// m_gizmos.set_flattening_data(model_object);
+// m_gizmos.set_sla_support_data(model_object, m_selection);
+// }
+// else if (m_selection.is_single_volume() || m_selection.is_single_modifier())
+// {
+// const GLVolume* volume = m_volumes.volumes[*m_selection.get_volume_idxs().begin()];
+// m_gizmos.set_scale(volume->get_volume_scaling_factor());
+// m_gizmos.set_rotation(Vec3d::Zero());
+// m_gizmos.set_flattening_data(nullptr);
+// m_gizmos.set_sla_support_data(nullptr, m_selection);
+// }
+// else
+// {
+// m_gizmos.set_scale(Vec3d::Ones());
+// m_gizmos.set_rotation(Vec3d::Zero());
+// m_gizmos.set_flattening_data(m_selection.is_from_single_object() ? m_model->objects[m_selection.get_object_idx()] : nullptr);
+// m_gizmos.set_sla_support_data(nullptr, m_selection);
+// }
+//}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void GLCanvas3D::_perform_layer_editing_action(wxMouseEvent* evt)
{
diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp
index bc9932e75..f18c4a4f1 100644
--- a/src/slic3r/GUI/GLCanvas3D.hpp
+++ b/src/slic3r/GUI/GLCanvas3D.hpp
@@ -430,6 +430,9 @@ private:
bool m_regenerate_volumes;
bool m_moving;
bool m_tab_down;
+
+ // Following variable is obsolete and it should be safe to remove it.
+ // I just don't want to do it now before a release (Lukas Matena 24.3.2019)
bool m_render_sla_auxiliaries;
std::string m_color_by;
@@ -456,7 +459,7 @@ public:
void reset_volumes();
int check_volumes_outside_state() const;
- void toggle_sla_auxiliaries_visibility(bool visible);
+ void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
void set_config(const DynamicPrintConfig* config);
@@ -562,6 +565,10 @@ public:
float get_view_toolbar_height() const { return m_view_toolbar.get_height(); }
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ void update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
private:
bool _is_shown_on_screen() const;
@@ -601,7 +608,9 @@ private:
void _render_selection_sidebar_hints() const;
void _update_volumes_hover_state() const;
- void _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+// void _update_gizmos_data();
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void _perform_layer_editing_action(wxMouseEvent* evt = nullptr);
diff --git a/src/slic3r/GUI/GLToolbar.cpp b/src/slic3r/GUI/GLToolbar.cpp
index ac79784ad..de3236fc8 100644
--- a/src/slic3r/GUI/GLToolbar.cpp
+++ b/src/slic3r/GUI/GLToolbar.cpp
@@ -157,7 +157,6 @@ GLToolbar::GLToolbar(GLToolbar::EType type)
#if ENABLE_SVG_ICONS
, m_icons_texture_dirty(true)
#endif // ENABLE_SVG_ICONS
- , m_mouse_capture({ false, false, false, nullptr })
, m_tooltip("")
{
}
@@ -410,6 +409,16 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
bool processed = false;
// mouse anywhere
+ if (!evt.Dragging() && !evt.Leaving() && !evt.Entering() && (m_mouse_capture.parent != nullptr))
+ {
+ if (m_mouse_capture.any() && (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()))
+ // prevents loosing selection into the scene if mouse down was done inside the toolbar and mouse up was down outside it,
+ // as when switching between views
+ processed = true;
+
+ m_mouse_capture.reset();
+ }
+
if (evt.Moving())
m_tooltip = update_hover_state(mouse_pos, parent);
else if (evt.LeftUp())
@@ -418,17 +427,9 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
m_mouse_capture.middle = false;
else if (evt.RightUp())
m_mouse_capture.right = false;
- else if (m_mouse_capture.any())
- {
- if (evt.Dragging())
- processed = true;
- else if (evt.Entering() && (m_mouse_capture.parent == &parent))
- // Resets the mouse capture state to avoid setting the dragging event as processed when, for example,
- // the item action opens a modal dialog
- // Keeps the mouse capture state if the entering event happens on different parent from the one
- // who received the button down event, to prevent, for example, dragging when switching between scene views
- m_mouse_capture.reset();
- }
+ else if (evt.Dragging() && m_mouse_capture.any())
+ // if the button down was done on this toolbar, prevent from dragging into the scene
+ processed = true;
int item_id = contains_mouse(mouse_pos, parent);
if (item_id == -1)
@@ -443,11 +444,16 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
{
m_mouse_capture.left = true;
m_mouse_capture.parent = &parent;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ processed = true;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
if ((item_id != -2) && !m_items[item_id]->is_separator())
{
// mouse is inside an icon
do_action((unsigned int)item_id, parent);
- processed = true;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+// processed = true;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
}
}
else if (evt.MiddleDown())
diff --git a/src/slic3r/GUI/GLToolbar.hpp b/src/slic3r/GUI/GLToolbar.hpp
index 5fe96df5f..0f8b17e04 100644
--- a/src/slic3r/GUI/GLToolbar.hpp
+++ b/src/slic3r/GUI/GLToolbar.hpp
@@ -239,6 +239,8 @@ private:
bool right;
GLCanvas3D* parent;
+ MouseCapture() { reset(); }
+
bool any() const { return left || middle || right; }
void reset() { left = middle = right = false; parent = nullptr; }
};
diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
index f759250b3..6c8fdcab7 100644
--- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp
+++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp
@@ -209,8 +209,8 @@ 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_instance_transformation().get_matrix(true, true) * volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size();
- m_new_enabled = true;
+ m_new_size = volume->get_volume_transformation().get_matrix(true, true) * volume->bounding_box.size();
+ m_new_enabled = true;
}
else if (wxGetApp().obj_list()->multiple_selection())
{
diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp
index 3781cbf45..dbfdb8e6c 100644
--- a/src/slic3r/GUI/GUI_ObjectSettings.cpp
+++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp
@@ -10,6 +10,8 @@
#include "I18N.hpp"
+#include <wx/wupdlock.h>
+
namespace Slic3r
{
namespace GUI
@@ -40,7 +42,7 @@ void OG_Settings::Hide()
void OG_Settings::UpdateAndShow(const bool show)
{
Show(show);
-// m_parent->Layout();
+// m_parent->Layout();
}
wxSizer* OG_Settings::get_sizer()
@@ -84,6 +86,7 @@ void ObjectSettings::update_settings_list()
btn->Bind(wxEVT_BUTTON, [opt_key, config, this](wxEvent &event) {
config->erase(opt_key);
wxTheApp->CallAfter([this]() {
+ wxWindowUpdateLocker noUpdates(m_parent);
update_settings_list();
m_parent->Layout();
});
@@ -119,7 +122,7 @@ void ObjectSettings::update_settings_list()
if (cat.second.size() == 1 && cat.second[0] == "extruder")
continue;
- auto optgroup = std::make_shared<ConfigOptionsGroup>(m_parent, cat.first, config, false, extra_column);
+ auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), cat.first, config, false, extra_column);
optgroup->label_width = 15 * wxGetApp().em_unit();//150;
optgroup->sidetext_width = 7 * wxGetApp().em_unit();//70;
diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp
index be3fad9ec..2361ff6d3 100644
--- a/src/slic3r/GUI/GUI_Preview.cpp
+++ b/src/slic3r/GUI/GUI_Preview.cpp
@@ -174,7 +174,9 @@ Preview::Preview(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_t
, m_loaded(false)
, m_enabled(false)
, m_schedule_background_process(schedule_background_process_func)
+#ifdef __linux__
, m_volumes_cleanup_required(false)
+#endif // __linux__
{
if (init(parent, bed, camera, view_toolbar))
{
@@ -354,31 +356,28 @@ void Preview::load_print(bool keep_z_range)
void Preview::reload_print(bool keep_volumes)
{
-#ifndef __linux__
- if (m_volumes_cleanup_required || !keep_volumes)
- {
- m_canvas->reset_volumes();
- m_canvas->reset_legend_texture();
- m_loaded = false;
- m_volumes_cleanup_required = false;
- }
-#endif // __linux__
-
+#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: a delayed release of OpenGL vertex buffers.
if (!IsShown())
{
m_volumes_cleanup_required = !keep_volumes;
return;
}
-
+#endif /* __linux __ */
+ if (
#ifdef __linux__
- if (m_volumes_cleanup_required || !keep_volumes)
+ m_volumes_cleanup_required ||
+#endif /* __linux__ */
+ !keep_volumes)
{
m_canvas->reset_volumes();
m_canvas->reset_legend_texture();
m_loaded = false;
+#ifdef __linux__
m_volumes_cleanup_required = false;
+#endif /* __linux__ */
}
-#endif // __linux__
load_print();
}
@@ -770,19 +769,17 @@ void Preview::load_print_as_sla()
unsigned int n_layers = 0;
const SLAPrint* print = m_process->sla_print();
- std::set<double> zs;
+ std::vector<double> zs;
+ double initial_layer_height = print->material_config().initial_layer_height.value;
for (const SLAPrintObject* obj : print->objects())
- {
- double shift_z = obj->get_current_elevation();
if (obj->is_step_done(slaposIndexSlices))
{
- const SLAPrintObject::SliceIndex& index = obj->get_slice_index();
- for (const SLAPrintObject::SliceIndex::value_type& id : index)
- {
- zs.insert(shift_z + id.first);
- }
+ auto slicerecords = obj->get_slice_records();
+ auto low_coord = slicerecords.begin()->key();
+ for (auto& rec : slicerecords)
+ zs.emplace_back(initial_layer_height + (rec.key() - low_coord) * SCALING_FACTOR);
}
- }
+ sort_remove_duplicates(zs);
n_layers = (unsigned int)zs.size();
if (n_layers == 0)
@@ -797,11 +794,7 @@ void Preview::load_print_as_sla()
show_hide_ui_elements("none");
if (n_layers > 0)
- {
- std::vector<double> layer_zs;
- std::copy(zs.begin(), zs.end(), std::back_inserter(layer_zs));
- update_sliders(layer_zs);
- }
+ update_sliders(zs);
m_loaded = true;
}
diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp
index 182eaa952..96c49e54f 100644
--- a/src/slic3r/GUI/GUI_Preview.hpp
+++ b/src/slic3r/GUI/GUI_Preview.hpp
@@ -84,7 +84,11 @@ class Preview : public wxPanel
BackgroundSlicingProcess* m_process;
GCodePreviewData* m_gcode_preview_data;
+#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;
+#endif /* __linux__ */
// Calling this function object forces Plater::schedule_background_process.
std::function<void()> m_schedule_background_process;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
index e62a116a7..0f6713e0d 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp
@@ -329,6 +329,10 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
// left down without selection rectangle - place point on the mesh:
if (action == SLAGizmoEventType::LeftDown && !m_selection_rectangle_active && !shift_down) {
+ // If any point is in hover state, this should initiate its move - return control back to GLCanvas:
+ if (m_hover_id != -1)
+ return false;
+
// If there is some selection, don't add new point and deselect everything instead.
if (m_selection_empty) {
try {
@@ -663,7 +667,7 @@ RENDER_AGAIN:
m_imgui->end();
if (m_editing_mode != m_old_editing_state) { // user toggled between editing/non-editing mode
- m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode);
+ m_parent.toggle_sla_auxiliaries_visibility(!m_editing_mode, m_model_object, m_active_instance);
force_refresh = true;
}
m_old_editing_state = m_editing_mode;
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
index 89668162e..9ac7af516 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp
@@ -23,6 +23,9 @@ GLGizmosManager::GLGizmosManager()
, m_overlay_scale(1.0f)
, m_overlay_border(5.0f)
, m_overlay_gap_y(5.0f)
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ , m_tooltip("")
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
{
}
#else
@@ -186,51 +189,53 @@ void GLGizmosManager::set_overlay_scale(float scale)
#endif // ENABLE_SVG_ICONS
}
-std::string GLGizmosManager::update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection)
-{
- std::string name = "";
-
- if (!m_enabled)
- return name;
-
- float cnv_h = (float)canvas.get_canvas_size().get_height();
- float height = get_total_overlay_height();
-#if ENABLE_SVG_ICONS
- float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
- float scaled_border = m_overlay_border * m_overlay_scale;
- float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
- float scaled_stride_y = scaled_icons_size + scaled_gap_y;
- float top_y = 0.5f * (cnv_h - height) + scaled_border;
-#else
- float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
- float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
-#endif // ENABLE_SVG_ICONS
-
- for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
- {
- if ((it->second == nullptr) || !it->second->is_selectable())
- continue;
-
-#if ENABLE_SVG_ICONS
- bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
-#else
- bool inside = (m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
-#endif // ENABLE_SVG_ICONS
- if (inside)
- name = it->second->get_name();
-
- if (it->second->is_activable(selection) && (it->second->get_state() != GLGizmoBase::On))
- it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off);
-
-#if ENABLE_SVG_ICONS
- top_y += scaled_stride_y;
-#else
- top_y += (scaled_icons_size + m_overlay_gap_y);
-#endif // ENABLE_SVG_ICONS
- }
-
- return name;
-}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//std::string GLGizmosManager::update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection)
+//{
+// std::string name = "";
+//
+// if (!m_enabled)
+// return name;
+//
+// float cnv_h = (float)canvas.get_canvas_size().get_height();
+// float height = get_total_overlay_height();
+//#if ENABLE_SVG_ICONS
+// float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
+// float scaled_border = m_overlay_border * m_overlay_scale;
+// float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
+// float scaled_stride_y = scaled_icons_size + scaled_gap_y;
+// float top_y = 0.5f * (cnv_h - height) + scaled_border;
+//#else
+// float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
+// float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
+//#endif // ENABLE_SVG_ICONS
+//
+// for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
+// {
+// if ((it->second == nullptr) || !it->second->is_selectable())
+// continue;
+//
+//#if ENABLE_SVG_ICONS
+// bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
+//#else
+// bool inside = (m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
+//#endif // ENABLE_SVG_ICONS
+// if (inside)
+// name = it->second->get_name();
+//
+// if (it->second->is_activable(selection) && (it->second->get_state() != GLGizmoBase::On))
+// it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off);
+//
+//#if ENABLE_SVG_ICONS
+// top_y += scaled_stride_y;
+//#else
+// top_y += (scaled_icons_size + m_overlay_gap_y);
+//#endif // ENABLE_SVG_ICONS
+// }
+//
+// return name;
+//}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void GLGizmosManager::update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection)
{
@@ -346,46 +351,48 @@ void GLGizmosManager::enable_grabber(EType type, unsigned int id, bool enable)
}
}
-bool GLGizmosManager::overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const
-{
- if (!m_enabled)
- return false;
-
- float cnv_h = (float)canvas.get_canvas_size().get_height();
- float height = get_total_overlay_height();
-
-#if ENABLE_SVG_ICONS
- float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
- float scaled_border = m_overlay_border * m_overlay_scale;
- float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
- float scaled_stride_y = scaled_icons_size + scaled_gap_y;
- float top_y = 0.5f * (cnv_h - height) + scaled_border;
-#else
- float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
- float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
-#endif // ENABLE_SVG_ICONS
-
- for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
- {
- if ((it->second == nullptr) || !it->second->is_selectable())
- continue;
-
-#if ENABLE_SVG_ICONS
- if ((scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
-#else
- if ((m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
-#endif // ENABLE_SVG_ICONS
- return true;
-
-#if ENABLE_SVG_ICONS
- top_y += scaled_stride_y;
-#else
- top_y += (scaled_icons_size + m_overlay_gap_y);
-#endif // ENABLE_SVG_ICONS
- }
-
- return false;
-}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+//bool GLGizmosManager::overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const
+//{
+// if (!m_enabled)
+// return false;
+//
+// float cnv_h = (float)canvas.get_canvas_size().get_height();
+// float height = get_total_overlay_height();
+//
+//#if ENABLE_SVG_ICONS
+// float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
+// float scaled_border = m_overlay_border * m_overlay_scale;
+// float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
+// float scaled_stride_y = scaled_icons_size + scaled_gap_y;
+// float top_y = 0.5f * (cnv_h - height) + scaled_border;
+//#else
+// float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
+// float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
+//#endif // ENABLE_SVG_ICONS
+//
+// for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
+// {
+// if ((it->second == nullptr) || !it->second->is_selectable())
+// continue;
+//
+//#if ENABLE_SVG_ICONS
+// if ((scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
+//#else
+// if ((m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
+//#endif // ENABLE_SVG_ICONS
+// return true;
+//
+//#if ENABLE_SVG_ICONS
+// top_y += scaled_stride_y;
+//#else
+// top_y += (scaled_icons_size + m_overlay_gap_y);
+//#endif // ENABLE_SVG_ICONS
+// }
+//
+// return false;
+//}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
bool GLGizmosManager::grabber_contains_mouse() const
{
@@ -614,6 +621,78 @@ void GLGizmosManager::render_overlay(const GLCanvas3D& canvas, const Selection&
glsafe(::glPopMatrix());
}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
+{
+ Vec2d mouse_pos((double)evt.GetX(), (double)evt.GetY());
+
+ std::cout << to_string(mouse_pos) << std::endl;
+
+
+ const Selection& selection = canvas.get_selection();
+ bool processed = false;
+
+ // mouse anywhere
+ if (!evt.Dragging() && !evt.Leaving() && !evt.Entering() && (m_mouse_capture.parent != nullptr))
+ {
+ if (m_mouse_capture.any() && (evt.LeftUp() || evt.MiddleUp() || evt.RightUp()))
+ // prevents loosing selection into the scene if mouse down was done inside the toolbar and mouse up was down outside it
+ processed = true;
+
+ m_mouse_capture.reset();
+ }
+
+ // mouse anywhere
+ if (evt.Moving())
+ m_tooltip = update_hover_state(canvas, mouse_pos);
+ else if (evt.LeftUp())
+ m_mouse_capture.left = false;
+ else if (evt.MiddleUp())
+ m_mouse_capture.middle = false;
+ else if (evt.RightUp())
+ m_mouse_capture.right = false;
+ else if (evt.Dragging() && m_mouse_capture.any())
+ // if the button down was done on this toolbar, prevent from dragging into the scene
+ processed = true;
+
+ if (!overlay_contains_mouse(canvas, mouse_pos))
+ {
+ // mouse is outside the toolbar
+ m_tooltip = "";
+ }
+ else
+ {
+ // mouse inside toolbar
+ if (evt.LeftDown() || evt.LeftDClick())
+ {
+ m_mouse_capture.left = true;
+ m_mouse_capture.parent = &canvas;
+ processed = true;
+ if (!selection.is_empty())
+ {
+ update_on_off_state(canvas, mouse_pos, selection);
+ canvas.update_gizmos_data();
+ canvas.set_as_dirty();
+ }
+ }
+ else if (evt.MiddleDown())
+ {
+ m_mouse_capture.middle = true;
+ m_mouse_capture.parent = &canvas;
+ }
+ else if (evt.RightDown())
+ {
+ m_mouse_capture.right = true;
+ m_mouse_capture.parent = &canvas;
+ }
+ else if (evt.LeftUp())
+ processed = true;
+ }
+
+ return processed;
+}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
void GLGizmosManager::reset()
{
for (GizmosMap::value_type& gizmo : m_gizmos)
@@ -861,5 +940,96 @@ bool GLGizmosManager::generate_icons_texture() const
}
#endif // ENABLE_SVG_ICONS
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+std::string GLGizmosManager::update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos)
+{
+ std::string name = "";
+
+ if (!m_enabled)
+ return name;
+
+ const Selection& selection = canvas.get_selection();
+
+ float cnv_h = (float)canvas.get_canvas_size().get_height();
+ float height = get_total_overlay_height();
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
+ float scaled_border = m_overlay_border * m_overlay_scale;
+ float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
+ float scaled_stride_y = scaled_icons_size + scaled_gap_y;
+ float top_y = 0.5f * (cnv_h - height) + scaled_border;
+#else
+ float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
+ float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
+#endif // ENABLE_SVG_ICONS
+
+ for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
+ {
+ if ((it->second == nullptr) || !it->second->is_selectable())
+ continue;
+
+#if ENABLE_SVG_ICONS
+ bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
+#else
+ bool inside = (m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
+#endif // ENABLE_SVG_ICONS
+ if (inside)
+ name = it->second->get_name();
+
+ if (it->second->is_activable(selection) && (it->second->get_state() != GLGizmoBase::On))
+ it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off);
+
+#if ENABLE_SVG_ICONS
+ top_y += scaled_stride_y;
+#else
+ top_y += (scaled_icons_size + m_overlay_gap_y);
+#endif // ENABLE_SVG_ICONS
+ }
+
+ return name;
+}
+
+bool GLGizmosManager::overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const
+{
+ if (!m_enabled)
+ return false;
+
+ float cnv_h = (float)canvas.get_canvas_size().get_height();
+ float height = get_total_overlay_height();
+
+#if ENABLE_SVG_ICONS
+ float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
+ float scaled_border = m_overlay_border * m_overlay_scale;
+ float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
+ float scaled_stride_y = scaled_icons_size + scaled_gap_y;
+ float top_y = 0.5f * (cnv_h - height) + scaled_border;
+#else
+ float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
+ float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
+#endif // ENABLE_SVG_ICONS
+
+ for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
+ {
+ if ((it->second == nullptr) || !it->second->is_selectable())
+ continue;
+
+#if ENABLE_SVG_ICONS
+ if ((scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
+#else
+ if ((m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
+#endif // ENABLE_SVG_ICONS
+ return true;
+
+#if ENABLE_SVG_ICONS
+ top_y += scaled_stride_y;
+#else
+ top_y += (scaled_icons_size + m_overlay_gap_y);
+#endif // ENABLE_SVG_ICONS
+ }
+
+ return false;
+}
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
} // namespace GUI
} // namespace Slic3r
diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
index cb121352a..c280eda50 100644
--- a/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
+++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.hpp
@@ -83,6 +83,24 @@ private:
float m_overlay_border;
float m_overlay_gap_y;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ struct MouseCapture
+ {
+ bool left;
+ bool middle;
+ bool right;
+ GLCanvas3D* parent;
+
+ MouseCapture() { reset(); }
+
+ bool any() const { return left || middle || right; }
+ void reset() { left = middle = right = false; parent = nullptr; }
+ };
+
+ MouseCapture m_mouse_capture;
+ std::string m_tooltip;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
public:
GLGizmosManager();
~GLGizmosManager();
@@ -97,7 +115,9 @@ public:
#endif // ENABLE_SVG_ICONS
void set_overlay_scale(float scale);
- std::string update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection);
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+// std::string update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection);
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection);
void update_on_off_state(const Selection& selection);
void reset_all_states();
@@ -105,7 +125,9 @@ public:
void set_hover_id(int id);
void enable_grabber(EType type, unsigned int id, bool enable);
- bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+// bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
bool grabber_contains_mouse() const;
void update(const Linef3& mouse_ray, const Selection& selection, bool shift_down, const Point* mouse_pos = nullptr);
Rect get_reset_rect_viewport(const GLCanvas3D& canvas) const;
@@ -138,6 +160,12 @@ public:
void render_overlay(const GLCanvas3D& canvas, const Selection& selection) const;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ const std::string& get_tooltip() const { return m_tooltip; }
+
+ bool on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas);
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
private:
void reset();
@@ -151,6 +179,11 @@ private:
#if ENABLE_SVG_ICONS
bool generate_icons_texture() const;
#endif // ENABLE_SVG_ICONS
+
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+ std::string update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos);
+ bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const;
+//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
};
} // namespace GUI
diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp
index 2acc2cec4..e15882125 100644
--- a/src/slic3r/GUI/Plater.cpp
+++ b/src/slic3r/GUI/Plater.cpp
@@ -57,6 +57,7 @@
#include "BackgroundSlicingProcess.hpp"
#include "ProgressStatusBar.hpp"
#include "PrintHostDialogs.hpp"
+#include "ConfigWizard.hpp"
#include "../Utils/ASCIIFolding.hpp"
#include "../Utils/PrintHost.hpp"
#include "../Utils/FixModelByWin10.hpp"
@@ -233,9 +234,11 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 *
auto selected_item = this->GetSelection();
auto marker = reinterpret_cast<Marker>(this->GetClientData(selected_item));
- if (marker == LABEL_ITEM_MARKER) {
+ if (marker == LABEL_ITEM_MARKER || marker == LABEL_ITEM_CONFIG_WIZARD) {
this->SetSelection(this->last_selected);
evt.StopPropagation();
+ if (marker == LABEL_ITEM_CONFIG_WIZARD)
+ wxTheApp->CallAfter([]() { Slic3r::GUI::config_wizard(Slic3r::GUI::ConfigWizard::RR_USER); });
} else if ( this->last_selected != selected_item ||
wxGetApp().get_tab(this->preset_type)->get_presets()->current_is_dirty() ) {
this->last_selected = selected_item;
@@ -317,15 +320,14 @@ PresetComboBox::~PresetComboBox()
}
-void PresetComboBox::set_label_marker(int item)
+void PresetComboBox::set_label_marker(int item, LabelItemType label_item_type)
{
- this->SetClientData(item, (void*)LABEL_ITEM_MARKER);
+ this->SetClientData(item, (void*)label_item_type);
}
void PresetComboBox::check_selection()
{
- if (this->last_selected != GetSelection())
- this->last_selected = GetSelection();
+ this->last_selected = GetSelection();
}
// Frequently changed parameters
@@ -826,10 +828,7 @@ void Sidebar::update_presets(Preset::Type preset_type)
preset_bundle.sla_materials.update_platter_ui(p->combo_sla_material);
}
// Update the printer choosers, update the dirty flags.
- auto prev_selection = p->combo_printer->GetSelection();
preset_bundle.printers.update_platter_ui(p->combo_printer);
- if (prev_selection != p->combo_printer->GetSelection())
- p->combo_printer->check_selection();
// Update the filament choosers to only contain the compatible presets, update the color preview,
// update the dirty flags.
if (print_tech == ptFFF) {
@@ -1617,7 +1616,11 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
if (type_3mf || type_any_amf) {
#endif // !ENABLE_VOLUMES_CENTERING_FIXES
for (ModelObject* model_object : model.objects) {
+#if ENABLE_VOLUMES_CENTERING_FIXES
+ model_object->center_around_origin(false);
+#else
model_object->center_around_origin();
+#endif // ENABLE_VOLUMES_CENTERING_FIXES
model_object->ensure_on_bed();
}
#if !ENABLE_VOLUMES_CENTERING_FIXES
@@ -1710,8 +1713,8 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
object->center_around_origin();
new_instances.emplace_back(object->add_instance());
#else /* AUTOPLACEMENT_ON_LOAD */
- // if object has no defined position(s) we need to rearrange everything after loading object->center_around_origin();
- need_arrange = true;
+ // if object has no defined position(s) we need to rearrange everything after loading
+ need_arrange = true;
// add a default instance and center object around origin
object->center_around_origin(); // also aligns object to Z = 0
ModelInstance* instance = object->add_instance();
diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp
index f3e195ad0..f830edce3 100644
--- a/src/slic3r/GUI/Plater.hpp
+++ b/src/slic3r/GUI/Plater.hpp
@@ -48,14 +48,18 @@ public:
wxButton* edit_btn { nullptr };
- void set_label_marker(int item);
+ enum LabelItemType {
+ LABEL_ITEM_MARKER = 0x4d,
+ LABEL_ITEM_CONFIG_WIZARD = 0x4e
+ };
+
+ void set_label_marker(int item, LabelItemType label_item_type = LABEL_ITEM_MARKER);
void set_extruder_idx(const int extr_idx) { extruder_idx = extr_idx; }
int get_extruder_idx() const { return extruder_idx; }
void check_selection();
private:
typedef std::size_t Marker;
- enum { LABEL_ITEM_MARKER = 0x4d };
Preset::Type preset_type;
int last_selected;
diff --git a/src/slic3r/GUI/Preset.cpp b/src/slic3r/GUI/Preset.cpp
index 656658b0b..82223b15c 100644
--- a/src/slic3r/GUI/Preset.cpp
+++ b/src/slic3r/GUI/Preset.cpp
@@ -519,6 +519,7 @@ PresetCollection::PresetCollection(Preset::Type type, const std::vector<std::str
m_edited_preset(type, "", false),
m_idx_selected(0),
m_bitmap_main_frame(new wxBitmap),
+ m_bitmap_add(new wxBitmap),
m_bitmap_cache(new GUI::BitmapCache)
{
// Insert just the default preset.
@@ -530,6 +531,8 @@ PresetCollection::~PresetCollection()
{
delete m_bitmap_main_frame;
m_bitmap_main_frame = nullptr;
+ delete m_bitmap_add;
+ m_bitmap_add = nullptr;
delete m_bitmap_cache;
m_bitmap_cache = nullptr;
}
@@ -740,6 +743,8 @@ void PresetCollection::save_current_preset(const std::string &new_name)
return;
// Overwriting an existing preset.
preset.config = std::move(m_edited_preset.config);
+ // The newly saved preset will be activated -> make it visible.
+ preset.is_visible = true;
} else {
// Creating a new preset.
Preset &preset = *m_presets.insert(it, m_edited_preset);
@@ -761,18 +766,20 @@ void PresetCollection::save_current_preset(const std::string &new_name)
preset.is_default = false;
preset.is_system = false;
preset.is_external = false;
- }
+ // The newly saved preset will be activated -> make it visible.
+ preset.is_visible = true;
+ }
// 2) Activate the saved preset.
this->select_preset_by_name(new_name, true);
// 2) Store the active preset to disk.
this->get_selected_preset().save();
}
-void PresetCollection::delete_current_preset()
+bool PresetCollection::delete_current_preset()
{
const Preset &selected = this->get_selected_preset();
- if (selected.is_default)
- return;
+ if (selected.is_default)
+ return false;
if (! selected.is_external && ! selected.is_system) {
// Erase the preset file.
boost::nowide::remove(selected.file.c_str());
@@ -786,6 +793,7 @@ void PresetCollection::delete_current_preset()
if (new_selected_idx == m_presets.size())
for (--new_selected_idx; new_selected_idx > 0 && !m_presets[new_selected_idx].is_visible; --new_selected_idx);
this->select_preset(new_selected_idx);
+ return true;
}
bool PresetCollection::load_bitmap_default(const std::string &file_name)
@@ -793,6 +801,11 @@ bool PresetCollection::load_bitmap_default(const std::string &file_name)
return m_bitmap_main_frame->LoadFile(wxString::FromUTF8(Slic3r::var(file_name).c_str()), wxBITMAP_TYPE_PNG);
}
+bool PresetCollection::load_bitmap_add(const std::string &file_name)
+{
+ return m_bitmap_add->LoadFile(wxString::FromUTF8(Slic3r::var(file_name).c_str()), wxBITMAP_TYPE_PNG);
+}
+
const Preset* PresetCollection::get_selected_preset_parent() const
{
const std::string &inherits = this->get_edited_preset().inherits();
@@ -843,7 +856,9 @@ void PresetCollection::set_default_suppressed(bool default_suppressed)
{
if (m_default_suppressed != default_suppressed) {
m_default_suppressed = default_suppressed;
- m_presets.front().is_visible = ! default_suppressed || (m_presets.size() > m_num_default_presets && m_idx_selected > 0);
+ bool default_visible = ! default_suppressed || m_idx_selected < m_num_default_presets;
+ for (size_t i = 0; i < m_num_default_presets; ++ i)
+ m_presets[i].is_visible = default_visible;
}
}
@@ -895,8 +910,8 @@ void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui)
std::map<wxString, wxBitmap*> nonsys_presets;
wxString selected = "";
if (!this->m_presets.front().is_visible)
- ui->set_label_marker(ui->Append("------- " + _(L("System presets")) + " -------", wxNullBitmap));
- for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++i) {
+ ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap));
+ for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++ i) {
const Preset &preset = this->m_presets[i];
if (! preset.is_visible || (! preset.is_compatible && i != m_idx_selected))
continue;
@@ -935,20 +950,45 @@ void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui)
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str());
}
if (i + 1 == m_num_default_presets)
- ui->set_label_marker(ui->Append("------- " + _(L("System presets")) + " -------", wxNullBitmap));
+ ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap));
}
if (!nonsys_presets.empty())
{
- ui->set_label_marker(ui->Append("------- " + _(L("User presets")) + " -------", wxNullBitmap));
+ ui->set_label_marker(ui->Append(PresetCollection::separator(L("User presets")), wxNullBitmap));
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
ui->Append(it->first, *it->second);
if (it->first == selected)
selected_preset_item = ui->GetCount() - 1;
}
}
+ if (m_type == Preset::TYPE_PRINTER) {
+ std::string bitmap_key = "";
+ // If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
+ // to the filament color image.
+ if (wide_icons)
+ bitmap_key += "wide,";
+ bitmap_key += "add_printer";
+ wxBitmap *bmp = m_bitmap_cache->find(bitmap_key);
+ if (bmp == nullptr) {
+ // Create the bitmap with color bars.
+ std::vector<wxBitmap> bmps;
+ if (wide_icons)
+ // Paint a red flag for incompatible presets.
+ bmps.emplace_back(m_bitmap_cache->mkclear(16, 16));
+ // Paint the color bars.
+ bmps.emplace_back(m_bitmap_cache->mkclear(4, 16));
+ bmps.emplace_back(*m_bitmap_main_frame);
+ // Paint a lock at the system presets.
+ bmps.emplace_back(m_bitmap_cache->mkclear(6, 16));
+ bmps.emplace_back(m_bitmap_add ? *m_bitmap_add : wxNullBitmap);
+ bmp = m_bitmap_cache->insert(bitmap_key, bmps);
+ }
+ ui->set_label_marker(ui->Append(PresetCollection::separator(L("Add a new printer")), *bmp), GUI::PresetComboBox::LABEL_ITEM_CONFIG_WIZARD);
+ }
ui->SetSelection(selected_preset_item);
ui->SetToolTip(ui->GetString(selected_preset_item));
+ ui->check_selection();
ui->Thaw();
}
@@ -963,7 +1003,7 @@ size_t PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompati
std::map<wxString, wxBitmap*> nonsys_presets;
wxString selected = "";
if (!this->m_presets.front().is_visible)
- ui->Append("------- " + _(L("System presets")) + " -------", wxNullBitmap);
+ ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap);
for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++i) {
const Preset &preset = this->m_presets[i];
if (! preset.is_visible || (! show_incompatible && ! preset.is_compatible && i != m_idx_selected))
@@ -994,18 +1034,29 @@ size_t PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompati
if (i == m_idx_selected)
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str());
}
- if (i + 1 == m_num_default_presets)
- ui->Append("------- " + _(L("System presets")) + " -------", wxNullBitmap);
+ if (i + 1 == m_num_default_presets)
+ ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap);
}
if (!nonsys_presets.empty())
{
- ui->Append("------- " + _(L("User presets")) + " -------", wxNullBitmap);
+ ui->Append(PresetCollection::separator(L("User presets")), wxNullBitmap);
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
ui->Append(it->first, *it->second);
if (it->first == selected)
selected_preset_item = ui->GetCount() - 1;
}
}
+ if (m_type == Preset::TYPE_PRINTER) {
+ wxBitmap *bmp = m_bitmap_cache->find("add_printer_tab");
+ if (bmp == nullptr) {
+ // Create the bitmap with color bars.
+ std::vector<wxBitmap> bmps;
+ bmps.emplace_back(*m_bitmap_main_frame);
+ bmps.emplace_back(m_bitmap_add ? *m_bitmap_add : wxNullBitmap);
+ bmp = m_bitmap_cache->insert("add_printer_tab", bmps);
+ }
+ ui->Append(PresetCollection::separator("Add a new printer"), *bmp);
+ }
ui->SetSelection(selected_preset_item);
ui->SetToolTip(ui->GetString(selected_preset_item));
ui->Thaw();
@@ -1114,7 +1165,9 @@ Preset& PresetCollection::select_preset(size_t idx)
idx = first_visible_idx();
m_idx_selected = idx;
m_edited_preset = m_presets[idx];
- m_presets.front().is_visible = ! m_default_suppressed || m_idx_selected == 0;
+ bool default_visible = ! m_default_suppressed || m_idx_selected < m_num_default_presets;
+ for (size_t i = 0; i < m_num_default_presets; ++i)
+ m_presets[i].is_visible = default_visible;
return m_presets[idx];
}
@@ -1232,6 +1285,11 @@ std::string PresetCollection::path_from_name(const std::string &new_name) const
return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string();
}
+wxString PresetCollection::separator(const std::string &label)
+{
+ return wxString::FromUTF8(PresetCollection::separator_head()) + _(label) + wxString::FromUTF8(PresetCollection::separator_tail());
+}
+
const Preset& PrinterPresetCollection::default_preset_for(const DynamicPrintConfig &config) const
{
const ConfigOptionEnumGeneric *opt_printer_technology = config.opt<ConfigOptionEnumGeneric>("printer_technology");
diff --git a/src/slic3r/GUI/Preset.hpp b/src/slic3r/GUI/Preset.hpp
index 511313715..ac1171e18 100644
--- a/src/slic3r/GUI/Preset.hpp
+++ b/src/slic3r/GUI/Preset.hpp
@@ -11,9 +11,10 @@
#include "slic3r/Utils/Semver.hpp"
class wxBitmap;
-class wxChoice;
class wxBitmapComboBox;
+class wxChoice;
class wxItemContainer;
+class wxString;
namespace Slic3r {
@@ -115,6 +116,8 @@ public:
// Is this preset compatible with the currently active printer?
bool is_compatible = true;
+ bool is_user() const { return ! this->is_default && ! this->is_system; }
+
// Name of the preset, usually derived form the file name.
std::string name;
// File name of the preset. This could be a Print / Filament / Printer preset,
@@ -269,11 +272,15 @@ public:
void save_current_preset(const std::string &new_name);
// Delete the current preset, activate the first visible preset.
- void delete_current_preset();
+ // returns true if the preset was deleted successfully.
+ bool delete_current_preset();
// Load default bitmap to be placed at the wxBitmapComboBox of a MainFrame.
bool load_bitmap_default(const std::string &file_name);
+ // Load "add new printer" bitmap to be placed at the wxBitmapComboBox of a MainFrame.
+ bool load_bitmap_add(const std::string &file_name);
+
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items.
void set_bitmap_compatible (const wxBitmap *bmp) { m_bitmap_compatible = bmp; }
void set_bitmap_incompatible(const wxBitmap *bmp) { m_bitmap_incompatible = bmp; }
@@ -404,6 +411,15 @@ public:
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
std::string path_from_name(const std::string &new_name) const;
+#ifdef __linux__
+ static const char* separator_head() { return "------- "; }
+ static const char* separator_tail() { return " -------"; }
+#else /* __linux__ */
+ static const char* separator_head() { return "————— "; }
+ static const char* separator_tail() { return " —————"; }
+#endif /* __linux__ */
+ static wxString separator(const std::string &label);
+
protected:
// Select a preset, if it exists. If it does not exist, select an invalid (-1) index.
// This is a temporary state, which shall be fixed immediately by the following step.
@@ -464,6 +480,8 @@ private:
// Marks placed at the wxBitmapComboBox of a MainFrame.
// These bitmaps are owned by PresetCollection.
wxBitmap *m_bitmap_main_frame;
+ // "Add printer profile" icon, owned by PresetCollection.
+ wxBitmap *m_bitmap_add;
// Path to the directory to store the config files into.
std::string m_dir_path;
diff --git a/src/slic3r/GUI/PresetBundle.cpp b/src/slic3r/GUI/PresetBundle.cpp
index b8c9fedac..f78a04126 100644
--- a/src/slic3r/GUI/PresetBundle.cpp
+++ b/src/slic3r/GUI/PresetBundle.cpp
@@ -107,6 +107,7 @@ PresetBundle::PresetBundle() :
this->filaments .load_bitmap_default("spool.png");
this->sla_materials.load_bitmap_default("package_green.png");
this->printers .load_bitmap_default("printer_empty.png");
+ this->printers .load_bitmap_add("add.png");
this->load_compatible_bitmaps();
// Re-activate the default presets, so their "edited" preset copies will be updated with the additional configuration values above.
@@ -1405,7 +1406,7 @@ void PresetBundle::export_configbundle(const std::string &path, bool export_syst
// an optional "(modified)" suffix will be removed from the filament name.
void PresetBundle::set_filament_preset(size_t idx, const std::string &name)
{
- if (name.find_first_of("-------") == 0)
+ if (name.find_first_of(PresetCollection::separator_head()) == 0)
return;
if (idx >= filament_presets.size())
@@ -1461,7 +1462,7 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr
std::map<wxString, wxBitmap*> nonsys_presets;
wxString selected_str = "";
if (!this->filaments().front().is_visible)
- ui->set_label_marker(ui->Append("------- " + _(L("System presets")) + " -------", wxNullBitmap));
+ ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap));
for (int i = this->filaments().front().is_visible ? 0 : 1; i < int(this->filaments().size()); ++i) {
const Preset &preset = this->filaments.preset(i);
bool selected = this->filament_presets[idx_extruder] == preset.name;
@@ -1514,12 +1515,12 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr
selected_str = wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str());
}
if (preset.is_default)
- ui->set_label_marker(ui->Append("------- " + _(L("System presets")) + " -------", wxNullBitmap));
+ ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap));
}
if (!nonsys_presets.empty())
{
- ui->set_label_marker(ui->Append("------- " + _(L("User presets")) + " -------", wxNullBitmap));
+ ui->set_label_marker(ui->Append(PresetCollection::separator(L("User presets")), wxNullBitmap));
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
ui->Append(it->first, *it->second);
if (it->first == selected_str)
@@ -1528,6 +1529,7 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::Pr
}
ui->SetSelection(selected_preset_item);
ui->SetToolTip(ui->GetString(selected_preset_item));
+ ui->check_selection();
ui->Thaw();
}
diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp
index 46a6de6ab..48d9ece47 100644
--- a/src/slic3r/GUI/Tab.cpp
+++ b/src/slic3r/GUI/Tab.cpp
@@ -29,6 +29,7 @@
#include "GUI_App.hpp"
#include "GUI_ObjectList.hpp"
+#include "ConfigWizard.hpp"
namespace Slic3r {
namespace GUI {
@@ -248,10 +249,12 @@ void Tab::create_preset_tab()
return;
if (selected_item >= 0) {
std::string selected_string = m_presets_choice->GetString(selected_item).ToUTF8().data();
- if (selected_string.find("-------") == 0
+ if (selected_string.find(PresetCollection::separator_head()) == 0
/*selected_string == "------- System presets -------" ||
selected_string == "------- User presets -------"*/) {
m_presets_choice->SetSelection(m_selected_preset_item);
+ if (wxString::FromUTF8(selected_string.c_str()) == PresetCollection::separator(L("Add a new printer")))
+ wxTheApp->CallAfter([]() { Slic3r::GUI::config_wizard(Slic3r::GUI::ConfigWizard::RR_USER); });
return;
}
m_selected_preset_item = selected_item;
@@ -385,7 +388,7 @@ void Tab::update_changed_ui()
if (m_postpone_update_ui)
return;
- const bool deep_compare = (m_name == "printer" || m_name == "sla_material");
+ const bool deep_compare = (m_type == Slic3r::Preset::TYPE_PRINTER || m_type == Slic3r::Preset::TYPE_SLA_MATERIAL);
auto dirty_options = m_presets->current_dirty_options(deep_compare);
auto nonsys_options = m_presets->current_different_from_parent_options(deep_compare);
if (m_type == Slic3r::Preset::TYPE_PRINTER) {
@@ -2395,7 +2398,7 @@ void Tab::load_current_preset()
(preset.is_default || preset.is_system) ? m_btn_delete_preset->Disable() : m_btn_delete_preset->Enable(true);
update();
- if (m_name == "printer") {
+ if (m_type == Slic3r::Preset::TYPE_PRINTER) {
// For the printer profile, generate the extruder pages.
if (preset.printer_technology() == ptFFF)
on_preset_loaded();
@@ -2425,7 +2428,7 @@ void Tab::load_current_preset()
update_tab_ui();
// update show/hide tabs
- if (m_name == "printer") {
+ if (m_type == Slic3r::Preset::TYPE_PRINTER) {
const PrinterTechnology printer_technology = m_presets->get_edited_preset().printer_technology();
if (printer_technology != static_cast<TabPrinter*>(this)->m_printer_technology)
{
@@ -2458,7 +2461,7 @@ void Tab::load_current_preset()
}
else {
on_presets_changed();
- if (m_type == Preset::TYPE_SLA_PRINT || m_type == Preset::TYPE_PRINT)// if (m_name == "print")
+ if (m_type == Preset::TYPE_SLA_PRINT || m_type == Preset::TYPE_PRINT)
update_frequently_changed_parameters();
}
@@ -2526,20 +2529,35 @@ void Tab::update_page_tree_visibility()
}
-// Called by the UI combo box when the user switches profiles.
+// Called by the UI combo box when the user switches profiles, and also to delete the current profile.
// Select a preset by a name.If !defined(name), then the default preset is selected.
// If the current profile is modified, user is asked to save the changes.
-void Tab::select_preset(std::string preset_name)
-{
- // If no name is provided, select the "-- default --" preset.
- if (preset_name.empty())
- preset_name = m_presets->default_preset().name;
- bool current_dirty = m_presets->current_is_dirty();
+void Tab::select_preset(std::string preset_name, bool delete_current)
+{
+ if (preset_name.empty()) {
+ if (delete_current) {
+ // Find an alternate preset to be selected after the current preset is deleted.
+ const std::deque<Preset> &presets = this->m_presets->get_presets();
+ size_t idx_current = this->m_presets->get_idx_selected();
+ // Find the next visible preset.
+ size_t idx_new = idx_current + 1;
+ if (idx_new < presets.size())
+ for (; idx_new < presets.size() && ! presets[idx_new].is_visible; ++ idx_new) ;
+ if (idx_new == presets.size())
+ for (idx_new = idx_current - 1; idx_new > 0 && ! presets[idx_new].is_visible; -- idx_new);
+ preset_name = presets[idx_new].name;
+ } else {
+ // If no name is provided, select the "-- default --" preset.
+ preset_name = m_presets->default_preset().name;
+ }
+ }
+ assert(! delete_current || (m_presets->get_edited_preset().name != preset_name && m_presets->get_edited_preset().is_user()));
+ bool current_dirty = ! delete_current && m_presets->current_is_dirty();
bool print_tab = m_presets->type() == Preset::TYPE_PRINT || m_presets->type() == Preset::TYPE_SLA_PRINT;
bool printer_tab = m_presets->type() == Preset::TYPE_PRINTER;
bool canceled = false;
m_dependent_tabs = {};
- if (current_dirty && !may_discard_current_dirty_preset()) {
+ if (current_dirty && ! may_discard_current_dirty_preset()) {
canceled = true;
} else if (print_tab) {
// Before switching the print profile to a new one, verify, whether the currently active filament or SLA material
@@ -2602,6 +2620,19 @@ void Tab::select_preset(std::string preset_name)
}
}
}
+
+ if (! canceled && delete_current) {
+ // Delete the file and select some other reasonable preset.
+ // It does not matter which preset will be made active as the preset will be re-selected from the preset_name variable.
+ // The 'external' presets will only be removed from the preset list, their files will not be deleted.
+ try {
+ m_presets->delete_current_preset();
+ } catch (const std::exception & /* e */) {
+ //FIXME add some error reporting!
+ canceled = true;
+ }
+ }
+
if (canceled) {
update_tab_ui();
// Trigger the on_presets_changed event so that we also restore the previous value in the plater selector,
@@ -2610,17 +2641,19 @@ void Tab::select_preset(std::string preset_name)
} else {
if (current_dirty)
m_presets->discard_current_changes();
- const bool is_selected = m_presets->select_preset_by_name(preset_name, false);
+
+ const bool is_selected = m_presets->select_preset_by_name(preset_name, false) || delete_current;
+ assert(m_presets->get_edited_preset().name == preset_name || ! is_selected);
// Mark the print & filament enabled if they are compatible with the currently selected preset.
// The following method should not discard changes of current print or filament presets on change of a printer profile,
// if they are compatible with the current printer.
- if (current_dirty || print_tab || printer_tab)
+ if (current_dirty || delete_current || print_tab || printer_tab)
m_preset_bundle->update_compatible(true);
// Initialize the UI from the current preset.
if (printer_tab)
static_cast<TabPrinter*>(this)->update_pages();
- if (!is_selected && printer_tab)
+ if (! is_selected && printer_tab)
{
/* There is a case, when :
* after Config Wizard applying we try to select previously selected preset, but
@@ -2631,15 +2664,10 @@ void Tab::select_preset(std::string preset_name)
* to the corresponding printer_technology
*/
const PrinterTechnology printer_technology = m_presets->get_edited_preset().printer_technology();
- if (printer_technology == ptFFF && m_dependent_tabs.front() != Preset::Type::TYPE_PRINT ||
- printer_technology == ptSLA && m_dependent_tabs.front() != Preset::Type::TYPE_SLA_PRINT )
- {
- m_dependent_tabs.clear();
- if (printer_technology == ptFFF)
- m_dependent_tabs = { Preset::Type::TYPE_PRINT, Preset::Type::TYPE_FILAMENT };
- else
- m_dependent_tabs = { Preset::Type::TYPE_SLA_PRINT, Preset::Type::TYPE_SLA_MATERIAL };
- }
+ if (printer_technology == ptFFF && m_dependent_tabs.front() != Preset::Type::TYPE_PRINT)
+ m_dependent_tabs = { Preset::Type::TYPE_PRINT, Preset::Type::TYPE_FILAMENT };
+ else if (printer_technology == ptSLA && m_dependent_tabs.front() != Preset::Type::TYPE_SLA_PRINT)
+ m_dependent_tabs = { Preset::Type::TYPE_SLA_PRINT, Preset::Type::TYPE_SLA_MATERIAL };
}
load_current_preset();
}
@@ -2771,11 +2799,14 @@ void Tab::save_preset(std::string name /*= ""*/)
//! m_treectrl->OnSetFocus();
if (name.empty()) {
- auto preset = m_presets->get_selected_preset();
+ const Preset &preset = m_presets->get_selected_preset();
auto default_name = preset.is_default ? "Untitled" : preset.name;
+ if (preset.is_system) {
+ default_name += " - ";
+ default_name += _(L("Copy")).ToUTF8().data();
+ }
bool have_extention = boost::iends_with(default_name, ".ini");
- if (have_extention)
- {
+ if (have_extention) {
size_t len = default_name.length()-4;
default_name.resize(len);
}
@@ -2819,7 +2850,7 @@ void Tab::save_preset(std::string name /*= ""*/)
// If current profile is saved, "delete preset" button have to be enabled
m_btn_delete_preset->Enable(true);
- if (m_name == "printer")
+ if (m_type == Preset::TYPE_PRINTER)
static_cast<TabPrinter*>(this)->m_initial_extruders_count = static_cast<TabPrinter*>(this)->m_extruders_count;
update_changed_ui();
}
@@ -2836,15 +2867,9 @@ void Tab::delete_preset()
if (current_preset.is_default ||
wxID_YES != wxMessageDialog(parent(), msg, title, wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION).ShowModal())
return;
- // Delete the file and select some other reasonable preset.
- // The 'external' presets will only be removed from the preset list, their files will not be deleted.
- try{ m_presets->delete_current_preset(); }
- catch (const std::exception & /* e */)
- {
- return;
- }
- // Load the newly selected preset into the UI, update selection combo boxes with their dirty flags.
- load_current_preset();
+ // Select will handle of the preset dependencies, of saving & closing the depending profiles, and
+ // finally of deleting the preset.
+ this->select_preset("", true);
}
void Tab::toggle_show_hide_incompatible()
diff --git a/src/slic3r/GUI/Tab.hpp b/src/slic3r/GUI/Tab.hpp
index 15ae0443c..58950990c 100644
--- a/src/slic3r/GUI/Tab.hpp
+++ b/src/slic3r/GUI/Tab.hpp
@@ -239,7 +239,8 @@ public:
void load_current_preset();
void rebuild_page_tree();
void update_page_tree_visibility();
- void select_preset(std::string preset_name = "");
+ // Select a new preset, possibly delete the current one.
+ void select_preset(std::string preset_name = "", bool delete_current = false);
bool may_discard_current_dirty_preset(PresetCollection* presets = nullptr, const std::string& new_printer_name = "");
bool may_switch_to_SLA_preset();