Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_labels
This commit is contained in:
commit
251a7d1329
40 changed files with 3008 additions and 2809 deletions
7
resources/profiles/Creality.idx
Normal file
7
resources/profiles/Creality.idx
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
min_slic3r_version = 2.2.0-alpha3
|
||||||
|
0.0.2-alpha0 Print bed textures are now configurable from the Preset Bundle. Requires PrusaSlicer 2.2.0-alpha3 and newer.
|
||||||
|
# The following line (max_slic3r_version) forces the users of PrusaSlicer 2.2.0-alpha3 and newer to update the profiles to 1.1.1-alpha3 and newer,
|
||||||
|
# so they will see the print bed.
|
||||||
|
max_slic3r_version = 2.2.0-alpha2
|
||||||
|
min_slic3r_version = 2.2.0-alpha0
|
||||||
|
0.0.1 Initial version
|
|
@ -5,7 +5,7 @@
|
||||||
name = Creality
|
name = Creality
|
||||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||||
config_version = 0.0.1
|
config_version = 0.0.2-alpha0
|
||||||
# Where to get the updates from?
|
# Where to get the updates from?
|
||||||
config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/
|
config_update_url = http://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Creality/
|
||||||
# changelog_url = http://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
|
# changelog_url = http://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
|
||||||
|
|
|
@ -958,7 +958,7 @@ namespace DoExport {
|
||||||
skirts.emplace_back(std::move(s));
|
skirts.emplace_back(std::move(s));
|
||||||
}
|
}
|
||||||
ooze_prevention.enable = true;
|
ooze_prevention.enable = true;
|
||||||
ooze_prevention.standby_points = offset(Slic3r::Geometry::convex_hull(skirts), scale_(3.f)).front().equally_spaced_points(scale_(10.));
|
ooze_prevention.standby_points = offset(Slic3r::Geometry::convex_hull(skirts), float(scale_(3.))).front().equally_spaced_points(float(scale_(10.)));
|
||||||
#if 0
|
#if 0
|
||||||
require "Slic3r/SVG.pm";
|
require "Slic3r/SVG.pm";
|
||||||
Slic3r::SVG::output(
|
Slic3r::SVG::output(
|
||||||
|
@ -1091,7 +1091,7 @@ namespace DoExport {
|
||||||
static inline std::vector<const PrintInstance*> sort_object_instances_by_max_z(const Print &print)
|
static inline std::vector<const PrintInstance*> sort_object_instances_by_max_z(const Print &print)
|
||||||
{
|
{
|
||||||
std::vector<const PrintObject*> objects(print.objects().begin(), print.objects().end());
|
std::vector<const PrintObject*> objects(print.objects().begin(), print.objects().end());
|
||||||
std::sort(objects.begin(), objects.end(), [](const PrintObject *po1, const PrintObject *po2) { return po1->size(2) < po2->size(2); });
|
std::sort(objects.begin(), objects.end(), [](const PrintObject *po1, const PrintObject *po2) { return po1->size()(2) < po2->size()(2); });
|
||||||
std::vector<const PrintInstance*> instances;
|
std::vector<const PrintInstance*> instances;
|
||||||
instances.reserve(objects.size());
|
instances.reserve(objects.size());
|
||||||
for (const PrintObject *object : objects)
|
for (const PrintObject *object : objects)
|
||||||
|
|
|
@ -907,10 +907,8 @@ const BoundingBoxf3& ModelObject::raw_bounding_box() const
|
||||||
|
|
||||||
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
|
const Transform3d& inst_matrix = this->instances.front()->get_transformation().get_matrix(true);
|
||||||
for (const ModelVolume *v : this->volumes)
|
for (const ModelVolume *v : this->volumes)
|
||||||
{
|
|
||||||
if (v->is_model_part())
|
if (v->is_model_part())
|
||||||
m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
|
m_raw_bounding_box.merge(v->mesh().transformed_bounding_box(inst_matrix * v->get_matrix()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return m_raw_bounding_box;
|
return m_raw_bounding_box;
|
||||||
}
|
}
|
||||||
|
@ -1115,7 +1113,7 @@ ModelObjectPtrs ModelObject::cut(size_t instance, coordf_t z, bool keep_upper, b
|
||||||
if (keep_upper) {
|
if (keep_upper) {
|
||||||
upper->set_model(nullptr);
|
upper->set_model(nullptr);
|
||||||
upper->sla_support_points.clear();
|
upper->sla_support_points.clear();
|
||||||
lower->sla_drain_holes.clear();
|
upper->sla_drain_holes.clear();
|
||||||
upper->sla_points_status = sla::PointsStatus::NoPoints;
|
upper->sla_points_status = sla::PointsStatus::NoPoints;
|
||||||
upper->clear_volumes();
|
upper->clear_volumes();
|
||||||
upper->input_file = "";
|
upper->input_file = "";
|
||||||
|
|
|
@ -836,7 +836,7 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||||
// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
|
// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
|
||||||
assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved);
|
assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved);
|
||||||
// Check whether a model part volume was added or removed, their transformations or order changed.
|
// Check whether a model part volume was added or removed, their transformations or order changed.
|
||||||
// Only volume IDs, volume types and their order are checked, configuration and other parameters are NOT checked.
|
// Only volume IDs, volume types, transformation matrices and their order are checked, configuration and other parameters are NOT checked.
|
||||||
bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART);
|
bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART);
|
||||||
bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::PARAMETER_MODIFIER);
|
bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::PARAMETER_MODIFIER);
|
||||||
bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER);
|
bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER);
|
||||||
|
@ -899,10 +899,14 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||||
model_object.instances.emplace_back(new ModelInstance(*model_instance));
|
model_object.instances.emplace_back(new ModelInstance(*model_instance));
|
||||||
model_object.instances.back()->set_model_object(&model_object);
|
model_object.instances.back()->set_model_object(&model_object);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (! std::equal(model_object.instances.begin(), model_object.instances.end(), model_object_new.instances.begin(),
|
||||||
// Just synchronize the content of the instances. This avoids memory allocation and it does not invalidate ModelInstance pointers,
|
[](auto l, auto r){ return l->print_volume_state == r->print_volume_state && l->printable == r->printable &&
|
||||||
// which may be accessed by G-code export in the meanwhile to deduce sequential print order.
|
l->get_transformation().get_matrix().isApprox(r->get_transformation().get_matrix()); })) {
|
||||||
auto new_instance = model_object_new.instances.begin();
|
// If some of the instances changed, the bounding box of the updated ModelObject is likely no more valid.
|
||||||
|
// This is safe as the ModelObject's bounding box is only accessed from this function, which is called from the main thread only.
|
||||||
|
model_object.invalidate_bounding_box();
|
||||||
|
// Synchronize the content of instances.
|
||||||
|
auto new_instance = model_object_new.instances.begin();
|
||||||
for (auto old_instance = model_object.instances.begin(); old_instance != model_object.instances.end(); ++ old_instance, ++ new_instance) {
|
for (auto old_instance = model_object.instances.begin(); old_instance != model_object.instances.end(); ++ old_instance, ++ new_instance) {
|
||||||
(*old_instance)->set_transformation((*new_instance)->get_transformation());
|
(*old_instance)->set_transformation((*new_instance)->get_transformation());
|
||||||
(*old_instance)->print_volume_state = (*new_instance)->print_volume_state;
|
(*old_instance)->print_volume_state = (*new_instance)->print_volume_state;
|
||||||
|
@ -1197,7 +1201,7 @@ std::string Print::validate() const
|
||||||
{
|
{
|
||||||
std::vector<coord_t> object_height;
|
std::vector<coord_t> object_height;
|
||||||
for (const PrintObject *object : m_objects)
|
for (const PrintObject *object : m_objects)
|
||||||
object_height.insert(object_height.end(), object->instances().size(), object->size(2));
|
object_height.insert(object_height.end(), object->instances().size(), object->size()(2));
|
||||||
std::sort(object_height.begin(), object_height.end());
|
std::sort(object_height.begin(), object_height.end());
|
||||||
// Ignore the tallest *copy* (this is why we repeat height for all of them):
|
// Ignore the tallest *copy* (this is why we repeat height for all of them):
|
||||||
// it will be printed as last one so its height doesn't matter.
|
// it will be printed as last one so its height doesn't matter.
|
||||||
|
@ -1429,7 +1433,7 @@ BoundingBox Print::bounding_box() const
|
||||||
for (const PrintObject *object : m_objects)
|
for (const PrintObject *object : m_objects)
|
||||||
for (const PrintInstance &instance : object->instances()) {
|
for (const PrintInstance &instance : object->instances()) {
|
||||||
bb.merge(instance.shift);
|
bb.merge(instance.shift);
|
||||||
bb.merge(instance.shift + to_2d(object->size));
|
bb.merge(instance.shift + to_2d(object->size()));
|
||||||
}
|
}
|
||||||
return bb;
|
return bb;
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,17 +120,17 @@ public:
|
||||||
// so that next call to make_perimeters() performs a union() before computing loops
|
// so that next call to make_perimeters() performs a union() before computing loops
|
||||||
bool typed_slices;
|
bool typed_slices;
|
||||||
|
|
||||||
Vec3crd size; // XYZ in scaled coordinates
|
// XYZ in scaled coordinates
|
||||||
|
const Vec3crd& size() const { return m_size; }
|
||||||
const PrintObjectConfig& config() const { return m_config; }
|
const PrintObjectConfig& config() const { return m_config; }
|
||||||
const LayerPtrs& layers() const { return m_layers; }
|
const LayerPtrs& layers() const { return m_layers; }
|
||||||
const SupportLayerPtrs& support_layers() const { return m_support_layers; }
|
const SupportLayerPtrs& support_layers() const { return m_support_layers; }
|
||||||
const Transform3d& trafo() const { return m_trafo; }
|
const Transform3d& trafo() const { return m_trafo; }
|
||||||
const PrintInstances& instances() const { return m_instances; }
|
const PrintInstances& instances() const { return m_instances; }
|
||||||
const Point instance_center(size_t idx) const { return m_instances[idx].shift + m_copies_shift + Point(this->size.x() / 2, this->size.y() / 2); }
|
const Point instance_center(size_t idx) const { return m_instances[idx].shift + m_copies_shift + Point(this->size().x() / 2, this->size().y() / 2); }
|
||||||
|
|
||||||
// since the object is aligned to origin, bounding box coincides with size
|
// since the object is aligned to origin, bounding box coincides with size
|
||||||
BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size)); }
|
BoundingBox bounding_box() const { return BoundingBox(Point(0,0), to_2d(this->size())); }
|
||||||
|
|
||||||
// adds region_id, too, if necessary
|
// adds region_id, too, if necessary
|
||||||
void add_region_volume(unsigned int region_id, int volume_id, const t_layer_height_range &layer_range) {
|
void add_region_volume(unsigned int region_id, int volume_id, const t_layer_height_range &layer_range) {
|
||||||
|
@ -235,6 +235,8 @@ private:
|
||||||
void combine_infill();
|
void combine_infill();
|
||||||
void _generate_support_material();
|
void _generate_support_material();
|
||||||
|
|
||||||
|
// XYZ in scaled coordinates
|
||||||
|
Vec3crd m_size;
|
||||||
PrintObjectConfig m_config;
|
PrintObjectConfig m_config;
|
||||||
// Translation in Z + Rotation + Scaling / Mirroring.
|
// Translation in Z + Rotation + Scaling / Mirroring.
|
||||||
Transform3d m_trafo = Transform3d::Identity();
|
Transform3d m_trafo = Transform3d::Identity();
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace Slic3r {
|
||||||
PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_instances) :
|
PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_instances) :
|
||||||
PrintObjectBaseWithState(print, model_object),
|
PrintObjectBaseWithState(print, model_object),
|
||||||
typed_slices(false),
|
typed_slices(false),
|
||||||
size(Vec3crd::Zero())
|
m_size(Vec3crd::Zero())
|
||||||
{
|
{
|
||||||
// Compute the translation to be applied to our meshes so that we work with smaller coordinates
|
// Compute the translation to be applied to our meshes so that we work with smaller coordinates
|
||||||
{
|
{
|
||||||
|
@ -56,7 +56,7 @@ PrintObject::PrintObject(Print* print, ModelObject* model_object, bool add_insta
|
||||||
const BoundingBoxf3 modobj_bbox = model_object->raw_bounding_box();
|
const BoundingBoxf3 modobj_bbox = model_object->raw_bounding_box();
|
||||||
m_copies_shift = Point::new_scale(modobj_bbox.min(0), modobj_bbox.min(1));
|
m_copies_shift = Point::new_scale(modobj_bbox.min(0), modobj_bbox.min(1));
|
||||||
// Scale the object size and store it
|
// Scale the object size and store it
|
||||||
this->size = (modobj_bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
|
this->m_size = (modobj_bbox.size() * (1. / SCALING_FACTOR)).cast<coord_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (add_instances) {
|
if (add_instances) {
|
||||||
|
@ -1450,7 +1450,7 @@ void PrintObject::update_slicing_parameters()
|
||||||
{
|
{
|
||||||
if (! m_slicing_params.valid)
|
if (! m_slicing_params.valid)
|
||||||
m_slicing_params = SlicingParameters::create_from_config(
|
m_slicing_params = SlicingParameters::create_from_config(
|
||||||
this->print()->config(), m_config, unscale<double>(this->size(2)), this->object_extruders());
|
this->print()->config(), m_config, unscale<double>(this->size()(2)), this->object_extruders());
|
||||||
}
|
}
|
||||||
|
|
||||||
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z)
|
SlicingParameters PrintObject::slicing_parameters(const DynamicPrintConfig& full_config, const ModelObject& model_object, float object_max_z)
|
||||||
|
|
|
@ -678,7 +678,7 @@ void SLAPrint::process()
|
||||||
|
|
||||||
// We want to first process all objects...
|
// We want to first process all objects...
|
||||||
std::vector<SLAPrintObjectStep> level1_obj_steps = {
|
std::vector<SLAPrintObjectStep> level1_obj_steps = {
|
||||||
slaposHollowing, slaposObjectSlice, slaposSupportPoints, slaposSupportTree, slaposPad
|
slaposHollowing, slaposDrillHoles, slaposObjectSlice, slaposSupportPoints, slaposSupportTree, slaposPad
|
||||||
};
|
};
|
||||||
|
|
||||||
// and then slice all supports to allow preview to be displayed ASAP
|
// and then slice all supports to allow preview to be displayed ASAP
|
||||||
|
@ -984,10 +984,10 @@ bool SLAPrintObject::invalidate_step(SLAPrintObjectStep step)
|
||||||
// propagate to dependent steps
|
// propagate to dependent steps
|
||||||
if (step == slaposHollowing) {
|
if (step == slaposHollowing) {
|
||||||
invalidated |= this->invalidate_all_steps();
|
invalidated |= this->invalidate_all_steps();
|
||||||
} else if (step == slaposObjectSlice) {
|
} else if (step == slaposDrillHoles) {
|
||||||
invalidated |= this->invalidate_steps({ slaposDrillHolesIfHollowed, slaposSupportPoints, slaposSupportTree, slaposPad, slaposSliceSupports });
|
invalidated |= this->invalidate_steps({ slaposObjectSlice, slaposSupportPoints, slaposSupportTree, slaposPad, slaposSliceSupports });
|
||||||
invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval);
|
invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval);
|
||||||
} else if (step == slaposDrillHolesIfHollowed) {
|
} else if (step == slaposObjectSlice) {
|
||||||
invalidated |= this->invalidate_steps({ slaposSupportPoints, slaposSupportTree, slaposPad, slaposSliceSupports });
|
invalidated |= this->invalidate_steps({ slaposSupportPoints, slaposSupportTree, slaposPad, slaposSliceSupports });
|
||||||
invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval);
|
invalidated |= m_print->invalidate_step(slapsMergeSlicesAndEval);
|
||||||
} else if (step == slaposSupportPoints) {
|
} else if (step == slaposSupportPoints) {
|
||||||
|
|
|
@ -20,8 +20,8 @@ enum SLAPrintStep : unsigned int {
|
||||||
|
|
||||||
enum SLAPrintObjectStep : unsigned int {
|
enum SLAPrintObjectStep : unsigned int {
|
||||||
slaposHollowing,
|
slaposHollowing,
|
||||||
|
slaposDrillHoles,
|
||||||
slaposObjectSlice,
|
slaposObjectSlice,
|
||||||
slaposDrillHolesIfHollowed,
|
|
||||||
slaposSupportPoints,
|
slaposSupportPoints,
|
||||||
slaposSupportTree,
|
slaposSupportTree,
|
||||||
slaposPad,
|
slaposPad,
|
||||||
|
|
|
@ -26,9 +26,9 @@ namespace Slic3r {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const std::array<unsigned, slaposCount> OBJ_STEP_LEVELS = {
|
const std::array<unsigned, slaposCount> OBJ_STEP_LEVELS = {
|
||||||
5, // slaposHollowing,
|
10, // slaposHollowing,
|
||||||
20, // slaposObjectSlice,
|
10, // slaposDrillHolesIfHollowed
|
||||||
5, // slaposDrillHolesIfHollowed
|
10, // slaposObjectSlice,
|
||||||
20, // slaposSupportPoints,
|
20, // slaposSupportPoints,
|
||||||
10, // slaposSupportTree,
|
10, // slaposSupportTree,
|
||||||
10, // slaposPad,
|
10, // slaposPad,
|
||||||
|
@ -38,9 +38,9 @@ const std::array<unsigned, slaposCount> OBJ_STEP_LEVELS = {
|
||||||
std::string OBJ_STEP_LABELS(size_t idx)
|
std::string OBJ_STEP_LABELS(size_t idx)
|
||||||
{
|
{
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
case slaposHollowing: return L("Hollowing and drilling holes");
|
case slaposHollowing: return L("Hollowing model");
|
||||||
|
case slaposDrillHoles: return L("Drilling holes into hollowed model.");
|
||||||
case slaposObjectSlice: return L("Slicing model");
|
case slaposObjectSlice: return L("Slicing model");
|
||||||
case slaposDrillHolesIfHollowed: return L("Drilling holes into hollowed model.");
|
|
||||||
case slaposSupportPoints: return L("Generating support points");
|
case slaposSupportPoints: return L("Generating support points");
|
||||||
case slaposSupportTree: return L("Generating support tree");
|
case slaposSupportTree: return L("Generating support tree");
|
||||||
case slaposPad: return L("Generating pad");
|
case slaposPad: return L("Generating pad");
|
||||||
|
@ -80,57 +80,69 @@ SLAPrint::Steps::Steps(SLAPrint *print)
|
||||||
void SLAPrint::Steps::hollow_model(SLAPrintObject &po)
|
void SLAPrint::Steps::hollow_model(SLAPrintObject &po)
|
||||||
{
|
{
|
||||||
po.m_hollowing_data.reset();
|
po.m_hollowing_data.reset();
|
||||||
if (! po.m_config.hollowing_enable.getBool())
|
if (! po.m_config.hollowing_enable.getBool()) {
|
||||||
BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!";
|
BOOST_LOG_TRIVIAL(info) << "Skipping hollowing step!";
|
||||||
else {
|
return;
|
||||||
BOOST_LOG_TRIVIAL(info) << "Performing hollowing step!";
|
|
||||||
|
|
||||||
double thickness = po.m_config.hollowing_min_thickness.getFloat();
|
|
||||||
double quality = po.m_config.hollowing_quality.getFloat();
|
|
||||||
double closing_d = po.m_config.hollowing_closing_distance.getFloat();
|
|
||||||
sla::HollowingConfig hlwcfg{thickness, quality, closing_d};
|
|
||||||
auto meshptr = generate_interior(po.transformed_mesh(), hlwcfg);
|
|
||||||
|
|
||||||
if (meshptr->empty())
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "Hollowed interior is empty!";
|
|
||||||
else {
|
|
||||||
po.m_hollowing_data.reset(new SLAPrintObject::HollowingData());
|
|
||||||
po.m_hollowing_data->interior = *meshptr;
|
|
||||||
auto &hollowed_mesh = po.m_hollowing_data->hollow_mesh_with_holes;
|
|
||||||
hollowed_mesh = po.transformed_mesh();
|
|
||||||
hollowed_mesh.merge(po.m_hollowing_data->interior);
|
|
||||||
hollowed_mesh.require_shared_vertices();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Performing hollowing step!";
|
||||||
|
|
||||||
// Drill holes into the hollowed/original mesh.
|
double thickness = po.m_config.hollowing_min_thickness.getFloat();
|
||||||
if (po.m_model_object->sla_drain_holes.empty())
|
double quality = po.m_config.hollowing_quality.getFloat();
|
||||||
BOOST_LOG_TRIVIAL(info) << "Drilling skipped (no holes).";
|
double closing_d = po.m_config.hollowing_closing_distance.getFloat();
|
||||||
|
sla::HollowingConfig hlwcfg{thickness, quality, closing_d};
|
||||||
|
auto meshptr = generate_interior(po.transformed_mesh(), hlwcfg);
|
||||||
|
|
||||||
|
if (meshptr->empty())
|
||||||
|
BOOST_LOG_TRIVIAL(warning) << "Hollowed interior is empty!";
|
||||||
else {
|
else {
|
||||||
BOOST_LOG_TRIVIAL(info) << "Drilling drainage holes.";
|
po.m_hollowing_data.reset(new SLAPrintObject::HollowingData());
|
||||||
sla::DrainHoles drainholes = po.transformed_drainhole_points();
|
po.m_hollowing_data->interior = *meshptr;
|
||||||
|
auto &hollowed_mesh = po.m_hollowing_data->hollow_mesh_with_holes;
|
||||||
TriangleMesh holes_mesh;
|
hollowed_mesh = po.transformed_mesh();
|
||||||
|
hollowed_mesh.merge(po.m_hollowing_data->interior);
|
||||||
for (const sla::DrainHole &holept : drainholes)
|
|
||||||
holes_mesh.merge(sla::to_triangle_mesh(holept.to_mesh()));
|
|
||||||
|
|
||||||
holes_mesh.require_shared_vertices();
|
|
||||||
MeshBoolean::self_union(holes_mesh); //FIXME-fix and use the cgal version
|
|
||||||
|
|
||||||
// If there is no hollowed mesh yet, copy the original mesh.
|
|
||||||
if (! po.m_hollowing_data) {
|
|
||||||
po.m_hollowing_data.reset(new SLAPrintObject::HollowingData());
|
|
||||||
po.m_hollowing_data->hollow_mesh_with_holes = po.transformed_mesh();
|
|
||||||
}
|
|
||||||
|
|
||||||
TriangleMesh &hollowed_mesh = po.m_hollowing_data->hollow_mesh_with_holes;
|
|
||||||
hollowed_mesh = po.get_mesh_to_print();
|
|
||||||
MeshBoolean::cgal::minus(hollowed_mesh, holes_mesh);
|
|
||||||
hollowed_mesh.require_shared_vertices();
|
hollowed_mesh.require_shared_vertices();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SLAPrint::Steps::drill_holes(SLAPrintObject &po)
|
||||||
|
{
|
||||||
|
// Drill holes into the hollowed/original mesh.
|
||||||
|
if (po.m_model_object->sla_drain_holes.empty()) {
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Drilling skipped (no holes).";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG_TRIVIAL(info) << "Drilling drainage holes.";
|
||||||
|
sla::DrainHoles drainholes = po.transformed_drainhole_points();
|
||||||
|
|
||||||
|
TriangleMesh holes_mesh;
|
||||||
|
|
||||||
|
for (const sla::DrainHole &holept : drainholes)
|
||||||
|
holes_mesh.merge(sla::to_triangle_mesh(holept.to_mesh()));
|
||||||
|
|
||||||
|
holes_mesh.require_shared_vertices();
|
||||||
|
MeshBoolean::cgal::self_union(holes_mesh); //FIXME-fix and use the cgal version
|
||||||
|
|
||||||
|
// If there is no hollowed mesh yet, copy the original mesh.
|
||||||
|
if (! po.m_hollowing_data) {
|
||||||
|
po.m_hollowing_data.reset(new SLAPrintObject::HollowingData());
|
||||||
|
po.m_hollowing_data->hollow_mesh_with_holes = po.transformed_mesh();
|
||||||
|
}
|
||||||
|
|
||||||
|
TriangleMesh &hollowed_mesh = po.m_hollowing_data->hollow_mesh_with_holes;
|
||||||
|
|
||||||
|
try {
|
||||||
|
MeshBoolean::cgal::minus(hollowed_mesh, holes_mesh);
|
||||||
|
} catch (const std::runtime_error &ex) {
|
||||||
|
throw std::runtime_error(L(
|
||||||
|
"Drilling holes into the mesh failed. "
|
||||||
|
"This is usually caused by broken model. Try to fix it first."));
|
||||||
|
}
|
||||||
|
|
||||||
|
hollowed_mesh.require_shared_vertices();
|
||||||
|
}
|
||||||
|
|
||||||
// The slicing will be performed on an imaginary 1D grid which starts from
|
// The slicing will be performed on an imaginary 1D grid which starts from
|
||||||
// the bottom of the bounding box created around the supported model. So
|
// the bottom of the bounding box created around the supported model. So
|
||||||
// the first layer which is usually thicker will be part of the supports
|
// the first layer which is usually thicker will be part of the supports
|
||||||
|
@ -850,8 +862,8 @@ void SLAPrint::Steps::execute(SLAPrintObjectStep step, SLAPrintObject &obj)
|
||||||
{
|
{
|
||||||
switch(step) {
|
switch(step) {
|
||||||
case slaposHollowing: hollow_model(obj); break;
|
case slaposHollowing: hollow_model(obj); break;
|
||||||
|
case slaposDrillHoles: drill_holes(obj); break;
|
||||||
case slaposObjectSlice: slice_model(obj); break;
|
case slaposObjectSlice: slice_model(obj); break;
|
||||||
case slaposDrillHolesIfHollowed: break;
|
|
||||||
case slaposSupportPoints: support_points(obj); break;
|
case slaposSupportPoints: support_points(obj); break;
|
||||||
case slaposSupportTree: support_tree(obj); break;
|
case slaposSupportTree: support_tree(obj); break;
|
||||||
case slaposPad: generate_pad(obj); break;
|
case slaposPad: generate_pad(obj); break;
|
||||||
|
|
|
@ -44,6 +44,7 @@ public:
|
||||||
Steps(SLAPrint *print);
|
Steps(SLAPrint *print);
|
||||||
|
|
||||||
void hollow_model(SLAPrintObject &po);
|
void hollow_model(SLAPrintObject &po);
|
||||||
|
void drill_holes (SLAPrintObject &po);
|
||||||
void slice_model(SLAPrintObject& po);
|
void slice_model(SLAPrintObject& po);
|
||||||
void support_points(SLAPrintObject& po);
|
void support_points(SLAPrintObject& po);
|
||||||
void support_tree(SLAPrintObject& po);
|
void support_tree(SLAPrintObject& po);
|
||||||
|
|
|
@ -147,6 +147,8 @@ set(SLIC3R_GUI_SOURCES
|
||||||
GUI/Mouse3DController.hpp
|
GUI/Mouse3DController.hpp
|
||||||
GUI/DoubleSlider.cpp
|
GUI/DoubleSlider.cpp
|
||||||
GUI/DoubleSlider.hpp
|
GUI/DoubleSlider.hpp
|
||||||
|
GUI/ObjectDataViewModel.cpp
|
||||||
|
GUI/ObjectDataViewModel.hpp
|
||||||
Utils/Http.cpp
|
Utils/Http.cpp
|
||||||
Utils/Http.hpp
|
Utils/Http.hpp
|
||||||
Utils/FixModelByWin10.cpp
|
Utils/FixModelByWin10.cpp
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include "libslic3r/SLAPrint.hpp"
|
#include "libslic3r/SLAPrint.hpp"
|
||||||
#include "libslic3r/Slicing.hpp"
|
#include "libslic3r/Slicing.hpp"
|
||||||
#include "libslic3r/GCode/Analyzer.hpp"
|
#include "libslic3r/GCode/Analyzer.hpp"
|
||||||
#include "slic3r/GUI/PresetBundle.hpp"
|
#include "slic3r/GUI/BitmapCache.hpp"
|
||||||
#include "libslic3r/Format/STL.hpp"
|
#include "libslic3r/Format/STL.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
|
|
||||||
|
@ -792,14 +792,14 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con
|
||||||
for (unsigned int i = 0; i < colors_count; ++i)
|
for (unsigned int i = 0; i < colors_count; ++i)
|
||||||
{
|
{
|
||||||
const std::string& txt_color = config->opt_string("extruder_colour", i);
|
const std::string& txt_color = config->opt_string("extruder_colour", i);
|
||||||
if (PresetBundle::parse_color(txt_color, rgb))
|
if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
|
||||||
{
|
{
|
||||||
colors[i].set(txt_color, rgb);
|
colors[i].set(txt_color, rgb);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const std::string& txt_color = config->opt_string("filament_colour", i);
|
const std::string& txt_color = config->opt_string("filament_colour", i);
|
||||||
if (PresetBundle::parse_color(txt_color, rgb))
|
if (Slic3r::GUI::BitmapCache::parse_color(txt_color, rgb))
|
||||||
colors[i].set(txt_color, rgb);
|
colors[i].set(txt_color, rgb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
#include "BitmapCache.hpp"
|
#include "BitmapCache.hpp"
|
||||||
|
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
|
#include "../Utils/MacDarkMode.hpp"
|
||||||
|
#include "GUI.hpp"
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
#if ! defined(WIN32) && ! defined(__APPLE__)
|
#if ! defined(WIN32) && ! defined(__APPLE__)
|
||||||
|
@ -20,6 +23,16 @@
|
||||||
|
|
||||||
namespace Slic3r { namespace GUI {
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
|
BitmapCache::BitmapCache()
|
||||||
|
{
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// Note: win->GetContentScaleFactor() is not used anymore here because it tends to
|
||||||
|
// return bogus results quite often (such as 1.0 on Retina or even 0.0).
|
||||||
|
// We're using the max scaling factor across all screens because it's very likely to be good enough.
|
||||||
|
m_scale = mac_max_scaling_factor();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void BitmapCache::clear()
|
void BitmapCache::clear()
|
||||||
{
|
{
|
||||||
for (std::pair<const std::string, wxBitmap*> &bitmap : m_map)
|
for (std::pair<const std::string, wxBitmap*> &bitmap : m_map)
|
||||||
|
@ -49,7 +62,7 @@ static wxBitmap wxImage_to_wxBitmap_with_alpha(wxImage &&image, float scale = 1.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height, float scale/* = 1.0f*/)
|
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height)
|
||||||
{
|
{
|
||||||
wxBitmap *bitmap = nullptr;
|
wxBitmap *bitmap = nullptr;
|
||||||
auto it = m_map.find(bitmap_key);
|
auto it = m_map.find(bitmap_key);
|
||||||
|
@ -61,7 +74,7 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_
|
||||||
// So, We need to let the Mac OS wxBitmap implementation
|
// So, We need to let the Mac OS wxBitmap implementation
|
||||||
// know that the image may already be scaled appropriately for Retina,
|
// know that the image may already be scaled appropriately for Retina,
|
||||||
// and thereby that it's not supposed to upscale it.
|
// and thereby that it's not supposed to upscale it.
|
||||||
bitmap->CreateScaled(width, height, -1, scale);
|
bitmap->CreateScaled(width, height, -1, m_scale);
|
||||||
#endif
|
#endif
|
||||||
m_map[bitmap_key] = bitmap;
|
m_map[bitmap_key] = bitmap;
|
||||||
} else {
|
} else {
|
||||||
|
@ -103,13 +116,18 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp
|
||||||
return this->insert(bitmap_key, bmps, bmps + 3);
|
return this->insert(bitmap_key, bmps, bmps + 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *begin, const wxBitmap *end, float scale/* = 1.0f*/)
|
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *begin, const wxBitmap *end)
|
||||||
{
|
{
|
||||||
size_t width = 0;
|
size_t width = 0;
|
||||||
size_t height = 0;
|
size_t height = 0;
|
||||||
for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) {
|
for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
width += bmp->GetScaledWidth();
|
||||||
|
height = std::max<size_t>(height, bmp->GetScaledHeight());
|
||||||
|
#else
|
||||||
width += bmp->GetWidth();
|
width += bmp->GetWidth();
|
||||||
height = std::max<size_t>(height, bmp->GetHeight());
|
height = std::max<size_t>(height, bmp->GetHeight());
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef BROKEN_ALPHA
|
#ifdef BROKEN_ALPHA
|
||||||
|
@ -166,13 +184,7 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#ifdef __APPLE__
|
wxBitmap *bitmap = this->insert(bitmap_key, width, height);
|
||||||
// Note, for this moment width and height are scaled, so divide them by scale to avoid one more multiplication inside CreateScaled()
|
|
||||||
width *= 1.0 / scale;
|
|
||||||
height *= 1.0 / scale;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wxBitmap *bitmap = this->insert(bitmap_key, width, height, scale);
|
|
||||||
wxMemoryDC memDC;
|
wxMemoryDC memDC;
|
||||||
memDC.SelectObject(*bitmap);
|
memDC.SelectObject(*bitmap);
|
||||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||||
|
@ -181,8 +193,12 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg
|
||||||
for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) {
|
for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) {
|
||||||
if (bmp->GetWidth() > 0)
|
if (bmp->GetWidth() > 0)
|
||||||
memDC.DrawBitmap(*bmp, x, 0, true);
|
memDC.DrawBitmap(*bmp, x, 0, true);
|
||||||
|
#ifdef __APPLE__
|
||||||
// we should "move" with step equal to non-scaled width
|
// we should "move" with step equal to non-scaled width
|
||||||
x += bmp->GetWidth()/scale;
|
x += bmp->GetScaledWidth();
|
||||||
|
#else
|
||||||
|
x += bmp->GetWidth();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
memDC.SelectObject(wxNullBitmap);
|
memDC.SelectObject(wxNullBitmap);
|
||||||
return bitmap;
|
return bitmap;
|
||||||
|
@ -190,7 +206,7 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, float scale /* = 1.0f */, const bool grayscale/* = false*/)
|
wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, const bool grayscale/* = false*/)
|
||||||
{
|
{
|
||||||
wxImage image(width, height);
|
wxImage image(width, height);
|
||||||
image.InitAlpha();
|
image.InitAlpha();
|
||||||
|
@ -207,7 +223,7 @@ wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned w
|
||||||
if (grayscale)
|
if (grayscale)
|
||||||
image = image.ConvertToGreyscale(m_gs, m_gs, m_gs);
|
image = image.ConvertToGreyscale(m_gs, m_gs, m_gs);
|
||||||
|
|
||||||
return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image), scale));
|
return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image), m_scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width, unsigned height,
|
wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width, unsigned height,
|
||||||
|
@ -242,12 +258,12 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned width,
|
||||||
}
|
}
|
||||||
|
|
||||||
wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_width, unsigned target_height,
|
wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_width, unsigned target_height,
|
||||||
float scale /* = 1.0f */, const bool grayscale/* = false*/, const bool dark_mode/* = false*/)
|
const bool grayscale/* = false*/, const bool dark_mode/* = false*/)
|
||||||
{
|
{
|
||||||
std::string bitmap_key = bitmap_name + ( target_height !=0 ?
|
std::string bitmap_key = bitmap_name + ( target_height !=0 ?
|
||||||
"-h" + std::to_string(target_height) :
|
"-h" + std::to_string(target_height) :
|
||||||
"-w" + std::to_string(target_width))
|
"-w" + std::to_string(target_width))
|
||||||
+ (scale != 1.0f ? "-s" + std::to_string(scale) : "")
|
+ (m_scale != 1.0f ? "-s" + std::to_string(m_scale) : "")
|
||||||
+ (grayscale ? "-gs" : "");
|
+ (grayscale ? "-gs" : "");
|
||||||
|
|
||||||
/* For the Dark mode of any platform, we should draw icons in respect to OS background
|
/* For the Dark mode of any platform, we should draw icons in respect to OS background
|
||||||
|
@ -287,7 +303,7 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_
|
||||||
if (image == nullptr)
|
if (image == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
target_height != 0 ? target_height *= scale : target_width *= scale;
|
target_height != 0 ? target_height *= m_scale : target_width *= m_scale;
|
||||||
|
|
||||||
float svg_scale = target_height != 0 ?
|
float svg_scale = target_height != 0 ?
|
||||||
(float)target_height / image->height : target_width != 0 ?
|
(float)target_height / image->height : target_width != 0 ?
|
||||||
|
@ -312,11 +328,16 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_
|
||||||
::nsvgDeleteRasterizer(rast);
|
::nsvgDeleteRasterizer(rast);
|
||||||
::nsvgDelete(image);
|
::nsvgDelete(image);
|
||||||
|
|
||||||
return this->insert_raw_rgba(bitmap_key, width, height, data.data(), scale, grayscale);
|
return this->insert_raw_rgba(bitmap_key, width, height, data.data(), grayscale);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency)
|
//we make scaled solid bitmaps only for the cases, when its will be used with scaled SVG icon in one output bitmap
|
||||||
|
wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, bool suppress_scaling/* = false*/)
|
||||||
{
|
{
|
||||||
|
double scale = suppress_scaling ? 1.0f : m_scale;
|
||||||
|
width *= scale;
|
||||||
|
height *= scale;
|
||||||
|
|
||||||
wxImage image(width, height);
|
wxImage image(width, height);
|
||||||
image.InitAlpha();
|
image.InitAlpha();
|
||||||
unsigned char* imgdata = image.GetData();
|
unsigned char* imgdata = image.GetData();
|
||||||
|
@ -327,7 +348,32 @@ wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsi
|
||||||
*imgdata ++ = b;
|
*imgdata ++ = b;
|
||||||
*imgalpha ++ = transparency;
|
*imgalpha ++ = transparency;
|
||||||
}
|
}
|
||||||
return wxImage_to_wxBitmap_with_alpha(std::move(image));
|
return wxImage_to_wxBitmap_with_alpha(std::move(image), scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int hex_digit_to_int(const char c)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
(c >= '0' && c <= '9') ? int(c - '0') :
|
||||||
|
(c >= 'A' && c <= 'F') ? int(c - 'A') + 10 :
|
||||||
|
(c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BitmapCache::parse_color(const std::string& scolor, unsigned char* rgb_out)
|
||||||
|
{
|
||||||
|
rgb_out[0] = rgb_out[1] = rgb_out[2] = 0;
|
||||||
|
if (scolor.size() != 7 || scolor.front() != '#')
|
||||||
|
return false;
|
||||||
|
const char* c = scolor.data() + 1;
|
||||||
|
for (size_t i = 0; i < 3; ++i) {
|
||||||
|
int digit1 = hex_digit_to_int(*c++);
|
||||||
|
int digit2 = hex_digit_to_int(*c++);
|
||||||
|
if (digit1 == -1 || digit2 == -1)
|
||||||
|
return false;
|
||||||
|
rgb_out[i] = (unsigned char)(digit1 * 16 + digit2);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
|
|
|
@ -6,43 +6,42 @@
|
||||||
#include <wx/wx.h>
|
#include <wx/wx.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "libslic3r/libslic3r.h"
|
|
||||||
#include "libslic3r/Config.hpp"
|
|
||||||
|
|
||||||
#include "GUI.hpp"
|
|
||||||
|
|
||||||
namespace Slic3r { namespace GUI {
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
class BitmapCache
|
class BitmapCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
BitmapCache() {}
|
BitmapCache();
|
||||||
~BitmapCache() { clear(); }
|
~BitmapCache() { clear(); }
|
||||||
void clear();
|
void clear();
|
||||||
|
double scale() { return m_scale; }
|
||||||
|
|
||||||
wxBitmap* find(const std::string &name) { auto it = m_map.find(name); return (it == m_map.end()) ? nullptr : it->second; }
|
wxBitmap* find(const std::string &name) { auto it = m_map.find(name); return (it == m_map.end()) ? nullptr : it->second; }
|
||||||
const wxBitmap* find(const std::string &name) const { return const_cast<BitmapCache*>(this)->find(name); }
|
const wxBitmap* find(const std::string &name) const { return const_cast<BitmapCache*>(this)->find(name); }
|
||||||
|
|
||||||
wxBitmap* insert(const std::string &name, size_t width, size_t height, float scale = 1.0f);
|
wxBitmap* insert(const std::string &name, size_t width, size_t height);
|
||||||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp);
|
wxBitmap* insert(const std::string &name, const wxBitmap &bmp);
|
||||||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2);
|
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2);
|
||||||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3);
|
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3);
|
||||||
wxBitmap* insert(const std::string &name, const std::vector<wxBitmap> &bmps, float scale = 1.0f) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size(), scale); }
|
wxBitmap* insert(const std::string &name, const std::vector<wxBitmap> &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); }
|
||||||
wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end, float scale = 1.0f);
|
wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end);
|
||||||
wxBitmap* insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, float scale = 1.0f, const bool grayscale = false);
|
wxBitmap* insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, const bool grayscale = false);
|
||||||
|
|
||||||
// Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height/width if nonzero.
|
// Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height/width if nonzero.
|
||||||
wxBitmap* load_png(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false);
|
wxBitmap* load_png(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false);
|
||||||
// Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height/width.
|
// Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height/width.
|
||||||
wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, float scale = 1.0f, const bool grayscale = false, const bool dark_mode = false);
|
wxBitmap* load_svg(const std::string &bitmap_key, unsigned width = 0, unsigned height = 0, const bool grayscale = false, const bool dark_mode = false);
|
||||||
|
|
||||||
static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency);
|
/*static */wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency, bool suppress_scaling = false);
|
||||||
static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }
|
/*static */wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3], bool suppress_scaling = false) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }
|
||||||
static wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); }
|
/*static */wxBitmap mkclear(size_t width, size_t height) { return mksolid(width, height, 0, 0, 0, wxALPHA_TRANSPARENT); }
|
||||||
|
|
||||||
|
static bool parse_color(const std::string& scolor, unsigned char* rgb_out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<std::string, wxBitmap*> m_map;
|
std::map<std::string, wxBitmap*> m_map;
|
||||||
double m_gs = 0.2; // value, used for image.ConvertToGreyscale(m_gs, m_gs, m_gs)
|
double m_gs = 0.2; // value, used for image.ConvertToGreyscale(m_gs, m_gs, m_gs)
|
||||||
|
double m_scale = 1.0; // value, used for correct scaling of SVG icons on Retina display
|
||||||
};
|
};
|
||||||
|
|
||||||
} // GUI
|
} // GUI
|
||||||
|
|
|
@ -52,28 +52,26 @@ Control::Control( wxWindow *parent,
|
||||||
if (!is_osx)
|
if (!is_osx)
|
||||||
SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX
|
SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX
|
||||||
|
|
||||||
const float scale_factor = get_svg_scale_factor(this);
|
|
||||||
|
|
||||||
m_bmp_thumb_higher = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "right_half_circle.png") : ScalableBitmap(this, "thumb_up"));
|
m_bmp_thumb_higher = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "right_half_circle.png") : ScalableBitmap(this, "thumb_up"));
|
||||||
m_bmp_thumb_lower = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "left_half_circle.png" ) : ScalableBitmap(this, "thumb_down"));
|
m_bmp_thumb_lower = (style == wxSL_HORIZONTAL ? ScalableBitmap(this, "left_half_circle.png" ) : ScalableBitmap(this, "thumb_down"));
|
||||||
m_thumb_size = m_bmp_thumb_lower.bmp().GetSize()*(1.0/scale_factor);
|
m_thumb_size = m_bmp_thumb_lower.GetBmpSize();
|
||||||
|
|
||||||
m_bmp_add_tick_on = ScalableBitmap(this, "colorchange_add");
|
m_bmp_add_tick_on = ScalableBitmap(this, "colorchange_add");
|
||||||
m_bmp_add_tick_off = ScalableBitmap(this, "colorchange_add_f");
|
m_bmp_add_tick_off = ScalableBitmap(this, "colorchange_add_f");
|
||||||
m_bmp_del_tick_on = ScalableBitmap(this, "colorchange_del");
|
m_bmp_del_tick_on = ScalableBitmap(this, "colorchange_del");
|
||||||
m_bmp_del_tick_off = ScalableBitmap(this, "colorchange_del_f");
|
m_bmp_del_tick_off = ScalableBitmap(this, "colorchange_del_f");
|
||||||
m_tick_icon_dim = int((float)m_bmp_add_tick_on.bmp().GetSize().x / scale_factor);
|
m_tick_icon_dim = m_bmp_add_tick_on.GetBmpWidth();
|
||||||
|
|
||||||
m_bmp_one_layer_lock_on = ScalableBitmap(this, "lock_closed");
|
m_bmp_one_layer_lock_on = ScalableBitmap(this, "lock_closed");
|
||||||
m_bmp_one_layer_lock_off = ScalableBitmap(this, "lock_closed_f");
|
m_bmp_one_layer_lock_off = ScalableBitmap(this, "lock_closed_f");
|
||||||
m_bmp_one_layer_unlock_on = ScalableBitmap(this, "lock_open");
|
m_bmp_one_layer_unlock_on = ScalableBitmap(this, "lock_open");
|
||||||
m_bmp_one_layer_unlock_off = ScalableBitmap(this, "lock_open_f");
|
m_bmp_one_layer_unlock_off = ScalableBitmap(this, "lock_open_f");
|
||||||
m_lock_icon_dim = int((float)m_bmp_one_layer_lock_on.bmp().GetSize().x / scale_factor);
|
m_lock_icon_dim = m_bmp_one_layer_lock_on.GetBmpWidth();
|
||||||
|
|
||||||
m_bmp_revert = ScalableBitmap(this, "undo");
|
m_bmp_revert = ScalableBitmap(this, "undo");
|
||||||
m_revert_icon_dim = int((float)m_bmp_revert.bmp().GetSize().x / scale_factor);
|
m_revert_icon_dim = m_bmp_revert.GetBmpWidth();
|
||||||
m_bmp_cog = ScalableBitmap(this, "cog");
|
m_bmp_cog = ScalableBitmap(this, "cog");
|
||||||
m_cog_icon_dim = int((float)m_bmp_cog.bmp().GetSize().x / scale_factor);
|
m_cog_icon_dim = m_bmp_cog.GetBmpWidth();
|
||||||
|
|
||||||
m_selection = ssUndef;
|
m_selection = ssUndef;
|
||||||
m_ticks.set_pause_print_msg(_utf8(L("Place bearings in slots and resume")));
|
m_ticks.set_pause_print_msg(_utf8(L("Place bearings in slots and resume")));
|
||||||
|
@ -554,9 +552,9 @@ void Control::draw_ticks(wxDC& dc)
|
||||||
|
|
||||||
// Draw icon for "Pause print" or "Custom Gcode"
|
// Draw icon for "Pause print" or "Custom Gcode"
|
||||||
if (tick.gcode != ColorChangeCode && tick.gcode != ToolChangeCode)
|
if (tick.gcode != ColorChangeCode && tick.gcode != ToolChangeCode)
|
||||||
icon = create_scaled_bitmap(this, tick.gcode == PausePrintCode ? "pause_print" : "edit_gcode");
|
icon = create_scaled_bitmap(tick.gcode == PausePrintCode ? "pause_print" : "edit_gcode");
|
||||||
else if (m_ticks.is_conflict_tick(tick, m_mode, m_only_extruder, m_values[tick.tick]))
|
else if (m_ticks.is_conflict_tick(tick, m_mode, m_only_extruder, m_values[tick.tick]))
|
||||||
icon = create_scaled_bitmap(this, "error_tick");
|
icon = create_scaled_bitmap("error_tick");
|
||||||
|
|
||||||
if (!icon.IsNull())
|
if (!icon.IsNull())
|
||||||
{
|
{
|
||||||
|
@ -937,9 +935,12 @@ wxString Control::get_tooltip(IconFocus icon_focus)
|
||||||
if (conflict == ctModeConflict)
|
if (conflict == ctModeConflict)
|
||||||
tooltip += _(L("G-code of this tick has a conflict with slider(print) mode.\n"
|
tooltip += _(L("G-code of this tick has a conflict with slider(print) mode.\n"
|
||||||
"Any its editing will cause a changes of DoubleSlider data."));
|
"Any its editing will cause a changes of DoubleSlider data."));
|
||||||
else if (conflict == ctMeaningless)
|
else if (conflict == ctMeaninglessColorChange)
|
||||||
tooltip += _(L("There is a color change for extruder that wouldn't be used till the end of printing.\n"
|
tooltip += _(L("There is a color change for extruder that wouldn't be used till the end of printing.\n"
|
||||||
"This code wouldn't be processed during GCode generation."));
|
"This code wouldn't be processed during GCode generation."));
|
||||||
|
else if (conflict == ctMeaninglessToolChange)
|
||||||
|
tooltip += _(L("There is a extruder change to the same extruder.\n"
|
||||||
|
"This code wouldn't be processed during GCode generation."));
|
||||||
else if (conflict == ctRedundant)
|
else if (conflict == ctRedundant)
|
||||||
tooltip += _(L("There is a color change for extruder that has not been used before.\n"
|
tooltip += _(L("There is a color change for extruder that has not been used before.\n"
|
||||||
"Check your choice to avoid redundant color changes."));
|
"Check your choice to avoid redundant color changes."));
|
||||||
|
@ -1028,7 +1029,7 @@ void Control::append_change_extruder_menu_item(wxMenu* menu, bool switch_current
|
||||||
_(L("Change extruder (N/A)"));
|
_(L("Change extruder (N/A)"));
|
||||||
|
|
||||||
wxMenuItem* change_extruder_menu_item = menu->AppendSubMenu(change_extruder_menu, change_extruder_menu_name, _(L("Use another extruder")));
|
wxMenuItem* change_extruder_menu_item = menu->AppendSubMenu(change_extruder_menu, change_extruder_menu_name, _(L("Use another extruder")));
|
||||||
change_extruder_menu_item->SetBitmap(create_scaled_bitmap(this, active_extruders[1] > 0 ? "edit_uni" : "change_extruder"));
|
change_extruder_menu_item->SetBitmap(create_scaled_bitmap(active_extruders[1] > 0 ? "edit_uni" : "change_extruder"));
|
||||||
|
|
||||||
GUI::wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this, change_extruder_menu_item](wxUpdateUIEvent& evt) {
|
GUI::wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this, change_extruder_menu_item](wxUpdateUIEvent& evt) {
|
||||||
enable_menu_item(evt, [this]() {return m_mode == t_mode::MultiAsSingle; }, change_extruder_menu_item, this); },
|
enable_menu_item(evt, [this]() {return m_mode == t_mode::MultiAsSingle; }, change_extruder_menu_item, this); },
|
||||||
|
@ -1062,7 +1063,7 @@ void Control::append_add_color_change_menu_item(wxMenu* menu, bool switch_curren
|
||||||
from_u8((boost::format(_utf8(L("Switch code to Color change (%1%) for:"))) % ColorChangeCode).str()) :
|
from_u8((boost::format(_utf8(L("Switch code to Color change (%1%) for:"))) % ColorChangeCode).str()) :
|
||||||
from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % ColorChangeCode).str());
|
from_u8((boost::format(_utf8(L("Add color change (%1%) for:"))) % ColorChangeCode).str());
|
||||||
wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, "");
|
wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, "");
|
||||||
add_color_change_menu_item->SetBitmap(create_scaled_bitmap(this, "colorchange_add_m"));
|
add_color_change_menu_item->SetBitmap(create_scaled_bitmap("colorchange_add_m"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1837,12 +1838,12 @@ ConflictType TickCodeInfo::is_conflict_tick(const TickCode& tick, t_mode out_mod
|
||||||
// check ColorChange tick
|
// check ColorChange tick
|
||||||
if (tick.gcode == ColorChangeCode)
|
if (tick.gcode == ColorChangeCode)
|
||||||
{
|
{
|
||||||
// We should mark a tick as a "Meaningless",
|
// We should mark a tick as a "MeaninglessColorChange",
|
||||||
// if it has a ColorChange for unused extruder from current print to end of the print
|
// if it has a ColorChange for unused extruder from current print to end of the print
|
||||||
std::set<int> used_extruders_for_tick = get_used_extruders_for_tick(tick.tick, only_extruder, print_z);
|
std::set<int> used_extruders_for_tick = get_used_extruders_for_tick(tick.tick, only_extruder, print_z);
|
||||||
|
|
||||||
if (used_extruders_for_tick.find(tick.extruder) == used_extruders_for_tick.end())
|
if (used_extruders_for_tick.find(tick.extruder) == used_extruders_for_tick.end())
|
||||||
return ctMeaningless;
|
return ctMeaninglessColorChange;
|
||||||
|
|
||||||
// We should mark a tick as a "Redundant",
|
// We should mark a tick as a "Redundant",
|
||||||
// if it has a ColorChange for extruder that has not been used before
|
// if it has a ColorChange for extruder that has not been used before
|
||||||
|
@ -1862,6 +1863,21 @@ ConflictType TickCodeInfo::is_conflict_tick(const TickCode& tick, t_mode out_mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check ToolChange tick
|
||||||
|
if (mode == t_mode::MultiAsSingle && tick.gcode == ToolChangeCode)
|
||||||
|
{
|
||||||
|
// We should mark a tick as a "MeaninglessToolChange",
|
||||||
|
// if it has a ToolChange to the same extruder
|
||||||
|
|
||||||
|
auto it = ticks.find(tick);
|
||||||
|
if (it == ticks.begin())
|
||||||
|
return tick.extruder == std::max<int>(only_extruder, 1) ? ctMeaninglessToolChange : ctNone;
|
||||||
|
|
||||||
|
--it;
|
||||||
|
if (it->gcode == ToolChangeCode && tick.extruder == it->extruder)
|
||||||
|
return ctMeaninglessToolChange;
|
||||||
|
}
|
||||||
|
|
||||||
return ctNone;
|
return ctNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,8 @@ enum ConflictType
|
||||||
{
|
{
|
||||||
ctNone,
|
ctNone,
|
||||||
ctModeConflict,
|
ctModeConflict,
|
||||||
ctMeaningless,
|
ctMeaninglessColorChange,
|
||||||
|
ctMeaninglessToolChange,
|
||||||
ctRedundant
|
ctRedundant
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1399,6 +1399,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
||||||
wxDEFINE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
|
wxDEFINE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
|
||||||
wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
|
wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
|
||||||
wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
|
wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
|
||||||
|
wxDEFINE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
|
||||||
|
|
||||||
#if ENABLE_THUMBNAIL_GENERATOR
|
#if ENABLE_THUMBNAIL_GENERATOR
|
||||||
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
|
const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25;
|
||||||
|
@ -1855,7 +1856,11 @@ void GLCanvas3D::render()
|
||||||
|
|
||||||
const Size& cnv_size = get_canvas_size();
|
const Size& cnv_size = get_canvas_size();
|
||||||
#if ENABLE_6DOF_CAMERA
|
#if ENABLE_6DOF_CAMERA
|
||||||
m_camera.apply_viewport(0, 0, (unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height());
|
// Probably due to different order of events on Linux/GTK2, when one switched from 3D scene
|
||||||
|
// to preview, this was called before canvas had its final size. It reported zero width
|
||||||
|
// and the viewport was set incorrectly, leading to tripping glAsserts further down
|
||||||
|
// the road (in apply_projection). That's why the minimum size is forced to 10.
|
||||||
|
m_camera.apply_viewport(0, 0, std::max(10u, (unsigned int)cnv_size.get_width()), std::max(10u, (unsigned int)cnv_size.get_height()));
|
||||||
#endif // ENABLE_6DOF_CAMERA
|
#endif // ENABLE_6DOF_CAMERA
|
||||||
|
|
||||||
if (m_camera.requires_zoom_to_bed)
|
if (m_camera.requires_zoom_to_bed)
|
||||||
|
@ -2769,6 +2774,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
|
||||||
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE));
|
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE));
|
||||||
break;
|
break;
|
||||||
case WXK_ESCAPE: { deselect_all(); break; }
|
case WXK_ESCAPE: { deselect_all(); break; }
|
||||||
|
case WXK_F5: { post_event(SimpleEvent(EVT_GLCANVAS_RELOAD_FROM_DISK)); break; }
|
||||||
case '0': { select_view("iso"); break; }
|
case '0': { select_view("iso"); break; }
|
||||||
case '1': { select_view("top"); break; }
|
case '1': { select_view("top"); break; }
|
||||||
case '2': { select_view("bottom"); break; }
|
case '2': { select_view("bottom"); break; }
|
||||||
|
|
|
@ -108,6 +108,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
||||||
wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
|
wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent);
|
||||||
wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
|
wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event<float>);
|
||||||
wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
|
wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent);
|
||||||
|
wxDECLARE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent);
|
||||||
|
|
||||||
class GLCanvas3D
|
class GLCanvas3D
|
||||||
{
|
{
|
||||||
|
|
|
@ -90,20 +90,20 @@ ObjectList::ObjectList(wxWindow* parent) :
|
||||||
// see note in PresetBundle::load_compatible_bitmaps()
|
// see note in PresetBundle::load_compatible_bitmaps()
|
||||||
|
|
||||||
// ptFFF
|
// ptFFF
|
||||||
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap(this, "layers");
|
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap("layers");
|
||||||
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap(this, "infill");
|
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill");
|
||||||
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap(this, "support");
|
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap("support");
|
||||||
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap(this, "time");
|
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap("time");
|
||||||
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap(this, "funnel");
|
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap("funnel");
|
||||||
CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap(this, "funnel");
|
CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap("funnel");
|
||||||
CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap(this, "funnel");
|
CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap("funnel");
|
||||||
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap(this, "skirt+brim");
|
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap("skirt+brim");
|
||||||
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap(this, "time");
|
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap("time");
|
||||||
CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap(this, "wrench");
|
CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap("wrench");
|
||||||
// ptSLA
|
// ptSLA
|
||||||
CATEGORY_ICON[L("Supports")] = create_scaled_bitmap(this, "support"/*"sla_supports"*/);
|
CATEGORY_ICON[L("Supports")] = create_scaled_bitmap("support"/*"sla_supports"*/);
|
||||||
CATEGORY_ICON[L("Pad")] = create_scaled_bitmap(this, "pad");
|
CATEGORY_ICON[L("Pad")] = create_scaled_bitmap("pad");
|
||||||
CATEGORY_ICON[L("Hollowing")] = create_scaled_bitmap(this, "hollowing");
|
CATEGORY_ICON[L("Hollowing")] = create_scaled_bitmap("hollowing");
|
||||||
}
|
}
|
||||||
|
|
||||||
// create control
|
// create control
|
||||||
|
@ -607,23 +607,20 @@ void ObjectList::msw_rescale_icons()
|
||||||
|
|
||||||
// Update CATEGORY_ICON according to new scale
|
// Update CATEGORY_ICON according to new scale
|
||||||
{
|
{
|
||||||
// Note: `this` isn't passed to create_scaled_bitmap() here because of bugs in the widget,
|
|
||||||
// see note in PresetBundle::load_compatible_bitmaps()
|
|
||||||
|
|
||||||
// ptFFF
|
// ptFFF
|
||||||
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap(nullptr, "layers");
|
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap("layers");
|
||||||
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap(nullptr, "infill");
|
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill");
|
||||||
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap(nullptr, "support");
|
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap("support");
|
||||||
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap(nullptr, "time");
|
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap("time");
|
||||||
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap(nullptr, "funnel");
|
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap("funnel");
|
||||||
CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap(nullptr, "funnel");
|
CATEGORY_ICON[L("Extrusion Width")] = create_scaled_bitmap("funnel");
|
||||||
CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap(nullptr, "funnel");
|
CATEGORY_ICON[L("Wipe options")] = create_scaled_bitmap("funnel");
|
||||||
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap(nullptr, "skirt+brim");
|
// CATEGORY_ICON[L("Skirt and brim")] = create_scaled_bitmap("skirt+brim");
|
||||||
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap(nullptr, "time");
|
// CATEGORY_ICON[L("Speed > Acceleration")] = create_scaled_bitmap("time");
|
||||||
CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap(nullptr, "wrench");
|
CATEGORY_ICON[L("Advanced")] = create_scaled_bitmap("wrench");
|
||||||
// ptSLA
|
// ptSLA
|
||||||
CATEGORY_ICON[L("Supports")] = create_scaled_bitmap(nullptr, "support"/*"sla_supports"*/);
|
CATEGORY_ICON[L("Supports")] = create_scaled_bitmap("support"/*"sla_supports"*/);
|
||||||
CATEGORY_ICON[L("Pad")] = create_scaled_bitmap(nullptr, "pad");
|
CATEGORY_ICON[L("Pad")] = create_scaled_bitmap("pad");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1003,14 +1000,13 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
|
||||||
const bool mult_sel = multiple_selection();
|
const bool mult_sel = multiple_selection();
|
||||||
|
|
||||||
if ((mult_sel && !selected_instances_of_same_object()) ||
|
if ((mult_sel && !selected_instances_of_same_object()) ||
|
||||||
(!mult_sel && (GetSelection() != item)) ||
|
(!mult_sel && (GetSelection() != item)) ) {
|
||||||
m_objects_model->GetParent(item) == wxDataViewItem(nullptr) ) {
|
|
||||||
event.Veto();
|
event.Veto();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ItemType& type = m_objects_model->GetItemType(item);
|
const ItemType& type = m_objects_model->GetItemType(item);
|
||||||
if (!(type & (itVolume | itInstance))) {
|
if (!(type & (itVolume | itObject | itInstance))) {
|
||||||
event.Veto();
|
event.Veto();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1024,11 +1020,13 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
|
||||||
for (auto sel : sels )
|
for (auto sel : sels )
|
||||||
sub_obj_idxs.insert(m_objects_model->GetInstanceIdByItem(sel));
|
sub_obj_idxs.insert(m_objects_model->GetInstanceIdByItem(sel));
|
||||||
}
|
}
|
||||||
else
|
else if (type & itObject)
|
||||||
|
m_dragged_data.init(m_objects_model->GetIdByItem(item), type);
|
||||||
|
else
|
||||||
m_dragged_data.init(m_objects_model->GetObjectIdByItem(item),
|
m_dragged_data.init(m_objects_model->GetObjectIdByItem(item),
|
||||||
type&itVolume ? m_objects_model->GetVolumeIdByItem(item) :
|
type&itVolume ? m_objects_model->GetVolumeIdByItem(item) :
|
||||||
m_objects_model->GetInstanceIdByItem(item),
|
m_objects_model->GetInstanceIdByItem(item),
|
||||||
type);
|
type);
|
||||||
|
|
||||||
/* Under MSW or OSX, DnD moves an item to the place of another selected item
|
/* Under MSW or OSX, DnD moves an item to the place of another selected item
|
||||||
* But under GTK, DnD moves an item between another two items.
|
* But under GTK, DnD moves an item between another two items.
|
||||||
|
@ -1049,10 +1047,20 @@ void ObjectList::OnBeginDrag(wxDataViewEvent &event)
|
||||||
|
|
||||||
bool ObjectList::can_drop(const wxDataViewItem& item) const
|
bool ObjectList::can_drop(const wxDataViewItem& item) const
|
||||||
{
|
{
|
||||||
return (m_dragged_data.type() == itInstance && !item.IsOk()) ||
|
// move instance(s) or object on "empty place" of ObjectList
|
||||||
(m_dragged_data.type() == itVolume && item.IsOk() &&
|
if ( (m_dragged_data.type() & (itInstance | itObject)) && !item.IsOk() )
|
||||||
m_objects_model->GetItemType(item) == itVolume &&
|
return true;
|
||||||
m_dragged_data.obj_idx() == m_objects_model->GetObjectIdByItem(item));
|
|
||||||
|
// type of moved item should be the same as a "destination" item
|
||||||
|
if (!item.IsOk() || !(m_dragged_data.type() & (itVolume|itObject)) ||
|
||||||
|
m_objects_model->GetItemType(item) != m_dragged_data.type() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// move volumes inside one object only
|
||||||
|
if (m_dragged_data.type() & itVolume)
|
||||||
|
return m_dragged_data.obj_idx() == m_objects_model->GetObjectIdByItem(item);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::OnDropPossible(wxDataViewEvent &event)
|
void ObjectList::OnDropPossible(wxDataViewEvent &event)
|
||||||
|
@ -1082,9 +1090,6 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int from_volume_id = m_dragged_data.sub_obj_idx();
|
|
||||||
int to_volume_id = m_objects_model->GetVolumeIdByItem(item);
|
|
||||||
|
|
||||||
// It looks like a fixed in current version of the wxWidgets
|
// It looks like a fixed in current version of the wxWidgets
|
||||||
// #ifdef __WXGTK__
|
// #ifdef __WXGTK__
|
||||||
// /* Under GTK, DnD moves an item between another two items.
|
// /* Under GTK, DnD moves an item between another two items.
|
||||||
|
@ -1096,14 +1101,33 @@ void ObjectList::OnDrop(wxDataViewEvent &event)
|
||||||
|
|
||||||
take_snapshot(_((m_dragged_data.type() == itVolume) ? L("Volumes in Object reordered") : L("Object reordered")));
|
take_snapshot(_((m_dragged_data.type() == itVolume) ? L("Volumes in Object reordered") : L("Object reordered")));
|
||||||
|
|
||||||
auto& volumes = (*m_objects)[m_dragged_data.obj_idx()]->volumes;
|
if (m_dragged_data.type() & itVolume)
|
||||||
auto delta = to_volume_id < from_volume_id ? -1 : 1;
|
{
|
||||||
int cnt = 0;
|
int from_volume_id = m_dragged_data.sub_obj_idx();
|
||||||
for (int id = from_volume_id; cnt < abs(from_volume_id - to_volume_id); id += delta, cnt++)
|
int to_volume_id = m_objects_model->GetVolumeIdByItem(item);
|
||||||
std::swap(volumes[id], volumes[id + delta]);
|
int delta = to_volume_id < from_volume_id ? -1 : 1;
|
||||||
|
|
||||||
select_item(m_objects_model->ReorganizeChildren(from_volume_id, to_volume_id,
|
auto& volumes = (*m_objects)[m_dragged_data.obj_idx()]->volumes;
|
||||||
m_objects_model->GetParent(item)));
|
|
||||||
|
int cnt = 0;
|
||||||
|
for (int id = from_volume_id; cnt < abs(from_volume_id - to_volume_id); id += delta, cnt++)
|
||||||
|
std::swap(volumes[id], volumes[id + delta]);
|
||||||
|
|
||||||
|
select_item(m_objects_model->ReorganizeChildren(from_volume_id, to_volume_id, m_objects_model->GetParent(item)));
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (m_dragged_data.type() & itObject)
|
||||||
|
{
|
||||||
|
int from_obj_id = m_dragged_data.obj_idx();
|
||||||
|
int to_obj_id = item.IsOk() ? m_objects_model->GetIdByItem(item) : ((int)m_objects->size()-1);
|
||||||
|
int delta = to_obj_id < from_obj_id ? -1 : 1;
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
for (int id = from_obj_id; cnt < abs(from_obj_id - to_obj_id); id += delta, cnt++)
|
||||||
|
std::swap((*m_objects)[id], (*m_objects)[id + delta]);
|
||||||
|
|
||||||
|
select_item(m_objects_model->ReorganizeObjects(from_obj_id, to_obj_id));
|
||||||
|
}
|
||||||
|
|
||||||
changed_object(m_dragged_data.obj_idx());
|
changed_object(m_dragged_data.obj_idx());
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include "Event.hpp"
|
#include "Event.hpp"
|
||||||
#include "wxExtensions.hpp"
|
#include "wxExtensions.hpp"
|
||||||
|
#include "ObjectDataViewModel.hpp"
|
||||||
|
|
||||||
class wxBoxSizer;
|
class wxBoxSizer;
|
||||||
class wxBitmapComboBox;
|
class wxBitmapComboBox;
|
||||||
|
|
|
@ -68,7 +68,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
||||||
/* Load default preset bitmaps before a tabpanel initialization,
|
/* Load default preset bitmaps before a tabpanel initialization,
|
||||||
* but after filling of an em_unit value
|
* but after filling of an em_unit value
|
||||||
*/
|
*/
|
||||||
wxGetApp().preset_bundle->load_default_preset_bitmaps(this);
|
wxGetApp().preset_bundle->load_default_preset_bitmaps();
|
||||||
|
|
||||||
// initialize tabpanel and menubar
|
// initialize tabpanel and menubar
|
||||||
init_tabpanel();
|
init_tabpanel();
|
||||||
|
@ -345,7 +345,7 @@ void MainFrame::on_dpi_changed(const wxRect &suggested_rect)
|
||||||
/* Load default preset bitmaps before a tabpanel initialization,
|
/* Load default preset bitmaps before a tabpanel initialization,
|
||||||
* but after filling of an em_unit value
|
* but after filling of an em_unit value
|
||||||
*/
|
*/
|
||||||
wxGetApp().preset_bundle->load_default_preset_bitmaps(this);
|
wxGetApp().preset_bundle->load_default_preset_bitmaps();
|
||||||
|
|
||||||
// update Plater
|
// update Plater
|
||||||
wxGetApp().plater()->msw_rescale();
|
wxGetApp().plater()->msw_rescale();
|
||||||
|
@ -578,6 +578,11 @@ void MainFrame::init_menubar()
|
||||||
append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "V",
|
append_menu_item(editMenu, wxID_ANY, _(L("&Paste")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "V",
|
||||||
_(L("Paste clipboard")), [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); },
|
_(L("Paste clipboard")), [this](wxCommandEvent&) { m_plater->paste_from_clipboard(); },
|
||||||
"paste_menu", nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this);
|
"paste_menu", nullptr, [this](){return m_plater->can_paste_from_clipboard(); }, this);
|
||||||
|
|
||||||
|
editMenu->AppendSeparator();
|
||||||
|
append_menu_item(editMenu, wxID_ANY, _(L("Re&load from disk")) + sep + "F5",
|
||||||
|
_(L("Reload the plater from disk")), [this](wxCommandEvent&) { m_plater->reload_all_from_disk(); },
|
||||||
|
"", nullptr, [this]() {return !m_plater->model().objects.empty(); }, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Window menu
|
// Window menu
|
||||||
|
@ -728,7 +733,7 @@ void MainFrame::update_menubar()
|
||||||
m_changeable_menu_items[miSend] ->SetItemLabel((is_fff ? _(L("S&end G-code")) : _(L("S&end to print"))) + dots + "\tCtrl+Shift+G");
|
m_changeable_menu_items[miSend] ->SetItemLabel((is_fff ? _(L("S&end G-code")) : _(L("S&end to print"))) + dots + "\tCtrl+Shift+G");
|
||||||
|
|
||||||
m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3");
|
m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3");
|
||||||
m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, is_fff ? "spool": "resin"));
|
m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(is_fff ? "spool": "resin"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG".
|
// To perform the "Quck Slice", "Quick Slice and Save As", "Repeat last Quick Slice" and "Slice to SVG".
|
||||||
|
|
|
@ -53,7 +53,7 @@ MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &he
|
||||||
rightsizer->Add(btn_sizer, 0, wxALIGN_RIGHT);
|
rightsizer->Add(btn_sizer, 0, wxALIGN_RIGHT);
|
||||||
|
|
||||||
if (! bitmap.IsOk()) {
|
if (! bitmap.IsOk()) {
|
||||||
bitmap = create_scaled_bitmap(this, "PrusaSlicer_192px.png", 192);
|
bitmap = create_scaled_bitmap("PrusaSlicer_192px.png", this, 192);
|
||||||
}
|
}
|
||||||
|
|
||||||
logo = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap);
|
logo = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap);
|
||||||
|
@ -99,7 +99,7 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg)
|
||||||
btn_ok->SetFocus();
|
btn_ok->SetFocus();
|
||||||
btn_sizer->Add(btn_ok, 0, wxRIGHT, HORIZ_SPACING);
|
btn_sizer->Add(btn_ok, 0, wxRIGHT, HORIZ_SPACING);
|
||||||
|
|
||||||
logo->SetBitmap(create_scaled_bitmap(this, "PrusaSlicer_192px_grayscale.png", 192));
|
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, 192));
|
||||||
|
|
||||||
SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT*wxGetApp().em_unit()));
|
SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT*wxGetApp().em_unit()));
|
||||||
Fit();
|
Fit();
|
||||||
|
|
1764
src/slic3r/GUI/ObjectDataViewModel.cpp
Normal file
1764
src/slic3r/GUI/ObjectDataViewModel.cpp
Normal file
File diff suppressed because it is too large
Load diff
516
src/slic3r/GUI/ObjectDataViewModel.hpp
Normal file
516
src/slic3r/GUI/ObjectDataViewModel.hpp
Normal file
|
@ -0,0 +1,516 @@
|
||||||
|
#ifndef slic3r_GUI_ObjectDataViewModel_hpp_
|
||||||
|
#define slic3r_GUI_ObjectDataViewModel_hpp_
|
||||||
|
|
||||||
|
#include <wx/dataview.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
|
||||||
|
enum class ModelVolumeType : int;
|
||||||
|
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
typedef double coordf_t;
|
||||||
|
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// DataViewBitmapText: helper class used by BitmapTextRenderer
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class DataViewBitmapText : public wxObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DataViewBitmapText( const wxString &text = wxEmptyString,
|
||||||
|
const wxBitmap& bmp = wxNullBitmap) :
|
||||||
|
m_text(text),
|
||||||
|
m_bmp(bmp)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
DataViewBitmapText(const DataViewBitmapText &other)
|
||||||
|
: wxObject(),
|
||||||
|
m_text(other.m_text),
|
||||||
|
m_bmp(other.m_bmp)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void SetText(const wxString &text) { m_text = text; }
|
||||||
|
wxString GetText() const { return m_text; }
|
||||||
|
void SetBitmap(const wxBitmap &bmp) { m_bmp = bmp; }
|
||||||
|
const wxBitmap &GetBitmap() const { return m_bmp; }
|
||||||
|
|
||||||
|
bool IsSameAs(const DataViewBitmapText& other) const {
|
||||||
|
return m_text == other.m_text && m_bmp.IsSameAs(other.m_bmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const DataViewBitmapText& other) const {
|
||||||
|
return IsSameAs(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const DataViewBitmapText& other) const {
|
||||||
|
return !IsSameAs(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxString m_text;
|
||||||
|
wxBitmap m_bmp;
|
||||||
|
|
||||||
|
wxDECLARE_DYNAMIC_CLASS(DataViewBitmapText);
|
||||||
|
};
|
||||||
|
DECLARE_VARIANT_OBJECT(DataViewBitmapText)
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// BitmapTextRenderer
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
||||||
|
class BitmapTextRenderer : public wxDataViewRenderer
|
||||||
|
#else
|
||||||
|
class BitmapTextRenderer : public wxDataViewCustomRenderer
|
||||||
|
#endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BitmapTextRenderer(wxWindow* parent,
|
||||||
|
wxDataViewCellMode mode =
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
wxDATAVIEW_CELL_INERT
|
||||||
|
#else
|
||||||
|
wxDATAVIEW_CELL_EDITABLE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
, int align = wxDVR_DEFAULT_ALIGNMENT
|
||||||
|
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
||||||
|
);
|
||||||
|
#else
|
||||||
|
) :
|
||||||
|
wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align),
|
||||||
|
m_parent(parent)
|
||||||
|
{}
|
||||||
|
#endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
||||||
|
|
||||||
|
bool SetValue(const wxVariant& value);
|
||||||
|
bool GetValue(wxVariant& value) const;
|
||||||
|
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY
|
||||||
|
virtual wxString GetAccessibleDescription() const override;
|
||||||
|
#endif // wxUSE_ACCESSIBILITY && ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
||||||
|
|
||||||
|
virtual bool Render(wxRect cell, wxDC* dc, int state) override;
|
||||||
|
virtual wxSize GetSize() const override;
|
||||||
|
|
||||||
|
bool HasEditorCtrl() const override
|
||||||
|
{
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
wxWindow* CreateEditorCtrl(wxWindow* parent,
|
||||||
|
wxRect labelRect,
|
||||||
|
const wxVariant& value) override;
|
||||||
|
bool GetValueFromEditorCtrl(wxWindow* ctrl,
|
||||||
|
wxVariant& value) override;
|
||||||
|
bool WasCanceled() const { return m_was_unusable_symbol; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
DataViewBitmapText m_value;
|
||||||
|
bool m_was_unusable_symbol{ false };
|
||||||
|
wxWindow* m_parent{ nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// BitmapChoiceRenderer
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
class BitmapChoiceRenderer : public wxDataViewCustomRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BitmapChoiceRenderer(wxDataViewCellMode mode =
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
wxDATAVIEW_CELL_INERT
|
||||||
|
#else
|
||||||
|
wxDATAVIEW_CELL_EDITABLE
|
||||||
|
#endif
|
||||||
|
, int align = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL
|
||||||
|
) : wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align) {}
|
||||||
|
|
||||||
|
bool SetValue(const wxVariant& value);
|
||||||
|
bool GetValue(wxVariant& value) const;
|
||||||
|
|
||||||
|
virtual bool Render(wxRect cell, wxDC* dc, int state) override;
|
||||||
|
virtual wxSize GetSize() const override;
|
||||||
|
|
||||||
|
bool HasEditorCtrl() const override { return true; }
|
||||||
|
wxWindow* CreateEditorCtrl(wxWindow* parent,
|
||||||
|
wxRect labelRect,
|
||||||
|
const wxVariant& value) override;
|
||||||
|
bool GetValueFromEditorCtrl(wxWindow* ctrl,
|
||||||
|
wxVariant& value) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DataViewBitmapText m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// ObjectDataViewModelNode: a node inside ObjectDataViewModel
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
enum ItemType {
|
||||||
|
itUndef = 0,
|
||||||
|
itObject = 1,
|
||||||
|
itVolume = 2,
|
||||||
|
itInstanceRoot = 4,
|
||||||
|
itInstance = 8,
|
||||||
|
itSettings = 16,
|
||||||
|
itLayerRoot = 32,
|
||||||
|
itLayer = 64,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ColumnNumber
|
||||||
|
{
|
||||||
|
colName = 0, // item name
|
||||||
|
colPrint , // printable property
|
||||||
|
colExtruder , // extruder selection
|
||||||
|
colEditing , // item editing
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PrintIndicator
|
||||||
|
{
|
||||||
|
piUndef = 0, // no print indicator
|
||||||
|
piPrintable , // printable
|
||||||
|
piUnprintable , // unprintable
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectDataViewModelNode;
|
||||||
|
WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray);
|
||||||
|
|
||||||
|
class ObjectDataViewModelNode
|
||||||
|
{
|
||||||
|
ObjectDataViewModelNode* m_parent;
|
||||||
|
MyObjectTreeModelNodePtrArray m_children;
|
||||||
|
wxBitmap m_empty_bmp;
|
||||||
|
size_t m_volumes_cnt = 0;
|
||||||
|
std::vector< std::string > m_opt_categories;
|
||||||
|
t_layer_height_range m_layer_range = { 0.0f, 0.0f };
|
||||||
|
|
||||||
|
wxString m_name;
|
||||||
|
wxBitmap& m_bmp = m_empty_bmp;
|
||||||
|
ItemType m_type;
|
||||||
|
int m_idx = -1;
|
||||||
|
bool m_container = false;
|
||||||
|
wxString m_extruder = "default";
|
||||||
|
wxBitmap m_extruder_bmp;
|
||||||
|
wxBitmap m_action_icon;
|
||||||
|
PrintIndicator m_printable {piUndef};
|
||||||
|
wxBitmap m_printable_icon;
|
||||||
|
|
||||||
|
std::string m_action_icon_name = "";
|
||||||
|
ModelVolumeType m_volume_type;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ObjectDataViewModelNode(const wxString& name,
|
||||||
|
const wxString& extruder):
|
||||||
|
m_parent(NULL),
|
||||||
|
m_name(name),
|
||||||
|
m_type(itObject),
|
||||||
|
m_extruder(extruder)
|
||||||
|
{
|
||||||
|
set_action_and_extruder_icons();
|
||||||
|
init_container();
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
||||||
|
const wxString& sub_obj_name,
|
||||||
|
const wxBitmap& bmp,
|
||||||
|
const wxString& extruder,
|
||||||
|
const int idx = -1 ) :
|
||||||
|
m_parent (parent),
|
||||||
|
m_name (sub_obj_name),
|
||||||
|
m_type (itVolume),
|
||||||
|
m_idx (idx),
|
||||||
|
m_extruder (extruder)
|
||||||
|
{
|
||||||
|
m_bmp = bmp;
|
||||||
|
set_action_and_extruder_icons();
|
||||||
|
init_container();
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
||||||
|
const t_layer_height_range& layer_range,
|
||||||
|
const int idx = -1,
|
||||||
|
const wxString& extruder = wxEmptyString );
|
||||||
|
|
||||||
|
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type);
|
||||||
|
|
||||||
|
~ObjectDataViewModelNode()
|
||||||
|
{
|
||||||
|
// free all our children nodes
|
||||||
|
size_t count = m_children.GetCount();
|
||||||
|
for (size_t i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
ObjectDataViewModelNode *child = m_children[i];
|
||||||
|
delete child;
|
||||||
|
}
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Indicate that the object was deleted.
|
||||||
|
m_idx = -2;
|
||||||
|
#endif /* NDEBUG */
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_container();
|
||||||
|
bool IsContainer() const
|
||||||
|
{
|
||||||
|
return m_container;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectDataViewModelNode* GetParent()
|
||||||
|
{
|
||||||
|
assert(m_parent == nullptr || m_parent->valid());
|
||||||
|
return m_parent;
|
||||||
|
}
|
||||||
|
MyObjectTreeModelNodePtrArray& GetChildren()
|
||||||
|
{
|
||||||
|
return m_children;
|
||||||
|
}
|
||||||
|
ObjectDataViewModelNode* GetNthChild(unsigned int n)
|
||||||
|
{
|
||||||
|
return m_children.Item(n);
|
||||||
|
}
|
||||||
|
void Insert(ObjectDataViewModelNode* child, unsigned int n)
|
||||||
|
{
|
||||||
|
if (!m_container)
|
||||||
|
m_container = true;
|
||||||
|
m_children.Insert(child, n);
|
||||||
|
}
|
||||||
|
void Append(ObjectDataViewModelNode* child)
|
||||||
|
{
|
||||||
|
if (!m_container)
|
||||||
|
m_container = true;
|
||||||
|
m_children.Add(child);
|
||||||
|
}
|
||||||
|
void RemoveAllChildren()
|
||||||
|
{
|
||||||
|
if (GetChildCount() == 0)
|
||||||
|
return;
|
||||||
|
for (int id = int(GetChildCount()) - 1; id >= 0; --id)
|
||||||
|
{
|
||||||
|
if (m_children.Item(id)->GetChildCount() > 0)
|
||||||
|
m_children[id]->RemoveAllChildren();
|
||||||
|
auto node = m_children[id];
|
||||||
|
m_children.RemoveAt(id);
|
||||||
|
delete node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetChildCount() const
|
||||||
|
{
|
||||||
|
return m_children.GetCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetValue(const wxVariant &variant, unsigned int col);
|
||||||
|
|
||||||
|
void SetBitmap(const wxBitmap &icon) { m_bmp = icon; }
|
||||||
|
const wxBitmap& GetBitmap() const { return m_bmp; }
|
||||||
|
const wxString& GetName() const { return m_name; }
|
||||||
|
ItemType GetType() const { return m_type; }
|
||||||
|
void SetIdx(const int& idx);
|
||||||
|
int GetIdx() const { return m_idx; }
|
||||||
|
t_layer_height_range GetLayerRange() const { return m_layer_range; }
|
||||||
|
PrintIndicator IsPrintable() const { return m_printable; }
|
||||||
|
|
||||||
|
// use this function only for childrens
|
||||||
|
void AssignAllVal(ObjectDataViewModelNode& from_node)
|
||||||
|
{
|
||||||
|
// ! Don't overwrite other values because of equality of this values for all children --
|
||||||
|
m_name = from_node.m_name;
|
||||||
|
m_bmp = from_node.m_bmp;
|
||||||
|
m_idx = from_node.m_idx;
|
||||||
|
m_extruder = from_node.m_extruder;
|
||||||
|
m_type = from_node.m_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SwapChildrens(int frst_id, int scnd_id) {
|
||||||
|
if (GetChildCount() < 2 ||
|
||||||
|
frst_id < 0 || (size_t)frst_id >= GetChildCount() ||
|
||||||
|
scnd_id < 0 || (size_t)scnd_id >= GetChildCount())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ObjectDataViewModelNode new_scnd = *GetNthChild(frst_id);
|
||||||
|
ObjectDataViewModelNode new_frst = *GetNthChild(scnd_id);
|
||||||
|
|
||||||
|
new_scnd.m_idx = m_children.Item(scnd_id)->m_idx;
|
||||||
|
new_frst.m_idx = m_children.Item(frst_id)->m_idx;
|
||||||
|
|
||||||
|
m_children.Item(frst_id)->AssignAllVal(new_frst);
|
||||||
|
m_children.Item(scnd_id)->AssignAllVal(new_scnd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set action icons for node
|
||||||
|
void set_action_and_extruder_icons();
|
||||||
|
// Set printable icon for node
|
||||||
|
void set_printable_icon(PrintIndicator printable);
|
||||||
|
|
||||||
|
void update_settings_digest_bitmaps();
|
||||||
|
bool update_settings_digest(const std::vector<std::string>& categories);
|
||||||
|
int volume_type() const { return int(m_volume_type); }
|
||||||
|
void msw_rescale();
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
bool valid();
|
||||||
|
#endif /* NDEBUG */
|
||||||
|
bool invalid() const { return m_idx < -1; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class ObjectDataViewModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// ObjectDataViewModel
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// custom message the model sends to associated control to notify a last volume deleted from the object:
|
||||||
|
wxDECLARE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent);
|
||||||
|
|
||||||
|
class ObjectDataViewModel :public wxDataViewModel
|
||||||
|
{
|
||||||
|
std::vector<ObjectDataViewModelNode*> m_objects;
|
||||||
|
std::vector<wxBitmap*> m_volume_bmps;
|
||||||
|
wxBitmap* m_warning_bmp { nullptr };
|
||||||
|
|
||||||
|
wxDataViewCtrl* m_ctrl { nullptr };
|
||||||
|
|
||||||
|
public:
|
||||||
|
ObjectDataViewModel();
|
||||||
|
~ObjectDataViewModel();
|
||||||
|
|
||||||
|
wxDataViewItem Add( const wxString &name,
|
||||||
|
const int extruder,
|
||||||
|
const bool has_errors = false);
|
||||||
|
wxDataViewItem AddVolumeChild( const wxDataViewItem &parent_item,
|
||||||
|
const wxString &name,
|
||||||
|
const Slic3r::ModelVolumeType volume_type,
|
||||||
|
const bool has_errors = false,
|
||||||
|
const int extruder = 0,
|
||||||
|
const bool create_frst_child = true);
|
||||||
|
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
|
||||||
|
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
|
||||||
|
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, const std::vector<bool>& print_indicator);
|
||||||
|
wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
|
||||||
|
wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item,
|
||||||
|
const t_layer_height_range& layer_range,
|
||||||
|
const int extruder = 0,
|
||||||
|
const int index = -1);
|
||||||
|
wxDataViewItem Delete(const wxDataViewItem &item);
|
||||||
|
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
|
||||||
|
void DeleteAll();
|
||||||
|
void DeleteChildren(wxDataViewItem& parent);
|
||||||
|
void DeleteVolumeChildren(wxDataViewItem& parent);
|
||||||
|
void DeleteSettings(const wxDataViewItem& parent);
|
||||||
|
wxDataViewItem GetItemById(int obj_idx);
|
||||||
|
wxDataViewItem GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type);
|
||||||
|
wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
|
||||||
|
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
|
||||||
|
wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx);
|
||||||
|
wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
|
||||||
|
int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
|
||||||
|
int GetIdByItem(const wxDataViewItem& item) const;
|
||||||
|
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
|
||||||
|
int GetObjectIdByItem(const wxDataViewItem& item) const;
|
||||||
|
int GetVolumeIdByItem(const wxDataViewItem& item) const;
|
||||||
|
int GetInstanceIdByItem(const wxDataViewItem& item) const;
|
||||||
|
int GetLayerIdByItem(const wxDataViewItem& item) const;
|
||||||
|
void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
|
||||||
|
int GetRowByItem(const wxDataViewItem& item) const;
|
||||||
|
bool IsEmpty() { return m_objects.empty(); }
|
||||||
|
bool InvalidItem(const wxDataViewItem& item);
|
||||||
|
|
||||||
|
// helper method for wxLog
|
||||||
|
|
||||||
|
wxString GetName(const wxDataViewItem &item) const;
|
||||||
|
wxBitmap& GetBitmap(const wxDataViewItem &item) const;
|
||||||
|
wxString GetExtruder(const wxDataViewItem &item) const;
|
||||||
|
int GetExtruderNumber(const wxDataViewItem &item) const;
|
||||||
|
|
||||||
|
// helper methods to change the model
|
||||||
|
|
||||||
|
virtual unsigned int GetColumnCount() const override { return 3;}
|
||||||
|
virtual wxString GetColumnType(unsigned int col) const override{ return wxT("string"); }
|
||||||
|
|
||||||
|
virtual void GetValue( wxVariant &variant,
|
||||||
|
const wxDataViewItem &item,
|
||||||
|
unsigned int col) const override;
|
||||||
|
virtual bool SetValue( const wxVariant &variant,
|
||||||
|
const wxDataViewItem &item,
|
||||||
|
unsigned int col) override;
|
||||||
|
bool SetValue( const wxVariant &variant,
|
||||||
|
const int item_idx,
|
||||||
|
unsigned int col);
|
||||||
|
|
||||||
|
void SetExtruder(const wxString& extruder, wxDataViewItem item);
|
||||||
|
|
||||||
|
// For parent move child from cur_volume_id place to new_volume_id
|
||||||
|
// Remaining items will moved up/down accordingly
|
||||||
|
wxDataViewItem ReorganizeChildren( const int cur_volume_id,
|
||||||
|
const int new_volume_id,
|
||||||
|
const wxDataViewItem &parent);
|
||||||
|
wxDataViewItem ReorganizeObjects( int current_id, int new_id);
|
||||||
|
|
||||||
|
virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override;
|
||||||
|
|
||||||
|
virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override;
|
||||||
|
// get object item
|
||||||
|
wxDataViewItem GetTopParent(const wxDataViewItem &item) const;
|
||||||
|
virtual bool IsContainer(const wxDataViewItem &item) const override;
|
||||||
|
virtual unsigned int GetChildren(const wxDataViewItem &parent,
|
||||||
|
wxDataViewItemArray &array) const override;
|
||||||
|
void GetAllChildren(const wxDataViewItem &parent,wxDataViewItemArray &array) const;
|
||||||
|
// Is the container just a header or an item with all columns
|
||||||
|
// In our case it is an item with all columns
|
||||||
|
virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; }
|
||||||
|
|
||||||
|
ItemType GetItemType(const wxDataViewItem &item) const ;
|
||||||
|
wxDataViewItem GetItemByType( const wxDataViewItem &parent_item,
|
||||||
|
ItemType type) const;
|
||||||
|
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
|
||||||
|
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
|
||||||
|
wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const;
|
||||||
|
bool IsSettingsItem(const wxDataViewItem &item) const;
|
||||||
|
void UpdateSettingsDigest( const wxDataViewItem &item,
|
||||||
|
const std::vector<std::string>& categories);
|
||||||
|
|
||||||
|
bool IsPrintable(const wxDataViewItem &item) const;
|
||||||
|
void UpdateObjectPrintable(wxDataViewItem parent_item);
|
||||||
|
void UpdateInstancesPrintable(wxDataViewItem parent_item);
|
||||||
|
|
||||||
|
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
|
||||||
|
void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; }
|
||||||
|
void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type);
|
||||||
|
wxDataViewItem SetPrintableState( PrintIndicator printable, int obj_idx,
|
||||||
|
int subobj_idx = -1,
|
||||||
|
ItemType subobj_type = itInstance);
|
||||||
|
wxDataViewItem SetObjectPrintableState(PrintIndicator printable, wxDataViewItem obj_item);
|
||||||
|
|
||||||
|
void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; }
|
||||||
|
// Rescale bitmaps for existing Items
|
||||||
|
void Rescale();
|
||||||
|
|
||||||
|
wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,
|
||||||
|
const bool is_marked = false);
|
||||||
|
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
|
||||||
|
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
|
||||||
|
|
||||||
|
bool UpdateColumValues(unsigned col);
|
||||||
|
void UpdateExtruderBitmap(wxDataViewItem item);
|
||||||
|
|
||||||
|
private:
|
||||||
|
wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type);
|
||||||
|
wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // slic3r_GUI_ObjectDataViewModel_hpp_
|
|
@ -169,7 +169,7 @@ ObjectInfo::ObjectInfo(wxWindow *parent) :
|
||||||
info_manifold_text->SetFont(wxGetApp().small_font());
|
info_manifold_text->SetFont(wxGetApp().small_font());
|
||||||
info_manifold = new wxStaticText(parent, wxID_ANY, "");
|
info_manifold = new wxStaticText(parent, wxID_ANY, "");
|
||||||
info_manifold->SetFont(wxGetApp().small_font());
|
info_manifold->SetFont(wxGetApp().small_font());
|
||||||
manifold_warning_icon = new wxStaticBitmap(parent, wxID_ANY, create_scaled_bitmap(parent, "exclamation"));
|
manifold_warning_icon = new wxStaticBitmap(parent, wxID_ANY, create_scaled_bitmap("exclamation"));
|
||||||
auto *sizer_manifold = new wxBoxSizer(wxHORIZONTAL);
|
auto *sizer_manifold = new wxBoxSizer(wxHORIZONTAL);
|
||||||
sizer_manifold->Add(info_manifold_text, 0);
|
sizer_manifold->Add(info_manifold_text, 0);
|
||||||
sizer_manifold->Add(manifold_warning_icon, 0, wxLEFT, 2);
|
sizer_manifold->Add(manifold_warning_icon, 0, wxLEFT, 2);
|
||||||
|
@ -188,7 +188,7 @@ void ObjectInfo::show_sizer(bool show)
|
||||||
|
|
||||||
void ObjectInfo::msw_rescale()
|
void ObjectInfo::msw_rescale()
|
||||||
{
|
{
|
||||||
manifold_warning_icon->SetBitmap(create_scaled_bitmap(nullptr, "exclamation"));
|
manifold_warning_icon->SetBitmap(create_scaled_bitmap("exclamation"));
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SlicedInfoIdx
|
enum SlicedInfoIdx
|
||||||
|
@ -258,7 +258,7 @@ void SlicedInfo::SetTextAndShow(SlicedInfoIdx idx, const wxString& text, const w
|
||||||
}
|
}
|
||||||
|
|
||||||
PresetComboBox::PresetComboBox(wxWindow *parent, Preset::Type preset_type) :
|
PresetComboBox::PresetComboBox(wxWindow *parent, Preset::Type preset_type) :
|
||||||
wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * wxGetApp().em_unit(), -1), 0, nullptr, wxCB_READONLY),
|
PresetBitmapComboBox(parent, wxSize(15 * wxGetApp().em_unit(), -1)),
|
||||||
preset_type(preset_type),
|
preset_type(preset_type),
|
||||||
last_selected(wxNOT_FOUND),
|
last_selected(wxNOT_FOUND),
|
||||||
m_em_unit(wxGetApp().em_unit())
|
m_em_unit(wxGetApp().em_unit())
|
||||||
|
@ -1875,6 +1875,7 @@ struct Plater::priv
|
||||||
}
|
}
|
||||||
void export_gcode(fs::path output_path, PrintHostJob upload_job);
|
void export_gcode(fs::path output_path, PrintHostJob upload_job);
|
||||||
void reload_from_disk();
|
void reload_from_disk();
|
||||||
|
void reload_all_from_disk();
|
||||||
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
|
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
|
||||||
|
|
||||||
void set_current_panel(wxPanel* panel);
|
void set_current_panel(wxPanel* panel);
|
||||||
|
@ -2075,6 +2076,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
||||||
view3D_canvas->Bind(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, [this](SimpleEvent&) { this->view3D->get_canvas3d()->reset_layer_height_profile(); });
|
view3D_canvas->Bind(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, [this](SimpleEvent&) { this->view3D->get_canvas3d()->reset_layer_height_profile(); });
|
||||||
view3D_canvas->Bind(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, [this](Event<float>& evt) { this->view3D->get_canvas3d()->adaptive_layer_height_profile(evt.data); });
|
view3D_canvas->Bind(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, [this](Event<float>& evt) { this->view3D->get_canvas3d()->adaptive_layer_height_profile(evt.data); });
|
||||||
view3D_canvas->Bind(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, [this](HeightProfileSmoothEvent& evt) { this->view3D->get_canvas3d()->smooth_layer_height_profile(evt.data); });
|
view3D_canvas->Bind(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, [this](HeightProfileSmoothEvent& evt) { this->view3D->get_canvas3d()->smooth_layer_height_profile(evt.data); });
|
||||||
|
view3D_canvas->Bind(EVT_GLCANVAS_RELOAD_FROM_DISK, [this](SimpleEvent&) { if (!this->model.objects.empty()) this->reload_all_from_disk(); });
|
||||||
|
|
||||||
// 3DScene/Toolbar:
|
// 3DScene/Toolbar:
|
||||||
view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this);
|
view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this);
|
||||||
|
@ -3447,6 +3449,24 @@ void Plater::priv::reload_from_disk()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Plater::priv::reload_all_from_disk()
|
||||||
|
{
|
||||||
|
Plater::TakeSnapshot snapshot(q, _(L("Reload all from disk")));
|
||||||
|
Plater::SuppressSnapshots suppress(q);
|
||||||
|
|
||||||
|
Selection& selection = get_selection();
|
||||||
|
Selection::IndicesList curr_idxs = selection.get_volume_idxs();
|
||||||
|
// reload from disk uses selection
|
||||||
|
select_all();
|
||||||
|
reload_from_disk();
|
||||||
|
// restore previous selection
|
||||||
|
selection.clear();
|
||||||
|
for (unsigned int idx : curr_idxs)
|
||||||
|
{
|
||||||
|
selection.add(idx, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/)
|
void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* = -1*/)
|
||||||
{
|
{
|
||||||
if (obj_idx < 0)
|
if (obj_idx < 0)
|
||||||
|
@ -5034,6 +5054,11 @@ void Plater::reload_from_disk()
|
||||||
p->reload_from_disk();
|
p->reload_from_disk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Plater::reload_all_from_disk()
|
||||||
|
{
|
||||||
|
p->reload_all_from_disk();
|
||||||
|
}
|
||||||
|
|
||||||
bool Plater::has_toolpaths_to_export() const
|
bool Plater::has_toolpaths_to_export() const
|
||||||
{
|
{
|
||||||
return p->preview->get_canvas3d()->has_toolpaths_to_export();
|
return p->preview->get_canvas3d()->has_toolpaths_to_export();
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "3DScene.hpp"
|
#include "3DScene.hpp"
|
||||||
#include "GLTexture.hpp"
|
#include "GLTexture.hpp"
|
||||||
|
#include "wxExtensions.hpp"
|
||||||
|
|
||||||
class wxButton;
|
class wxButton;
|
||||||
class ScalableButton;
|
class ScalableButton;
|
||||||
|
@ -49,7 +50,7 @@ using t_optgroups = std::vector <std::shared_ptr<ConfigOptionsGroup>>;
|
||||||
class Plater;
|
class Plater;
|
||||||
enum class ActionButtonType : int;
|
enum class ActionButtonType : int;
|
||||||
|
|
||||||
class PresetComboBox : public wxBitmapComboBox
|
class PresetComboBox : public PresetBitmapComboBox
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PresetComboBox(wxWindow *parent, Preset::Type preset_type);
|
PresetComboBox(wxWindow *parent, Preset::Type preset_type);
|
||||||
|
@ -193,6 +194,7 @@ public:
|
||||||
void export_amf();
|
void export_amf();
|
||||||
void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path());
|
void export_3mf(const boost::filesystem::path& output_path = boost::filesystem::path());
|
||||||
void reload_from_disk();
|
void reload_from_disk();
|
||||||
|
void reload_all_from_disk();
|
||||||
bool has_toolpaths_to_export() const;
|
bool has_toolpaths_to_export() const;
|
||||||
void export_toolpaths_to_obj() const;
|
void export_toolpaths_to_obj() const;
|
||||||
void hollow();
|
void hollow();
|
||||||
|
|
|
@ -873,18 +873,14 @@ bool PresetCollection::delete_preset(const std::string& name)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresetCollection::load_bitmap_default(wxWindow *window, const std::string &file_name)
|
void PresetCollection::load_bitmap_default(const std::string &file_name)
|
||||||
{
|
{
|
||||||
// XXX: See note in PresetBundle::load_compatible_bitmaps()
|
*m_bitmap_main_frame = create_scaled_bitmap(file_name);
|
||||||
(void)window;
|
|
||||||
*m_bitmap_main_frame = create_scaled_bitmap(nullptr, file_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresetCollection::load_bitmap_add(wxWindow *window, const std::string &file_name)
|
void PresetCollection::load_bitmap_add(const std::string &file_name)
|
||||||
{
|
{
|
||||||
// XXX: See note in PresetBundle::load_compatible_bitmaps()
|
*m_bitmap_add = create_scaled_bitmap(file_name);
|
||||||
(void)window;
|
|
||||||
*m_bitmap_add = create_scaled_bitmap(nullptr, file_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Preset* PresetCollection::get_selected_preset_parent() const
|
const Preset* PresetCollection::get_selected_preset_parent() const
|
||||||
|
|
|
@ -313,10 +313,10 @@ public:
|
||||||
bool delete_preset(const std::string& name);
|
bool delete_preset(const std::string& name);
|
||||||
|
|
||||||
// Load default bitmap to be placed at the wxBitmapComboBox of a MainFrame.
|
// Load default bitmap to be placed at the wxBitmapComboBox of a MainFrame.
|
||||||
void load_bitmap_default(wxWindow *window, const std::string &file_name);
|
void load_bitmap_default(const std::string &file_name);
|
||||||
|
|
||||||
// Load "add new printer" bitmap to be placed at the wxBitmapComboBox of a MainFrame.
|
// Load "add new printer" bitmap to be placed at the wxBitmapComboBox of a MainFrame.
|
||||||
void load_bitmap_add(wxWindow *window, const std::string &file_name);
|
void load_bitmap_add(const std::string &file_name);
|
||||||
|
|
||||||
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items.
|
// Compatible & incompatible marks, to be placed at the wxBitmapComboBox items.
|
||||||
void set_bitmap_compatible (const wxBitmap *bmp) { m_bitmap_compatible = bmp; }
|
void set_bitmap_compatible (const wxBitmap *bmp) { m_bitmap_compatible = bmp; }
|
||||||
|
|
|
@ -480,19 +480,12 @@ void PresetBundle::export_selections(AppConfig &config)
|
||||||
config.set("presets", "printer", printers.get_selected_preset_name());
|
config.set("presets", "printer", printers.get_selected_preset_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresetBundle::load_compatible_bitmaps(wxWindow *window)
|
void PresetBundle::load_compatible_bitmaps()
|
||||||
{
|
{
|
||||||
// We don't actually pass the window pointer here and instead generate
|
*m_bitmapCompatible = create_scaled_bitmap("flag_green");
|
||||||
// a low DPI bitmap, because the wxBitmapComboBox and wxDataViewCtrl don't support
|
*m_bitmapIncompatible = create_scaled_bitmap("flag_red");
|
||||||
// high DPI bitmaps very well, they compute their dimensions wrong.
|
*m_bitmapLock = create_scaled_bitmap("lock_closed");
|
||||||
// TODO: Update this when fixed in wxWidgets
|
*m_bitmapLockOpen = create_scaled_bitmap("lock_open");
|
||||||
// See also PresetCollection::load_bitmap_default() and PresetCollection::load_bitmap_add()
|
|
||||||
|
|
||||||
(void)window;
|
|
||||||
*m_bitmapCompatible = create_scaled_bitmap(nullptr, "flag_green");
|
|
||||||
*m_bitmapIncompatible = create_scaled_bitmap(nullptr, "flag_red");
|
|
||||||
*m_bitmapLock = create_scaled_bitmap(nullptr, "lock_closed");
|
|
||||||
*m_bitmapLockOpen = create_scaled_bitmap(nullptr, "lock_open");
|
|
||||||
|
|
||||||
prints .set_bitmap_compatible(m_bitmapCompatible);
|
prints .set_bitmap_compatible(m_bitmapCompatible);
|
||||||
filaments .set_bitmap_compatible(m_bitmapCompatible);
|
filaments .set_bitmap_compatible(m_bitmapCompatible);
|
||||||
|
@ -1536,31 +1529,7 @@ void PresetBundle::set_filament_preset(size_t idx, const std::string &name)
|
||||||
filament_presets[idx] = Preset::remove_suffix_modified(name);
|
filament_presets[idx] = Preset::remove_suffix_modified(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int hex_digit_to_int(const char c)
|
void PresetBundle::load_default_preset_bitmaps()
|
||||||
{
|
|
||||||
return
|
|
||||||
(c >= '0' && c <= '9') ? int(c - '0') :
|
|
||||||
(c >= 'A' && c <= 'F') ? int(c - 'A') + 10 :
|
|
||||||
(c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PresetBundle::parse_color(const std::string &scolor, unsigned char *rgb_out)
|
|
||||||
{
|
|
||||||
rgb_out[0] = rgb_out[1] = rgb_out[2] = 0;
|
|
||||||
if (scolor.size() != 7 || scolor.front() != '#')
|
|
||||||
return false;
|
|
||||||
const char *c = scolor.data() + 1;
|
|
||||||
for (size_t i = 0; i < 3; ++ i) {
|
|
||||||
int digit1 = hex_digit_to_int(*c ++);
|
|
||||||
int digit2 = hex_digit_to_int(*c ++);
|
|
||||||
if (digit1 == -1 || digit2 == -1)
|
|
||||||
return false;
|
|
||||||
rgb_out[i] = (unsigned char)(digit1 * 16 + digit2);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PresetBundle::load_default_preset_bitmaps(wxWindow *window)
|
|
||||||
{
|
{
|
||||||
// Clear bitmap cache, before load new scaled default preset bitmaps
|
// Clear bitmap cache, before load new scaled default preset bitmaps
|
||||||
m_bitmapCache->clear();
|
m_bitmapCache->clear();
|
||||||
|
@ -1570,13 +1539,13 @@ void PresetBundle::load_default_preset_bitmaps(wxWindow *window)
|
||||||
this->sla_materials.clear_bitmap_cache();
|
this->sla_materials.clear_bitmap_cache();
|
||||||
this->printers.clear_bitmap_cache();
|
this->printers.clear_bitmap_cache();
|
||||||
|
|
||||||
this->prints.load_bitmap_default(window, "cog");
|
this->prints.load_bitmap_default("cog");
|
||||||
this->sla_prints.load_bitmap_default(window, "cog");
|
this->sla_prints.load_bitmap_default("cog");
|
||||||
this->filaments.load_bitmap_default(window, "spool.png");
|
this->filaments.load_bitmap_default("spool.png");
|
||||||
this->sla_materials.load_bitmap_default(window, "resin");
|
this->sla_materials.load_bitmap_default("resin");
|
||||||
this->printers.load_bitmap_default(window, "printer");
|
this->printers.load_bitmap_default("printer");
|
||||||
this->printers.load_bitmap_add(window, "add.png");
|
this->printers.load_bitmap_add("add.png");
|
||||||
this->load_compatible_bitmaps(window);
|
this->load_compatible_bitmaps();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui)
|
void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui)
|
||||||
|
@ -1587,7 +1556,7 @@ void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::Pre
|
||||||
|
|
||||||
unsigned char rgb[3];
|
unsigned char rgb[3];
|
||||||
std::string extruder_color = this->printers.get_edited_preset().config.opt_string("extruder_colour", idx_extruder);
|
std::string extruder_color = this->printers.get_edited_preset().config.opt_string("extruder_colour", idx_extruder);
|
||||||
if (! parse_color(extruder_color, rgb))
|
if (!m_bitmapCache->parse_color(extruder_color, rgb))
|
||||||
// Extruder color is not defined.
|
// Extruder color is not defined.
|
||||||
extruder_color.clear();
|
extruder_color.clear();
|
||||||
|
|
||||||
|
@ -1623,7 +1592,12 @@ void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::Pre
|
||||||
|
|
||||||
// To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so
|
// To avoid asserts, each added bitmap to wxBitmapCombobox should be the same size, so
|
||||||
// set a bitmap height to m_bitmapLock->GetHeight()
|
// set a bitmap height to m_bitmapLock->GetHeight()
|
||||||
const int icon_height = m_bitmapLock->GetHeight();//2 * icon_unit; //16 * scale_f + 0.5f;
|
// Note, under OSX we should use a ScaledHeight because of Retina scale
|
||||||
|
#ifdef __APPLE__
|
||||||
|
const int icon_height = m_bitmapLock->GetScaledHeight();
|
||||||
|
#else
|
||||||
|
const int icon_height = m_bitmapLock->GetHeight();
|
||||||
|
#endif
|
||||||
|
|
||||||
wxString tooltip = "";
|
wxString tooltip = "";
|
||||||
|
|
||||||
|
@ -1652,10 +1626,10 @@ void PresetBundle::update_plater_filament_ui(unsigned int idx_extruder, GUI::Pre
|
||||||
// Paint a red flag for incompatible presets.
|
// Paint a red flag for incompatible presets.
|
||||||
bmps.emplace_back(preset.is_compatible ? m_bitmapCache->mkclear(normal_icon_width, icon_height) : *m_bitmapIncompatible);
|
bmps.emplace_back(preset.is_compatible ? m_bitmapCache->mkclear(normal_icon_width, icon_height) : *m_bitmapIncompatible);
|
||||||
// Paint the color bars.
|
// Paint the color bars.
|
||||||
parse_color(filament_rgb, rgb);
|
m_bitmapCache->parse_color(filament_rgb, rgb);
|
||||||
bmps.emplace_back(m_bitmapCache->mksolid(single_bar ? wide_icon_width : normal_icon_width, icon_height, rgb));
|
bmps.emplace_back(m_bitmapCache->mksolid(single_bar ? wide_icon_width : normal_icon_width, icon_height, rgb));
|
||||||
if (! single_bar) {
|
if (! single_bar) {
|
||||||
parse_color(extruder_rgb, rgb);
|
m_bitmapCache->parse_color(extruder_rgb, rgb);
|
||||||
bmps.emplace_back(m_bitmapCache->mksolid(thin_icon_width, icon_height, rgb));
|
bmps.emplace_back(m_bitmapCache->mksolid(thin_icon_width, icon_height, rgb));
|
||||||
}
|
}
|
||||||
// Paint a lock at the system presets.
|
// Paint a lock at the system presets.
|
||||||
|
|
|
@ -129,9 +129,7 @@ public:
|
||||||
// preset if the current print or filament preset is not compatible.
|
// preset if the current print or filament preset is not compatible.
|
||||||
void update_compatible(bool select_other_if_incompatible);
|
void update_compatible(bool select_other_if_incompatible);
|
||||||
|
|
||||||
static bool parse_color(const std::string &scolor, unsigned char *rgb_out);
|
void load_default_preset_bitmaps();
|
||||||
|
|
||||||
void load_default_preset_bitmaps(wxWindow *window);
|
|
||||||
|
|
||||||
// Set the is_visible flag for printer vendors, printer models and printer variants
|
// Set the is_visible flag for printer vendors, printer models and printer variants
|
||||||
// based on the user configuration.
|
// based on the user configuration.
|
||||||
|
@ -160,7 +158,7 @@ private:
|
||||||
// If it is not an external config, then the config will be stored into the user profile directory.
|
// If it is not an external config, then the config will be stored into the user profile directory.
|
||||||
void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config);
|
void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config);
|
||||||
void load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree);
|
void load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree);
|
||||||
void load_compatible_bitmaps(wxWindow *window);
|
void load_compatible_bitmaps();
|
||||||
|
|
||||||
DynamicPrintConfig full_fff_config() const;
|
DynamicPrintConfig full_fff_config() const;
|
||||||
DynamicPrintConfig full_sla_config() const;
|
DynamicPrintConfig full_sla_config() const;
|
||||||
|
|
|
@ -114,7 +114,7 @@ void Tab::create_preset_tab()
|
||||||
#endif //__WXOSX__
|
#endif //__WXOSX__
|
||||||
|
|
||||||
// preset chooser
|
// preset chooser
|
||||||
m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(35 * m_em_unit, -1), 0, 0, wxCB_READONLY);
|
m_presets_choice = new PresetBitmapComboBox(panel, wxSize(35 * m_em_unit, -1));
|
||||||
|
|
||||||
auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
||||||
|
|
||||||
|
@ -1690,7 +1690,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup)
|
||||||
auto printhost_cafile_browse = [this, optgroup] (wxWindow* parent) {
|
auto printhost_cafile_browse = [this, optgroup] (wxWindow* parent) {
|
||||||
auto btn = new wxButton(parent, wxID_ANY, " " + _(L("Browse"))+" " +dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
|
auto btn = new wxButton(parent, wxID_ANY, " " + _(L("Browse"))+" " +dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT);
|
||||||
btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
btn->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||||
btn->SetBitmap(create_scaled_bitmap(this, "browse"));
|
btn->SetBitmap(create_scaled_bitmap("browse"));
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
sizer->Add(btn);
|
sizer->Add(btn);
|
||||||
|
|
||||||
|
|
|
@ -120,7 +120,7 @@ protected:
|
||||||
Preset::Type m_type;
|
Preset::Type m_type;
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
const wxString m_title;
|
const wxString m_title;
|
||||||
wxBitmapComboBox* m_presets_choice;
|
PresetBitmapComboBox* m_presets_choice;
|
||||||
ScalableButton* m_btn_save_preset;
|
ScalableButton* m_btn_save_preset;
|
||||||
ScalableButton* m_btn_delete_preset;
|
ScalableButton* m_btn_delete_preset;
|
||||||
ScalableButton* m_btn_hide_incompatible_presets;
|
ScalableButton* m_btn_hide_incompatible_presets;
|
||||||
|
|
|
@ -149,7 +149,7 @@ MsgDataIncompatible::MsgDataIncompatible(const std::unordered_map<std::string, w
|
||||||
MsgDialog(nullptr, wxString::Format(_(L("%s incompatibility")), SLIC3R_APP_NAME),
|
MsgDialog(nullptr, wxString::Format(_(L("%s incompatibility")), SLIC3R_APP_NAME),
|
||||||
wxString::Format(_(L("%s configuration is incompatible")), SLIC3R_APP_NAME), wxID_NONE)
|
wxString::Format(_(L("%s configuration is incompatible")), SLIC3R_APP_NAME), wxID_NONE)
|
||||||
{
|
{
|
||||||
logo->SetBitmap(create_scaled_bitmap(this, "PrusaSlicer_192px_grayscale.png", 192));
|
logo->SetBitmap(create_scaled_bitmap("PrusaSlicer_192px_grayscale.png", this, 192));
|
||||||
|
|
||||||
auto *text = new wxStaticText(this, wxID_ANY, wxString::Format(_(L(
|
auto *text = new wxStaticText(this, wxID_ANY, wxString::Format(_(L(
|
||||||
"This version of %s is not compatible with currently installed configuration bundles.\n"
|
"This version of %s is not compatible with currently installed configuration bundles.\n"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include "WipeTowerDialog.hpp"
|
#include "WipeTowerDialog.hpp"
|
||||||
#include "PresetBundle.hpp"
|
#include "BitmapCache.hpp"
|
||||||
#include "GUI.hpp"
|
#include "GUI.hpp"
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
|
@ -191,7 +191,7 @@ WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, con
|
||||||
|
|
||||||
for (const std::string& color : extruder_colours) {
|
for (const std::string& color : extruder_colours) {
|
||||||
unsigned char rgb[3];
|
unsigned char rgb[3];
|
||||||
Slic3r::PresetBundle::parse_color(color, rgb);
|
Slic3r::GUI::BitmapCache::parse_color(color, rgb);
|
||||||
m_colours.push_back(wxColor(rgb[0], rgb[1], rgb[2]));
|
m_colours.push_back(wxColor(rgb[0], rgb[1], rgb[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,23 +4,14 @@
|
||||||
#include <wx/checklst.h>
|
#include <wx/checklst.h>
|
||||||
#include <wx/combo.h>
|
#include <wx/combo.h>
|
||||||
#include <wx/dataview.h>
|
#include <wx/dataview.h>
|
||||||
#include <wx/dc.h>
|
|
||||||
#include <wx/wupdlock.h>
|
|
||||||
#include <wx/button.h>
|
#include <wx/button.h>
|
||||||
#include <wx/sizer.h>
|
#include <wx/sizer.h>
|
||||||
#include <wx/menu.h>
|
#include <wx/menu.h>
|
||||||
#include <wx/wx.h>
|
#include <wx/bmpcbox.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace Slic3r {
|
|
||||||
enum class ModelVolumeType : int;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef double coordf_t;
|
|
||||||
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
|
||||||
|
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
void msw_rescale_menu(wxMenu* menu);
|
void msw_rescale_menu(wxMenu* menu);
|
||||||
|
@ -48,14 +39,12 @@ wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string,
|
||||||
void enable_menu_item(wxUpdateUIEvent& evt, std::function<bool()> const cb_condition, wxMenuItem* item, wxWindow* win);
|
void enable_menu_item(wxUpdateUIEvent& evt, std::function<bool()> const cb_condition, wxMenuItem* item, wxWindow* win);
|
||||||
|
|
||||||
class wxDialog;
|
class wxDialog;
|
||||||
class wxBitmapComboBox;
|
|
||||||
|
|
||||||
void edit_tooltip(wxString& tooltip);
|
void edit_tooltip(wxString& tooltip);
|
||||||
void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector<int>& btn_ids);
|
void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector<int>& btn_ids);
|
||||||
int em_unit(wxWindow* win);
|
int em_unit(wxWindow* win);
|
||||||
float get_svg_scale_factor(wxWindow* win);
|
|
||||||
|
|
||||||
wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name,
|
wxBitmap create_scaled_bitmap(const std::string& bmp_name, wxWindow *win = nullptr,
|
||||||
const int px_cnt = 16, const bool grayscale = false);
|
const int px_cnt = 16, const bool grayscale = false);
|
||||||
|
|
||||||
std::vector<wxBitmap*> get_extruder_color_icons(bool thin_icon = false);
|
std::vector<wxBitmap*> get_extruder_color_icons(bool thin_icon = false);
|
||||||
|
@ -102,6 +91,37 @@ public:
|
||||||
void OnListBoxSelection(wxCommandEvent& evt);
|
void OnListBoxSelection(wxCommandEvent& evt);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
namespace GUI {
|
||||||
|
// *** PresetBitmapComboBox ***
|
||||||
|
|
||||||
|
// BitmapComboBox used to presets list on Sidebar and Tabs
|
||||||
|
class PresetBitmapComboBox: public wxBitmapComboBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PresetBitmapComboBox(wxWindow* parent, const wxSize& size = wxDefaultSize);
|
||||||
|
~PresetBitmapComboBox() {}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
protected:
|
||||||
|
/* For PresetBitmapComboBox we use bitmaps that are created from images that are already scaled appropriately for Retina
|
||||||
|
* (Contrary to the intuition, the `scale` argument for Bitmap's constructor doesn't mean
|
||||||
|
* "please scale this to such and such" but rather
|
||||||
|
* "the wxImage is already sized for backing scale such and such". )
|
||||||
|
* Unfortunately, the constructor changes the size of wxBitmap too.
|
||||||
|
* Thus We need to use unscaled size value for bitmaps that we use
|
||||||
|
* to avoid scaled size of control items.
|
||||||
|
* For this purpose control drawing methods and
|
||||||
|
* control size calculation methods (virtual) are overridden.
|
||||||
|
**/
|
||||||
|
virtual bool OnAddBitmap(const wxBitmap& bitmap) override;
|
||||||
|
virtual void OnDrawItem(wxDC& dc, const wxRect& rect, int item, int flags) const override;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// *** wxDataViewTreeCtrlComboBox ***
|
// *** wxDataViewTreeCtrlComboBox ***
|
||||||
|
|
||||||
|
@ -127,598 +147,6 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// DataViewBitmapText: helper class used by PrusaBitmapTextRenderer
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class DataViewBitmapText : public wxObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DataViewBitmapText( const wxString &text = wxEmptyString,
|
|
||||||
const wxBitmap& bmp = wxNullBitmap) :
|
|
||||||
m_text(text),
|
|
||||||
m_bmp(bmp)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
DataViewBitmapText(const DataViewBitmapText &other)
|
|
||||||
: wxObject(),
|
|
||||||
m_text(other.m_text),
|
|
||||||
m_bmp(other.m_bmp)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void SetText(const wxString &text) { m_text = text; }
|
|
||||||
wxString GetText() const { return m_text; }
|
|
||||||
void SetBitmap(const wxBitmap &bmp) { m_bmp = bmp; }
|
|
||||||
const wxBitmap &GetBitmap() const { return m_bmp; }
|
|
||||||
|
|
||||||
bool IsSameAs(const DataViewBitmapText& other) const {
|
|
||||||
return m_text == other.m_text && m_bmp.IsSameAs(other.m_bmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const DataViewBitmapText& other) const {
|
|
||||||
return IsSameAs(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const DataViewBitmapText& other) const {
|
|
||||||
return !IsSameAs(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
wxString m_text;
|
|
||||||
wxBitmap m_bmp;
|
|
||||||
|
|
||||||
wxDECLARE_DYNAMIC_CLASS(DataViewBitmapText);
|
|
||||||
};
|
|
||||||
DECLARE_VARIANT_OBJECT(DataViewBitmapText)
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// ObjectDataViewModelNode: a node inside ObjectDataViewModel
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
enum ItemType {
|
|
||||||
itUndef = 0,
|
|
||||||
itObject = 1,
|
|
||||||
itVolume = 2,
|
|
||||||
itInstanceRoot = 4,
|
|
||||||
itInstance = 8,
|
|
||||||
itSettings = 16,
|
|
||||||
itLayerRoot = 32,
|
|
||||||
itLayer = 64,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum ColumnNumber
|
|
||||||
{
|
|
||||||
colName = 0, // item name
|
|
||||||
colPrint , // printable property
|
|
||||||
colExtruder , // extruder selection
|
|
||||||
colEditing , // item editing
|
|
||||||
};
|
|
||||||
|
|
||||||
enum PrintIndicator
|
|
||||||
{
|
|
||||||
piUndef = 0, // no print indicator
|
|
||||||
piPrintable , // printable
|
|
||||||
piUnprintable , // unprintable
|
|
||||||
};
|
|
||||||
|
|
||||||
class ObjectDataViewModelNode;
|
|
||||||
WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray);
|
|
||||||
|
|
||||||
class ObjectDataViewModelNode
|
|
||||||
{
|
|
||||||
ObjectDataViewModelNode* m_parent;
|
|
||||||
MyObjectTreeModelNodePtrArray m_children;
|
|
||||||
wxBitmap m_empty_bmp;
|
|
||||||
size_t m_volumes_cnt = 0;
|
|
||||||
std::vector< std::string > m_opt_categories;
|
|
||||||
t_layer_height_range m_layer_range = { 0.0f, 0.0f };
|
|
||||||
|
|
||||||
wxString m_name;
|
|
||||||
wxBitmap& m_bmp = m_empty_bmp;
|
|
||||||
ItemType m_type;
|
|
||||||
int m_idx = -1;
|
|
||||||
bool m_container = false;
|
|
||||||
wxString m_extruder = "default";
|
|
||||||
wxBitmap m_extruder_bmp;
|
|
||||||
wxBitmap m_action_icon;
|
|
||||||
PrintIndicator m_printable {piUndef};
|
|
||||||
wxBitmap m_printable_icon;
|
|
||||||
|
|
||||||
std::string m_action_icon_name = "";
|
|
||||||
Slic3r::ModelVolumeType m_volume_type;
|
|
||||||
|
|
||||||
// pointer to control (is needed to create scaled bitmaps)
|
|
||||||
wxDataViewCtrl* m_ctrl{ nullptr };
|
|
||||||
|
|
||||||
public:
|
|
||||||
ObjectDataViewModelNode(const wxString& name,
|
|
||||||
const wxString& extruder,
|
|
||||||
wxDataViewCtrl* ctrl):
|
|
||||||
m_parent(NULL),
|
|
||||||
m_name(name),
|
|
||||||
m_type(itObject),
|
|
||||||
m_extruder(extruder),
|
|
||||||
m_ctrl(ctrl)
|
|
||||||
{
|
|
||||||
set_action_and_extruder_icons();
|
|
||||||
init_container();
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
|
||||||
const wxString& sub_obj_name,
|
|
||||||
const wxBitmap& bmp,
|
|
||||||
const wxString& extruder,
|
|
||||||
const int idx = -1 ) :
|
|
||||||
m_parent (parent),
|
|
||||||
m_name (sub_obj_name),
|
|
||||||
m_type (itVolume),
|
|
||||||
m_idx (idx),
|
|
||||||
m_extruder (extruder),
|
|
||||||
m_ctrl (parent->m_ctrl)
|
|
||||||
{
|
|
||||||
m_bmp = bmp;
|
|
||||||
set_action_and_extruder_icons();
|
|
||||||
init_container();
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
|
||||||
const t_layer_height_range& layer_range,
|
|
||||||
const int idx = -1,
|
|
||||||
const wxString& extruder = wxEmptyString );
|
|
||||||
|
|
||||||
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type);
|
|
||||||
|
|
||||||
~ObjectDataViewModelNode()
|
|
||||||
{
|
|
||||||
// free all our children nodes
|
|
||||||
size_t count = m_children.GetCount();
|
|
||||||
for (size_t i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
ObjectDataViewModelNode *child = m_children[i];
|
|
||||||
delete child;
|
|
||||||
}
|
|
||||||
#ifndef NDEBUG
|
|
||||||
// Indicate that the object was deleted.
|
|
||||||
m_idx = -2;
|
|
||||||
#endif /* NDEBUG */
|
|
||||||
}
|
|
||||||
|
|
||||||
void init_container();
|
|
||||||
bool IsContainer() const
|
|
||||||
{
|
|
||||||
return m_container;
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectDataViewModelNode* GetParent()
|
|
||||||
{
|
|
||||||
assert(m_parent == nullptr || m_parent->valid());
|
|
||||||
return m_parent;
|
|
||||||
}
|
|
||||||
MyObjectTreeModelNodePtrArray& GetChildren()
|
|
||||||
{
|
|
||||||
return m_children;
|
|
||||||
}
|
|
||||||
ObjectDataViewModelNode* GetNthChild(unsigned int n)
|
|
||||||
{
|
|
||||||
return m_children.Item(n);
|
|
||||||
}
|
|
||||||
void Insert(ObjectDataViewModelNode* child, unsigned int n)
|
|
||||||
{
|
|
||||||
if (!m_container)
|
|
||||||
m_container = true;
|
|
||||||
m_children.Insert(child, n);
|
|
||||||
}
|
|
||||||
void Append(ObjectDataViewModelNode* child)
|
|
||||||
{
|
|
||||||
if (!m_container)
|
|
||||||
m_container = true;
|
|
||||||
m_children.Add(child);
|
|
||||||
}
|
|
||||||
void RemoveAllChildren()
|
|
||||||
{
|
|
||||||
if (GetChildCount() == 0)
|
|
||||||
return;
|
|
||||||
for (int id = int(GetChildCount()) - 1; id >= 0; --id)
|
|
||||||
{
|
|
||||||
if (m_children.Item(id)->GetChildCount() > 0)
|
|
||||||
m_children[id]->RemoveAllChildren();
|
|
||||||
auto node = m_children[id];
|
|
||||||
m_children.RemoveAt(id);
|
|
||||||
delete node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t GetChildCount() const
|
|
||||||
{
|
|
||||||
return m_children.GetCount();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SetValue(const wxVariant &variant, unsigned int col);
|
|
||||||
|
|
||||||
void SetBitmap(const wxBitmap &icon) { m_bmp = icon; }
|
|
||||||
const wxBitmap& GetBitmap() const { return m_bmp; }
|
|
||||||
const wxString& GetName() const { return m_name; }
|
|
||||||
ItemType GetType() const { return m_type; }
|
|
||||||
void SetIdx(const int& idx);
|
|
||||||
int GetIdx() const { return m_idx; }
|
|
||||||
t_layer_height_range GetLayerRange() const { return m_layer_range; }
|
|
||||||
PrintIndicator IsPrintable() const { return m_printable; }
|
|
||||||
|
|
||||||
// use this function only for childrens
|
|
||||||
void AssignAllVal(ObjectDataViewModelNode& from_node)
|
|
||||||
{
|
|
||||||
// ! Don't overwrite other values because of equality of this values for all children --
|
|
||||||
m_name = from_node.m_name;
|
|
||||||
m_bmp = from_node.m_bmp;
|
|
||||||
m_idx = from_node.m_idx;
|
|
||||||
m_extruder = from_node.m_extruder;
|
|
||||||
m_type = from_node.m_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SwapChildrens(int frst_id, int scnd_id) {
|
|
||||||
if (GetChildCount() < 2 ||
|
|
||||||
frst_id < 0 || (size_t)frst_id >= GetChildCount() ||
|
|
||||||
scnd_id < 0 || (size_t)scnd_id >= GetChildCount())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
ObjectDataViewModelNode new_scnd = *GetNthChild(frst_id);
|
|
||||||
ObjectDataViewModelNode new_frst = *GetNthChild(scnd_id);
|
|
||||||
|
|
||||||
new_scnd.m_idx = m_children.Item(scnd_id)->m_idx;
|
|
||||||
new_frst.m_idx = m_children.Item(frst_id)->m_idx;
|
|
||||||
|
|
||||||
m_children.Item(frst_id)->AssignAllVal(new_frst);
|
|
||||||
m_children.Item(scnd_id)->AssignAllVal(new_scnd);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set action icons for node
|
|
||||||
void set_action_and_extruder_icons();
|
|
||||||
// Set printable icon for node
|
|
||||||
void set_printable_icon(PrintIndicator printable);
|
|
||||||
|
|
||||||
void update_settings_digest_bitmaps();
|
|
||||||
bool update_settings_digest(const std::vector<std::string>& categories);
|
|
||||||
int volume_type() const { return int(m_volume_type); }
|
|
||||||
void msw_rescale();
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
bool valid();
|
|
||||||
#endif /* NDEBUG */
|
|
||||||
bool invalid() const { return m_idx < -1; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend class ObjectDataViewModel;
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// ObjectDataViewModel
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// custom message the model sends to associated control to notify a last volume deleted from the object:
|
|
||||||
wxDECLARE_EVENT(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, wxCommandEvent);
|
|
||||||
|
|
||||||
class ObjectDataViewModel :public wxDataViewModel
|
|
||||||
{
|
|
||||||
std::vector<ObjectDataViewModelNode*> m_objects;
|
|
||||||
std::vector<wxBitmap*> m_volume_bmps;
|
|
||||||
wxBitmap* m_warning_bmp { nullptr };
|
|
||||||
|
|
||||||
wxDataViewCtrl* m_ctrl { nullptr };
|
|
||||||
|
|
||||||
public:
|
|
||||||
ObjectDataViewModel();
|
|
||||||
~ObjectDataViewModel();
|
|
||||||
|
|
||||||
wxDataViewItem Add( const wxString &name,
|
|
||||||
const int extruder,
|
|
||||||
const bool has_errors = false);
|
|
||||||
wxDataViewItem AddVolumeChild( const wxDataViewItem &parent_item,
|
|
||||||
const wxString &name,
|
|
||||||
const Slic3r::ModelVolumeType volume_type,
|
|
||||||
const bool has_errors = false,
|
|
||||||
const int extruder = 0,
|
|
||||||
const bool create_frst_child = true);
|
|
||||||
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
|
|
||||||
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
|
|
||||||
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, const std::vector<bool>& print_indicator);
|
|
||||||
wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
|
|
||||||
wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item,
|
|
||||||
const t_layer_height_range& layer_range,
|
|
||||||
const int extruder = 0,
|
|
||||||
const int index = -1);
|
|
||||||
wxDataViewItem Delete(const wxDataViewItem &item);
|
|
||||||
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
|
|
||||||
void DeleteAll();
|
|
||||||
void DeleteChildren(wxDataViewItem& parent);
|
|
||||||
void DeleteVolumeChildren(wxDataViewItem& parent);
|
|
||||||
void DeleteSettings(const wxDataViewItem& parent);
|
|
||||||
wxDataViewItem GetItemById(int obj_idx);
|
|
||||||
wxDataViewItem GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type);
|
|
||||||
wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
|
|
||||||
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
|
|
||||||
wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx);
|
|
||||||
wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
|
|
||||||
int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
|
|
||||||
int GetIdByItem(const wxDataViewItem& item) const;
|
|
||||||
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
|
|
||||||
int GetObjectIdByItem(const wxDataViewItem& item) const;
|
|
||||||
int GetVolumeIdByItem(const wxDataViewItem& item) const;
|
|
||||||
int GetInstanceIdByItem(const wxDataViewItem& item) const;
|
|
||||||
int GetLayerIdByItem(const wxDataViewItem& item) const;
|
|
||||||
void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
|
|
||||||
int GetRowByItem(const wxDataViewItem& item) const;
|
|
||||||
bool IsEmpty() { return m_objects.empty(); }
|
|
||||||
bool InvalidItem(const wxDataViewItem& item);
|
|
||||||
|
|
||||||
// helper method for wxLog
|
|
||||||
|
|
||||||
wxString GetName(const wxDataViewItem &item) const;
|
|
||||||
wxBitmap& GetBitmap(const wxDataViewItem &item) const;
|
|
||||||
wxString GetExtruder(const wxDataViewItem &item) const;
|
|
||||||
int GetExtruderNumber(const wxDataViewItem &item) const;
|
|
||||||
|
|
||||||
// helper methods to change the model
|
|
||||||
|
|
||||||
virtual unsigned int GetColumnCount() const override { return 3;}
|
|
||||||
virtual wxString GetColumnType(unsigned int col) const override{ return wxT("string"); }
|
|
||||||
|
|
||||||
virtual void GetValue( wxVariant &variant,
|
|
||||||
const wxDataViewItem &item,
|
|
||||||
unsigned int col) const override;
|
|
||||||
virtual bool SetValue( const wxVariant &variant,
|
|
||||||
const wxDataViewItem &item,
|
|
||||||
unsigned int col) override;
|
|
||||||
bool SetValue( const wxVariant &variant,
|
|
||||||
const int item_idx,
|
|
||||||
unsigned int col);
|
|
||||||
|
|
||||||
void SetExtruder(const wxString& extruder, wxDataViewItem item);
|
|
||||||
|
|
||||||
// For parent move child from cur_volume_id place to new_volume_id
|
|
||||||
// Remaining items will moved up/down accordingly
|
|
||||||
wxDataViewItem ReorganizeChildren( const int cur_volume_id,
|
|
||||||
const int new_volume_id,
|
|
||||||
const wxDataViewItem &parent);
|
|
||||||
|
|
||||||
virtual bool IsEnabled(const wxDataViewItem &item, unsigned int col) const override;
|
|
||||||
|
|
||||||
virtual wxDataViewItem GetParent(const wxDataViewItem &item) const override;
|
|
||||||
// get object item
|
|
||||||
wxDataViewItem GetTopParent(const wxDataViewItem &item) const;
|
|
||||||
virtual bool IsContainer(const wxDataViewItem &item) const override;
|
|
||||||
virtual unsigned int GetChildren(const wxDataViewItem &parent,
|
|
||||||
wxDataViewItemArray &array) const override;
|
|
||||||
void GetAllChildren(const wxDataViewItem &parent,wxDataViewItemArray &array) const;
|
|
||||||
// Is the container just a header or an item with all columns
|
|
||||||
// In our case it is an item with all columns
|
|
||||||
virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; }
|
|
||||||
|
|
||||||
ItemType GetItemType(const wxDataViewItem &item) const ;
|
|
||||||
wxDataViewItem GetItemByType( const wxDataViewItem &parent_item,
|
|
||||||
ItemType type) const;
|
|
||||||
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
|
|
||||||
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
|
|
||||||
wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const;
|
|
||||||
bool IsSettingsItem(const wxDataViewItem &item) const;
|
|
||||||
void UpdateSettingsDigest( const wxDataViewItem &item,
|
|
||||||
const std::vector<std::string>& categories);
|
|
||||||
|
|
||||||
bool IsPrintable(const wxDataViewItem &item) const;
|
|
||||||
void UpdateObjectPrintable(wxDataViewItem parent_item);
|
|
||||||
void UpdateInstancesPrintable(wxDataViewItem parent_item);
|
|
||||||
|
|
||||||
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
|
|
||||||
void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; }
|
|
||||||
void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type);
|
|
||||||
wxDataViewItem SetPrintableState( PrintIndicator printable, int obj_idx,
|
|
||||||
int subobj_idx = -1,
|
|
||||||
ItemType subobj_type = itInstance);
|
|
||||||
wxDataViewItem SetObjectPrintableState(PrintIndicator printable, wxDataViewItem obj_item);
|
|
||||||
|
|
||||||
void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; }
|
|
||||||
// Rescale bitmaps for existing Items
|
|
||||||
void Rescale();
|
|
||||||
|
|
||||||
wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,
|
|
||||||
const bool is_marked = false);
|
|
||||||
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
|
|
||||||
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
|
|
||||||
|
|
||||||
bool UpdateColumValues(unsigned col);
|
|
||||||
void UpdateExtruderBitmap(wxDataViewItem item);
|
|
||||||
|
|
||||||
private:
|
|
||||||
wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type);
|
|
||||||
wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item);
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// BitmapTextRenderer
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
|
||||||
class BitmapTextRenderer : public wxDataViewRenderer
|
|
||||||
#else
|
|
||||||
class BitmapTextRenderer : public wxDataViewCustomRenderer
|
|
||||||
#endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BitmapTextRenderer( wxWindow* parent,
|
|
||||||
wxDataViewCellMode mode =
|
|
||||||
#ifdef __WXOSX__
|
|
||||||
wxDATAVIEW_CELL_INERT
|
|
||||||
#else
|
|
||||||
wxDATAVIEW_CELL_EDITABLE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
,int align = wxDVR_DEFAULT_ALIGNMENT
|
|
||||||
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
) :
|
|
||||||
wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align),
|
|
||||||
m_parent(parent)
|
|
||||||
{}
|
|
||||||
#endif //ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
|
||||||
|
|
||||||
bool SetValue(const wxVariant &value);
|
|
||||||
bool GetValue(wxVariant &value) const;
|
|
||||||
#if ENABLE_NONCUSTOM_DATA_VIEW_RENDERING && wxUSE_ACCESSIBILITY
|
|
||||||
virtual wxString GetAccessibleDescription() const override;
|
|
||||||
#endif // wxUSE_ACCESSIBILITY && ENABLE_NONCUSTOM_DATA_VIEW_RENDERING
|
|
||||||
|
|
||||||
virtual bool Render(wxRect cell, wxDC *dc, int state);
|
|
||||||
virtual wxSize GetSize() const;
|
|
||||||
|
|
||||||
bool HasEditorCtrl() const override
|
|
||||||
{
|
|
||||||
#ifdef __WXOSX__
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
wxWindow* CreateEditorCtrl(wxWindow* parent,
|
|
||||||
wxRect labelRect,
|
|
||||||
const wxVariant& value) override;
|
|
||||||
bool GetValueFromEditorCtrl( wxWindow* ctrl,
|
|
||||||
wxVariant& value) override;
|
|
||||||
bool WasCanceled() const { return m_was_unusable_symbol; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
DataViewBitmapText m_value;
|
|
||||||
bool m_was_unusable_symbol {false};
|
|
||||||
wxWindow* m_parent {nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// BitmapChoiceRenderer
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class BitmapChoiceRenderer : public wxDataViewCustomRenderer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BitmapChoiceRenderer(wxDataViewCellMode mode =
|
|
||||||
#ifdef __WXOSX__
|
|
||||||
wxDATAVIEW_CELL_INERT
|
|
||||||
#else
|
|
||||||
wxDATAVIEW_CELL_EDITABLE
|
|
||||||
#endif
|
|
||||||
,int align = wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL
|
|
||||||
) : wxDataViewCustomRenderer(wxT("DataViewBitmapText"), mode, align) {}
|
|
||||||
|
|
||||||
bool SetValue(const wxVariant& value);
|
|
||||||
bool GetValue(wxVariant& value) const;
|
|
||||||
|
|
||||||
virtual bool Render(wxRect cell, wxDC* dc, int state);
|
|
||||||
virtual wxSize GetSize() const;
|
|
||||||
|
|
||||||
bool HasEditorCtrl() const override { return true; }
|
|
||||||
wxWindow* CreateEditorCtrl(wxWindow* parent,
|
|
||||||
wxRect labelRect,
|
|
||||||
const wxVariant& value) override;
|
|
||||||
bool GetValueFromEditorCtrl( wxWindow* ctrl,
|
|
||||||
wxVariant& value) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
DataViewBitmapText m_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// MyCustomRenderer
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
class MyCustomRenderer : public wxDataViewCustomRenderer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// This renderer can be either activatable or editable, for demonstration
|
|
||||||
// purposes. In real programs, you should select whether the user should be
|
|
||||||
// able to activate or edit the cell and it doesn't make sense to switch
|
|
||||||
// between the two -- but this is just an example, so it doesn't stop us.
|
|
||||||
explicit MyCustomRenderer(wxDataViewCellMode mode)
|
|
||||||
: wxDataViewCustomRenderer("string", mode, wxALIGN_CENTER)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
virtual bool Render(wxRect rect, wxDC *dc, int state) override/*wxOVERRIDE*/
|
|
||||||
{
|
|
||||||
dc->SetBrush(*wxLIGHT_GREY_BRUSH);
|
|
||||||
dc->SetPen(*wxTRANSPARENT_PEN);
|
|
||||||
|
|
||||||
rect.Deflate(2);
|
|
||||||
dc->DrawRoundedRectangle(rect, 5);
|
|
||||||
|
|
||||||
RenderText(m_value,
|
|
||||||
0, // no offset
|
|
||||||
wxRect(dc->GetTextExtent(m_value)).CentreIn(rect),
|
|
||||||
dc,
|
|
||||||
state);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool ActivateCell(const wxRect& WXUNUSED(cell),
|
|
||||||
wxDataViewModel *WXUNUSED(model),
|
|
||||||
const wxDataViewItem &WXUNUSED(item),
|
|
||||||
unsigned int WXUNUSED(col),
|
|
||||||
const wxMouseEvent *mouseEvent) override/*wxOVERRIDE*/
|
|
||||||
{
|
|
||||||
wxString position;
|
|
||||||
if (mouseEvent)
|
|
||||||
position = wxString::Format("via mouse at %d, %d", mouseEvent->m_x, mouseEvent->m_y);
|
|
||||||
else
|
|
||||||
position = "from keyboard";
|
|
||||||
// wxLogMessage("MyCustomRenderer ActivateCell() %s", position);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual wxSize GetSize() const override/*wxOVERRIDE*/
|
|
||||||
{
|
|
||||||
return wxSize(60, 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool SetValue(const wxVariant &value) override/*wxOVERRIDE*/
|
|
||||||
{
|
|
||||||
m_value = value.GetString();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool GetValue(wxVariant &WXUNUSED(value)) const override/*wxOVERRIDE*/{ return true; }
|
|
||||||
|
|
||||||
virtual bool HasEditorCtrl() const override/*wxOVERRIDE*/{ return true; }
|
|
||||||
|
|
||||||
virtual wxWindow*
|
|
||||||
CreateEditorCtrl(wxWindow* parent,
|
|
||||||
wxRect labelRect,
|
|
||||||
const wxVariant& value) override/*wxOVERRIDE*/
|
|
||||||
{
|
|
||||||
wxTextCtrl* text = new wxTextCtrl(parent, wxID_ANY, value,
|
|
||||||
labelRect.GetPosition(),
|
|
||||||
labelRect.GetSize(),
|
|
||||||
wxTE_PROCESS_ENTER);
|
|
||||||
text->SetInsertionPointEnd();
|
|
||||||
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool
|
|
||||||
GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value) override/*wxOVERRIDE*/
|
|
||||||
{
|
|
||||||
wxTextCtrl* text = wxDynamicCast(ctrl, wxTextCtrl);
|
|
||||||
if (!text)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
value = text->GetValue();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
wxString m_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// ScalableBitmap
|
// ScalableBitmap
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
@ -733,6 +161,10 @@ public:
|
||||||
|
|
||||||
~ScalableBitmap() {}
|
~ScalableBitmap() {}
|
||||||
|
|
||||||
|
wxSize GetBmpSize() const;
|
||||||
|
int GetBmpWidth() const;
|
||||||
|
int GetBmpHeight() const;
|
||||||
|
|
||||||
void msw_rescale();
|
void msw_rescale();
|
||||||
|
|
||||||
const wxBitmap& bmp() const { return m_bmp; }
|
const wxBitmap& bmp() const { return m_bmp; }
|
||||||
|
|
|
@ -26,58 +26,6 @@ const char *const SUPPORT_TEST_MODELS[] = {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Test pair hash for 'nums' random number pairs.
|
|
||||||
template <class I, class II> void test_pairhash()
|
|
||||||
{
|
|
||||||
const constexpr size_t nums = 1000;
|
|
||||||
I A[nums] = {0}, B[nums] = {0};
|
|
||||||
std::unordered_set<I> CH;
|
|
||||||
std::unordered_map<II, std::pair<I, I>> ints;
|
|
||||||
|
|
||||||
std::random_device rd;
|
|
||||||
std::mt19937 gen(rd());
|
|
||||||
|
|
||||||
const I Ibits = int(sizeof(I) * CHAR_BIT);
|
|
||||||
const II IIbits = int(sizeof(II) * CHAR_BIT);
|
|
||||||
|
|
||||||
int bits = IIbits / 2 < Ibits ? Ibits / 2 : Ibits;
|
|
||||||
if (std::is_signed<I>::value) bits -= 1;
|
|
||||||
const I Imin = 0;
|
|
||||||
const I Imax = I(std::pow(2., bits) - 1);
|
|
||||||
|
|
||||||
std::uniform_int_distribution<I> dis(Imin, Imax);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < nums;) {
|
|
||||||
I a = dis(gen);
|
|
||||||
if (CH.find(a) == CH.end()) { CH.insert(a); A[i] = a; ++i; }
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < nums;) {
|
|
||||||
I b = dis(gen);
|
|
||||||
if (CH.find(b) == CH.end()) { CH.insert(b); B[i] = b; ++i; }
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < nums; ++i) {
|
|
||||||
I a = A[i], b = B[i];
|
|
||||||
|
|
||||||
REQUIRE(a != b);
|
|
||||||
|
|
||||||
II hash_ab = sla::pairhash<I, II>(a, b);
|
|
||||||
II hash_ba = sla::pairhash<I, II>(b, a);
|
|
||||||
REQUIRE(hash_ab == hash_ba);
|
|
||||||
|
|
||||||
auto it = ints.find(hash_ab);
|
|
||||||
|
|
||||||
if (it != ints.end()) {
|
|
||||||
REQUIRE((
|
|
||||||
(it->second.first == a && it->second.second == b) ||
|
|
||||||
(it->second.first == b && it->second.second == a)
|
|
||||||
));
|
|
||||||
} else
|
|
||||||
ints[hash_ab] = std::make_pair(a, b);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("Pillar pairhash should be unique", "[SLASupportGeneration]") {
|
TEST_CASE("Pillar pairhash should be unique", "[SLASupportGeneration]") {
|
||||||
test_pairhash<int, int>();
|
test_pairhash<int, int>();
|
||||||
test_pairhash<int, long>();
|
test_pairhash<int, long>();
|
||||||
|
@ -225,69 +173,6 @@ TEST_CASE("InitializedRasterShouldBeNONEmpty", "[SLARasterOutput]") {
|
||||||
REQUIRE(raster.pixel_dimensions().h_mm == Approx(pixdim.h_mm));
|
REQUIRE(raster.pixel_dimensions().h_mm == Approx(pixdim.h_mm));
|
||||||
}
|
}
|
||||||
|
|
||||||
using TPixel = uint8_t;
|
|
||||||
static constexpr const TPixel FullWhite = 255;
|
|
||||||
static constexpr const TPixel FullBlack = 0;
|
|
||||||
|
|
||||||
template <class A, int N> constexpr int arraysize(const A (&)[N]) { return N; }
|
|
||||||
|
|
||||||
static void check_raster_transformations(sla::Raster::Orientation o,
|
|
||||||
sla::Raster::TMirroring mirroring)
|
|
||||||
{
|
|
||||||
double disp_w = 120., disp_h = 68.;
|
|
||||||
sla::Raster::Resolution res{2560, 1440};
|
|
||||||
sla::Raster::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px};
|
|
||||||
|
|
||||||
auto bb = BoundingBox({0, 0}, {scaled(disp_w), scaled(disp_h)});
|
|
||||||
sla::Raster::Trafo trafo{o, mirroring};
|
|
||||||
trafo.origin_x = bb.center().x();
|
|
||||||
trafo.origin_y = bb.center().y();
|
|
||||||
|
|
||||||
sla::Raster raster{res, pixdim, trafo};
|
|
||||||
|
|
||||||
// create box of size 32x32 pixels (not 1x1 to avoid antialiasing errors)
|
|
||||||
coord_t pw = 32 * coord_t(std::ceil(scaled<double>(pixdim.w_mm)));
|
|
||||||
coord_t ph = 32 * coord_t(std::ceil(scaled<double>(pixdim.h_mm)));
|
|
||||||
ExPolygon box;
|
|
||||||
box.contour.points = {{-pw, -ph}, {pw, -ph}, {pw, ph}, {-pw, ph}};
|
|
||||||
|
|
||||||
double tr_x = scaled<double>(20.), tr_y = tr_x;
|
|
||||||
|
|
||||||
box.translate(tr_x, tr_y);
|
|
||||||
ExPolygon expected_box = box;
|
|
||||||
|
|
||||||
// Now calculate the position of the translated box according to output
|
|
||||||
// trafo.
|
|
||||||
if (o == sla::Raster::Orientation::roPortrait) expected_box.rotate(PI / 2.);
|
|
||||||
|
|
||||||
if (mirroring[X])
|
|
||||||
for (auto &p : expected_box.contour.points) p.x() = -p.x();
|
|
||||||
|
|
||||||
if (mirroring[Y])
|
|
||||||
for (auto &p : expected_box.contour.points) p.y() = -p.y();
|
|
||||||
|
|
||||||
raster.draw(box);
|
|
||||||
|
|
||||||
Point expected_coords = expected_box.contour.bounding_box().center();
|
|
||||||
double rx = unscaled(expected_coords.x() + bb.center().x()) / pixdim.w_mm;
|
|
||||||
double ry = unscaled(expected_coords.y() + bb.center().y()) / pixdim.h_mm;
|
|
||||||
auto w = size_t(std::floor(rx));
|
|
||||||
auto h = res.height_px - size_t(std::floor(ry));
|
|
||||||
|
|
||||||
REQUIRE((w < res.width_px && h < res.height_px));
|
|
||||||
|
|
||||||
auto px = raster.read_pixel(w, h);
|
|
||||||
|
|
||||||
if (px != FullWhite) {
|
|
||||||
sla::PNGImage img;
|
|
||||||
std::fstream outf("out.png", std::ios::out);
|
|
||||||
|
|
||||||
outf << img.serialize(raster);
|
|
||||||
}
|
|
||||||
|
|
||||||
REQUIRE(px == FullWhite);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("MirroringShouldBeCorrect", "[SLARasterOutput]") {
|
TEST_CASE("MirroringShouldBeCorrect", "[SLARasterOutput]") {
|
||||||
sla::Raster::TMirroring mirrorings[] = {sla::Raster::NoMirror,
|
sla::Raster::TMirroring mirrorings[] = {sla::Raster::NoMirror,
|
||||||
sla::Raster::MirrorX,
|
sla::Raster::MirrorX,
|
||||||
|
@ -301,54 +186,6 @@ TEST_CASE("MirroringShouldBeCorrect", "[SLARasterOutput]") {
|
||||||
check_raster_transformations(orientation, mirror);
|
check_raster_transformations(orientation, mirror);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ExPolygon square_with_hole(double v)
|
|
||||||
{
|
|
||||||
ExPolygon poly;
|
|
||||||
coord_t V = scaled(v / 2.);
|
|
||||||
|
|
||||||
poly.contour.points = {{-V, -V}, {V, -V}, {V, V}, {-V, V}};
|
|
||||||
poly.holes.emplace_back();
|
|
||||||
V = V / 2;
|
|
||||||
poly.holes.front().points = {{-V, V}, {V, V}, {V, -V}, {-V, -V}};
|
|
||||||
return poly;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double pixel_area(TPixel px, const sla::Raster::PixelDim &pxdim)
|
|
||||||
{
|
|
||||||
return (pxdim.h_mm * pxdim.w_mm) * px * 1. / (FullWhite - FullBlack);
|
|
||||||
}
|
|
||||||
|
|
||||||
static double raster_white_area(const sla::Raster &raster)
|
|
||||||
{
|
|
||||||
if (raster.empty()) return std::nan("");
|
|
||||||
|
|
||||||
auto res = raster.resolution();
|
|
||||||
double a = 0;
|
|
||||||
|
|
||||||
for (size_t x = 0; x < res.width_px; ++x)
|
|
||||||
for (size_t y = 0; y < res.height_px; ++y) {
|
|
||||||
auto px = raster.read_pixel(x, y);
|
|
||||||
a += pixel_area(px, raster.pixel_dimensions());
|
|
||||||
}
|
|
||||||
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
static double predict_error(const ExPolygon &p, const sla::Raster::PixelDim &pd)
|
|
||||||
{
|
|
||||||
auto lines = p.lines();
|
|
||||||
double pix_err = pixel_area(FullWhite, pd) / 2.;
|
|
||||||
|
|
||||||
// Worst case is when a line is parallel to the shorter axis of one pixel,
|
|
||||||
// when the line will be composed of the max number of pixels
|
|
||||||
double pix_l = std::min(pd.h_mm, pd.w_mm);
|
|
||||||
|
|
||||||
double error = 0.;
|
|
||||||
for (auto &l : lines)
|
|
||||||
error += (unscaled(l.length()) / pix_l) * pix_err;
|
|
||||||
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_CASE("RasterizedPolygonAreaShouldMatch", "[SLARasterOutput]") {
|
TEST_CASE("RasterizedPolygonAreaShouldMatch", "[SLARasterOutput]") {
|
||||||
double disp_w = 120., disp_h = 68.;
|
double disp_w = 120., disp_h = 68.;
|
||||||
|
@ -388,8 +225,4 @@ TEST_CASE("Triangle mesh conversions should be correct", "[SLAConversions]")
|
||||||
std::fstream infile{"extruder_idler_quads.obj", std::ios::in};
|
std::fstream infile{"extruder_idler_quads.obj", std::ios::in};
|
||||||
cntr.from_obj(infile);
|
cntr.from_obj(infile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -292,3 +292,103 @@ void check_validity(const TriangleMesh &input_mesh, int flags)
|
||||||
REQUIRE(mesh.is_manifold());
|
REQUIRE(mesh.is_manifold());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void check_raster_transformations(sla::Raster::Orientation o, sla::Raster::TMirroring mirroring)
|
||||||
|
{
|
||||||
|
double disp_w = 120., disp_h = 68.;
|
||||||
|
sla::Raster::Resolution res{2560, 1440};
|
||||||
|
sla::Raster::PixelDim pixdim{disp_w / res.width_px, disp_h / res.height_px};
|
||||||
|
|
||||||
|
auto bb = BoundingBox({0, 0}, {scaled(disp_w), scaled(disp_h)});
|
||||||
|
sla::Raster::Trafo trafo{o, mirroring};
|
||||||
|
trafo.origin_x = bb.center().x();
|
||||||
|
trafo.origin_y = bb.center().y();
|
||||||
|
|
||||||
|
sla::Raster raster{res, pixdim, trafo};
|
||||||
|
|
||||||
|
// create box of size 32x32 pixels (not 1x1 to avoid antialiasing errors)
|
||||||
|
coord_t pw = 32 * coord_t(std::ceil(scaled<double>(pixdim.w_mm)));
|
||||||
|
coord_t ph = 32 * coord_t(std::ceil(scaled<double>(pixdim.h_mm)));
|
||||||
|
ExPolygon box;
|
||||||
|
box.contour.points = {{-pw, -ph}, {pw, -ph}, {pw, ph}, {-pw, ph}};
|
||||||
|
|
||||||
|
double tr_x = scaled<double>(20.), tr_y = tr_x;
|
||||||
|
|
||||||
|
box.translate(tr_x, tr_y);
|
||||||
|
ExPolygon expected_box = box;
|
||||||
|
|
||||||
|
// Now calculate the position of the translated box according to output
|
||||||
|
// trafo.
|
||||||
|
if (o == sla::Raster::Orientation::roPortrait) expected_box.rotate(PI / 2.);
|
||||||
|
|
||||||
|
if (mirroring[X])
|
||||||
|
for (auto &p : expected_box.contour.points) p.x() = -p.x();
|
||||||
|
|
||||||
|
if (mirroring[Y])
|
||||||
|
for (auto &p : expected_box.contour.points) p.y() = -p.y();
|
||||||
|
|
||||||
|
raster.draw(box);
|
||||||
|
|
||||||
|
Point expected_coords = expected_box.contour.bounding_box().center();
|
||||||
|
double rx = unscaled(expected_coords.x() + bb.center().x()) / pixdim.w_mm;
|
||||||
|
double ry = unscaled(expected_coords.y() + bb.center().y()) / pixdim.h_mm;
|
||||||
|
auto w = size_t(std::floor(rx));
|
||||||
|
auto h = res.height_px - size_t(std::floor(ry));
|
||||||
|
|
||||||
|
REQUIRE((w < res.width_px && h < res.height_px));
|
||||||
|
|
||||||
|
auto px = raster.read_pixel(w, h);
|
||||||
|
|
||||||
|
if (px != FullWhite) {
|
||||||
|
sla::PNGImage img;
|
||||||
|
std::fstream outf("out.png", std::ios::out);
|
||||||
|
|
||||||
|
outf << img.serialize(raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
REQUIRE(px == FullWhite);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExPolygon square_with_hole(double v)
|
||||||
|
{
|
||||||
|
ExPolygon poly;
|
||||||
|
coord_t V = scaled(v / 2.);
|
||||||
|
|
||||||
|
poly.contour.points = {{-V, -V}, {V, -V}, {V, V}, {-V, V}};
|
||||||
|
poly.holes.emplace_back();
|
||||||
|
V = V / 2;
|
||||||
|
poly.holes.front().points = {{-V, V}, {V, V}, {V, -V}, {-V, -V}};
|
||||||
|
return poly;
|
||||||
|
}
|
||||||
|
|
||||||
|
double raster_white_area(const sla::Raster &raster)
|
||||||
|
{
|
||||||
|
if (raster.empty()) return std::nan("");
|
||||||
|
|
||||||
|
auto res = raster.resolution();
|
||||||
|
double a = 0;
|
||||||
|
|
||||||
|
for (size_t x = 0; x < res.width_px; ++x)
|
||||||
|
for (size_t y = 0; y < res.height_px; ++y) {
|
||||||
|
auto px = raster.read_pixel(x, y);
|
||||||
|
a += pixel_area(px, raster.pixel_dimensions());
|
||||||
|
}
|
||||||
|
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
double predict_error(const ExPolygon &p, const sla::Raster::PixelDim &pd)
|
||||||
|
{
|
||||||
|
auto lines = p.lines();
|
||||||
|
double pix_err = pixel_area(FullWhite, pd) / 2.;
|
||||||
|
|
||||||
|
// Worst case is when a line is parallel to the shorter axis of one pixel,
|
||||||
|
// when the line will be composed of the max number of pixels
|
||||||
|
double pix_l = std::min(pd.h_mm, pd.w_mm);
|
||||||
|
|
||||||
|
double error = 0.;
|
||||||
|
for (auto &l : lines)
|
||||||
|
error += (unscaled(l.length()) / pix_l) * pix_err;
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
// Debug
|
// Debug
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
#include "libslic3r/Format/OBJ.hpp"
|
#include "libslic3r/Format/OBJ.hpp"
|
||||||
|
@ -109,4 +110,78 @@ inline void test_support_model_collision(
|
||||||
test_support_model_collision(obj_filename, input_supportcfg, hcfg, {});
|
test_support_model_collision(obj_filename, input_supportcfg, hcfg, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test pair hash for 'nums' random number pairs.
|
||||||
|
template <class I, class II> void test_pairhash()
|
||||||
|
{
|
||||||
|
const constexpr size_t nums = 1000;
|
||||||
|
I A[nums] = {0}, B[nums] = {0};
|
||||||
|
std::unordered_set<I> CH;
|
||||||
|
std::unordered_map<II, std::pair<I, I>> ints;
|
||||||
|
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
|
||||||
|
const I Ibits = int(sizeof(I) * CHAR_BIT);
|
||||||
|
const II IIbits = int(sizeof(II) * CHAR_BIT);
|
||||||
|
|
||||||
|
int bits = IIbits / 2 < Ibits ? Ibits / 2 : Ibits;
|
||||||
|
if (std::is_signed<I>::value) bits -= 1;
|
||||||
|
const I Imin = 0;
|
||||||
|
const I Imax = I(std::pow(2., bits) - 1);
|
||||||
|
|
||||||
|
std::uniform_int_distribution<I> dis(Imin, Imax);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nums;) {
|
||||||
|
I a = dis(gen);
|
||||||
|
if (CH.find(a) == CH.end()) { CH.insert(a); A[i] = a; ++i; }
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nums;) {
|
||||||
|
I b = dis(gen);
|
||||||
|
if (CH.find(b) == CH.end()) { CH.insert(b); B[i] = b; ++i; }
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nums; ++i) {
|
||||||
|
I a = A[i], b = B[i];
|
||||||
|
|
||||||
|
REQUIRE(a != b);
|
||||||
|
|
||||||
|
II hash_ab = sla::pairhash<I, II>(a, b);
|
||||||
|
II hash_ba = sla::pairhash<I, II>(b, a);
|
||||||
|
REQUIRE(hash_ab == hash_ba);
|
||||||
|
|
||||||
|
auto it = ints.find(hash_ab);
|
||||||
|
|
||||||
|
if (it != ints.end()) {
|
||||||
|
REQUIRE((
|
||||||
|
(it->second.first == a && it->second.second == b) ||
|
||||||
|
(it->second.first == b && it->second.second == a)
|
||||||
|
));
|
||||||
|
} else
|
||||||
|
ints[hash_ab] = std::make_pair(a, b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SLA Raster test utils:
|
||||||
|
|
||||||
|
using TPixel = uint8_t;
|
||||||
|
static constexpr const TPixel FullWhite = 255;
|
||||||
|
static constexpr const TPixel FullBlack = 0;
|
||||||
|
|
||||||
|
template <class A, int N> constexpr int arraysize(const A (&)[N]) { return N; }
|
||||||
|
|
||||||
|
void check_raster_transformations(sla::Raster::Orientation o,
|
||||||
|
sla::Raster::TMirroring mirroring);
|
||||||
|
|
||||||
|
ExPolygon square_with_hole(double v);
|
||||||
|
|
||||||
|
inline double pixel_area(TPixel px, const sla::Raster::PixelDim &pxdim)
|
||||||
|
{
|
||||||
|
return (pxdim.h_mm * pxdim.w_mm) * px * 1. / (FullWhite - FullBlack);
|
||||||
|
}
|
||||||
|
|
||||||
|
double raster_white_area(const sla::Raster &raster);
|
||||||
|
|
||||||
|
double predict_error(const ExPolygon &p, const sla::Raster::PixelDim &pd);
|
||||||
|
|
||||||
#endif // SLA_TEST_UTILS_HPP
|
#endif // SLA_TEST_UTILS_HPP
|
||||||
|
|
Loading…
Reference in a new issue