1st installment of gizmos refactoring
1) GLCanvas3D::Gizmos moved into a standalone class GLGizmosManager 2) GLGizmosManager handles mouse events by calling its on_mouse method (wip)
This commit is contained in:
commit
3818bfa19a
28 changed files with 1346 additions and 522 deletions
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_slices.clear();
|
||||
|
||||
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);
|
||||
|
||||
std::vector<float> heights; heights.reserve(po.m_slice_index.size());
|
||||
|
||||
for(auto& rec : po.m_slice_index) {
|
||||
heights.emplace_back(rec.slice_level());
|
||||
}
|
||||
|
||||
sd->support_slices = sd->support_tree_ptr->slice(
|
||||
heights, float(po.config().slice_closing_radius.value));
|
||||
}
|
||||
|
||||
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) {
|
||||
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];
|
||||
|
||||
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(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());
|
||||
|
||||
for(int i = 0; i < int(sslices.size()); ++i) {
|
||||
LevelID h = sminZ + sih + i * slh;
|
||||
po.m_supportdata->level_ids.emplace_back(h);
|
||||
|
||||
float fh = float(double(h) * SCALING_FACTOR);
|
||||
|
||||
SLAPrintObject::SliceRecord& sr = po.m_slice_index[fh];
|
||||
assert(sr.support_slices_idx == SLAPrintObject::SliceRecord::NONE);
|
||||
sr.support_slices_idx = SLAPrintObject::SliceRecord::Idx(i);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
LevelID gndlvl = o->get_slice_index().front().key();
|
||||
for(auto& slicerecord : o->get_slice_index()) {
|
||||
auto& lyrs = m_printer_input[slicerecord.key() - gndlvl];
|
||||
|
||||
// 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));
|
||||
const ExPolygons& objslices = o->get_slices_from_record(slicerecord, soModel);
|
||||
const ExPolygons& supslices = o->get_slices_from_record(slicerecord, soSupport);
|
||||
|
||||
// now merge this object's support and object slices with the rest
|
||||
// of the print object slices
|
||||
if(!objslices.empty())
|
||||
lyrs.emplace_back(objslices, o->instances());
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
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;
|
||||
|
||||
using Idx = size_t;
|
||||
static const Idx NONE = Idx(-1); // this will be the max limit of size_t
|
||||
public:
|
||||
_SliceRecord(Key key, float slicez, float height):
|
||||
SliceRecord(key, slicez, height) {}
|
||||
|
||||
Idx model_slices_idx = NONE;
|
||||
Idx support_slices_idx = NONE;
|
||||
// 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;
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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; }
|
||||
};
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
void Tab::select_preset(std::string preset_name, bool delete_current)
|
||||
{
|
||||
// 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();
|
||||
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()
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue