mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-11 08:47:52 -06:00
Merge remote-tracking branch 'remotes/origin/ys_new_features'
This commit is contained in:
commit
0c95d4e0d9
26 changed files with 1603 additions and 165 deletions
BIN
resources/icons/row.png
Normal file
BIN
resources/icons/row.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
resources/icons/table.png
Normal file
BIN
resources/icons/table.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 465 B |
|
@ -11,6 +11,7 @@
|
||||||
#include <boost/algorithm/string/classification.hpp>
|
#include <boost/algorithm/string/classification.hpp>
|
||||||
#include <boost/algorithm/string/split.hpp>
|
#include <boost/algorithm/string/split.hpp>
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
#include <boost/filesystem/operations.hpp>
|
#include <boost/filesystem/operations.hpp>
|
||||||
#include <boost/nowide/fstream.hpp>
|
#include <boost/nowide/fstream.hpp>
|
||||||
#include <boost/nowide/cstdio.hpp>
|
#include <boost/nowide/cstdio.hpp>
|
||||||
|
@ -33,6 +34,7 @@ const std::string RELATIONSHIPS_FILE = "_rels/.rels";
|
||||||
const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
|
const std::string PRINT_CONFIG_FILE = "Metadata/Slic3r_PE.config";
|
||||||
const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
|
const std::string MODEL_CONFIG_FILE = "Metadata/Slic3r_PE_model.config";
|
||||||
const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
|
const std::string LAYER_HEIGHTS_PROFILE_FILE = "Metadata/Slic3r_PE_layer_heights_profile.txt";
|
||||||
|
const std::string LAYER_CONFIG_RANGES_FILE = "Metadata/Slic3r_PE_layer_config_ranges.txt";
|
||||||
const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
|
const std::string SLA_SUPPORT_POINTS_FILE = "Metadata/Slic3r_PE_sla_support_points.txt";
|
||||||
|
|
||||||
const char* MODEL_TAG = "model";
|
const char* MODEL_TAG = "model";
|
||||||
|
@ -331,6 +333,7 @@ namespace Slic3r {
|
||||||
typedef std::map<int, ObjectMetadata> IdToMetadataMap;
|
typedef std::map<int, ObjectMetadata> IdToMetadataMap;
|
||||||
typedef std::map<int, Geometry> IdToGeometryMap;
|
typedef std::map<int, Geometry> IdToGeometryMap;
|
||||||
typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
|
typedef std::map<int, std::vector<coordf_t>> IdToLayerHeightsProfileMap;
|
||||||
|
typedef std::map<int, t_layer_config_ranges> IdToLayerConfigRangesMap;
|
||||||
typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
|
typedef std::map<int, std::vector<sla::SupportPoint>> IdToSlaSupportPointsMap;
|
||||||
|
|
||||||
// Version of the 3mf file
|
// Version of the 3mf file
|
||||||
|
@ -347,6 +350,7 @@ namespace Slic3r {
|
||||||
CurrentConfig m_curr_config;
|
CurrentConfig m_curr_config;
|
||||||
IdToMetadataMap m_objects_metadata;
|
IdToMetadataMap m_objects_metadata;
|
||||||
IdToLayerHeightsProfileMap m_layer_heights_profiles;
|
IdToLayerHeightsProfileMap m_layer_heights_profiles;
|
||||||
|
IdToLayerConfigRangesMap m_layer_config_ranges;
|
||||||
IdToSlaSupportPointsMap m_sla_support_points;
|
IdToSlaSupportPointsMap m_sla_support_points;
|
||||||
std::string m_curr_metadata_name;
|
std::string m_curr_metadata_name;
|
||||||
std::string m_curr_characters;
|
std::string m_curr_characters;
|
||||||
|
@ -365,6 +369,7 @@ namespace Slic3r {
|
||||||
bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config);
|
bool _load_model_from_file(const std::string& filename, Model& model, DynamicPrintConfig& config);
|
||||||
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
bool _extract_model_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||||
void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
void _extract_layer_heights_profile_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||||
|
void _extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||||
void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
void _extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat);
|
||||||
|
|
||||||
void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, const std::string& archive_filename);
|
void _extract_print_config_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat, DynamicPrintConfig& config, const std::string& archive_filename);
|
||||||
|
@ -476,6 +481,7 @@ namespace Slic3r {
|
||||||
m_curr_config.volume_id = -1;
|
m_curr_config.volume_id = -1;
|
||||||
m_objects_metadata.clear();
|
m_objects_metadata.clear();
|
||||||
m_layer_heights_profiles.clear();
|
m_layer_heights_profiles.clear();
|
||||||
|
m_layer_config_ranges.clear();
|
||||||
m_sla_support_points.clear();
|
m_sla_support_points.clear();
|
||||||
m_curr_metadata_name.clear();
|
m_curr_metadata_name.clear();
|
||||||
m_curr_characters.clear();
|
m_curr_characters.clear();
|
||||||
|
@ -546,9 +552,14 @@ namespace Slic3r {
|
||||||
|
|
||||||
if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE))
|
if (boost::algorithm::iequals(name, LAYER_HEIGHTS_PROFILE_FILE))
|
||||||
{
|
{
|
||||||
// extract slic3r lazer heights profile file
|
// extract slic3r layer heights profile file
|
||||||
_extract_layer_heights_profile_config_from_archive(archive, stat);
|
_extract_layer_heights_profile_config_from_archive(archive, stat);
|
||||||
}
|
}
|
||||||
|
if (boost::algorithm::iequals(name, LAYER_CONFIG_RANGES_FILE))
|
||||||
|
{
|
||||||
|
// extract slic3r layer config ranges file
|
||||||
|
_extract_layer_config_ranges_from_archive(archive, stat);
|
||||||
|
}
|
||||||
else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE))
|
else if (boost::algorithm::iequals(name, SLA_SUPPORT_POINTS_FILE))
|
||||||
{
|
{
|
||||||
// extract sla support points file
|
// extract sla support points file
|
||||||
|
@ -592,6 +603,11 @@ namespace Slic3r {
|
||||||
if (obj_layer_heights_profile != m_layer_heights_profiles.end())
|
if (obj_layer_heights_profile != m_layer_heights_profiles.end())
|
||||||
model_object->layer_height_profile = obj_layer_heights_profile->second;
|
model_object->layer_height_profile = obj_layer_heights_profile->second;
|
||||||
|
|
||||||
|
// m_layer_config_ranges are indexed by a 1 based model object index.
|
||||||
|
IdToLayerConfigRangesMap::iterator obj_layer_config_ranges = m_layer_config_ranges.find(object.second + 1);
|
||||||
|
if (obj_layer_config_ranges != m_layer_config_ranges.end())
|
||||||
|
model_object->layer_config_ranges = obj_layer_config_ranges->second;
|
||||||
|
|
||||||
// m_sla_support_points are indexed by a 1 based model object index.
|
// m_sla_support_points are indexed by a 1 based model object index.
|
||||||
IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.second + 1);
|
IdToSlaSupportPointsMap::iterator obj_sla_support_points = m_sla_support_points.find(object.second + 1);
|
||||||
if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) {
|
if (obj_sla_support_points != m_sla_support_points.end() && !obj_sla_support_points->second.empty()) {
|
||||||
|
@ -769,6 +785,115 @@ namespace Slic3r {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _3MF_Importer::_extract_layer_config_ranges_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
|
||||||
|
{
|
||||||
|
if (stat.m_uncomp_size > 0)
|
||||||
|
{
|
||||||
|
std::string buffer((size_t)stat.m_uncomp_size, 0);
|
||||||
|
mz_bool res = mz_zip_reader_extract_file_to_mem(&archive, stat.m_filename, (void*)buffer.data(), (size_t)stat.m_uncomp_size, 0);
|
||||||
|
if (res == 0) {
|
||||||
|
add_error("Error while reading layer config ranges data to buffer");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer.back() == '|')
|
||||||
|
buffer.pop_back();
|
||||||
|
|
||||||
|
std::vector<std::string> objects;
|
||||||
|
boost::split(objects, buffer, boost::is_any_of("|"), boost::token_compress_off);
|
||||||
|
|
||||||
|
for (std::string& object : objects)
|
||||||
|
{
|
||||||
|
// delete all spaces
|
||||||
|
boost::replace_all(object, " ", "");
|
||||||
|
|
||||||
|
std::vector<std::string> object_data;
|
||||||
|
boost::split(object_data, object, boost::is_any_of("*"), boost::token_compress_off);
|
||||||
|
/* there should be at least one layer config range in the object
|
||||||
|
* object_data[0] => object information
|
||||||
|
* object_data[i>=1] => range information
|
||||||
|
*/
|
||||||
|
if (object_data.size() < 2) {
|
||||||
|
add_error("Error while reading object data");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> object_data_id;
|
||||||
|
boost::split(object_data_id, object_data[0], boost::is_any_of("="), boost::token_compress_off);
|
||||||
|
if (object_data_id.size() != 2) {
|
||||||
|
add_error("Error while reading object id");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get object information
|
||||||
|
int object_id = std::atoi(object_data_id[1].c_str());
|
||||||
|
if (object_id == 0) {
|
||||||
|
add_error("Found invalid object id");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IdToLayerConfigRangesMap::iterator object_item = m_layer_config_ranges.find(object_id);
|
||||||
|
if (object_item != m_layer_config_ranges.end()) {
|
||||||
|
add_error("Found duplicated layer config range");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_layer_config_ranges config_ranges;
|
||||||
|
|
||||||
|
// get ranges information
|
||||||
|
for (size_t i = 1; i < object_data.size(); ++i)
|
||||||
|
{
|
||||||
|
if (object_data[i].back() == '\n')
|
||||||
|
object_data[i].pop_back();
|
||||||
|
|
||||||
|
std::vector<std::string> range_data;
|
||||||
|
boost::split(range_data, object_data[i], boost::is_any_of("\n"), boost::token_compress_off);
|
||||||
|
/* There should be at least two options for layer config range
|
||||||
|
* range_data[0] => Z range information
|
||||||
|
* range_data[i>=1] => configuration for the range
|
||||||
|
*/
|
||||||
|
if (range_data.size() < 3) {
|
||||||
|
add_error("Found invalid layer config range");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> z_range_str;
|
||||||
|
boost::split(z_range_str, range_data[0], boost::is_any_of("="), boost::token_compress_off);
|
||||||
|
if (z_range_str.size() != 2) {
|
||||||
|
add_error("Error while reading layer config range");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> z_values;
|
||||||
|
boost::split(z_values, z_range_str[1], boost::is_any_of(";"), boost::token_compress_off);
|
||||||
|
if (z_values.size() != 2) {
|
||||||
|
add_error("Found invalid layer config range");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get Z range information
|
||||||
|
t_layer_height_range z_range = { (coordf_t)std::atof(z_values[0].c_str()) , (coordf_t)std::atof(z_values[1].c_str()) };
|
||||||
|
DynamicPrintConfig& config = config_ranges[z_range];
|
||||||
|
|
||||||
|
// get configuration options for the range
|
||||||
|
for (size_t j = 1; j < range_data.size(); ++j)
|
||||||
|
{
|
||||||
|
std::vector<std::string> key_val;
|
||||||
|
boost::split(key_val, range_data[j], boost::is_any_of("="), boost::token_compress_off);
|
||||||
|
if (key_val.size() != 2) {
|
||||||
|
add_error("Error while reading config value");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
config.set_deserialize(key_val[0], key_val[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!config_ranges.empty())
|
||||||
|
m_layer_config_ranges.insert(IdToLayerConfigRangesMap::value_type(object_id, config_ranges));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _3MF_Importer::_extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
|
void _3MF_Importer::_extract_sla_support_points_from_archive(mz_zip_archive& archive, const mz_zip_archive_file_stat& stat)
|
||||||
{
|
{
|
||||||
if (stat.m_uncomp_size > 0)
|
if (stat.m_uncomp_size > 0)
|
||||||
|
@ -1624,6 +1749,7 @@ namespace Slic3r {
|
||||||
bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object, VolumeToOffsetsMap& volumes_offsets);
|
bool _add_mesh_to_object_stream(std::stringstream& stream, ModelObject& object, VolumeToOffsetsMap& volumes_offsets);
|
||||||
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
|
bool _add_build_to_model_stream(std::stringstream& stream, const BuildItemsList& build_items);
|
||||||
bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
|
bool _add_layer_height_profile_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||||
|
bool _add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||||
bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
|
bool _add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model);
|
||||||
bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config);
|
bool _add_print_config_file_to_archive(mz_zip_archive& archive, const DynamicPrintConfig &config);
|
||||||
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data);
|
bool _add_model_config_file_to_archive(mz_zip_archive& archive, const Model& model, const IdToObjectDataMap &objects_data);
|
||||||
|
@ -1684,6 +1810,16 @@ namespace Slic3r {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Adds layer config ranges file ("Metadata/Slic3r_PE_layer_config_ranges.txt").
|
||||||
|
// All layer height profiles of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
|
||||||
|
// The index differes from the index of an object ID of an object instance of a 3MF file!
|
||||||
|
if (!_add_layer_config_ranges_file_to_archive(archive, model))
|
||||||
|
{
|
||||||
|
close_zip_writer(&archive);
|
||||||
|
boost::filesystem::remove(filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Adds sla support points file ("Metadata/Slic3r_PE_sla_support_points.txt").
|
// Adds sla support points file ("Metadata/Slic3r_PE_sla_support_points.txt").
|
||||||
// All sla support points of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
|
// All sla support points of all ModelObjects are stored here, indexed by 1 based index of the ModelObject in Model.
|
||||||
// The index differes from the index of an object ID of an object instance of a 3MF file!
|
// The index differes from the index of an object ID of an object instance of a 3MF file!
|
||||||
|
@ -2013,6 +2149,50 @@ namespace Slic3r {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _3MF_Exporter::_add_layer_config_ranges_file_to_archive(mz_zip_archive& archive, Model& model)
|
||||||
|
{
|
||||||
|
std::string out = "";
|
||||||
|
char buffer[1024];
|
||||||
|
|
||||||
|
unsigned int object_cnt = 0;
|
||||||
|
for (const ModelObject* object : model.objects)
|
||||||
|
{
|
||||||
|
object_cnt++;
|
||||||
|
const t_layer_config_ranges& ranges = object->layer_config_ranges;
|
||||||
|
if (!ranges.empty())
|
||||||
|
{
|
||||||
|
sprintf(buffer, "object_id=%d\n", object_cnt);
|
||||||
|
out += buffer;
|
||||||
|
|
||||||
|
// Store the layer config ranges.
|
||||||
|
for (const auto& range : ranges)
|
||||||
|
{
|
||||||
|
// store minX and maxZ
|
||||||
|
sprintf(buffer, "*z_range = %f;%f\n", range.first.first, range.first.second);
|
||||||
|
out += buffer;
|
||||||
|
|
||||||
|
// store range configuration
|
||||||
|
const DynamicPrintConfig& config = range.second;
|
||||||
|
for (const std::string& key : config.keys())
|
||||||
|
out += " " + key + " = " + config.serialize(key) + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
out += "|";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!out.empty())
|
||||||
|
{
|
||||||
|
if (!mz_zip_writer_add_mem(&archive, LAYER_CONFIG_RANGES_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
|
||||||
|
{
|
||||||
|
add_error("Unable to add layer heights profile file to archive");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool _3MF_Exporter::_add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model)
|
bool _3MF_Exporter::_add_sla_support_points_file_to_archive(mz_zip_archive& archive, Model& model)
|
||||||
{
|
{
|
||||||
std::string out = "";
|
std::string out = "";
|
||||||
|
|
|
@ -106,6 +106,9 @@ struct AMFParserContext
|
||||||
// amf/material/metadata
|
// amf/material/metadata
|
||||||
NODE_TYPE_OBJECT, // amf/object
|
NODE_TYPE_OBJECT, // amf/object
|
||||||
// amf/object/metadata
|
// amf/object/metadata
|
||||||
|
NODE_TYPE_LAYER_CONFIG, // amf/object/layer_config_ranges
|
||||||
|
NODE_TYPE_RANGE, // amf/object/layer_config_ranges/range
|
||||||
|
// amf/object/layer_config_ranges/range/metadata
|
||||||
NODE_TYPE_MESH, // amf/object/mesh
|
NODE_TYPE_MESH, // amf/object/mesh
|
||||||
NODE_TYPE_VERTICES, // amf/object/mesh/vertices
|
NODE_TYPE_VERTICES, // amf/object/mesh/vertices
|
||||||
NODE_TYPE_VERTEX, // amf/object/mesh/vertices/vertex
|
NODE_TYPE_VERTEX, // amf/object/mesh/vertices/vertex
|
||||||
|
@ -260,7 +263,9 @@ void AMFParserContext::startElement(const char *name, const char **atts)
|
||||||
m_value[0] = get_attribute(atts, "type");
|
m_value[0] = get_attribute(atts, "type");
|
||||||
node_type_new = NODE_TYPE_METADATA;
|
node_type_new = NODE_TYPE_METADATA;
|
||||||
}
|
}
|
||||||
} else if (strcmp(name, "mesh") == 0) {
|
} else if (strcmp(name, "layer_config_ranges") == 0 && m_path[1] == NODE_TYPE_OBJECT)
|
||||||
|
node_type_new = NODE_TYPE_LAYER_CONFIG;
|
||||||
|
else if (strcmp(name, "mesh") == 0) {
|
||||||
if (m_path[1] == NODE_TYPE_OBJECT)
|
if (m_path[1] == NODE_TYPE_OBJECT)
|
||||||
node_type_new = NODE_TYPE_MESH;
|
node_type_new = NODE_TYPE_MESH;
|
||||||
} else if (strcmp(name, "instance") == 0) {
|
} else if (strcmp(name, "instance") == 0) {
|
||||||
|
@ -317,6 +322,10 @@ void AMFParserContext::startElement(const char *name, const char **atts)
|
||||||
else if (strcmp(name, "mirrorz") == 0)
|
else if (strcmp(name, "mirrorz") == 0)
|
||||||
node_type_new = NODE_TYPE_MIRRORZ;
|
node_type_new = NODE_TYPE_MIRRORZ;
|
||||||
}
|
}
|
||||||
|
else if (m_path[2] == NODE_TYPE_LAYER_CONFIG && strcmp(name, "range") == 0) {
|
||||||
|
assert(m_object);
|
||||||
|
node_type_new = NODE_TYPE_RANGE;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
if (m_path[3] == NODE_TYPE_VERTICES) {
|
if (m_path[3] == NODE_TYPE_VERTICES) {
|
||||||
|
@ -334,6 +343,10 @@ void AMFParserContext::startElement(const char *name, const char **atts)
|
||||||
} else if (strcmp(name, "triangle") == 0)
|
} else if (strcmp(name, "triangle") == 0)
|
||||||
node_type_new = NODE_TYPE_TRIANGLE;
|
node_type_new = NODE_TYPE_TRIANGLE;
|
||||||
}
|
}
|
||||||
|
else if (m_path[3] == NODE_TYPE_RANGE && strcmp(name, "metadata") == 0) {
|
||||||
|
m_value[0] = get_attribute(atts, "type");
|
||||||
|
node_type_new = NODE_TYPE_METADATA;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
if (strcmp(name, "coordinates") == 0) {
|
if (strcmp(name, "coordinates") == 0) {
|
||||||
|
@ -571,8 +584,13 @@ void AMFParserContext::endElement(const char * /* name */)
|
||||||
config = &m_material->config;
|
config = &m_material->config;
|
||||||
else if (m_path[1] == NODE_TYPE_OBJECT && m_object)
|
else if (m_path[1] == NODE_TYPE_OBJECT && m_object)
|
||||||
config = &m_object->config;
|
config = &m_object->config;
|
||||||
} else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume)
|
}
|
||||||
|
else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume)
|
||||||
config = &m_volume->config;
|
config = &m_volume->config;
|
||||||
|
else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_RANGE && m_object && !m_object->layer_config_ranges.empty()) {
|
||||||
|
auto it = --m_object->layer_config_ranges.end();
|
||||||
|
config = &it->second;
|
||||||
|
}
|
||||||
if (config)
|
if (config)
|
||||||
config->set_deserialize(opt_key, m_value[1]);
|
config->set_deserialize(opt_key, m_value[1]);
|
||||||
} else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "layer_height_profile") == 0) {
|
} else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "layer_height_profile") == 0) {
|
||||||
|
@ -609,6 +627,16 @@ void AMFParserContext::endElement(const char * /* name */)
|
||||||
}
|
}
|
||||||
m_object->sla_points_status = sla::PointsStatus::UserModified;
|
m_object->sla_points_status = sla::PointsStatus::UserModified;
|
||||||
}
|
}
|
||||||
|
else if (m_path.size() == 5 && m_path[1] == NODE_TYPE_OBJECT && m_path[3] == NODE_TYPE_RANGE &&
|
||||||
|
m_object && strcmp(opt_key, "layer_height_ranges") == 0) {
|
||||||
|
// Parse object's layer_height_ranges, a semicolon separated doubles.
|
||||||
|
char* p = const_cast<char*>(m_value[1].c_str());
|
||||||
|
char* end = strchr(p, ';');
|
||||||
|
*end = 0;
|
||||||
|
|
||||||
|
const t_layer_height_range range = {double(atof(p)), double(atof(end + 1))};
|
||||||
|
m_object->layer_config_ranges[range];
|
||||||
|
}
|
||||||
else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume) {
|
else if (m_path.size() == 5 && m_path[3] == NODE_TYPE_VOLUME && m_volume) {
|
||||||
if (strcmp(opt_key, "modifier") == 0) {
|
if (strcmp(opt_key, "modifier") == 0) {
|
||||||
// Is this volume a modifier volume?
|
// Is this volume a modifier volume?
|
||||||
|
@ -907,6 +935,31 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
|
||||||
}
|
}
|
||||||
//FIXME Store the layer height ranges (ModelObject::layer_height_ranges)
|
//FIXME Store the layer height ranges (ModelObject::layer_height_ranges)
|
||||||
|
|
||||||
|
|
||||||
|
// #ys_FIXME_experiment : Try to export layer config range
|
||||||
|
const t_layer_config_ranges& config_ranges = object->layer_config_ranges;
|
||||||
|
if (!config_ranges.empty())
|
||||||
|
{
|
||||||
|
// Store the layer config range as a single semicolon separated list.
|
||||||
|
stream << " <layer_config_ranges>\n";
|
||||||
|
size_t layer_counter = 0;
|
||||||
|
for (auto range : config_ranges) {
|
||||||
|
stream << " <range id=\"" << layer_counter << "\">\n";
|
||||||
|
|
||||||
|
stream << " <metadata type=\"slic3r.layer_height_ranges\">";
|
||||||
|
stream << range.first.first << ";" << range.first.second << "</metadata>\n";
|
||||||
|
|
||||||
|
for (const std::string& key : range.second.keys())
|
||||||
|
stream << " <metadata type=\"slic3r." << key << "\">" << range.second.serialize(key) << "</metadata>\n";
|
||||||
|
|
||||||
|
stream << " </range>\n";
|
||||||
|
layer_counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream << " </layer_config_ranges>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const std::vector<sla::SupportPoint>& sla_support_points = object->sla_support_points;
|
const std::vector<sla::SupportPoint>& sla_support_points = object->sla_support_points;
|
||||||
if (!sla_support_points.empty()) {
|
if (!sla_support_points.empty()) {
|
||||||
// Store the SLA supports as a single semicolon separated list.
|
// Store the SLA supports as a single semicolon separated list.
|
||||||
|
|
|
@ -594,6 +594,7 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
|
||||||
this->sla_support_points = rhs.sla_support_points;
|
this->sla_support_points = rhs.sla_support_points;
|
||||||
this->sla_points_status = rhs.sla_points_status;
|
this->sla_points_status = rhs.sla_points_status;
|
||||||
this->layer_height_ranges = rhs.layer_height_ranges;
|
this->layer_height_ranges = rhs.layer_height_ranges;
|
||||||
|
this->layer_config_ranges = rhs.layer_config_ranges; // #ys_FIXME_experiment
|
||||||
this->layer_height_profile = rhs.layer_height_profile;
|
this->layer_height_profile = rhs.layer_height_profile;
|
||||||
this->origin_translation = rhs.origin_translation;
|
this->origin_translation = rhs.origin_translation;
|
||||||
m_bounding_box = rhs.m_bounding_box;
|
m_bounding_box = rhs.m_bounding_box;
|
||||||
|
@ -630,6 +631,7 @@ ModelObject& ModelObject::assign_copy(ModelObject &&rhs)
|
||||||
this->sla_support_points = std::move(rhs.sla_support_points);
|
this->sla_support_points = std::move(rhs.sla_support_points);
|
||||||
this->sla_points_status = std::move(rhs.sla_points_status);
|
this->sla_points_status = std::move(rhs.sla_points_status);
|
||||||
this->layer_height_ranges = std::move(rhs.layer_height_ranges);
|
this->layer_height_ranges = std::move(rhs.layer_height_ranges);
|
||||||
|
this->layer_config_ranges = std::move(rhs.layer_config_ranges); // #ys_FIXME_experiment
|
||||||
this->layer_height_profile = std::move(rhs.layer_height_profile);
|
this->layer_height_profile = std::move(rhs.layer_height_profile);
|
||||||
this->origin_translation = std::move(rhs.origin_translation);
|
this->origin_translation = std::move(rhs.origin_translation);
|
||||||
m_bounding_box = std::move(rhs.m_bounding_box);
|
m_bounding_box = std::move(rhs.m_bounding_box);
|
||||||
|
|
|
@ -181,6 +181,8 @@ public:
|
||||||
DynamicPrintConfig config;
|
DynamicPrintConfig config;
|
||||||
// Variation of a layer thickness for spans of Z coordinates.
|
// Variation of a layer thickness for spans of Z coordinates.
|
||||||
t_layer_height_ranges layer_height_ranges;
|
t_layer_height_ranges layer_height_ranges;
|
||||||
|
// Variation of a layer thickness for spans of Z coordinates.
|
||||||
|
t_layer_config_ranges layer_config_ranges;
|
||||||
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
|
// Profile of increasing z to a layer height, to be linearly interpolated when calculating the layers.
|
||||||
// The pairs of <z, layer_height> are packed into a 1D array.
|
// The pairs of <z, layer_height> are packed into a 1D array.
|
||||||
std::vector<coordf_t> layer_height_profile;
|
std::vector<coordf_t> layer_height_profile;
|
||||||
|
|
|
@ -874,7 +874,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
|
||||||
bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER);
|
bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER);
|
||||||
if (model_parts_differ || modifiers_differ ||
|
if (model_parts_differ || modifiers_differ ||
|
||||||
model_object.origin_translation != model_object_new.origin_translation ||
|
model_object.origin_translation != model_object_new.origin_translation ||
|
||||||
model_object.layer_height_ranges != model_object_new.layer_height_ranges ||
|
// model_object.layer_height_ranges != model_object_new.layer_height_ranges ||
|
||||||
|
model_object.layer_config_ranges != model_object_new.layer_config_ranges || // #ys_FIXME_experiment
|
||||||
model_object.layer_height_profile != model_object_new.layer_height_profile) {
|
model_object.layer_height_profile != model_object_new.layer_height_profile) {
|
||||||
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
|
// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
|
||||||
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
|
||||||
|
@ -1227,7 +1228,8 @@ std::string Print::validate() const
|
||||||
bool has_custom_layering = false;
|
bool has_custom_layering = false;
|
||||||
std::vector<std::vector<coordf_t>> layer_height_profiles;
|
std::vector<std::vector<coordf_t>> layer_height_profiles;
|
||||||
for (const PrintObject *object : m_objects) {
|
for (const PrintObject *object : m_objects) {
|
||||||
has_custom_layering = ! object->model_object()->layer_height_ranges.empty() || ! object->model_object()->layer_height_profile.empty();
|
// has_custom_layering = ! object->model_object()->layer_height_ranges.empty() || ! object->model_object()->layer_height_profile.empty();
|
||||||
|
has_custom_layering = ! object->model_object()->layer_config_ranges.empty() || ! object->model_object()->layer_height_profile.empty(); // #ys_FIXME_experiment
|
||||||
if (has_custom_layering) {
|
if (has_custom_layering) {
|
||||||
layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
|
layer_height_profiles.assign(m_objects.size(), std::vector<coordf_t>());
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -1434,8 +1434,9 @@ bool PrintObject::update_layer_height_profile(const ModelObject &model_object, c
|
||||||
// if (this->layer_height_profile.empty())
|
// if (this->layer_height_profile.empty())
|
||||||
layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_height_ranges, model_object.volumes);
|
layer_height_profile = layer_height_profile_adaptive(slicing_parameters, model_object.layer_height_ranges, model_object.volumes);
|
||||||
else
|
else
|
||||||
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_height_ranges);
|
// layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_height_ranges);
|
||||||
updated = true;
|
layer_height_profile = layer_height_profile_from_ranges(slicing_parameters, model_object.layer_config_ranges); // #ys_FIXME_experiment
|
||||||
|
updated = true;
|
||||||
}
|
}
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,20 +157,25 @@ SlicingParameters SlicingParameters::create_from_config(
|
||||||
// in the height profile and the printed object may be lifted by the raft thickness at the time of the G-code generation.
|
// in the height profile and the printed object may be lifted by the raft thickness at the time of the G-code generation.
|
||||||
std::vector<coordf_t> layer_height_profile_from_ranges(
|
std::vector<coordf_t> layer_height_profile_from_ranges(
|
||||||
const SlicingParameters &slicing_params,
|
const SlicingParameters &slicing_params,
|
||||||
const t_layer_height_ranges &layer_height_ranges)
|
// const t_layer_height_ranges &layer_height_ranges)
|
||||||
|
const t_layer_config_ranges &layer_config_ranges) // #ys_FIXME_experiment
|
||||||
{
|
{
|
||||||
// 1) If there are any height ranges, trim one by the other to make them non-overlapping. Insert the 1st layer if fixed.
|
// 1) If there are any height ranges, trim one by the other to make them non-overlapping. Insert the 1st layer if fixed.
|
||||||
std::vector<std::pair<t_layer_height_range,coordf_t>> ranges_non_overlapping;
|
std::vector<std::pair<t_layer_height_range,coordf_t>> ranges_non_overlapping;
|
||||||
ranges_non_overlapping.reserve(layer_height_ranges.size() * 4);
|
// ranges_non_overlapping.reserve(layer_height_ranges.size() * 4);
|
||||||
|
ranges_non_overlapping.reserve(layer_config_ranges.size() * 4); // #ys_FIXME_experiment
|
||||||
if (slicing_params.first_object_layer_height_fixed())
|
if (slicing_params.first_object_layer_height_fixed())
|
||||||
ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>(
|
ranges_non_overlapping.push_back(std::pair<t_layer_height_range,coordf_t>(
|
||||||
t_layer_height_range(0., slicing_params.first_object_layer_height),
|
t_layer_height_range(0., slicing_params.first_object_layer_height),
|
||||||
slicing_params.first_object_layer_height));
|
slicing_params.first_object_layer_height));
|
||||||
// The height ranges are sorted lexicographically by low / high layer boundaries.
|
// The height ranges are sorted lexicographically by low / high layer boundaries.
|
||||||
for (t_layer_height_ranges::const_iterator it_range = layer_height_ranges.begin(); it_range != layer_height_ranges.end(); ++ it_range) {
|
// for (t_layer_height_ranges::const_iterator it_range = layer_height_ranges.begin(); it_range != layer_height_ranges.end(); ++ it_range) {
|
||||||
|
for (t_layer_config_ranges::const_iterator it_range = layer_config_ranges.begin();
|
||||||
|
it_range != layer_config_ranges.end(); ++ it_range) { // #ys_FIXME_experiment
|
||||||
coordf_t lo = it_range->first.first;
|
coordf_t lo = it_range->first.first;
|
||||||
coordf_t hi = std::min(it_range->first.second, slicing_params.object_print_z_height());
|
coordf_t hi = std::min(it_range->first.second, slicing_params.object_print_z_height());
|
||||||
coordf_t height = it_range->second;
|
// coordf_t height = it_range->second;
|
||||||
|
coordf_t height = it_range->second.option("layer_height")->getFloat(); // #ys_FIXME_experiment
|
||||||
if (! ranges_non_overlapping.empty())
|
if (! ranges_non_overlapping.empty())
|
||||||
// Trim current low with the last high.
|
// Trim current low with the last high.
|
||||||
lo = std::max(lo, ranges_non_overlapping.back().first.second);
|
lo = std::max(lo, ranges_non_overlapping.back().first.second);
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include "libslic3r.h"
|
#include "libslic3r.h"
|
||||||
#include "Utils.hpp"
|
#include "Utils.hpp"
|
||||||
|
#include "PrintConfig.hpp"
|
||||||
|
|
||||||
namespace Slic3r
|
namespace Slic3r
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -129,10 +131,12 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters
|
||||||
|
|
||||||
typedef std::pair<coordf_t,coordf_t> t_layer_height_range;
|
typedef std::pair<coordf_t,coordf_t> t_layer_height_range;
|
||||||
typedef std::map<t_layer_height_range,coordf_t> t_layer_height_ranges;
|
typedef std::map<t_layer_height_range,coordf_t> t_layer_height_ranges;
|
||||||
|
typedef std::map<t_layer_height_range, DynamicPrintConfig> t_layer_config_ranges;
|
||||||
|
|
||||||
extern std::vector<coordf_t> layer_height_profile_from_ranges(
|
extern std::vector<coordf_t> layer_height_profile_from_ranges(
|
||||||
const SlicingParameters &slicing_params,
|
const SlicingParameters &slicing_params,
|
||||||
const t_layer_height_ranges &layer_height_ranges);
|
// const t_layer_height_ranges &layer_height_ranges);
|
||||||
|
const t_layer_config_ranges &layer_config_ranges);
|
||||||
|
|
||||||
extern std::vector<coordf_t> layer_height_profile_adaptive(
|
extern std::vector<coordf_t> layer_height_profile_adaptive(
|
||||||
const SlicingParameters &slicing_params,
|
const SlicingParameters &slicing_params,
|
||||||
|
|
|
@ -81,6 +81,8 @@ set(SLIC3R_GUI_SOURCES
|
||||||
GUI/GUI_ObjectManipulation.hpp
|
GUI/GUI_ObjectManipulation.hpp
|
||||||
GUI/GUI_ObjectSettings.cpp
|
GUI/GUI_ObjectSettings.cpp
|
||||||
GUI/GUI_ObjectSettings.hpp
|
GUI/GUI_ObjectSettings.hpp
|
||||||
|
GUI/GUI_ObjectLayers.cpp
|
||||||
|
GUI/GUI_ObjectLayers.hpp
|
||||||
GUI/LambdaObjectDialog.cpp
|
GUI/LambdaObjectDialog.cpp
|
||||||
GUI/LambdaObjectDialog.hpp
|
GUI/LambdaObjectDialog.hpp
|
||||||
GUI/Tab.cpp
|
GUI/Tab.cpp
|
||||||
|
|
|
@ -924,6 +924,11 @@ ObjectList* GUI_App::obj_list()
|
||||||
return sidebar().obj_list();
|
return sidebar().obj_list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjectLayers* GUI_App::obj_layers()
|
||||||
|
{
|
||||||
|
return sidebar().obj_layers();
|
||||||
|
}
|
||||||
|
|
||||||
Plater* GUI_App::plater()
|
Plater* GUI_App::plater()
|
||||||
{
|
{
|
||||||
return plater_;
|
return plater_;
|
||||||
|
|
|
@ -155,6 +155,7 @@ public:
|
||||||
ObjectManipulation* obj_manipul();
|
ObjectManipulation* obj_manipul();
|
||||||
ObjectSettings* obj_settings();
|
ObjectSettings* obj_settings();
|
||||||
ObjectList* obj_list();
|
ObjectList* obj_list();
|
||||||
|
ObjectLayers* obj_layers();
|
||||||
Plater* plater();
|
Plater* plater();
|
||||||
std::vector<ModelObject*> *model_objects();
|
std::vector<ModelObject*> *model_objects();
|
||||||
|
|
||||||
|
|
320
src/slic3r/GUI/GUI_ObjectLayers.cpp
Normal file
320
src/slic3r/GUI/GUI_ObjectLayers.cpp
Normal file
|
@ -0,0 +1,320 @@
|
||||||
|
#include "GUI_ObjectLayers.hpp"
|
||||||
|
#include "GUI_ObjectList.hpp"
|
||||||
|
|
||||||
|
#include "OptionsGroup.hpp"
|
||||||
|
#include "PresetBundle.hpp"
|
||||||
|
#include "libslic3r/Model.hpp"
|
||||||
|
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
|
#include "I18N.hpp"
|
||||||
|
|
||||||
|
#include <wx/wupdlock.h>
|
||||||
|
|
||||||
|
namespace Slic3r
|
||||||
|
{
|
||||||
|
namespace GUI
|
||||||
|
{
|
||||||
|
|
||||||
|
ObjectLayers::ObjectLayers(wxWindow* parent) :
|
||||||
|
OG_Settings(parent, true)
|
||||||
|
{
|
||||||
|
m_grid_sizer = new wxFlexGridSizer(3, 5, 5); // "Min Z", "Max Z", "Layer height" & buttons sizer
|
||||||
|
m_grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
|
||||||
|
|
||||||
|
// Legend for object layers
|
||||||
|
for (const std::string col : { "Min Z", "Max Z", "Layer height" }) {
|
||||||
|
auto temp = new wxStaticText(m_parent, wxID_ANY, _(L(col)), wxDefaultPosition, /*size*/wxDefaultSize, wxST_ELLIPSIZE_MIDDLE);
|
||||||
|
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||||
|
temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||||
|
temp->SetFont(wxGetApp().bold_font());
|
||||||
|
|
||||||
|
m_grid_sizer->Add(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_og->sizer->Clear(true);
|
||||||
|
m_og->sizer->Add(m_grid_sizer, 0, wxEXPAND | wxALL, wxOSX ? 0 : 5);
|
||||||
|
|
||||||
|
m_bmp_delete = ScalableBitmap(parent, "remove_copies"/*"cross"*/);
|
||||||
|
m_bmp_add = ScalableBitmap(parent, "add_copies");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectLayers::select_editor(LayerRangeEditor* editor, const bool is_last_edited_range)
|
||||||
|
{
|
||||||
|
if (is_last_edited_range && m_selection_type == editor->type()) {
|
||||||
|
/* Workaround! Under OSX we should use CallAfter() for SetFocus() after LayerEditors "reorganizations",
|
||||||
|
* because of selected control's strange behavior:
|
||||||
|
* cursor is set to the control, but blue border - doesn't.
|
||||||
|
* And as a result we couldn't edit this control.
|
||||||
|
* */
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
wxTheApp->CallAfter([editor]() {
|
||||||
|
#endif
|
||||||
|
editor->SetFocus();
|
||||||
|
editor->SetInsertionPointEnd();
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
|
||||||
|
{
|
||||||
|
const bool is_last_edited_range = range == m_selectable_range;
|
||||||
|
|
||||||
|
auto set_focus_fn = [range, this](const EditorType type)
|
||||||
|
{
|
||||||
|
m_selectable_range = range;
|
||||||
|
m_selection_type = type;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto set_focus = [range, this](const t_layer_height_range& new_range, EditorType type, bool enter_pressed)
|
||||||
|
{
|
||||||
|
// change selectable range for new one, if enter was pressed or if same range was selected
|
||||||
|
if (enter_pressed || m_selectable_range == range)
|
||||||
|
m_selectable_range = new_range;
|
||||||
|
if (enter_pressed)
|
||||||
|
m_selection_type = type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add control for the "Min Z"
|
||||||
|
|
||||||
|
auto editor = new LayerRangeEditor(m_parent, double_to_string(range.first), etMinZ,
|
||||||
|
set_focus_fn, [range, set_focus, this](coordf_t min_z, bool enter_pressed)
|
||||||
|
{
|
||||||
|
if (fabs(min_z - range.first) < EPSILON || min_z > range.second) {
|
||||||
|
m_selection_type = etUndef;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// data for next focusing
|
||||||
|
const t_layer_height_range& new_range = { min_z, range.second };
|
||||||
|
set_focus(new_range, etMinZ, enter_pressed);
|
||||||
|
|
||||||
|
return wxGetApp().obj_list()->edit_layer_range(range, new_range);
|
||||||
|
});
|
||||||
|
|
||||||
|
select_editor(editor, is_last_edited_range);
|
||||||
|
m_grid_sizer->Add(editor);
|
||||||
|
|
||||||
|
// Add control for the "Max Z"
|
||||||
|
|
||||||
|
editor = new LayerRangeEditor(m_parent, double_to_string(range.second), etMaxZ,
|
||||||
|
set_focus_fn, [range, set_focus, this](coordf_t max_z, bool enter_pressed)
|
||||||
|
{
|
||||||
|
if (fabs(max_z - range.second) < EPSILON || range.first > max_z) {
|
||||||
|
m_selection_type = etUndef;
|
||||||
|
return false; // LayersList would not be updated/recreated
|
||||||
|
}
|
||||||
|
|
||||||
|
// data for next focusing
|
||||||
|
const t_layer_height_range& new_range = { range.first, max_z };
|
||||||
|
set_focus(new_range, etMaxZ, enter_pressed);
|
||||||
|
|
||||||
|
return wxGetApp().obj_list()->edit_layer_range(range, new_range);
|
||||||
|
});
|
||||||
|
|
||||||
|
select_editor(editor, is_last_edited_range);
|
||||||
|
m_grid_sizer->Add(editor);
|
||||||
|
|
||||||
|
// Add control for the "Layer height"
|
||||||
|
|
||||||
|
editor = new LayerRangeEditor(m_parent,
|
||||||
|
double_to_string(m_object->layer_config_ranges[range].option("layer_height")->getFloat()),
|
||||||
|
etLayerHeight, set_focus_fn, [range, this](coordf_t layer_height, bool)
|
||||||
|
{
|
||||||
|
return wxGetApp().obj_list()->edit_layer_range(range, layer_height);
|
||||||
|
});
|
||||||
|
|
||||||
|
select_editor(editor, is_last_edited_range);
|
||||||
|
|
||||||
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
sizer->Add(editor);
|
||||||
|
m_grid_sizer->Add(sizer);
|
||||||
|
|
||||||
|
return sizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectLayers::create_layers_list()
|
||||||
|
{
|
||||||
|
for (const auto layer : m_object->layer_config_ranges)
|
||||||
|
{
|
||||||
|
const t_layer_height_range& range = layer.first;
|
||||||
|
auto sizer = create_layer(range);
|
||||||
|
|
||||||
|
auto del_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_delete);
|
||||||
|
del_btn->SetToolTip(_(L("Remove layer")));
|
||||||
|
|
||||||
|
sizer->Add(del_btn, 0, wxRIGHT | wxLEFT, em_unit(m_parent));
|
||||||
|
|
||||||
|
del_btn->Bind(wxEVT_BUTTON, [this, range](wxEvent &event) {
|
||||||
|
wxGetApp().obj_list()->del_layer_range(range);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto add_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_add);
|
||||||
|
add_btn->SetToolTip(_(L("Add layer")));
|
||||||
|
|
||||||
|
sizer->Add(add_btn, 0, wxRIGHT, em_unit(m_parent));
|
||||||
|
|
||||||
|
add_btn->Bind(wxEVT_BUTTON, [this, range](wxEvent &event) {
|
||||||
|
wxGetApp().obj_list()->add_layer_range_after_current(range);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectLayers::update_layers_list()
|
||||||
|
{
|
||||||
|
ObjectList* objects_ctrl = wxGetApp().obj_list();
|
||||||
|
if (objects_ctrl->multiple_selection()) return;
|
||||||
|
|
||||||
|
const auto item = objects_ctrl->GetSelection();
|
||||||
|
if (!item) return;
|
||||||
|
|
||||||
|
const int obj_idx = objects_ctrl->get_selected_obj_idx();
|
||||||
|
if (obj_idx < 0) return;
|
||||||
|
|
||||||
|
const ItemType type = objects_ctrl->GetModel()->GetItemType(item);
|
||||||
|
if (!(type & (itLayerRoot | itLayer))) return;
|
||||||
|
|
||||||
|
m_object = objects_ctrl->object(obj_idx);
|
||||||
|
if (!m_object || m_object->layer_config_ranges.empty()) return;
|
||||||
|
|
||||||
|
// Delete all controls from options group except of the legends
|
||||||
|
|
||||||
|
const int cols = m_grid_sizer->GetEffectiveColsCount();
|
||||||
|
const int rows = m_grid_sizer->GetEffectiveRowsCount();
|
||||||
|
for (int idx = cols*rows-1; idx >= cols; idx--) {
|
||||||
|
wxSizerItem* t = m_grid_sizer->GetItem(idx);
|
||||||
|
if (t->IsSizer())
|
||||||
|
t->GetSizer()->Clear(true);
|
||||||
|
else
|
||||||
|
t->DeleteWindows();
|
||||||
|
m_grid_sizer->Remove(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new control according to the selected item
|
||||||
|
|
||||||
|
if (type & itLayerRoot)
|
||||||
|
create_layers_list();
|
||||||
|
else
|
||||||
|
create_layer(objects_ctrl->GetModel()->GetLayerRangeByItem(item));
|
||||||
|
|
||||||
|
m_parent->Layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectLayers::UpdateAndShow(const bool show)
|
||||||
|
{
|
||||||
|
if (show)
|
||||||
|
update_layers_list();
|
||||||
|
|
||||||
|
OG_Settings::UpdateAndShow(show);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectLayers::msw_rescale()
|
||||||
|
{
|
||||||
|
m_bmp_delete.msw_rescale();
|
||||||
|
m_bmp_add.msw_rescale();
|
||||||
|
}
|
||||||
|
|
||||||
|
LayerRangeEditor::LayerRangeEditor( wxWindow* parent,
|
||||||
|
const wxString& value,
|
||||||
|
EditorType type,
|
||||||
|
std::function<void(EditorType)> set_focus_fn,
|
||||||
|
std::function<bool(coordf_t, bool enter_pressed)> edit_fn
|
||||||
|
) :
|
||||||
|
m_valid_value(value),
|
||||||
|
m_type(type),
|
||||||
|
m_set_focus(set_focus_fn),
|
||||||
|
wxTextCtrl(parent, wxID_ANY, value, wxDefaultPosition,
|
||||||
|
wxSize(8 * em_unit(parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
|
||||||
|
{
|
||||||
|
this->SetFont(wxGetApp().normal_font());
|
||||||
|
|
||||||
|
this->Bind(wxEVT_TEXT_ENTER, [this, edit_fn](wxEvent&)
|
||||||
|
{
|
||||||
|
m_enter_pressed = true;
|
||||||
|
// If LayersList wasn't updated/recreated, we can call wxEVT_KILL_FOCUS.Skip()
|
||||||
|
if (m_type&etLayerHeight) {
|
||||||
|
if (!edit_fn(get_value(), true))
|
||||||
|
SetValue(m_valid_value);
|
||||||
|
else
|
||||||
|
m_valid_value = double_to_string(get_value());
|
||||||
|
m_call_kill_focus = true;
|
||||||
|
}
|
||||||
|
else if (!edit_fn(get_value(), true)) {
|
||||||
|
SetValue(m_valid_value);
|
||||||
|
m_call_kill_focus = true;
|
||||||
|
}
|
||||||
|
}, this->GetId());
|
||||||
|
|
||||||
|
this->Bind(wxEVT_KILL_FOCUS, [this, edit_fn](wxFocusEvent& e)
|
||||||
|
{
|
||||||
|
if (!m_enter_pressed) {
|
||||||
|
#ifndef __WXGTK__
|
||||||
|
/* Update data for next editor selection.
|
||||||
|
* But under GTK it lucks like there is no information about selected control at e.GetWindow(),
|
||||||
|
* so we'll take it from wxEVT_LEFT_DOWN event
|
||||||
|
* */
|
||||||
|
LayerRangeEditor* new_editor = dynamic_cast<LayerRangeEditor*>(e.GetWindow());
|
||||||
|
if (new_editor)
|
||||||
|
new_editor->set_focus();
|
||||||
|
#endif // not __WXGTK__
|
||||||
|
// If LayersList wasn't updated/recreated, we should call e.Skip()
|
||||||
|
if (m_type & etLayerHeight) {
|
||||||
|
if (!edit_fn(get_value(), false))
|
||||||
|
SetValue(m_valid_value);
|
||||||
|
else
|
||||||
|
m_valid_value = double_to_string(get_value());
|
||||||
|
e.Skip();
|
||||||
|
}
|
||||||
|
else if (!edit_fn(get_value(), false)) {
|
||||||
|
SetValue(m_valid_value);
|
||||||
|
e.Skip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_call_kill_focus) {
|
||||||
|
m_call_kill_focus = false;
|
||||||
|
e.Skip();
|
||||||
|
}
|
||||||
|
}, this->GetId());
|
||||||
|
|
||||||
|
#ifdef __WXGTK__ // Workaround! To take information about selectable range
|
||||||
|
this->Bind(wxEVT_LEFT_DOWN, [this](wxEvent& e)
|
||||||
|
{
|
||||||
|
set_focus();
|
||||||
|
e.Skip();
|
||||||
|
}, this->GetId());
|
||||||
|
#endif //__WXGTK__
|
||||||
|
|
||||||
|
this->Bind(wxEVT_CHAR, ([this](wxKeyEvent& event)
|
||||||
|
{
|
||||||
|
// select all text using Ctrl+A
|
||||||
|
if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL))
|
||||||
|
this->SetSelection(-1, -1); //select all
|
||||||
|
event.Skip();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
coordf_t LayerRangeEditor::get_value()
|
||||||
|
{
|
||||||
|
wxString str = GetValue();
|
||||||
|
|
||||||
|
coordf_t layer_height;
|
||||||
|
// Replace the first occurence of comma in decimal number.
|
||||||
|
str.Replace(",", ".", false);
|
||||||
|
if (str == ".")
|
||||||
|
layer_height = 0.0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!str.ToCDouble(&layer_height) || layer_height < 0.0f)
|
||||||
|
{
|
||||||
|
show_error(m_parent, _(L("Invalid numeric input.")));
|
||||||
|
SetValue(double_to_string(layer_height));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return layer_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
} //namespace GUI
|
||||||
|
} //namespace Slic3r
|
80
src/slic3r/GUI/GUI_ObjectLayers.hpp
Normal file
80
src/slic3r/GUI/GUI_ObjectLayers.hpp
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#ifndef slic3r_GUI_ObjectLayers_hpp_
|
||||||
|
#define slic3r_GUI_ObjectLayers_hpp_
|
||||||
|
|
||||||
|
#include "GUI_ObjectSettings.hpp"
|
||||||
|
#include "wxExtensions.hpp"
|
||||||
|
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
#include "../libslic3r/PrintConfig.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class wxBoxSizer;
|
||||||
|
|
||||||
|
namespace Slic3r {
|
||||||
|
class ModelObject;
|
||||||
|
|
||||||
|
namespace GUI {
|
||||||
|
class ConfigOptionsGroup;
|
||||||
|
|
||||||
|
typedef double coordf_t;
|
||||||
|
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||||
|
|
||||||
|
enum EditorType
|
||||||
|
{
|
||||||
|
etUndef = 0,
|
||||||
|
etMinZ = 1,
|
||||||
|
etMaxZ = 2,
|
||||||
|
etLayerHeight = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
class LayerRangeEditor : public wxTextCtrl
|
||||||
|
{
|
||||||
|
bool m_enter_pressed { false };
|
||||||
|
bool m_call_kill_focus { false };
|
||||||
|
wxString m_valid_value;
|
||||||
|
EditorType m_type;
|
||||||
|
|
||||||
|
std::function<void(EditorType)> m_set_focus;
|
||||||
|
|
||||||
|
public:
|
||||||
|
LayerRangeEditor( wxWindow* parent,
|
||||||
|
const wxString& value = wxEmptyString,
|
||||||
|
EditorType type = etUndef,
|
||||||
|
std::function<void(EditorType)> set_focus_fn = [](EditorType) {;},
|
||||||
|
std::function<bool(coordf_t, bool)> edit_fn = [](coordf_t, bool) {return false; }
|
||||||
|
);
|
||||||
|
~LayerRangeEditor() {}
|
||||||
|
|
||||||
|
EditorType type() const {return m_type;}
|
||||||
|
void set_focus() const { m_set_focus(m_type);}
|
||||||
|
|
||||||
|
private:
|
||||||
|
coordf_t get_value();
|
||||||
|
};
|
||||||
|
|
||||||
|
class ObjectLayers : public OG_Settings
|
||||||
|
{
|
||||||
|
ScalableBitmap m_bmp_delete;
|
||||||
|
ScalableBitmap m_bmp_add;
|
||||||
|
ModelObject* m_object {nullptr};
|
||||||
|
|
||||||
|
wxFlexGridSizer* m_grid_sizer;
|
||||||
|
t_layer_height_range m_selectable_range;
|
||||||
|
EditorType m_selection_type {etUndef};
|
||||||
|
|
||||||
|
public:
|
||||||
|
ObjectLayers(wxWindow* parent);
|
||||||
|
~ObjectLayers() {}
|
||||||
|
|
||||||
|
void select_editor(LayerRangeEditor* editor, const bool is_last_edited_range);
|
||||||
|
wxSizer* create_layer(const t_layer_height_range& range); // without_buttons
|
||||||
|
void create_layers_list();
|
||||||
|
void update_layers_list();
|
||||||
|
|
||||||
|
void UpdateAndShow(const bool show) override;
|
||||||
|
void msw_rescale();
|
||||||
|
};
|
||||||
|
|
||||||
|
}}
|
||||||
|
|
||||||
|
#endif // slic3r_GUI_ObjectLayers_hpp_
|
|
@ -1,6 +1,7 @@
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
#include "GUI_ObjectList.hpp"
|
#include "GUI_ObjectList.hpp"
|
||||||
#include "GUI_ObjectManipulation.hpp"
|
#include "GUI_ObjectManipulation.hpp"
|
||||||
|
#include "GUI_ObjectLayers.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
|
|
||||||
|
@ -147,10 +148,10 @@ ObjectList::ObjectList(wxWindow* parent) :
|
||||||
wxAcceleratorTable accel(6, entries);
|
wxAcceleratorTable accel(6, entries);
|
||||||
SetAcceleratorTable(accel);
|
SetAcceleratorTable(accel);
|
||||||
|
|
||||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY)); }, wxID_COPY);
|
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->copy(); }, wxID_COPY);
|
||||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE)); }, wxID_PASTE);
|
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->paste(); }, wxID_PASTE);
|
||||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->select_item_all_children(); }, wxID_SELECTALL);
|
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->select_item_all_children(); }, wxID_SELECTALL);
|
||||||
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->remove(); }, wxID_DELETE);
|
this->Bind(wxEVT_MENU, [this](wxCommandEvent &evt) { this->remove(); }, wxID_DELETE);
|
||||||
}
|
}
|
||||||
#else __WXOSX__
|
#else __WXOSX__
|
||||||
Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { key_event(event); }); // doesn't work on OSX
|
Bind(wxEVT_CHAR, [this](wxKeyEvent& event) { key_event(event); }); // doesn't work on OSX
|
||||||
|
@ -350,12 +351,13 @@ DynamicPrintConfig& ObjectList::get_item_config(const wxDataViewItem& item) cons
|
||||||
const ItemType type = m_objects_model->GetItemType(item);
|
const ItemType type = m_objects_model->GetItemType(item);
|
||||||
|
|
||||||
const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
|
const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
|
||||||
m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
|
m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
|
||||||
|
|
||||||
const int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1;
|
const int vol_idx = type & itVolume ? m_objects_model->GetVolumeIdByItem(item) : -1;
|
||||||
|
|
||||||
assert(obj_idx >= 0 || ((type & itVolume) && vol_idx >=0));
|
assert(obj_idx >= 0 || ((type & itVolume) && vol_idx >=0));
|
||||||
return type & itVolume ?(*m_objects)[obj_idx]->volumes[vol_idx]->config :
|
return type & itVolume ?(*m_objects)[obj_idx]->volumes[vol_idx]->config :
|
||||||
|
type & itLayer ?(*m_objects)[obj_idx]->layer_config_ranges[m_objects_model->GetLayerRangeByItem(item)] :
|
||||||
(*m_objects)[obj_idx]->config;
|
(*m_objects)[obj_idx]->config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,16 +443,23 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
|
||||||
{
|
{
|
||||||
if (m_prevent_update_extruder_in_config)
|
if (m_prevent_update_extruder_in_config)
|
||||||
return;
|
return;
|
||||||
if (m_objects_model->GetParent(item) == wxDataViewItem(0)) {
|
|
||||||
|
const ItemType item_type = m_objects_model->GetItemType(item);
|
||||||
|
if (item_type & itObject) {
|
||||||
const int obj_idx = m_objects_model->GetIdByItem(item);
|
const int obj_idx = m_objects_model->GetIdByItem(item);
|
||||||
m_config = &(*m_objects)[obj_idx]->config;
|
m_config = &(*m_objects)[obj_idx]->config;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
|
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
|
||||||
|
if (item_type & itVolume)
|
||||||
|
{
|
||||||
const int volume_id = m_objects_model->GetVolumeIdByItem(item);
|
const int volume_id = m_objects_model->GetVolumeIdByItem(item);
|
||||||
if (obj_idx < 0 || volume_id < 0)
|
if (obj_idx < 0 || volume_id < 0)
|
||||||
return;
|
return;
|
||||||
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
|
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
|
||||||
|
}
|
||||||
|
else if (item_type & itLayer)
|
||||||
|
m_config = &get_item_config(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxVariant variant;
|
wxVariant variant;
|
||||||
|
@ -572,6 +581,56 @@ void ObjectList::selection_changed()
|
||||||
part_selection_changed();
|
part_selection_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectList::fill_layer_config_ranges_cache()
|
||||||
|
{
|
||||||
|
wxDataViewItemArray sel_layers;
|
||||||
|
GetSelections(sel_layers);
|
||||||
|
|
||||||
|
const int obj_idx = m_objects_model->GetObjectIdByItem(sel_layers[0]);
|
||||||
|
if (obj_idx < 0 || (int)m_objects->size() <= obj_idx)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||||
|
m_layer_config_ranges_cache.clear();
|
||||||
|
|
||||||
|
for (const auto layer_item : sel_layers)
|
||||||
|
if (m_objects_model->GetItemType(layer_item) & itLayer) {
|
||||||
|
auto range = m_objects_model->GetLayerRangeByItem(layer_item);
|
||||||
|
auto it = ranges.find(range);
|
||||||
|
if (it != ranges.end())
|
||||||
|
m_layer_config_ranges_cache[it->first] = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectList::paste_layers_into_list()
|
||||||
|
{
|
||||||
|
const int obj_idx = m_objects_model->GetObjectIdByItem(GetSelection());
|
||||||
|
|
||||||
|
if (obj_idx < 0 || (int)m_objects->size() <= obj_idx ||
|
||||||
|
m_layer_config_ranges_cache.empty() || printer_technology() == ptSLA)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx);
|
||||||
|
wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(object_item);
|
||||||
|
if (layers_item)
|
||||||
|
m_objects_model->Delete(layers_item);
|
||||||
|
|
||||||
|
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||||
|
|
||||||
|
// and create Layer item(s) according to the layer_config_ranges
|
||||||
|
for (const auto range : m_layer_config_ranges_cache)
|
||||||
|
ranges.emplace(range);
|
||||||
|
|
||||||
|
layers_item = add_layer_root_item(object_item);
|
||||||
|
|
||||||
|
changed_object(obj_idx);
|
||||||
|
|
||||||
|
select_item(layers_item);
|
||||||
|
#ifndef __WXOSX__
|
||||||
|
selection_changed();
|
||||||
|
#endif //no __WXOSX__
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes)
|
void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes)
|
||||||
{
|
{
|
||||||
if ((obj_idx < 0) || ((int)m_objects->size() <= obj_idx))
|
if ((obj_idx < 0) || ((int)m_objects->size() <= obj_idx))
|
||||||
|
@ -653,7 +712,7 @@ void ObjectList::OnContextMenu(wxDataViewEvent&)
|
||||||
const wxPoint pt = get_mouse_position_in_control();
|
const wxPoint pt = get_mouse_position_in_control();
|
||||||
HitTest(pt, item, col);
|
HitTest(pt, item, col);
|
||||||
if (!item)
|
if (!item)
|
||||||
#ifdef __WXOSX__ // #ys_FIXME temporary workaround for OSX
|
#ifdef __WXOSX__ // temporary workaround for OSX
|
||||||
// after Yosemite OS X version, HitTest return undefined item
|
// after Yosemite OS X version, HitTest return undefined item
|
||||||
item = GetSelection();
|
item = GetSelection();
|
||||||
if (item)
|
if (item)
|
||||||
|
@ -699,10 +758,11 @@ void ObjectList::show_context_menu()
|
||||||
if (item)
|
if (item)
|
||||||
{
|
{
|
||||||
const ItemType type = m_objects_model->GetItemType(item);
|
const ItemType type = m_objects_model->GetItemType(item);
|
||||||
if (!(type & (itObject | itVolume | itInstance)))
|
if (!(type & (itObject | itVolume | itLayer | itInstance)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wxMenu* menu = type & itInstance ? &m_menu_instance :
|
wxMenu* menu = type & itInstance ? &m_menu_instance :
|
||||||
|
type & itLayer ? &m_menu_layer :
|
||||||
m_objects_model->GetParent(item) != wxDataViewItem(0) ? &m_menu_part :
|
m_objects_model->GetParent(item) != wxDataViewItem(0) ? &m_menu_part :
|
||||||
printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object;
|
printer_technology() == ptFFF ? &m_menu_object : &m_menu_sla_object;
|
||||||
|
|
||||||
|
@ -713,6 +773,22 @@ void ObjectList::show_context_menu()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectList::copy()
|
||||||
|
{
|
||||||
|
if (m_selection_mode & smLayer)
|
||||||
|
fill_layer_config_ranges_cache();
|
||||||
|
else
|
||||||
|
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectList::paste()
|
||||||
|
{
|
||||||
|
if (!m_layer_config_ranges_cache.empty())
|
||||||
|
paste_layers_into_list();
|
||||||
|
else
|
||||||
|
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef __WXOSX__
|
#ifndef __WXOSX__
|
||||||
void ObjectList::key_event(wxKeyEvent& event)
|
void ObjectList::key_event(wxKeyEvent& event)
|
||||||
{
|
{
|
||||||
|
@ -727,10 +803,10 @@ void ObjectList::key_event(wxKeyEvent& event)
|
||||||
}
|
}
|
||||||
else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))
|
else if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL/*WXK_SHIFT*/))
|
||||||
select_item_all_children();
|
select_item_all_children();
|
||||||
else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL))
|
else if (wxGetKeyState(wxKeyCode('C')) && wxGetKeyState(WXK_CONTROL))
|
||||||
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_COPY));
|
copy();
|
||||||
else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL))
|
else if (wxGetKeyState(wxKeyCode('V')) && wxGetKeyState(WXK_CONTROL))
|
||||||
wxPostEvent((wxEvtHandler*)wxGetApp().plater()->canvas3D()->get_wxglcanvas(), SimpleEvent(EVT_GLTOOLBAR_PASTE));
|
paste();
|
||||||
else
|
else
|
||||||
event.Skip();
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
@ -1033,7 +1109,17 @@ void ObjectList::get_settings_choice(const wxString& category_name)
|
||||||
|
|
||||||
void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
|
void ObjectList::get_freq_settings_choice(const wxString& bundle_name)
|
||||||
{
|
{
|
||||||
const std::vector<std::string>& options = get_options_for_bundle(bundle_name);
|
std::vector<std::string> options = get_options_for_bundle(bundle_name);
|
||||||
|
|
||||||
|
/* Because of we couldn't edited layer_height for ItVolume from settings list,
|
||||||
|
* correct options according to the selected item type :
|
||||||
|
* remove "layer_height" option
|
||||||
|
*/
|
||||||
|
if ((m_objects_model->GetItemType(GetSelection()) & itVolume) && bundle_name == _("Layers and Perimeters")) {
|
||||||
|
const auto layer_height_it = std::find(options.begin(), options.end(), "layer_height");
|
||||||
|
if (layer_height_it != options.end())
|
||||||
|
options.erase(layer_height_it);
|
||||||
|
}
|
||||||
|
|
||||||
assert(m_config);
|
assert(m_config);
|
||||||
auto opt_keys = m_config->keys();
|
auto opt_keys = m_config->keys();
|
||||||
|
@ -1137,6 +1223,12 @@ wxMenuItem* ObjectList::append_menu_item_split(wxMenu* menu)
|
||||||
[this]() { return is_splittable(); }, wxGetApp().plater());
|
[this]() { return is_splittable(); }, wxGetApp().plater());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxMenuItem* ObjectList::append_menu_item_layers_editing(wxMenu* menu)
|
||||||
|
{
|
||||||
|
return append_menu_item(menu, wxID_ANY, _(L("Edit Layers")), "",
|
||||||
|
[this](wxCommandEvent&) { layers_editing(); }, "layers", menu);
|
||||||
|
}
|
||||||
|
|
||||||
wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
|
wxMenuItem* ObjectList::append_menu_item_settings(wxMenu* menu_)
|
||||||
{
|
{
|
||||||
MenuWithSeparators* menu = dynamic_cast<MenuWithSeparators*>(menu_);
|
MenuWithSeparators* menu = dynamic_cast<MenuWithSeparators*>(menu_);
|
||||||
|
@ -1301,7 +1393,11 @@ void ObjectList::create_object_popupmenu(wxMenu *menu)
|
||||||
append_menu_item_scale_selection_to_fit_print_volume(menu);
|
append_menu_item_scale_selection_to_fit_print_volume(menu);
|
||||||
|
|
||||||
// Split object to parts
|
// Split object to parts
|
||||||
m_menu_item_split = append_menu_item_split(menu);
|
append_menu_item_split(menu);
|
||||||
|
menu->AppendSeparator();
|
||||||
|
|
||||||
|
// Layers Editing for object
|
||||||
|
append_menu_item_layers_editing(menu);
|
||||||
menu->AppendSeparator();
|
menu->AppendSeparator();
|
||||||
|
|
||||||
// rest of a object_menu will be added later in:
|
// rest of a object_menu will be added later in:
|
||||||
|
@ -1330,7 +1426,7 @@ void ObjectList::create_part_popupmenu(wxMenu *menu)
|
||||||
append_menu_item_fix_through_netfabb(menu);
|
append_menu_item_fix_through_netfabb(menu);
|
||||||
append_menu_item_export_stl(menu);
|
append_menu_item_export_stl(menu);
|
||||||
|
|
||||||
m_menu_item_split_part = append_menu_item_split(menu);
|
append_menu_item_split(menu);
|
||||||
|
|
||||||
// Append change part type
|
// Append change part type
|
||||||
menu->AppendSeparator();
|
menu->AppendSeparator();
|
||||||
|
@ -1636,38 +1732,52 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
|
||||||
ItemType type;
|
ItemType type;
|
||||||
|
|
||||||
m_objects_model->GetItemInfo(item, type, obj_idx, idx);
|
m_objects_model->GetItemInfo(item, type, obj_idx, idx);
|
||||||
if (type == itUndef)
|
if (type & itUndef)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (type == itSettings)
|
if (type & itSettings)
|
||||||
del_settings_from_config();
|
del_settings_from_config(m_objects_model->GetParent(item));
|
||||||
else if (type == itInstanceRoot && obj_idx != -1)
|
else if (type & itInstanceRoot && obj_idx != -1)
|
||||||
del_instances_from_object(obj_idx);
|
del_instances_from_object(obj_idx);
|
||||||
|
else if (type & itLayerRoot && obj_idx != -1)
|
||||||
|
del_layers_from_object(obj_idx);
|
||||||
|
else if (type & itLayer && obj_idx != -1)
|
||||||
|
del_layer_from_object(obj_idx, m_objects_model->GetLayerRangeByItem(item));
|
||||||
else if (idx == -1)
|
else if (idx == -1)
|
||||||
return;
|
return;
|
||||||
else if (!del_subobject_from_object(obj_idx, idx, type))
|
else if (!del_subobject_from_object(obj_idx, idx, type))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If last volume item with warning was deleted, unmark object item
|
// If last volume item with warning was deleted, unmark object item
|
||||||
if (type == itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
|
if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
|
||||||
m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item));
|
m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item));
|
||||||
|
|
||||||
m_objects_model->Delete(item);
|
m_objects_model->Delete(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::del_settings_from_config()
|
void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
|
||||||
{
|
{
|
||||||
auto opt_keys = m_config->keys();
|
const bool is_layer_settings = m_objects_model->GetItemType(parent_item) == itLayer;
|
||||||
if (opt_keys.size() == 1 && opt_keys[0] == "extruder")
|
|
||||||
|
const int opt_cnt = m_config->keys().size();
|
||||||
|
if (opt_cnt == 1 && m_config->has("extruder") ||
|
||||||
|
is_layer_settings && opt_cnt == 2 && m_config->has("extruder") && m_config->has("layer_height"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int extruder = -1;
|
int extruder = -1;
|
||||||
if (m_config->has("extruder"))
|
if (m_config->has("extruder"))
|
||||||
extruder = m_config->option<ConfigOptionInt>("extruder")->value;
|
extruder = m_config->option<ConfigOptionInt>("extruder")->value;
|
||||||
|
|
||||||
|
coordf_t layer_height = 0.0;
|
||||||
|
if (is_layer_settings)
|
||||||
|
layer_height = m_config->opt_float("layer_height");
|
||||||
|
|
||||||
m_config->clear();
|
m_config->clear();
|
||||||
|
|
||||||
if (extruder >= 0)
|
if (extruder >= 0)
|
||||||
m_config->set_key_value("extruder", new ConfigOptionInt(extruder));
|
m_config->set_key_value("extruder", new ConfigOptionInt(extruder));
|
||||||
|
if (is_layer_settings)
|
||||||
|
m_config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::del_instances_from_object(const int obj_idx)
|
void ObjectList::del_instances_from_object(const int obj_idx)
|
||||||
|
@ -1684,6 +1794,24 @@ void ObjectList::del_instances_from_object(const int obj_idx)
|
||||||
changed_object(obj_idx);
|
changed_object(obj_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectList::del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range)
|
||||||
|
{
|
||||||
|
const auto del_range = object(obj_idx)->layer_config_ranges.find(layer_range);
|
||||||
|
if (del_range == object(obj_idx)->layer_config_ranges.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
object(obj_idx)->layer_config_ranges.erase(del_range);
|
||||||
|
|
||||||
|
changed_object(obj_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectList::del_layers_from_object(const int obj_idx)
|
||||||
|
{
|
||||||
|
object(obj_idx)->layer_config_ranges.clear();
|
||||||
|
|
||||||
|
changed_object(obj_idx);
|
||||||
|
}
|
||||||
|
|
||||||
bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, const int type)
|
bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, const int type)
|
||||||
{
|
{
|
||||||
if (obj_idx == 1000)
|
if (obj_idx == 1000)
|
||||||
|
@ -1779,6 +1907,66 @@ void ObjectList::split()
|
||||||
changed_object(obj_idx);
|
changed_object(obj_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectList::layers_editing()
|
||||||
|
{
|
||||||
|
const auto item = GetSelection();
|
||||||
|
const int obj_idx = get_selected_obj_idx();
|
||||||
|
if (!item || obj_idx < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const wxDataViewItem obj_item = m_objects_model->GetTopParent(item);
|
||||||
|
wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(obj_item);
|
||||||
|
|
||||||
|
// if it doesn't exist now
|
||||||
|
if (!layers_item.IsOk())
|
||||||
|
{
|
||||||
|
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||||
|
|
||||||
|
// set some default value
|
||||||
|
if (ranges.empty())
|
||||||
|
ranges[{ 0.0f, 0.6f }] = get_default_layer_config(obj_idx);
|
||||||
|
|
||||||
|
// create layer root item
|
||||||
|
layers_item = add_layer_root_item(obj_item);
|
||||||
|
}
|
||||||
|
if (!layers_item.IsOk())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// select LayerRoor item and expand
|
||||||
|
select_item(layers_item);
|
||||||
|
Expand(layers_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxDataViewItem ObjectList::add_layer_root_item(const wxDataViewItem obj_item)
|
||||||
|
{
|
||||||
|
const int obj_idx = m_objects_model->GetIdByItem(obj_item);
|
||||||
|
if (obj_idx < 0 ||
|
||||||
|
object(obj_idx)->layer_config_ranges.empty() ||
|
||||||
|
printer_technology() == ptSLA)
|
||||||
|
return wxDataViewItem(0);
|
||||||
|
|
||||||
|
// create LayerRoot item
|
||||||
|
wxDataViewItem layers_item = m_objects_model->AddLayersRoot(obj_item);
|
||||||
|
|
||||||
|
// and create Layer item(s) according to the layer_config_ranges
|
||||||
|
for (const auto range : object(obj_idx)->layer_config_ranges)
|
||||||
|
add_layer_item(range.first, layers_item);
|
||||||
|
|
||||||
|
return layers_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicPrintConfig ObjectList::get_default_layer_config(const int obj_idx)
|
||||||
|
{
|
||||||
|
DynamicPrintConfig config;
|
||||||
|
coordf_t layer_height = object(obj_idx)->config.has("layer_height") ?
|
||||||
|
object(obj_idx)->config.opt_float("layer_height") :
|
||||||
|
wxGetApp().preset_bundle->prints.get_edited_preset().config.opt_float("layer_height");
|
||||||
|
config.set_key_value("layer_height",new ConfigOptionFloat(layer_height));
|
||||||
|
config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
bool ObjectList::get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume)
|
bool ObjectList::get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume)
|
||||||
{
|
{
|
||||||
auto obj_idx = get_selected_obj_idx();
|
auto obj_idx = get_selected_obj_idx();
|
||||||
|
@ -1848,6 +2036,7 @@ void ObjectList::part_selection_changed()
|
||||||
|
|
||||||
bool update_and_show_manipulations = false;
|
bool update_and_show_manipulations = false;
|
||||||
bool update_and_show_settings = false;
|
bool update_and_show_settings = false;
|
||||||
|
bool update_and_show_layers = false;
|
||||||
|
|
||||||
const auto item = GetSelection();
|
const auto item = GetSelection();
|
||||||
|
|
||||||
|
@ -1870,36 +2059,47 @@ void ObjectList::part_selection_changed()
|
||||||
update_and_show_manipulations = true;
|
update_and_show_manipulations = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
auto parent = m_objects_model->GetParent(item);
|
obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||||
// Take ID of the parent object to "inform" perl-side which object have to be selected on the scene
|
|
||||||
obj_idx = m_objects_model->GetIdByItem(parent);
|
const ItemType type = m_objects_model->GetItemType(item);
|
||||||
if (m_objects_model->GetItemType(item) == itSettings) {
|
if (type & itSettings) {
|
||||||
if (m_objects_model->GetParent(parent) == wxDataViewItem(0)) {
|
const auto parent = m_objects_model->GetParent(item);
|
||||||
|
const ItemType parent_type = m_objects_model->GetItemType(parent);
|
||||||
|
|
||||||
|
if (parent_type & itObject) {
|
||||||
og_name = _(L("Object Settings to modify"));
|
og_name = _(L("Object Settings to modify"));
|
||||||
m_config = &(*m_objects)[obj_idx]->config;
|
m_config = &(*m_objects)[obj_idx]->config;
|
||||||
}
|
}
|
||||||
else {
|
else if (parent_type & itVolume) {
|
||||||
og_name = _(L("Part Settings to modify"));
|
og_name = _(L("Part Settings to modify"));
|
||||||
auto main_parent = m_objects_model->GetParent(parent);
|
volume_id = m_objects_model->GetVolumeIdByItem(parent);
|
||||||
obj_idx = m_objects_model->GetIdByItem(main_parent);
|
|
||||||
const auto volume_id = m_objects_model->GetVolumeIdByItem(parent);
|
|
||||||
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
|
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
|
||||||
}
|
}
|
||||||
|
else if (parent_type & itLayer) {
|
||||||
|
og_name = _(L("Layer range Settings to modify"));
|
||||||
|
m_config = &get_item_config(parent);
|
||||||
|
}
|
||||||
update_and_show_settings = true;
|
update_and_show_settings = true;
|
||||||
}
|
}
|
||||||
else if (m_objects_model->GetItemType(item) == itVolume) {
|
else if (type & itVolume) {
|
||||||
og_name = _(L("Part manipulation"));
|
og_name = _(L("Part manipulation"));
|
||||||
volume_id = m_objects_model->GetVolumeIdByItem(item);
|
volume_id = m_objects_model->GetVolumeIdByItem(item);
|
||||||
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
|
m_config = &(*m_objects)[obj_idx]->volumes[volume_id]->config;
|
||||||
update_and_show_manipulations = true;
|
update_and_show_manipulations = true;
|
||||||
}
|
}
|
||||||
else if (m_objects_model->GetItemType(item) == itInstance) {
|
else if (type & itInstance) {
|
||||||
og_name = _(L("Instance manipulation"));
|
og_name = _(L("Instance manipulation"));
|
||||||
update_and_show_manipulations = true;
|
update_and_show_manipulations = true;
|
||||||
|
|
||||||
// fill m_config by object's values
|
// fill m_config by object's values
|
||||||
const int obj_idx_ = m_objects_model->GetObjectIdByItem(item);
|
m_config = &(*m_objects)[obj_idx]->config;
|
||||||
m_config = &(*m_objects)[obj_idx_]->config;
|
}
|
||||||
|
else if (type & (itLayerRoot|itLayer)) {
|
||||||
|
og_name = type & itLayerRoot ? _(L("Layers Editing")) : _(L("Layer Editing"));
|
||||||
|
update_and_show_layers = true;
|
||||||
|
|
||||||
|
if (type & itLayer)
|
||||||
|
m_config = &get_item_config(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1919,11 +2119,17 @@ void ObjectList::part_selection_changed()
|
||||||
if (update_and_show_settings)
|
if (update_and_show_settings)
|
||||||
wxGetApp().obj_settings()->get_og()->set_name(" " + og_name + " ");
|
wxGetApp().obj_settings()->get_og()->set_name(" " + og_name + " ");
|
||||||
|
|
||||||
|
if (printer_technology() == ptSLA)
|
||||||
|
update_and_show_layers = false;
|
||||||
|
else if (update_and_show_layers)
|
||||||
|
wxGetApp().obj_layers()->get_og()->set_name(" " + og_name + " ");
|
||||||
|
|
||||||
Sidebar& panel = wxGetApp().sidebar();
|
Sidebar& panel = wxGetApp().sidebar();
|
||||||
panel.Freeze();
|
panel.Freeze();
|
||||||
|
|
||||||
wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
|
wxGetApp().obj_manipul() ->UpdateAndShow(update_and_show_manipulations);
|
||||||
wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
|
wxGetApp().obj_settings()->UpdateAndShow(update_and_show_settings);
|
||||||
|
wxGetApp().obj_layers() ->UpdateAndShow(update_and_show_layers);
|
||||||
wxGetApp().sidebar().show_info_sizer();
|
wxGetApp().sidebar().show_info_sizer();
|
||||||
|
|
||||||
panel.Layout();
|
panel.Layout();
|
||||||
|
@ -1969,6 +2175,9 @@ void ObjectList::add_object_to_list(size_t obj_idx)
|
||||||
Expand(item);
|
Expand(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add layers if it has
|
||||||
|
add_layer_root_item(item);
|
||||||
|
|
||||||
#ifndef __WXOSX__
|
#ifndef __WXOSX__
|
||||||
selection_changed();
|
selection_changed();
|
||||||
#endif //__WXMSW__
|
#endif //__WXMSW__
|
||||||
|
@ -2113,16 +2322,196 @@ void ObjectList::remove()
|
||||||
wxDataViewItemArray sels;
|
wxDataViewItemArray sels;
|
||||||
GetSelections(sels);
|
GetSelections(sels);
|
||||||
|
|
||||||
|
wxDataViewItem parent = wxDataViewItem(0);
|
||||||
|
|
||||||
for (auto& item : sels)
|
for (auto& item : sels)
|
||||||
{
|
{
|
||||||
if (m_objects_model->GetParent(item) == wxDataViewItem(0))
|
if (m_objects_model->GetParent(item) == wxDataViewItem(0))
|
||||||
delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1);
|
delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1);
|
||||||
else {
|
else {
|
||||||
if (sels.size() == 1)
|
if (m_objects_model->GetItemType(item) & itLayer) {
|
||||||
|
parent = m_objects_model->GetParent(item);
|
||||||
|
wxDataViewItemArray children;
|
||||||
|
if (m_objects_model->GetChildren(parent, children) == 1)
|
||||||
|
parent = m_objects_model->GetTopParent(item);
|
||||||
|
}
|
||||||
|
else if (sels.size() == 1)
|
||||||
select_item(m_objects_model->GetParent(item));
|
select_item(m_objects_model->GetParent(item));
|
||||||
|
|
||||||
del_subobject_item(item);
|
del_subobject_item(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parent)
|
||||||
|
select_item(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectList::del_layer_range(const t_layer_height_range& range)
|
||||||
|
{
|
||||||
|
const int obj_idx = get_selected_obj_idx();
|
||||||
|
if (obj_idx < 0) return;
|
||||||
|
|
||||||
|
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||||
|
|
||||||
|
wxDataViewItem selectable_item = GetSelection();
|
||||||
|
|
||||||
|
if (ranges.size() == 1)
|
||||||
|
selectable_item = m_objects_model->GetParent(selectable_item);
|
||||||
|
|
||||||
|
wxDataViewItem layer_item = m_objects_model->GetItemByLayerRange(obj_idx, range);
|
||||||
|
del_subobject_item(layer_item);
|
||||||
|
|
||||||
|
select_item(selectable_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_min_layer_height(const int extruder_idx)
|
||||||
|
{
|
||||||
|
const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||||
|
return config.opt_float("min_layer_height", extruder_idx <= 0 ? 0 : extruder_idx-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_max_layer_height(const int extruder_idx)
|
||||||
|
{
|
||||||
|
const DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||||
|
return config.opt_float("max_layer_height", extruder_idx <= 0 ? 0 : extruder_idx-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectList::add_layer_range_after_current(const t_layer_height_range& current_range)
|
||||||
|
{
|
||||||
|
const int obj_idx = get_selected_obj_idx();
|
||||||
|
if (obj_idx < 0) return;
|
||||||
|
|
||||||
|
const wxDataViewItem layers_item = GetSelection();
|
||||||
|
|
||||||
|
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||||
|
|
||||||
|
const t_layer_height_range& last_range = (--ranges.end())->first;
|
||||||
|
|
||||||
|
if (current_range == last_range)
|
||||||
|
{
|
||||||
|
const t_layer_height_range& new_range = { last_range.second, last_range.second + 0.5f };
|
||||||
|
ranges[new_range] = get_default_layer_config(obj_idx);
|
||||||
|
add_layer_item(new_range, layers_item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const t_layer_height_range& next_range = (++ranges.find(current_range))->first;
|
||||||
|
|
||||||
|
if (current_range.second > next_range.first)
|
||||||
|
return; // range division has no sense
|
||||||
|
|
||||||
|
const int layer_idx = m_objects_model->GetItemIdByLayerRange(obj_idx, next_range);
|
||||||
|
if (layer_idx < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (current_range.second == next_range.first)
|
||||||
|
{
|
||||||
|
const auto old_config = ranges.at(next_range);
|
||||||
|
|
||||||
|
const coordf_t delta = (next_range.second - next_range.first);
|
||||||
|
if (delta < get_min_layer_height(old_config.opt_int("extruder"))/*0.05f*/) // next range division has no sense
|
||||||
|
return;
|
||||||
|
|
||||||
|
const coordf_t midl_layer = next_range.first + 0.5f * delta;
|
||||||
|
|
||||||
|
t_layer_height_range new_range = { midl_layer, next_range.second };
|
||||||
|
|
||||||
|
// delete old layer
|
||||||
|
|
||||||
|
wxDataViewItem layer_item = m_objects_model->GetItemByLayerRange(obj_idx, next_range);
|
||||||
|
del_subobject_item(layer_item);
|
||||||
|
|
||||||
|
// create new 2 layers instead of deleted one
|
||||||
|
|
||||||
|
ranges[new_range] = old_config;
|
||||||
|
add_layer_item(new_range, layers_item, layer_idx);
|
||||||
|
|
||||||
|
new_range = { current_range.second, midl_layer };
|
||||||
|
ranges[new_range] = get_default_layer_config(obj_idx);
|
||||||
|
add_layer_item(new_range, layers_item, layer_idx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const t_layer_height_range new_range = { current_range.second, next_range.first };
|
||||||
|
ranges[new_range] = get_default_layer_config(obj_idx);
|
||||||
|
add_layer_item(new_range, layers_item, layer_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
changed_object(obj_idx);
|
||||||
|
|
||||||
|
// select item to update layers sizer
|
||||||
|
select_item(layers_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectList::add_layer_item(const t_layer_height_range& range,
|
||||||
|
const wxDataViewItem layers_item,
|
||||||
|
const int layer_idx /* = -1*/)
|
||||||
|
{
|
||||||
|
const int obj_idx = m_objects_model->GetObjectIdByItem(layers_item);
|
||||||
|
if (obj_idx < 0) return;
|
||||||
|
|
||||||
|
const DynamicPrintConfig& config = object(obj_idx)->layer_config_ranges[range];
|
||||||
|
if (!config.has("extruder"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const auto layer_item = m_objects_model->AddLayersChild(layers_item,
|
||||||
|
range,
|
||||||
|
config.opt_int("extruder"),
|
||||||
|
layer_idx);
|
||||||
|
|
||||||
|
if (config.keys().size() > 2)
|
||||||
|
select_item(m_objects_model->AddSettingsChild(layer_item));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObjectList::edit_layer_range(const t_layer_height_range& range, coordf_t layer_height)
|
||||||
|
{
|
||||||
|
const int obj_idx = get_selected_obj_idx();
|
||||||
|
if (obj_idx < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DynamicPrintConfig* config = &object(obj_idx)->layer_config_ranges[range];
|
||||||
|
if (fabs(layer_height - config->opt_float("layer_height")) < EPSILON)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const int extruder_idx = config->opt_int("extruder");
|
||||||
|
|
||||||
|
if (layer_height >= get_min_layer_height(extruder_idx) &&
|
||||||
|
layer_height <= get_max_layer_height(extruder_idx))
|
||||||
|
{
|
||||||
|
config->set_key_value("layer_height", new ConfigOptionFloat(layer_height));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_layer_height_range& new_range)
|
||||||
|
{
|
||||||
|
const int obj_idx = get_selected_obj_idx();
|
||||||
|
if (obj_idx < 0) return false;
|
||||||
|
|
||||||
|
const ItemType sel_type = m_objects_model->GetItemType(GetSelection());
|
||||||
|
|
||||||
|
t_layer_config_ranges& ranges = object(obj_idx)->layer_config_ranges;
|
||||||
|
|
||||||
|
const DynamicPrintConfig config = ranges[range];
|
||||||
|
|
||||||
|
ranges.erase(range);
|
||||||
|
ranges[new_range] = config;
|
||||||
|
|
||||||
|
wxDataViewItem root_item = m_objects_model->GetLayerRootItem(m_objects_model->GetItemById(obj_idx));
|
||||||
|
m_objects_model->DeleteChildren(root_item);
|
||||||
|
|
||||||
|
if (root_item.IsOk())
|
||||||
|
// create Layer item(s) according to the layer_config_ranges
|
||||||
|
for (const auto r : ranges)
|
||||||
|
add_layer_item(r.first, root_item);
|
||||||
|
|
||||||
|
select_item(sel_type&itLayer ? m_objects_model->GetItemByLayerRange(obj_idx, new_range) : root_item);
|
||||||
|
Expand(root_item);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::init_objects()
|
void ObjectList::init_objects()
|
||||||
|
@ -2152,11 +2541,12 @@ void ObjectList::update_selections()
|
||||||
m_selection_mode = smInstance;
|
m_selection_mode = smInstance;
|
||||||
|
|
||||||
// We doesn't update selection if SettingsItem for the current object/part is selected
|
// We doesn't update selection if SettingsItem for the current object/part is selected
|
||||||
if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
|
// if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) == itSettings )
|
||||||
|
if (GetSelectedItemsCount() == 1 && m_objects_model->GetItemType(GetSelection()) & (itSettings | itLayerRoot | itLayer))
|
||||||
{
|
{
|
||||||
const auto item = GetSelection();
|
const auto item = GetSelection();
|
||||||
if (selection.is_single_full_object()) {
|
if (selection.is_single_full_object()) {
|
||||||
if ( m_objects_model->GetIdByItem(m_objects_model->GetParent(item)) == selection.get_object_idx())
|
if (m_objects_model->GetObjectIdByItem(item) == selection.get_object_idx())
|
||||||
return;
|
return;
|
||||||
sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));
|
sels.Add(m_objects_model->GetItemById(selection.get_object_idx()));
|
||||||
}
|
}
|
||||||
|
@ -2277,22 +2667,18 @@ void ObjectList::update_selections_on_canvas()
|
||||||
auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection)
|
auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection)
|
||||||
{
|
{
|
||||||
const ItemType& type = m_objects_model->GetItemType(item);
|
const ItemType& type = m_objects_model->GetItemType(item);
|
||||||
if ( type == itInstanceRoot || m_objects_model->GetParent(item) == wxDataViewItem(0) ) {
|
const int obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||||
wxDataViewItem obj_item = type == itInstanceRoot ? m_objects_model->GetParent(item) : item;
|
|
||||||
selection.add_object(m_objects_model->GetIdByItem(obj_item), as_single_selection);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == itVolume) {
|
if (type == itVolume) {
|
||||||
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
|
|
||||||
const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
|
const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
|
||||||
selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection);
|
selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection);
|
||||||
}
|
}
|
||||||
else if (type == itInstance) {
|
else if (type == itInstance) {
|
||||||
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
|
|
||||||
const int inst_idx = m_objects_model->GetInstanceIdByItem(item);
|
const int inst_idx = m_objects_model->GetInstanceIdByItem(item);
|
||||||
selection.add_instance(obj_idx, inst_idx, as_single_selection);
|
selection.add_instance(obj_idx, inst_idx, as_single_selection);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
selection.add_object(obj_idx, as_single_selection);
|
||||||
};
|
};
|
||||||
|
|
||||||
// stores current instance idx before to clear the selection
|
// stores current instance idx before to clear the selection
|
||||||
|
@ -2300,7 +2686,7 @@ void ObjectList::update_selections_on_canvas()
|
||||||
|
|
||||||
if (sel_cnt == 1) {
|
if (sel_cnt == 1) {
|
||||||
wxDataViewItem item = GetSelection();
|
wxDataViewItem item = GetSelection();
|
||||||
if (m_objects_model->GetItemType(item) & (itSettings|itInstanceRoot))
|
if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer))
|
||||||
add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, true);
|
add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, true);
|
||||||
else
|
else
|
||||||
add_to_selection(item, selection, instance_idx, true);
|
add_to_selection(item, selection, instance_idx, true);
|
||||||
|
@ -2363,11 +2749,13 @@ void ObjectList::select_item_all_children()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const auto item = GetSelection();
|
const auto item = GetSelection();
|
||||||
// Some volume(instance) is selected => select all volumes(instances) inside the current object
|
const ItemType item_type = m_objects_model->GetItemType(item);
|
||||||
if (m_objects_model->GetItemType(item) & (itVolume | itInstance))
|
// Some volume/layer/instance is selected => select all volumes/layers/instances inside the current object
|
||||||
|
if (item_type & (itVolume | itInstance | itLayer))
|
||||||
m_objects_model->GetChildren(m_objects_model->GetParent(item), sels);
|
m_objects_model->GetChildren(m_objects_model->GetParent(item), sels);
|
||||||
|
|
||||||
m_selection_mode = m_objects_model->GetItemType(item)&itVolume ? smVolume : smInstance;
|
m_selection_mode = item_type&itVolume ? smVolume :
|
||||||
|
item_type&itLayer ? smLayer : smInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSelections(sels);
|
SetSelections(sels);
|
||||||
|
@ -2386,8 +2774,9 @@ void ObjectList::update_selection_mode()
|
||||||
}
|
}
|
||||||
|
|
||||||
const ItemType type = m_objects_model->GetItemType(GetSelection());
|
const ItemType type = m_objects_model->GetItemType(GetSelection());
|
||||||
m_selection_mode = type&itSettings ? smUndef :
|
m_selection_mode = type & itSettings ? smUndef :
|
||||||
type&itVolume ? smVolume : smInstance;
|
type & itLayer ? smLayer :
|
||||||
|
type & itVolume ? smVolume : smInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check last selected item. If is it possible to select it
|
// check last selected item. If is it possible to select it
|
||||||
|
@ -2398,33 +2787,37 @@ bool ObjectList::check_last_selection(wxString& msg_str)
|
||||||
|
|
||||||
const bool is_shift_pressed = wxGetKeyState(WXK_SHIFT);
|
const bool is_shift_pressed = wxGetKeyState(WXK_SHIFT);
|
||||||
|
|
||||||
/* We can't mix Parts and Objects/Instances.
|
/* We can't mix Volumes, Layers and Objects/Instances.
|
||||||
* So, show information about it
|
* So, show information about it
|
||||||
*/
|
*/
|
||||||
const ItemType type = m_objects_model->GetItemType(m_last_selected_item);
|
const ItemType type = m_objects_model->GetItemType(m_last_selected_item);
|
||||||
|
|
||||||
// check a case of a selection of the Parts from different Objects
|
// check a case of a selection of the same type items from different Objects
|
||||||
bool impossible_multipart_selection = false;
|
auto impossible_multi_selection = [type, this](const ItemType item_type, const SELECTION_MODE selection_mode) {
|
||||||
if (type & itVolume && m_selection_mode == smVolume)
|
if (!(type & item_type && m_selection_mode & selection_mode))
|
||||||
{
|
return false;
|
||||||
|
|
||||||
wxDataViewItemArray sels;
|
wxDataViewItemArray sels;
|
||||||
GetSelections(sels);
|
GetSelections(sels);
|
||||||
for (const auto& sel: sels)
|
for (const auto& sel : sels)
|
||||||
if (sel != m_last_selected_item &&
|
if (sel != m_last_selected_item &&
|
||||||
m_objects_model->GetParent(sel) != m_objects_model->GetParent(m_last_selected_item))
|
m_objects_model->GetTopParent(sel) != m_objects_model->GetTopParent(m_last_selected_item))
|
||||||
{
|
return true;
|
||||||
impossible_multipart_selection = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (impossible_multipart_selection ||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (impossible_multi_selection(itVolume, smVolume) ||
|
||||||
|
impossible_multi_selection(itLayer, smLayer ) ||
|
||||||
type & itSettings ||
|
type & itSettings ||
|
||||||
type & itVolume && m_selection_mode == smInstance ||
|
type & itVolume && !(m_selection_mode & smVolume ) ||
|
||||||
!(type & itVolume) && m_selection_mode == smVolume)
|
type & itLayer && !(m_selection_mode & smLayer ) ||
|
||||||
|
type & itInstance && !(m_selection_mode & smInstance)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// Inform user why selection isn't complited
|
// Inform user why selection isn't complited
|
||||||
const wxString item_type = m_selection_mode == smInstance ? _(L("Object or Instance")) : _(L("Part"));
|
const wxString item_type = m_selection_mode & smInstance ? _(L("Object or Instance")) :
|
||||||
|
m_selection_mode & smVolume ? _(L("Part")) : _(L("Layer"));
|
||||||
|
|
||||||
msg_str = wxString::Format( _(L("Unsupported selection")) + "\n\n" +
|
msg_str = wxString::Format( _(L("Unsupported selection")) + "\n\n" +
|
||||||
_(L("You started your selection with %s Item.")) + "\n" +
|
_(L("You started your selection with %s Item.")) + "\n" +
|
||||||
|
@ -2461,7 +2854,7 @@ void ObjectList::fix_multiselection_conflicts()
|
||||||
wxDataViewItemArray sels;
|
wxDataViewItemArray sels;
|
||||||
GetSelections(sels);
|
GetSelections(sels);
|
||||||
|
|
||||||
if (m_selection_mode == smVolume)
|
if (m_selection_mode & (smVolume|smLayer))
|
||||||
{
|
{
|
||||||
// identify correct parent of the initial selected item
|
// identify correct parent of the initial selected item
|
||||||
const wxDataViewItem& parent = m_objects_model->GetParent(m_last_selected_item == sels.front() ? sels.back() : sels.front());
|
const wxDataViewItem& parent = m_objects_model->GetParent(m_last_selected_item == sels.front() ? sels.back() : sels.front());
|
||||||
|
@ -2470,8 +2863,10 @@ void ObjectList::fix_multiselection_conflicts()
|
||||||
wxDataViewItemArray children; // selected volumes from current parent
|
wxDataViewItemArray children; // selected volumes from current parent
|
||||||
m_objects_model->GetChildren(parent, children);
|
m_objects_model->GetChildren(parent, children);
|
||||||
|
|
||||||
|
const ItemType item_type = m_selection_mode & smVolume ? itVolume : itLayer;
|
||||||
|
|
||||||
for (const auto child : children)
|
for (const auto child : children)
|
||||||
if (IsSelected(child) && m_objects_model->GetItemType(child)&itVolume)
|
if (IsSelected(child) && m_objects_model->GetItemType(child) & item_type)
|
||||||
sels.Add(child);
|
sels.Add(child);
|
||||||
|
|
||||||
// If some part is selected, unselect all items except of selected parts of the current object
|
// If some part is selected, unselect all items except of selected parts of the current object
|
||||||
|
@ -2636,6 +3031,87 @@ void ObjectList::update_settings_items()
|
||||||
m_prevent_canvas_selection_update = false;
|
m_prevent_canvas_selection_update = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update settings item for item had it
|
||||||
|
void ObjectList::update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections)
|
||||||
|
{
|
||||||
|
const wxDataViewItem& settings_item = m_objects_model->GetSettingsItem(item);
|
||||||
|
select_item(settings_item ? settings_item : m_objects_model->AddSettingsChild(item));
|
||||||
|
|
||||||
|
// If settings item was deleted from the list,
|
||||||
|
// it's need to be deleted from selection array, if it was there
|
||||||
|
if (settings_item != m_objects_model->GetSettingsItem(item) &&
|
||||||
|
selections.Index(settings_item) != wxNOT_FOUND) {
|
||||||
|
selections.Remove(settings_item);
|
||||||
|
|
||||||
|
// Select item, if settings_item doesn't exist for item anymore, but was selected
|
||||||
|
if (selections.Index(item) == wxNOT_FOUND)
|
||||||
|
selections.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObjectList::update_object_list_by_printer_technology()
|
||||||
|
{
|
||||||
|
m_prevent_canvas_selection_update = true;
|
||||||
|
wxDataViewItemArray sel;
|
||||||
|
GetSelections(sel); // stash selection
|
||||||
|
|
||||||
|
wxDataViewItemArray object_items;
|
||||||
|
m_objects_model->GetChildren(wxDataViewItem(0), object_items);
|
||||||
|
|
||||||
|
for (auto& object_item : object_items) {
|
||||||
|
// Update Settings Item for object
|
||||||
|
update_settings_item_and_selection(object_item, sel);
|
||||||
|
|
||||||
|
// Update settings for Volumes
|
||||||
|
wxDataViewItemArray all_object_subitems;
|
||||||
|
m_objects_model->GetChildren(object_item, all_object_subitems);
|
||||||
|
for (auto item : all_object_subitems)
|
||||||
|
if (m_objects_model->GetItemType(item) & itVolume)
|
||||||
|
// update settings for volume
|
||||||
|
update_settings_item_and_selection(item, sel);
|
||||||
|
|
||||||
|
// Update Layers Items
|
||||||
|
wxDataViewItem layers_item = m_objects_model->GetLayerRootItem(object_item);
|
||||||
|
if (!layers_item)
|
||||||
|
layers_item = add_layer_root_item(object_item);
|
||||||
|
else if (printer_technology() == ptSLA) {
|
||||||
|
// If layers root item will be deleted from the list, so
|
||||||
|
// it's need to be deleted from selection array, if it was there
|
||||||
|
wxDataViewItemArray del_items;
|
||||||
|
bool some_layers_was_selected = false;
|
||||||
|
m_objects_model->GetAllChildren(layers_item, del_items);
|
||||||
|
for (auto& del_item:del_items)
|
||||||
|
if (sel.Index(del_item) != wxNOT_FOUND) {
|
||||||
|
some_layers_was_selected = true;
|
||||||
|
sel.Remove(del_item);
|
||||||
|
}
|
||||||
|
if (sel.Index(layers_item) != wxNOT_FOUND) {
|
||||||
|
some_layers_was_selected = true;
|
||||||
|
sel.Remove(layers_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete all "layers" items
|
||||||
|
m_objects_model->Delete(layers_item);
|
||||||
|
|
||||||
|
// Select object_item, if layers_item doesn't exist for item anymore, but was some of layer items was/were selected
|
||||||
|
if (some_layers_was_selected)
|
||||||
|
sel.Add(object_item);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
wxDataViewItemArray all_obj_layers;
|
||||||
|
m_objects_model->GetChildren(layers_item, all_obj_layers);
|
||||||
|
|
||||||
|
for (auto item : all_obj_layers)
|
||||||
|
// update settings for layer
|
||||||
|
update_settings_item_and_selection(item, sel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore selection:
|
||||||
|
SetSelections(sel);
|
||||||
|
m_prevent_canvas_selection_update = false;
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectList::update_object_menu()
|
void ObjectList::update_object_menu()
|
||||||
{
|
{
|
||||||
append_menu_items_add_volume(&m_menu_object);
|
append_menu_items_add_volume(&m_menu_object);
|
||||||
|
@ -2809,7 +3285,8 @@ void ObjectList::msw_rescale()
|
||||||
for (MenuWithSeparators* menu : { &m_menu_object,
|
for (MenuWithSeparators* menu : { &m_menu_object,
|
||||||
&m_menu_part,
|
&m_menu_part,
|
||||||
&m_menu_sla_object,
|
&m_menu_sla_object,
|
||||||
&m_menu_instance })
|
&m_menu_instance,
|
||||||
|
&m_menu_layer })
|
||||||
msw_rescale_menu(menu);
|
msw_rescale_menu(menu);
|
||||||
|
|
||||||
Layout();
|
Layout();
|
||||||
|
@ -2922,5 +3399,13 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const
|
||||||
wxGetApp().plater()->update();
|
wxGetApp().plater()->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModelObject* ObjectList::object(const int obj_idx) const
|
||||||
|
{
|
||||||
|
if (obj_idx < 0)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return (*m_objects)[obj_idx];
|
||||||
|
}
|
||||||
|
|
||||||
} //namespace GUI
|
} //namespace GUI
|
||||||
} //namespace Slic3r
|
} //namespace Slic3r
|
|
@ -33,6 +33,10 @@ typedef std::map< std::string, std::vector< std::pair<std::string, std::string>
|
||||||
|
|
||||||
typedef std::vector<ModelVolume*> ModelVolumePtrs;
|
typedef std::vector<ModelVolume*> ModelVolumePtrs;
|
||||||
|
|
||||||
|
typedef double coordf_t;
|
||||||
|
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||||
|
typedef std::map<t_layer_height_range, DynamicPrintConfig> t_layer_config_ranges;
|
||||||
|
|
||||||
namespace GUI {
|
namespace GUI {
|
||||||
|
|
||||||
wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent);
|
wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent);
|
||||||
|
@ -64,9 +68,10 @@ class ObjectList : public wxDataViewCtrl
|
||||||
{
|
{
|
||||||
enum SELECTION_MODE
|
enum SELECTION_MODE
|
||||||
{
|
{
|
||||||
smUndef,
|
smUndef = 0,
|
||||||
smVolume,
|
smVolume = 1,
|
||||||
smInstance
|
smInstance = 2,
|
||||||
|
smLayer = 4
|
||||||
} m_selection_mode {smUndef};
|
} m_selection_mode {smUndef};
|
||||||
|
|
||||||
struct dragged_item_data
|
struct dragged_item_data
|
||||||
|
@ -119,12 +124,17 @@ class ObjectList : public wxDataViewCtrl
|
||||||
MenuWithSeparators m_menu_part;
|
MenuWithSeparators m_menu_part;
|
||||||
MenuWithSeparators m_menu_sla_object;
|
MenuWithSeparators m_menu_sla_object;
|
||||||
MenuWithSeparators m_menu_instance;
|
MenuWithSeparators m_menu_instance;
|
||||||
wxMenuItem* m_menu_item_split { nullptr };
|
MenuWithSeparators m_menu_layer;
|
||||||
wxMenuItem* m_menu_item_split_part { nullptr };
|
|
||||||
wxMenuItem* m_menu_item_settings { nullptr };
|
wxMenuItem* m_menu_item_settings { nullptr };
|
||||||
wxMenuItem* m_menu_item_split_instances { nullptr };
|
wxMenuItem* m_menu_item_split_instances { nullptr };
|
||||||
|
|
||||||
std::vector<wxBitmap*> m_bmp_vector;
|
ObjectDataViewModel *m_objects_model{ nullptr };
|
||||||
|
DynamicPrintConfig *m_config {nullptr};
|
||||||
|
std::vector<ModelObject*> *m_objects{ nullptr };
|
||||||
|
|
||||||
|
std::vector<wxBitmap*> m_bmp_vector;
|
||||||
|
|
||||||
|
t_layer_config_ranges m_layer_config_ranges_cache;
|
||||||
|
|
||||||
int m_selected_object_id = -1;
|
int m_selected_object_id = -1;
|
||||||
bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select()
|
bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select()
|
||||||
|
@ -153,11 +163,11 @@ public:
|
||||||
|
|
||||||
std::map<std::string, wxBitmap> CATEGORY_ICON;
|
std::map<std::string, wxBitmap> CATEGORY_ICON;
|
||||||
|
|
||||||
ObjectDataViewModel *m_objects_model{ nullptr };
|
ObjectDataViewModel* GetModel() const { return m_objects_model; }
|
||||||
DynamicPrintConfig *m_config {nullptr};
|
DynamicPrintConfig* config() const { return m_config; }
|
||||||
|
std::vector<ModelObject*>* objects() const { return m_objects; }
|
||||||
std::vector<ModelObject*> *m_objects{ nullptr };
|
|
||||||
|
|
||||||
|
ModelObject* object(const int obj_idx) const ;
|
||||||
|
|
||||||
void create_objects_ctrl();
|
void create_objects_ctrl();
|
||||||
void create_popup_menus();
|
void create_popup_menus();
|
||||||
|
@ -192,6 +202,9 @@ public:
|
||||||
void key_event(wxKeyEvent& event);
|
void key_event(wxKeyEvent& event);
|
||||||
#endif /* __WXOSX__ */
|
#endif /* __WXOSX__ */
|
||||||
|
|
||||||
|
void copy();
|
||||||
|
void paste();
|
||||||
|
|
||||||
void get_settings_choice(const wxString& category_name);
|
void get_settings_choice(const wxString& category_name);
|
||||||
void get_freq_settings_choice(const wxString& bundle_name);
|
void get_freq_settings_choice(const wxString& bundle_name);
|
||||||
void update_settings_item();
|
void update_settings_item();
|
||||||
|
@ -199,6 +212,7 @@ public:
|
||||||
wxMenu* append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type);
|
wxMenu* append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type);
|
||||||
void append_menu_items_add_volume(wxMenu* menu);
|
void append_menu_items_add_volume(wxMenu* menu);
|
||||||
wxMenuItem* append_menu_item_split(wxMenu* menu);
|
wxMenuItem* append_menu_item_split(wxMenu* menu);
|
||||||
|
wxMenuItem* append_menu_item_layers_editing(wxMenu* menu);
|
||||||
wxMenuItem* append_menu_item_settings(wxMenu* menu);
|
wxMenuItem* append_menu_item_settings(wxMenu* menu);
|
||||||
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
|
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
|
||||||
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent);
|
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent);
|
||||||
|
@ -222,10 +236,17 @@ public:
|
||||||
void load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
|
void load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
|
||||||
void del_object(const int obj_idx);
|
void del_object(const int obj_idx);
|
||||||
void del_subobject_item(wxDataViewItem& item);
|
void del_subobject_item(wxDataViewItem& item);
|
||||||
void del_settings_from_config();
|
void del_settings_from_config(const wxDataViewItem& parent_item);
|
||||||
void del_instances_from_object(const int obj_idx);
|
void del_instances_from_object(const int obj_idx);
|
||||||
|
void del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range);
|
||||||
|
void del_layers_from_object(const int obj_idx);
|
||||||
bool del_subobject_from_object(const int obj_idx, const int idx, const int type);
|
bool del_subobject_from_object(const int obj_idx, const int idx, const int type);
|
||||||
void split();
|
void split();
|
||||||
|
void layers_editing();
|
||||||
|
|
||||||
|
wxDataViewItem add_layer_root_item(const wxDataViewItem obj_item);
|
||||||
|
|
||||||
|
DynamicPrintConfig get_default_layer_config(const int obj_idx);
|
||||||
bool get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
|
bool get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
|
||||||
bool is_splittable();
|
bool is_splittable();
|
||||||
bool selected_instances_of_same_object();
|
bool selected_instances_of_same_object();
|
||||||
|
@ -265,6 +286,14 @@ public:
|
||||||
|
|
||||||
// Remove objects/sub-object from the list
|
// Remove objects/sub-object from the list
|
||||||
void remove();
|
void remove();
|
||||||
|
void del_layer_range(const t_layer_height_range& range);
|
||||||
|
void add_layer_range_after_current(const t_layer_height_range& current_range);
|
||||||
|
void add_layer_item (const t_layer_height_range& range,
|
||||||
|
const wxDataViewItem layers_item,
|
||||||
|
const int layer_idx = -1);
|
||||||
|
bool edit_layer_range(const t_layer_height_range& range, coordf_t layer_height);
|
||||||
|
bool edit_layer_range(const t_layer_height_range& range,
|
||||||
|
const t_layer_height_range& new_range);
|
||||||
|
|
||||||
void init_objects();
|
void init_objects();
|
||||||
bool multiple_selection() const ;
|
bool multiple_selection() const ;
|
||||||
|
@ -286,6 +315,8 @@ public:
|
||||||
void last_volume_is_deleted(const int obj_idx);
|
void last_volume_is_deleted(const int obj_idx);
|
||||||
bool has_multi_part_objects();
|
bool has_multi_part_objects();
|
||||||
void update_settings_items();
|
void update_settings_items();
|
||||||
|
void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
|
||||||
|
void update_object_list_by_printer_technology();
|
||||||
void update_object_menu();
|
void update_object_menu();
|
||||||
|
|
||||||
void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx);
|
void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx);
|
||||||
|
@ -295,6 +326,8 @@ public:
|
||||||
void fix_through_netfabb();
|
void fix_through_netfabb();
|
||||||
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
|
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
|
||||||
|
|
||||||
|
void fill_layer_config_ranges_cache();
|
||||||
|
void paste_layers_into_list();
|
||||||
void paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes);
|
void paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes);
|
||||||
void paste_objects_into_list(const std::vector<size_t>& object_idxs);
|
void paste_objects_into_list(const std::vector<size_t>& object_idxs);
|
||||||
|
|
||||||
|
|
|
@ -68,10 +68,12 @@ void ObjectSettings::update_settings_list()
|
||||||
m_settings_list_sizer->Clear(true);
|
m_settings_list_sizer->Clear(true);
|
||||||
|
|
||||||
auto objects_ctrl = wxGetApp().obj_list();
|
auto objects_ctrl = wxGetApp().obj_list();
|
||||||
auto objects_model = wxGetApp().obj_list()->m_objects_model;
|
auto objects_model = wxGetApp().obj_list()->GetModel();
|
||||||
auto config = wxGetApp().obj_list()->m_config;
|
auto config = wxGetApp().obj_list()->config();
|
||||||
|
|
||||||
const auto item = objects_ctrl->GetSelection();
|
const auto item = objects_ctrl->GetSelection();
|
||||||
|
const bool is_layers_range_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itLayer;
|
||||||
|
|
||||||
if (item && !objects_ctrl->multiple_selection() &&
|
if (item && !objects_ctrl->multiple_selection() &&
|
||||||
config && objects_model->IsSettingsItem(item))
|
config && objects_model->IsSettingsItem(item))
|
||||||
{
|
{
|
||||||
|
@ -119,7 +121,8 @@ void ObjectSettings::update_settings_list()
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& cat : cat_options) {
|
for (auto& cat : cat_options) {
|
||||||
if (cat.second.size() == 1 && cat.second[0] == "extruder")
|
if (cat.second.size() == 1 &&
|
||||||
|
(cat.second[0] == "extruder" || is_layers_range_settings && cat.second[0] == "layer_height"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
|
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
|
||||||
|
@ -129,14 +132,14 @@ void ObjectSettings::update_settings_list()
|
||||||
optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) {
|
optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) {
|
||||||
wxGetApp().obj_list()->changed_object(); };
|
wxGetApp().obj_list()->changed_object(); };
|
||||||
|
|
||||||
const bool is_extriders_cat = cat.first == "Extruders";
|
const bool is_extruders_cat = cat.first == "Extruders";
|
||||||
for (auto& opt : cat.second)
|
for (auto& opt : cat.second)
|
||||||
{
|
{
|
||||||
if (opt == "extruder")
|
if (opt == "extruder" || is_layers_range_settings && opt == "layer_height")
|
||||||
continue;
|
continue;
|
||||||
Option option = optgroup->get_option(opt);
|
Option option = optgroup->get_option(opt);
|
||||||
option.opt.width = 12;
|
option.opt.width = 12;
|
||||||
if (is_extriders_cat)
|
if (is_extruders_cat)
|
||||||
option.opt.max = wxGetApp().extruders_cnt();
|
option.opt.max = wxGetApp().extruders_cnt();
|
||||||
optgroup->append_single_option_line(option);
|
optgroup->append_single_option_line(option);
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,6 +320,17 @@ Line OptionsGroup::create_single_option_line(const Option& option) const {
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OptionsGroup::clear_fields_except_of(const std::vector<std::string> left_fields)
|
||||||
|
{
|
||||||
|
auto it = m_fields.begin();
|
||||||
|
while (it != m_fields.end()) {
|
||||||
|
if (std::find(left_fields.begin(), left_fields.end(), it->first) == left_fields.end())
|
||||||
|
it = m_fields.erase(it);
|
||||||
|
else
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void OptionsGroup::on_set_focus(const std::string& opt_key)
|
void OptionsGroup::on_set_focus(const std::string& opt_key)
|
||||||
{
|
{
|
||||||
if (m_set_focus != nullptr)
|
if (m_set_focus != nullptr)
|
||||||
|
|
|
@ -160,6 +160,8 @@ public:
|
||||||
m_show_modified_btns = show;
|
m_show_modified_btns = show;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear_fields_except_of(const std::vector<std::string> left_fields);
|
||||||
|
|
||||||
OptionsGroup( wxWindow* _parent, const wxString& title, bool is_tab_opt = false,
|
OptionsGroup( wxWindow* _parent, const wxString& title, bool is_tab_opt = false,
|
||||||
column_t extra_clmn = nullptr) :
|
column_t extra_clmn = nullptr) :
|
||||||
m_parent(_parent), title(title),
|
m_parent(_parent), title(title),
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include "GUI_ObjectList.hpp"
|
#include "GUI_ObjectList.hpp"
|
||||||
#include "GUI_ObjectManipulation.hpp"
|
#include "GUI_ObjectManipulation.hpp"
|
||||||
|
#include "GUI_ObjectLayers.hpp"
|
||||||
#include "GUI_Utils.hpp"
|
#include "GUI_Utils.hpp"
|
||||||
#include "wxExtensions.hpp"
|
#include "wxExtensions.hpp"
|
||||||
#include "MainFrame.hpp"
|
#include "MainFrame.hpp"
|
||||||
|
@ -611,6 +612,7 @@ struct Sidebar::priv
|
||||||
ObjectList *object_list;
|
ObjectList *object_list;
|
||||||
ObjectManipulation *object_manipulation;
|
ObjectManipulation *object_manipulation;
|
||||||
ObjectSettings *object_settings;
|
ObjectSettings *object_settings;
|
||||||
|
ObjectLayers *object_layers;
|
||||||
ObjectInfo *object_info;
|
ObjectInfo *object_info;
|
||||||
SlicedInfo *sliced_info;
|
SlicedInfo *sliced_info;
|
||||||
|
|
||||||
|
@ -729,6 +731,11 @@ Sidebar::Sidebar(Plater *parent)
|
||||||
p->object_settings = new ObjectSettings(p->scrolled);
|
p->object_settings = new ObjectSettings(p->scrolled);
|
||||||
p->object_settings->Hide();
|
p->object_settings->Hide();
|
||||||
p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
|
p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
|
||||||
|
|
||||||
|
// Object Layers
|
||||||
|
p->object_layers = new ObjectLayers(p->scrolled);
|
||||||
|
p->object_layers->Hide();
|
||||||
|
p->sizer_params->Add(p->object_layers->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
|
||||||
|
|
||||||
// Info boxes
|
// Info boxes
|
||||||
p->object_info = new ObjectInfo(p->scrolled);
|
p->object_info = new ObjectInfo(p->scrolled);
|
||||||
|
@ -922,6 +929,7 @@ void Sidebar::msw_rescale()
|
||||||
p->object_list->msw_rescale();
|
p->object_list->msw_rescale();
|
||||||
p->object_manipulation->msw_rescale();
|
p->object_manipulation->msw_rescale();
|
||||||
p->object_settings->msw_rescale();
|
p->object_settings->msw_rescale();
|
||||||
|
p->object_layers->msw_rescale();
|
||||||
|
|
||||||
p->object_info->msw_rescale();
|
p->object_info->msw_rescale();
|
||||||
|
|
||||||
|
@ -943,6 +951,11 @@ ObjectSettings* Sidebar::obj_settings()
|
||||||
return p->object_settings;
|
return p->object_settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ObjectLayers* Sidebar::obj_layers()
|
||||||
|
{
|
||||||
|
return p->object_layers;
|
||||||
|
}
|
||||||
|
|
||||||
wxScrolledWindow* Sidebar::scrolled_panel()
|
wxScrolledWindow* Sidebar::scrolled_panel()
|
||||||
{
|
{
|
||||||
return p->scrolled;
|
return p->scrolled;
|
||||||
|
@ -2737,8 +2750,14 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
|
||||||
|
|
||||||
// update plater with new config
|
// update plater with new config
|
||||||
wxGetApp().plater()->on_config_change(wxGetApp().preset_bundle->full_config());
|
wxGetApp().plater()->on_config_change(wxGetApp().preset_bundle->full_config());
|
||||||
|
/* Settings list can be changed after printer preset changing, so
|
||||||
|
* update all settings items for all item had it.
|
||||||
|
* Furthermore, Layers editing is implemented only for FFF printers
|
||||||
|
* and for SLA presets they should be deleted
|
||||||
|
*/
|
||||||
if (preset_type == Preset::TYPE_PRINTER)
|
if (preset_type == Preset::TYPE_PRINTER)
|
||||||
wxGetApp().obj_list()->update_settings_items();
|
// wxGetApp().obj_list()->update_settings_items();
|
||||||
|
wxGetApp().obj_list()->update_object_list_by_printer_technology();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
|
void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
|
||||||
|
@ -3083,6 +3102,10 @@ bool Plater::priv::complit_init_object_menu()
|
||||||
[this]() { return can_split() && wxGetApp().get_mode() > comSimple; }, q);
|
[this]() { return can_split() && wxGetApp().get_mode() > comSimple; }, q);
|
||||||
object_menu.AppendSeparator();
|
object_menu.AppendSeparator();
|
||||||
|
|
||||||
|
// Layers Editing for object
|
||||||
|
sidebar->obj_list()->append_menu_item_layers_editing(&object_menu);
|
||||||
|
object_menu.AppendSeparator();
|
||||||
|
|
||||||
// "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
|
// "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -33,6 +33,7 @@ class MainFrame;
|
||||||
class ConfigOptionsGroup;
|
class ConfigOptionsGroup;
|
||||||
class ObjectManipulation;
|
class ObjectManipulation;
|
||||||
class ObjectSettings;
|
class ObjectSettings;
|
||||||
|
class ObjectLayers;
|
||||||
class ObjectList;
|
class ObjectList;
|
||||||
class GLCanvas3D;
|
class GLCanvas3D;
|
||||||
|
|
||||||
|
@ -93,6 +94,7 @@ public:
|
||||||
ObjectManipulation* obj_manipul();
|
ObjectManipulation* obj_manipul();
|
||||||
ObjectList* obj_list();
|
ObjectList* obj_list();
|
||||||
ObjectSettings* obj_settings();
|
ObjectSettings* obj_settings();
|
||||||
|
ObjectLayers* obj_layers();
|
||||||
wxScrolledWindow* scrolled_panel();
|
wxScrolledWindow* scrolled_panel();
|
||||||
wxPanel* presets_panel();
|
wxPanel* presets_panel();
|
||||||
|
|
||||||
|
|
|
@ -1129,7 +1129,8 @@ void Selection::copy_to_clipboard()
|
||||||
dst_object->config = src_object->config;
|
dst_object->config = src_object->config;
|
||||||
dst_object->sla_support_points = src_object->sla_support_points;
|
dst_object->sla_support_points = src_object->sla_support_points;
|
||||||
dst_object->sla_points_status = src_object->sla_points_status;
|
dst_object->sla_points_status = src_object->sla_points_status;
|
||||||
dst_object->layer_height_ranges = src_object->layer_height_ranges;
|
// dst_object->layer_height_ranges = src_object->layer_height_ranges;
|
||||||
|
dst_object->layer_config_ranges = src_object->layer_config_ranges; // #ys_FIXME_experiment
|
||||||
dst_object->layer_height_profile = src_object->layer_height_profile;
|
dst_object->layer_height_profile = src_object->layer_height_profile;
|
||||||
dst_object->origin_translation = src_object->origin_translation;
|
dst_object->origin_translation = src_object->origin_translation;
|
||||||
|
|
||||||
|
|
|
@ -3450,9 +3450,9 @@ void TabSLAMaterial::reload_config()
|
||||||
void TabSLAMaterial::update()
|
void TabSLAMaterial::update()
|
||||||
{
|
{
|
||||||
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
|
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
|
||||||
return; // #ys_FIXME
|
return;
|
||||||
|
|
||||||
// #ys_FIXME
|
// #ys_FIXME. Just a template for this function
|
||||||
// m_update_cnt++;
|
// m_update_cnt++;
|
||||||
// ! something to update
|
// ! something to update
|
||||||
// m_update_cnt--;
|
// m_update_cnt--;
|
||||||
|
@ -3550,9 +3550,8 @@ void TabSLAPrint::reload_config()
|
||||||
void TabSLAPrint::update()
|
void TabSLAPrint::update()
|
||||||
{
|
{
|
||||||
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
|
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
|
||||||
return; // #ys_FIXME
|
return;
|
||||||
|
|
||||||
// #ys_FIXME
|
|
||||||
m_update_cnt++;
|
m_update_cnt++;
|
||||||
|
|
||||||
double head_penetration = m_config->opt_float("support_head_penetration");
|
double head_penetration = m_config->opt_float("support_head_penetration");
|
||||||
|
|
|
@ -437,27 +437,69 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
|
||||||
m_type(type),
|
m_type(type),
|
||||||
m_extruder(wxEmptyString)
|
m_extruder(wxEmptyString)
|
||||||
{
|
{
|
||||||
if (type == itSettings) {
|
if (type == itSettings)
|
||||||
m_name = "Settings to modified";
|
m_name = "Settings to modified";
|
||||||
}
|
else if (type == itInstanceRoot)
|
||||||
else if (type == itInstanceRoot) {
|
|
||||||
m_name = _(L("Instances"));
|
m_name = _(L("Instances"));
|
||||||
#ifdef __WXGTK__
|
else if (type == itInstance)
|
||||||
m_container = true;
|
{
|
||||||
#endif //__WXGTK__
|
|
||||||
}
|
|
||||||
else if (type == itInstance) {
|
|
||||||
m_idx = parent->GetChildCount();
|
m_idx = parent->GetChildCount();
|
||||||
m_name = wxString::Format(_(L("Instance %d")), m_idx + 1);
|
m_name = wxString::Format(_(L("Instance %d")), m_idx + 1);
|
||||||
|
|
||||||
set_action_icon();
|
set_action_icon();
|
||||||
}
|
}
|
||||||
|
else if (type == itLayerRoot)
|
||||||
|
{
|
||||||
|
m_bmp = create_scaled_bitmap(nullptr, "layers"); // FIXME: pass window ptr
|
||||||
|
m_name = _(L("Layers"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __WXGTK__
|
||||||
|
// it's necessary on GTK because of control have to know if this item will be container
|
||||||
|
// in another case you couldn't to add subitem for this item
|
||||||
|
// it will be produce "segmentation fault"
|
||||||
|
if (type & (itInstanceRoot | itLayerRoot))
|
||||||
|
m_container = true;
|
||||||
|
#endif //__WXGTK__
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
||||||
|
const t_layer_height_range& layer_range,
|
||||||
|
const int idx /*= -1 */,
|
||||||
|
const wxString& extruder) :
|
||||||
|
m_parent(parent),
|
||||||
|
m_type(itLayer),
|
||||||
|
m_idx(idx),
|
||||||
|
m_layer_range(layer_range),
|
||||||
|
m_extruder(extruder)
|
||||||
|
{
|
||||||
|
const int children_cnt = parent->GetChildCount();
|
||||||
|
if (idx < 0)
|
||||||
|
m_idx = children_cnt;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// update indexes for another Laeyr Nodes
|
||||||
|
for (int i = m_idx; i < children_cnt; i++)
|
||||||
|
parent->GetNthChild(i)->SetIdx(i + 1);
|
||||||
|
}
|
||||||
|
const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str();
|
||||||
|
m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
|
||||||
|
m_bmp = create_scaled_bitmap(nullptr, "layers_white"); // FIXME: pass window ptr
|
||||||
|
|
||||||
|
#ifdef __WXGTK__
|
||||||
|
// it's necessary on GTK because of control have to know if this item will be container
|
||||||
|
// in another case you couldn't to add subitem for this item
|
||||||
|
// it will be produce "segmentation fault"
|
||||||
|
m_container = true;
|
||||||
|
#endif //__WXGTK__
|
||||||
|
|
||||||
|
set_action_icon();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectDataViewModelNode::set_action_icon()
|
void ObjectDataViewModelNode::set_action_icon()
|
||||||
{
|
{
|
||||||
m_action_icon_name = m_type == itObject ? "advanced_plus" :
|
m_action_icon_name = m_type & itObject ? "advanced_plus" :
|
||||||
m_type == itVolume ? "cog" : "set_separate_obj";
|
m_type & (itVolume | itLayer) ? "cog" : /*m_type & itInstance*/ "set_separate_obj";
|
||||||
m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name); // FIXME: pass window ptr
|
m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name); // FIXME: pass window ptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -523,6 +565,22 @@ void ObjectDataViewModelNode::SetIdx(const int& idx)
|
||||||
// ObjectDataViewModel
|
// ObjectDataViewModel
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType root_type)
|
||||||
|
{
|
||||||
|
// because of istance_root and layers_root are at the end of the list, so
|
||||||
|
// start locking from the end
|
||||||
|
for (int root_idx = parent_node->GetChildCount() - 1; root_idx >= 0; root_idx--)
|
||||||
|
{
|
||||||
|
// if there is SettingsItem or VolumeItem, then RootItems don't exist in current ObjectItem
|
||||||
|
if (parent_node->GetNthChild(root_idx)->GetType() & (itSettings | itVolume))
|
||||||
|
break;
|
||||||
|
if (parent_node->GetNthChild(root_idx)->GetType() & root_type)
|
||||||
|
return root_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
ObjectDataViewModel::ObjectDataViewModel()
|
ObjectDataViewModel::ObjectDataViewModel()
|
||||||
{
|
{
|
||||||
m_bitmap_cache = new Slic3r::GUI::BitmapCache;
|
m_bitmap_cache = new Slic3r::GUI::BitmapCache;
|
||||||
|
@ -567,10 +625,10 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
|
||||||
|
|
||||||
wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
|
wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
|
||||||
|
|
||||||
// because of istance_root is a last item of the object
|
// get insertion position according to the existed Layers and/or Instances Items
|
||||||
int insert_position = root->GetChildCount() - 1;
|
int insert_position = get_root_idx(root, itLayerRoot);
|
||||||
if (insert_position < 0 || root->GetNthChild(insert_position)->m_type != itInstanceRoot)
|
if (insert_position < 0)
|
||||||
insert_position = -1;
|
insert_position = get_root_idx(root, itInstanceRoot);
|
||||||
|
|
||||||
const bool obj_errors = root->m_bmp.IsOk();
|
const bool obj_errors = root->m_bmp.IsOk();
|
||||||
|
|
||||||
|
@ -619,15 +677,30 @@ wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &paren
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_istances_root_idx(ObjectDataViewModelNode *parent_node)
|
/* return values:
|
||||||
|
* true => root_node is created and added to the parent_root
|
||||||
|
* false => root node alredy exists
|
||||||
|
*/
|
||||||
|
static bool append_root_node(ObjectDataViewModelNode *parent_node,
|
||||||
|
ObjectDataViewModelNode **root_node,
|
||||||
|
const ItemType root_type)
|
||||||
{
|
{
|
||||||
// because of istance_root is a last item of the object
|
const int inst_root_id = get_root_idx(parent_node, root_type);
|
||||||
const int inst_root_idx = parent_node->GetChildCount()-1;
|
|
||||||
|
|
||||||
if (inst_root_idx < 0 || parent_node->GetNthChild(inst_root_idx)->GetType() == itInstanceRoot)
|
*root_node = inst_root_id < 0 ?
|
||||||
return inst_root_idx;
|
new ObjectDataViewModelNode(parent_node, root_type) :
|
||||||
|
parent_node->GetNthChild(inst_root_id);
|
||||||
|
|
||||||
return -1;
|
if (inst_root_id < 0) {
|
||||||
|
if ((root_type&itInstanceRoot) ||
|
||||||
|
(root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0)
|
||||||
|
parent_node->Append(*root_node);
|
||||||
|
else if (root_type&itLayerRoot)
|
||||||
|
parent_node->Insert(*root_node, static_cast<unsigned int>(get_root_idx(parent_node, itInstanceRoot)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
|
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
|
||||||
|
@ -635,20 +708,15 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
|
||||||
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||||
if (!parent_node) return wxDataViewItem(0);
|
if (!parent_node) return wxDataViewItem(0);
|
||||||
|
|
||||||
// Check and create/get instances root node
|
// get InstanceRoot node
|
||||||
const int inst_root_id = get_istances_root_idx(parent_node);
|
ObjectDataViewModelNode *inst_root_node { nullptr };
|
||||||
|
|
||||||
ObjectDataViewModelNode *inst_root_node = inst_root_id < 0 ?
|
const bool appended = append_root_node(parent_node, &inst_root_node, itInstanceRoot);
|
||||||
new ObjectDataViewModelNode(parent_node, itInstanceRoot) :
|
|
||||||
parent_node->GetNthChild(inst_root_id);
|
|
||||||
const wxDataViewItem inst_root_item((void*)inst_root_node);
|
const wxDataViewItem inst_root_item((void*)inst_root_node);
|
||||||
|
if (!inst_root_node) return wxDataViewItem(0);
|
||||||
|
|
||||||
if (inst_root_id < 0) {
|
if (appended)
|
||||||
parent_node->Append(inst_root_node);
|
ItemAdded(parent_item, inst_root_item);// notify control
|
||||||
// notify control
|
|
||||||
ItemAdded(parent_item, inst_root_item);
|
|
||||||
// if (num == 1) num++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add instance nodes
|
// Add instance nodes
|
||||||
ObjectDataViewModelNode *instance_node = nullptr;
|
ObjectDataViewModelNode *instance_node = nullptr;
|
||||||
|
@ -665,6 +733,63 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
|
||||||
return wxDataViewItem((void*)instance_node);
|
return wxDataViewItem((void*)instance_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_item)
|
||||||
|
{
|
||||||
|
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||||
|
if (!parent_node) return wxDataViewItem(0);
|
||||||
|
|
||||||
|
// get LayerRoot node
|
||||||
|
ObjectDataViewModelNode *layer_root_node{ nullptr };
|
||||||
|
const bool appended = append_root_node(parent_node, &layer_root_node, itLayerRoot);
|
||||||
|
if (!layer_root_node) return wxDataViewItem(0);
|
||||||
|
|
||||||
|
const wxDataViewItem layer_root_item((void*)layer_root_node);
|
||||||
|
|
||||||
|
if (appended)
|
||||||
|
ItemAdded(parent_item, layer_root_item);// notify control
|
||||||
|
|
||||||
|
return layer_root_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item,
|
||||||
|
const t_layer_height_range& layer_range,
|
||||||
|
const int extruder/* = 0*/,
|
||||||
|
const int index /* = -1*/)
|
||||||
|
{
|
||||||
|
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||||
|
if (!parent_node) return wxDataViewItem(0);
|
||||||
|
|
||||||
|
wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
|
||||||
|
|
||||||
|
// get LayerRoot node
|
||||||
|
ObjectDataViewModelNode *layer_root_node;
|
||||||
|
wxDataViewItem layer_root_item;
|
||||||
|
|
||||||
|
if (parent_node->GetType() & itLayerRoot) {
|
||||||
|
layer_root_node = parent_node;
|
||||||
|
layer_root_item = parent_item;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const int root_idx = get_root_idx(parent_node, itLayerRoot);
|
||||||
|
if (root_idx < 0) return wxDataViewItem(0);
|
||||||
|
layer_root_node = parent_node->GetNthChild(root_idx);
|
||||||
|
layer_root_item = wxDataViewItem((void*)layer_root_node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add layer node
|
||||||
|
ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, layer_range, index, extruder_str);
|
||||||
|
if (index < 0)
|
||||||
|
layer_root_node->Append(layer_node);
|
||||||
|
else
|
||||||
|
layer_root_node->Insert(layer_node, index);
|
||||||
|
|
||||||
|
// notify control
|
||||||
|
const wxDataViewItem layer_item((void*)layer_node);
|
||||||
|
ItemAdded(layer_root_item, layer_item);
|
||||||
|
|
||||||
|
return layer_item;
|
||||||
|
}
|
||||||
|
|
||||||
wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
||||||
{
|
{
|
||||||
auto ret_item = wxDataViewItem(0);
|
auto ret_item = wxDataViewItem(0);
|
||||||
|
@ -679,9 +804,9 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
||||||
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
|
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
|
||||||
// thus removing the node from it doesn't result in freeing it
|
// thus removing the node from it doesn't result in freeing it
|
||||||
if (node_parent) {
|
if (node_parent) {
|
||||||
if (node->m_type == itInstanceRoot)
|
if (node->m_type & (itInstanceRoot|itLayerRoot))
|
||||||
{
|
{
|
||||||
for (int i = node->GetChildCount() - 1; i > 0; i--)
|
for (int i = node->GetChildCount() - 1; i >= (node->m_type & itInstanceRoot ? 1 : 0); i--)
|
||||||
Delete(wxDataViewItem(node->GetNthChild(i)));
|
Delete(wxDataViewItem(node->GetNthChild(i)));
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
@ -690,7 +815,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
||||||
auto idx = node->GetIdx();
|
auto idx = node->GetIdx();
|
||||||
|
|
||||||
|
|
||||||
if (node->m_type == itVolume) {
|
if (node->m_type & (itVolume|itLayer)) {
|
||||||
node_parent->m_volumes_cnt--;
|
node_parent->m_volumes_cnt--;
|
||||||
DeleteSettings(item);
|
DeleteSettings(item);
|
||||||
}
|
}
|
||||||
|
@ -726,6 +851,22 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
||||||
delete node_parent;
|
delete node_parent;
|
||||||
ret_item = wxDataViewItem(obj_node);
|
ret_item = wxDataViewItem(obj_node);
|
||||||
|
|
||||||
|
#ifndef __WXGTK__
|
||||||
|
if (obj_node->GetChildCount() == 0)
|
||||||
|
obj_node->m_container = false;
|
||||||
|
#endif //__WXGTK__
|
||||||
|
ItemDeleted(ret_item, wxDataViewItem(node_parent));
|
||||||
|
return ret_item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there was last layer item, delete this one and layers root item
|
||||||
|
if (node_parent->GetChildCount() == 0 && node_parent->m_type == itLayerRoot)
|
||||||
|
{
|
||||||
|
ObjectDataViewModelNode *obj_node = node_parent->GetParent();
|
||||||
|
obj_node->GetChildren().Remove(node_parent);
|
||||||
|
delete node_parent;
|
||||||
|
ret_item = wxDataViewItem(obj_node);
|
||||||
|
|
||||||
#ifndef __WXGTK__
|
#ifndef __WXGTK__
|
||||||
if (obj_node->GetChildCount() == 0)
|
if (obj_node->GetChildCount() == 0)
|
||||||
obj_node->m_container = false;
|
obj_node->m_container = false;
|
||||||
|
@ -735,7 +876,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is last volume item after deleting, delete this last volume too
|
// if there is last volume item after deleting, delete this last volume too
|
||||||
if (node_parent->GetChildCount() <= 3)
|
if (node_parent->GetChildCount() <= 3) // 3??? #ys_FIXME
|
||||||
{
|
{
|
||||||
int vol_cnt = 0;
|
int vol_cnt = 0;
|
||||||
int vol_idx = 0;
|
int vol_idx = 0;
|
||||||
|
@ -817,7 +958,7 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par
|
||||||
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||||
if (!parent_node) return ret_item;
|
if (!parent_node) return ret_item;
|
||||||
|
|
||||||
const int inst_root_id = get_istances_root_idx(parent_node);
|
const int inst_root_id = get_root_idx(parent_node, itInstanceRoot);
|
||||||
if (inst_root_id < 0) return ret_item;
|
if (inst_root_id < 0) return ret_item;
|
||||||
|
|
||||||
wxDataViewItemArray items;
|
wxDataViewItemArray items;
|
||||||
|
@ -974,28 +1115,67 @@ wxDataViewItem ObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_id
|
||||||
return wxDataViewItem(0);
|
return wxDataViewItem(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
|
wxDataViewItem ObjectDataViewModel::GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type)
|
||||||
{
|
{
|
||||||
if (obj_idx >= m_objects.size() || obj_idx < 0) {
|
if (obj_idx >= m_objects.size() || obj_idx < 0) {
|
||||||
printf("Error! Out of objects range.\n");
|
printf("Error! Out of objects range.\n");
|
||||||
return wxDataViewItem(0);
|
return wxDataViewItem(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto instances_item = GetInstanceRootItem(wxDataViewItem(m_objects[obj_idx]));
|
auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), parent_type);
|
||||||
if (!instances_item)
|
if (!item)
|
||||||
return wxDataViewItem(0);
|
return wxDataViewItem(0);
|
||||||
|
|
||||||
auto parent = (ObjectDataViewModelNode*)instances_item.GetID();;
|
auto parent = (ObjectDataViewModelNode*)item.GetID();
|
||||||
for (size_t i = 0; i < parent->GetChildCount(); i++)
|
for (size_t i = 0; i < parent->GetChildCount(); i++)
|
||||||
if (parent->GetNthChild(i)->m_idx == inst_idx)
|
if (parent->GetNthChild(i)->m_idx == sub_obj_idx)
|
||||||
return wxDataViewItem(parent->GetNthChild(i));
|
return wxDataViewItem(parent->GetNthChild(i));
|
||||||
|
|
||||||
return wxDataViewItem(0);
|
return wxDataViewItem(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
|
||||||
|
{
|
||||||
|
return GetItemById(obj_idx, inst_idx, itInstanceRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxDataViewItem ObjectDataViewModel::GetItemByLayerId(int obj_idx, int layer_idx)
|
||||||
|
{
|
||||||
|
return GetItemById(obj_idx, layer_idx, itLayerRoot);
|
||||||
|
}
|
||||||
|
|
||||||
|
wxDataViewItem ObjectDataViewModel::GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
|
||||||
|
{
|
||||||
|
if (obj_idx >= m_objects.size() || obj_idx < 0) {
|
||||||
|
printf("Error! Out of objects range.\n");
|
||||||
|
return wxDataViewItem(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), itLayerRoot);
|
||||||
|
if (!item)
|
||||||
|
return wxDataViewItem(0);
|
||||||
|
|
||||||
|
auto parent = (ObjectDataViewModelNode*)item.GetID();
|
||||||
|
for (size_t i = 0; i < parent->GetChildCount(); i++)
|
||||||
|
if (parent->GetNthChild(i)->m_layer_range == layer_range)
|
||||||
|
return wxDataViewItem(parent->GetNthChild(i));
|
||||||
|
|
||||||
|
return wxDataViewItem(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ObjectDataViewModel::GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
|
||||||
|
{
|
||||||
|
wxDataViewItem item = GetItemByLayerRange(obj_idx, layer_range);
|
||||||
|
if (!item)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return GetLayerIdByItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
|
int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
|
||||||
{
|
{
|
||||||
wxASSERT(item.IsOk());
|
if(!item.IsOk())
|
||||||
|
return -1;
|
||||||
|
|
||||||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||||
auto it = find(m_objects.begin(), m_objects.end(), node);
|
auto it = find(m_objects.begin(), m_objects.end(), node);
|
||||||
|
@ -1030,13 +1210,28 @@ int ObjectDataViewModel::GetInstanceIdByItem(const wxDataViewItem& item) const
|
||||||
return GetIdByItemAndType(item, itInstance);
|
return GetIdByItemAndType(item, itInstance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ObjectDataViewModel::GetLayerIdByItem(const wxDataViewItem& item) const
|
||||||
|
{
|
||||||
|
return GetIdByItemAndType(item, itLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
t_layer_height_range ObjectDataViewModel::GetLayerRangeByItem(const wxDataViewItem& item) const
|
||||||
|
{
|
||||||
|
wxASSERT(item.IsOk());
|
||||||
|
|
||||||
|
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||||
|
if (!node || node->m_type != itLayer)
|
||||||
|
return { 0.0f, 0.0f };
|
||||||
|
return node->GetLayerRange();
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx)
|
void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx)
|
||||||
{
|
{
|
||||||
wxASSERT(item.IsOk());
|
wxASSERT(item.IsOk());
|
||||||
type = itUndef;
|
type = itUndef;
|
||||||
|
|
||||||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||||
if (!node || node->GetIdx() <-1 || node->GetIdx() ==-1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot)))
|
if (!node || node->GetIdx() <-1 || node->GetIdx() == -1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
idx = node->GetIdx();
|
idx = node->GetIdx();
|
||||||
|
@ -1044,9 +1239,10 @@ void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type
|
||||||
|
|
||||||
ObjectDataViewModelNode *parent_node = node->GetParent();
|
ObjectDataViewModelNode *parent_node = node->GetParent();
|
||||||
if (!parent_node) return;
|
if (!parent_node) return;
|
||||||
if (type == itInstance)
|
|
||||||
parent_node = node->GetParent()->GetParent();
|
// get top parent (Object) node
|
||||||
if (!parent_node || parent_node->m_type != itObject) { type = itUndef; return; }
|
while (parent_node->m_type != itObject)
|
||||||
|
parent_node = parent_node->GetParent();
|
||||||
|
|
||||||
auto it = find(m_objects.begin(), m_objects.end(), parent_node);
|
auto it = find(m_objects.begin(), m_objects.end(), parent_node);
|
||||||
if (it != m_objects.end())
|
if (it != m_objects.end())
|
||||||
|
@ -1214,10 +1410,7 @@ wxDataViewItem ObjectDataViewModel::GetTopParent(const wxDataViewItem &item) con
|
||||||
|
|
||||||
ObjectDataViewModelNode *parent_node = node->GetParent();
|
ObjectDataViewModelNode *parent_node = node->GetParent();
|
||||||
while (parent_node->m_type != itObject)
|
while (parent_node->m_type != itObject)
|
||||||
{
|
parent_node = parent_node->GetParent();
|
||||||
node = parent_node;
|
|
||||||
parent_node = node->GetParent();
|
|
||||||
}
|
|
||||||
|
|
||||||
return wxDataViewItem((void*)parent_node);
|
return wxDataViewItem((void*)parent_node);
|
||||||
}
|
}
|
||||||
|
@ -1318,6 +1511,11 @@ wxDataViewItem ObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &it
|
||||||
return GetItemByType(item, itInstanceRoot);
|
return GetItemByType(item, itInstanceRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wxDataViewItem ObjectDataViewModel::GetLayerRootItem(const wxDataViewItem &item) const
|
||||||
|
{
|
||||||
|
return GetItemByType(item, itLayerRoot);
|
||||||
|
}
|
||||||
|
|
||||||
bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
|
bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
|
||||||
{
|
{
|
||||||
if (!item.IsOk())
|
if (!item.IsOk())
|
||||||
|
@ -2573,7 +2771,7 @@ ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 10*/) :
|
||||||
m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first));;
|
m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first));;
|
||||||
#endif // __WXOSX__
|
#endif // __WXOSX__
|
||||||
|
|
||||||
m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, m_mode_btns.size() - 1));
|
m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, int(m_mode_btns.size() - 1)));
|
||||||
Add(m_mode_btns.back());
|
Add(m_mode_btns.back());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,9 @@ namespace Slic3r {
|
||||||
enum class ModelVolumeType : int;
|
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);
|
||||||
#else /* __WXMSW__ */
|
#else /* __WXMSW__ */
|
||||||
|
@ -159,12 +162,14 @@ DECLARE_VARIANT_OBJECT(DataViewBitmapText)
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
enum ItemType {
|
enum ItemType {
|
||||||
itUndef = 0,
|
itUndef = 0,
|
||||||
itObject = 1,
|
itObject = 1,
|
||||||
itVolume = 2,
|
itVolume = 2,
|
||||||
itInstanceRoot = 4,
|
itInstanceRoot = 4,
|
||||||
itInstance = 8,
|
itInstance = 8,
|
||||||
itSettings = 16
|
itSettings = 16,
|
||||||
|
itLayerRoot = 32,
|
||||||
|
itLayer = 64,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ObjectDataViewModelNode;
|
class ObjectDataViewModelNode;
|
||||||
|
@ -177,6 +182,7 @@ class ObjectDataViewModelNode
|
||||||
wxBitmap m_empty_bmp;
|
wxBitmap m_empty_bmp;
|
||||||
size_t m_volumes_cnt = 0;
|
size_t m_volumes_cnt = 0;
|
||||||
std::vector< std::string > m_opt_categories;
|
std::vector< std::string > m_opt_categories;
|
||||||
|
t_layer_height_range m_layer_range = { 0.0f, 0.0f };
|
||||||
|
|
||||||
wxString m_name;
|
wxString m_name;
|
||||||
wxBitmap& m_bmp = m_empty_bmp;
|
wxBitmap& m_bmp = m_empty_bmp;
|
||||||
|
@ -229,6 +235,11 @@ public:
|
||||||
set_action_icon();
|
set_action_icon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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(ObjectDataViewModelNode* parent, const ItemType type);
|
||||||
|
|
||||||
~ObjectDataViewModelNode()
|
~ObjectDataViewModelNode()
|
||||||
|
@ -318,6 +329,7 @@ public:
|
||||||
ItemType GetType() const { return m_type; }
|
ItemType GetType() const { return m_type; }
|
||||||
void SetIdx(const int& idx);
|
void SetIdx(const int& idx);
|
||||||
int GetIdx() const { return m_idx; }
|
int GetIdx() const { return m_idx; }
|
||||||
|
t_layer_height_range GetLayerRange() const { return m_layer_range; }
|
||||||
|
|
||||||
// use this function only for childrens
|
// use this function only for childrens
|
||||||
void AssignAllVal(ObjectDataViewModelNode& from_node)
|
void AssignAllVal(ObjectDataViewModelNode& from_node)
|
||||||
|
@ -348,7 +360,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set action icons for node
|
// Set action icons for node
|
||||||
void set_action_icon();
|
void set_action_icon();
|
||||||
|
|
||||||
void update_settings_digest_bitmaps();
|
void update_settings_digest_bitmaps();
|
||||||
bool update_settings_digest(const std::vector<std::string>& categories);
|
bool update_settings_digest(const std::vector<std::string>& categories);
|
||||||
|
@ -388,6 +400,11 @@ public:
|
||||||
const bool create_frst_child = true);
|
const bool create_frst_child = true);
|
||||||
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
|
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
|
||||||
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
|
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
|
||||||
|
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 Delete(const wxDataViewItem &item);
|
||||||
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
|
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
|
||||||
void DeleteAll();
|
void DeleteAll();
|
||||||
|
@ -395,13 +412,18 @@ public:
|
||||||
void DeleteVolumeChildren(wxDataViewItem& parent);
|
void DeleteVolumeChildren(wxDataViewItem& parent);
|
||||||
void DeleteSettings(const wxDataViewItem& parent);
|
void DeleteSettings(const wxDataViewItem& parent);
|
||||||
wxDataViewItem GetItemById(int obj_idx);
|
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 GetItemByVolumeId(int obj_idx, int volume_idx);
|
||||||
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_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 GetIdByItem(const wxDataViewItem& item) const;
|
||||||
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
|
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
|
||||||
int GetObjectIdByItem(const wxDataViewItem& item) const;
|
int GetObjectIdByItem(const wxDataViewItem& item) const;
|
||||||
int GetVolumeIdByItem(const wxDataViewItem& item) const;
|
int GetVolumeIdByItem(const wxDataViewItem& item) const;
|
||||||
int GetInstanceIdByItem(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);
|
void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
|
||||||
int GetRowByItem(const wxDataViewItem& item) const;
|
int GetRowByItem(const wxDataViewItem& item) const;
|
||||||
bool IsEmpty() { return m_objects.empty(); }
|
bool IsEmpty() { return m_objects.empty(); }
|
||||||
|
@ -450,6 +472,7 @@ public:
|
||||||
ItemType type) const;
|
ItemType type) const;
|
||||||
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
|
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
|
||||||
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
|
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
|
||||||
|
wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const;
|
||||||
bool IsSettingsItem(const wxDataViewItem &item) const;
|
bool IsSettingsItem(const wxDataViewItem &item) const;
|
||||||
void UpdateSettingsDigest( const wxDataViewItem &item,
|
void UpdateSettingsDigest( const wxDataViewItem &item,
|
||||||
const std::vector<std::string>& categories);
|
const std::vector<std::string>& categories);
|
||||||
|
@ -465,6 +488,7 @@ public:
|
||||||
wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,
|
wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,
|
||||||
const bool is_marked = false);
|
const bool is_marked = false);
|
||||||
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
|
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
|
||||||
|
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue