mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-08-04 04:24:04 -06:00
Merge branch 'master' into tm_clang_mingw
This commit is contained in:
commit
65368db49b
70 changed files with 6746 additions and 5247 deletions
|
@ -12,6 +12,7 @@
|
|||
#include "libslic3r/GCode/Analyzer.hpp"
|
||||
#include "slic3r/GUI/PresetBundle.hpp"
|
||||
#include "libslic3r/Format/STL.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -74,15 +75,19 @@ void GLIndexedVertexArray::load_mesh_full_shading(const TriangleMesh &mesh)
|
|||
}
|
||||
}
|
||||
|
||||
void GLIndexedVertexArray::finalize_geometry() const
|
||||
void GLIndexedVertexArray::finalize_geometry(bool opengl_initialized)
|
||||
{
|
||||
assert(this->vertices_and_normals_interleaved_VBO_id == 0);
|
||||
assert(this->triangle_indices_VBO_id == 0);
|
||||
assert(this->quad_indices_VBO_id == 0);
|
||||
|
||||
this->shrink_to_fit();
|
||||
if (! opengl_initialized) {
|
||||
// Shrink the data vectors to conserve memory in case the data cannot be transfered to the OpenGL driver yet.
|
||||
this->shrink_to_fit();
|
||||
return;
|
||||
}
|
||||
|
||||
if (! empty()) {
|
||||
if (! this->vertices_and_normals_interleaved.empty()) {
|
||||
glsafe(::glGenBuffers(1, &this->vertices_and_normals_interleaved_VBO_id));
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id));
|
||||
glsafe(::glBufferData(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved.size() * 4, this->vertices_and_normals_interleaved.data(), GL_STATIC_DRAW));
|
||||
|
@ -124,13 +129,8 @@ void GLIndexedVertexArray::release_geometry()
|
|||
|
||||
void GLIndexedVertexArray::render() const
|
||||
{
|
||||
if (this->vertices_and_normals_interleaved_VBO_id == 0)
|
||||
{
|
||||
// sends data to gpu, if not done yet
|
||||
finalize_geometry();
|
||||
if (this->vertices_and_normals_interleaved_VBO_id == 0)
|
||||
return;
|
||||
}
|
||||
assert(this->vertices_and_normals_interleaved_VBO_id != 0);
|
||||
assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0);
|
||||
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id));
|
||||
glsafe(::glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), (const void*)(3 * sizeof(float))));
|
||||
|
@ -161,13 +161,8 @@ void GLIndexedVertexArray::render(
|
|||
const std::pair<size_t, size_t>& tverts_range,
|
||||
const std::pair<size_t, size_t>& qverts_range) const
|
||||
{
|
||||
if (this->vertices_and_normals_interleaved_VBO_id == 0)
|
||||
{
|
||||
// sends data to gpu, if not done yet
|
||||
finalize_geometry();
|
||||
if (this->vertices_and_normals_interleaved_VBO_id == 0)
|
||||
return;
|
||||
}
|
||||
assert(this->vertices_and_normals_interleaved_VBO_id != 0);
|
||||
assert(this->triangle_indices_VBO_id != 0 || this->quad_indices_VBO_id != 0);
|
||||
|
||||
// Render using the Vertex Buffer Objects.
|
||||
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, this->vertices_and_normals_interleaved_VBO_id));
|
||||
|
@ -218,6 +213,7 @@ GLVolume::GLVolume(float r, float g, float b, float a)
|
|||
, extruder_id(0)
|
||||
, selected(false)
|
||||
, disabled(false)
|
||||
, printable(true)
|
||||
, is_active(true)
|
||||
, zoom_to_volumes(true)
|
||||
, shader_outside_printer_detection_enabled(false)
|
||||
|
@ -275,6 +271,13 @@ void GLVolume::set_render_color()
|
|||
set_render_color(color, 4);
|
||||
}
|
||||
|
||||
if (!printable)
|
||||
{
|
||||
render_color[0] /= 4;
|
||||
render_color[1] /= 4;
|
||||
render_color[2] /= 4;
|
||||
}
|
||||
|
||||
if (force_transparent)
|
||||
render_color[3] = color[3];
|
||||
}
|
||||
|
@ -415,30 +418,32 @@ bool GLVolume::is_sla_support() const { return this->composite_id.volume_id == -
|
|||
bool GLVolume::is_sla_pad() const { return this->composite_id.volume_id == -int(slaposBasePool); }
|
||||
|
||||
std::vector<int> GLVolumeCollection::load_object(
|
||||
const ModelObject* model_object,
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
const std::vector<int>& instance_idxs,
|
||||
const std::string& color_by)
|
||||
const std::vector<int> &instance_idxs,
|
||||
const std::string &color_by,
|
||||
bool opengl_initialized)
|
||||
{
|
||||
std::vector<int> volumes_idx;
|
||||
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++volume_idx)
|
||||
for (int instance_idx : instance_idxs)
|
||||
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by));
|
||||
volumes_idx.emplace_back(this->GLVolumeCollection::load_object_volume(model_object, obj_idx, volume_idx, instance_idx, color_by, opengl_initialized));
|
||||
return volumes_idx;
|
||||
}
|
||||
|
||||
int GLVolumeCollection::load_object_volume(
|
||||
const ModelObject* model_object,
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx,
|
||||
const std::string& color_by)
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx,
|
||||
const std::string &color_by,
|
||||
bool opengl_initialized)
|
||||
{
|
||||
const ModelVolume* model_volume = model_object->volumes[volume_idx];
|
||||
const int extruder_id = model_volume->extruder_id();
|
||||
const ModelInstance* instance = model_object->instances[instance_idx];
|
||||
const TriangleMesh& mesh = model_volume->mesh();
|
||||
float color[4];
|
||||
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
||||
const int extruder_id = model_volume->extruder_id();
|
||||
const ModelInstance *instance = model_object->instances[instance_idx];
|
||||
const TriangleMesh &mesh = model_volume->mesh();
|
||||
float color[4];
|
||||
memcpy(color, GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
|
||||
/* if (model_volume->is_support_blocker()) {
|
||||
color[0] = 1.0f;
|
||||
|
@ -455,6 +460,7 @@ int GLVolumeCollection::load_object_volume(
|
|||
GLVolume& v = *this->volumes.back();
|
||||
v.set_color_from_model_volume(model_volume);
|
||||
v.indexed_vertex_array.load_mesh(mesh);
|
||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||
v.composite_id = GLVolume::CompositeID(obj_idx, volume_idx, instance_idx);
|
||||
if (model_volume->is_model_part())
|
||||
{
|
||||
|
@ -475,13 +481,14 @@ int GLVolumeCollection::load_object_volume(
|
|||
// This function produces volumes for multiple instances in a single shot,
|
||||
// as some object specific mesh conversions may be expensive.
|
||||
void GLVolumeCollection::load_object_auxiliary(
|
||||
const SLAPrintObject* print_object,
|
||||
const SLAPrintObject *print_object,
|
||||
int obj_idx,
|
||||
// pairs of <instance_idx, print_instance_idx>
|
||||
const std::vector<std::pair<size_t, size_t>>& instances,
|
||||
SLAPrintObjectStep milestone,
|
||||
// Timestamp of the last change of the milestone
|
||||
size_t timestamp)
|
||||
size_t timestamp,
|
||||
bool opengl_initialized)
|
||||
{
|
||||
assert(print_object->is_step_done(milestone));
|
||||
Transform3d mesh_trafo_inv = print_object->trafo().inverse();
|
||||
|
@ -495,6 +502,7 @@ void GLVolumeCollection::load_object_auxiliary(
|
|||
this->volumes.emplace_back(new GLVolume((milestone == slaposBasePool) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR));
|
||||
GLVolume& v = *this->volumes.back();
|
||||
v.indexed_vertex_array.load_mesh(mesh);
|
||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||
v.composite_id = GLVolume::CompositeID(obj_idx, -int(milestone), (int)instance_idx.first);
|
||||
v.geometry_id = std::pair<size_t, size_t>(timestamp, model_instance.id().id);
|
||||
// Create a copy of the convex hull mesh for each instance. Use a move operator on the last instance.
|
||||
|
@ -511,7 +519,7 @@ void GLVolumeCollection::load_object_auxiliary(
|
|||
}
|
||||
|
||||
int GLVolumeCollection::load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width)
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized)
|
||||
{
|
||||
if (depth < 0.01f)
|
||||
return int(this->volumes.size() - 1);
|
||||
|
@ -564,6 +572,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||
this->volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume& v = *this->volumes.back();
|
||||
v.indexed_vertex_array.load_mesh(mesh);
|
||||
v.indexed_vertex_array.finalize_geometry(opengl_initialized);
|
||||
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
|
||||
v.set_volume_rotation(Vec3d(0., 0., (M_PI / 180.) * rotation_angle));
|
||||
v.composite_id = GLVolume::CompositeID(obj_idx, 0, 0);
|
||||
|
@ -823,6 +832,27 @@ std::vector<double> GLVolumeCollection::get_current_print_zs(bool active_only) c
|
|||
return print_zs;
|
||||
}
|
||||
|
||||
size_t GLVolumeCollection::cpu_memory_used() const
|
||||
{
|
||||
size_t memsize = sizeof(*this) + this->volumes.capacity() * sizeof(GLVolume);
|
||||
for (const GLVolume *volume : this->volumes)
|
||||
memsize += volume->cpu_memory_used();
|
||||
return memsize;
|
||||
}
|
||||
|
||||
size_t GLVolumeCollection::gpu_memory_used() const
|
||||
{
|
||||
size_t memsize = 0;
|
||||
for (const GLVolume *volume : this->volumes)
|
||||
memsize += volume->gpu_memory_used();
|
||||
return memsize;
|
||||
}
|
||||
|
||||
std::string GLVolumeCollection::log_memory_info() const
|
||||
{
|
||||
return " (GLVolumeCollection RAM: " + format_memsize_MB(this->cpu_memory_used()) + " GPU: " + format_memsize_MB(this->gpu_memory_used()) + " Both: " + format_memsize_MB(this->gpu_memory_used()) + ")";
|
||||
}
|
||||
|
||||
// caller is responsible for supplying NO lines with zero length
|
||||
static void thick_lines_to_indexed_vertex_array(
|
||||
const Lines &lines,
|
||||
|
@ -1598,6 +1628,7 @@ bool GLArrow::on_init()
|
|||
triangles.emplace_back(7, 13, 6);
|
||||
|
||||
m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles));
|
||||
m_volume.indexed_vertex_array.finalize_geometry(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1711,6 +1742,7 @@ bool GLCurvedArrow::on_init()
|
|||
triangles.emplace_back(vertices_per_level, 2 * vertices_per_level + 1, vertices_per_level + 1);
|
||||
|
||||
m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles));
|
||||
m_volume.indexed_vertex_array.finalize_geometry(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1737,6 +1769,7 @@ bool GLBed::on_init_from_file(const std::string& filename)
|
|||
m_filename = filename;
|
||||
|
||||
m_volume.indexed_vertex_array.load_mesh(model.mesh());
|
||||
m_volume.indexed_vertex_array.finalize_geometry(true);
|
||||
|
||||
float color[4] = { 0.235f, 0.235f, 0.235f, 1.0f };
|
||||
set_color(color, 4);
|
||||
|
|
|
@ -64,7 +64,7 @@ public:
|
|||
vertices_and_normals_interleaved_VBO_id(0),
|
||||
triangle_indices_VBO_id(0),
|
||||
quad_indices_VBO_id(0)
|
||||
{}
|
||||
{ assert(! rhs.has_VBOs()); }
|
||||
GLIndexedVertexArray(GLIndexedVertexArray &&rhs) :
|
||||
vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)),
|
||||
triangle_indices(std::move(rhs.triangle_indices)),
|
||||
|
@ -72,7 +72,7 @@ public:
|
|||
vertices_and_normals_interleaved_VBO_id(0),
|
||||
triangle_indices_VBO_id(0),
|
||||
quad_indices_VBO_id(0)
|
||||
{}
|
||||
{ assert(! rhs.has_VBOs()); }
|
||||
|
||||
~GLIndexedVertexArray() { release_geometry(); }
|
||||
|
||||
|
@ -80,14 +80,17 @@ public:
|
|||
{
|
||||
assert(vertices_and_normals_interleaved_VBO_id == 0);
|
||||
assert(triangle_indices_VBO_id == 0);
|
||||
assert(triangle_indices_VBO_id == 0);
|
||||
this->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved;
|
||||
this->triangle_indices = rhs.triangle_indices;
|
||||
this->quad_indices = rhs.quad_indices;
|
||||
this->m_bounding_box = rhs.m_bounding_box;
|
||||
vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size;
|
||||
triangle_indices_size = rhs.triangle_indices_size;
|
||||
quad_indices_size = rhs.quad_indices_size;
|
||||
assert(quad_indices_VBO_id == 0);
|
||||
assert(rhs.vertices_and_normals_interleaved_VBO_id == 0);
|
||||
assert(rhs.triangle_indices_VBO_id == 0);
|
||||
assert(rhs.quad_indices_VBO_id == 0);
|
||||
this->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved;
|
||||
this->triangle_indices = rhs.triangle_indices;
|
||||
this->quad_indices = rhs.quad_indices;
|
||||
this->m_bounding_box = rhs.m_bounding_box;
|
||||
this->vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size;
|
||||
this->triangle_indices_size = rhs.triangle_indices_size;
|
||||
this->quad_indices_size = rhs.quad_indices_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -95,21 +98,24 @@ public:
|
|||
{
|
||||
assert(vertices_and_normals_interleaved_VBO_id == 0);
|
||||
assert(triangle_indices_VBO_id == 0);
|
||||
assert(triangle_indices_VBO_id == 0);
|
||||
this->vertices_and_normals_interleaved = std::move(rhs.vertices_and_normals_interleaved);
|
||||
this->triangle_indices = std::move(rhs.triangle_indices);
|
||||
this->quad_indices = std::move(rhs.quad_indices);
|
||||
this->m_bounding_box = std::move(rhs.m_bounding_box);
|
||||
vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size;
|
||||
triangle_indices_size = rhs.triangle_indices_size;
|
||||
quad_indices_size = rhs.quad_indices_size;
|
||||
assert(quad_indices_VBO_id == 0);
|
||||
assert(rhs.vertices_and_normals_interleaved_VBO_id == 0);
|
||||
assert(rhs.triangle_indices_VBO_id == 0);
|
||||
assert(rhs.quad_indices_VBO_id == 0);
|
||||
this->vertices_and_normals_interleaved = std::move(rhs.vertices_and_normals_interleaved);
|
||||
this->triangle_indices = std::move(rhs.triangle_indices);
|
||||
this->quad_indices = std::move(rhs.quad_indices);
|
||||
this->m_bounding_box = std::move(rhs.m_bounding_box);
|
||||
this->vertices_and_normals_interleaved_size = rhs.vertices_and_normals_interleaved_size;
|
||||
this->triangle_indices_size = rhs.triangle_indices_size;
|
||||
this->quad_indices_size = rhs.quad_indices_size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Vertices and their normals, interleaved to be used by void glInterleavedArrays(GL_N3F_V3F, 0, x)
|
||||
mutable std::vector<float> vertices_and_normals_interleaved;
|
||||
mutable std::vector<int> triangle_indices;
|
||||
mutable std::vector<int> quad_indices;
|
||||
std::vector<float> vertices_and_normals_interleaved;
|
||||
std::vector<int> triangle_indices;
|
||||
std::vector<int> quad_indices;
|
||||
|
||||
// When the geometry data is loaded into the graphics card as Vertex Buffer Objects,
|
||||
// the above mentioned std::vectors are cleared and the following variables keep their original length.
|
||||
|
@ -119,9 +125,9 @@ public:
|
|||
|
||||
// IDs of the Vertex Array Objects, into which the geometry has been loaded.
|
||||
// Zero if the VBOs are not sent to GPU yet.
|
||||
mutable unsigned int vertices_and_normals_interleaved_VBO_id{ 0 };
|
||||
mutable unsigned int triangle_indices_VBO_id{ 0 };
|
||||
mutable unsigned int quad_indices_VBO_id{ 0 };
|
||||
unsigned int vertices_and_normals_interleaved_VBO_id{ 0 };
|
||||
unsigned int triangle_indices_VBO_id{ 0 };
|
||||
unsigned int quad_indices_VBO_id{ 0 };
|
||||
|
||||
void load_mesh_full_shading(const TriangleMesh &mesh);
|
||||
void load_mesh(const TriangleMesh& mesh) { this->load_mesh_full_shading(mesh); }
|
||||
|
@ -141,12 +147,12 @@ public:
|
|||
|
||||
if (this->vertices_and_normals_interleaved.size() + 6 > this->vertices_and_normals_interleaved.capacity())
|
||||
this->vertices_and_normals_interleaved.reserve(next_highest_power_of_2(this->vertices_and_normals_interleaved.size() + 6));
|
||||
this->vertices_and_normals_interleaved.push_back(nx);
|
||||
this->vertices_and_normals_interleaved.push_back(ny);
|
||||
this->vertices_and_normals_interleaved.push_back(nz);
|
||||
this->vertices_and_normals_interleaved.push_back(x);
|
||||
this->vertices_and_normals_interleaved.push_back(y);
|
||||
this->vertices_and_normals_interleaved.push_back(z);
|
||||
this->vertices_and_normals_interleaved.emplace_back(nx);
|
||||
this->vertices_and_normals_interleaved.emplace_back(ny);
|
||||
this->vertices_and_normals_interleaved.emplace_back(nz);
|
||||
this->vertices_and_normals_interleaved.emplace_back(x);
|
||||
this->vertices_and_normals_interleaved.emplace_back(y);
|
||||
this->vertices_and_normals_interleaved.emplace_back(z);
|
||||
|
||||
this->vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size();
|
||||
m_bounding_box.merge(Vec3f(x, y, z).cast<double>());
|
||||
|
@ -167,9 +173,9 @@ public:
|
|||
|
||||
if (this->triangle_indices.size() + 3 > this->vertices_and_normals_interleaved.capacity())
|
||||
this->triangle_indices.reserve(next_highest_power_of_2(this->triangle_indices.size() + 3));
|
||||
this->triangle_indices.push_back(idx1);
|
||||
this->triangle_indices.push_back(idx2);
|
||||
this->triangle_indices.push_back(idx3);
|
||||
this->triangle_indices.emplace_back(idx1);
|
||||
this->triangle_indices.emplace_back(idx2);
|
||||
this->triangle_indices.emplace_back(idx3);
|
||||
this->triangle_indices_size = this->triangle_indices.size();
|
||||
};
|
||||
|
||||
|
@ -180,17 +186,17 @@ public:
|
|||
|
||||
if (this->quad_indices.size() + 4 > this->vertices_and_normals_interleaved.capacity())
|
||||
this->quad_indices.reserve(next_highest_power_of_2(this->quad_indices.size() + 4));
|
||||
this->quad_indices.push_back(idx1);
|
||||
this->quad_indices.push_back(idx2);
|
||||
this->quad_indices.push_back(idx3);
|
||||
this->quad_indices.push_back(idx4);
|
||||
this->quad_indices.emplace_back(idx1);
|
||||
this->quad_indices.emplace_back(idx2);
|
||||
this->quad_indices.emplace_back(idx3);
|
||||
this->quad_indices.emplace_back(idx4);
|
||||
this->quad_indices_size = this->quad_indices.size();
|
||||
};
|
||||
|
||||
// Finalize the initialization of the geometry & indices,
|
||||
// upload the geometry and indices to OpenGL VBO objects
|
||||
// and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs.
|
||||
void finalize_geometry() const;
|
||||
void finalize_geometry(bool opengl_initialized);
|
||||
// Release the geometry data, release OpenGL VBOs.
|
||||
void release_geometry();
|
||||
|
||||
|
@ -211,7 +217,7 @@ public:
|
|||
}
|
||||
|
||||
// Shrink the internal storage to tighly fit the data stored.
|
||||
void shrink_to_fit() const {
|
||||
void shrink_to_fit() {
|
||||
this->vertices_and_normals_interleaved.shrink_to_fit();
|
||||
this->triangle_indices.shrink_to_fit();
|
||||
this->quad_indices.shrink_to_fit();
|
||||
|
@ -219,6 +225,22 @@ public:
|
|||
|
||||
const BoundingBoxf3& bounding_box() const { return m_bounding_box; }
|
||||
|
||||
// Return an estimate of the memory consumed by this class.
|
||||
size_t cpu_memory_used() const { return sizeof(*this) + vertices_and_normals_interleaved.capacity() * sizeof(float) + triangle_indices.capacity() * sizeof(int) + quad_indices.capacity() * sizeof(int); }
|
||||
// Return an estimate of the memory held by GPU vertex buffers.
|
||||
size_t gpu_memory_used() const
|
||||
{
|
||||
size_t memsize = 0;
|
||||
if (this->vertices_and_normals_interleaved_VBO_id != 0)
|
||||
memsize += this->vertices_and_normals_interleaved_size * 4;
|
||||
if (this->triangle_indices_VBO_id != 0)
|
||||
memsize += this->triangle_indices_size * 4;
|
||||
if (this->quad_indices_VBO_id != 0)
|
||||
memsize += this->quad_indices_size * 4;
|
||||
return memsize;
|
||||
}
|
||||
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
|
||||
|
||||
private:
|
||||
BoundingBoxf3 m_bounding_box;
|
||||
};
|
||||
|
@ -250,7 +272,7 @@ private:
|
|||
Geometry::Transformation m_volume_transformation;
|
||||
|
||||
// Shift in z required by sla supports+pad
|
||||
double m_sla_shift_z;
|
||||
double m_sla_shift_z;
|
||||
// Bounding box of this volume, in unscaled coordinates.
|
||||
mutable BoundingBoxf3 m_transformed_bounding_box;
|
||||
// Whether or not is needed to recalculate the transformed bounding box.
|
||||
|
@ -294,6 +316,8 @@ public:
|
|||
bool selected;
|
||||
// Is this object disabled from selection?
|
||||
bool disabled;
|
||||
// Is this object printable?
|
||||
bool printable;
|
||||
// Whether or not this volume is active for rendering
|
||||
bool is_active;
|
||||
// Whether or not to use this volume when applying zoom_to_volumes()
|
||||
|
@ -420,13 +444,22 @@ public:
|
|||
void render() const;
|
||||
void render(int color_id, int detection_id, int worldmatrix_id) const;
|
||||
|
||||
void finalize_geometry() { this->indexed_vertex_array.finalize_geometry(); }
|
||||
void finalize_geometry(bool opengl_initialized) { this->indexed_vertex_array.finalize_geometry(opengl_initialized); }
|
||||
void release_geometry() { this->indexed_vertex_array.release_geometry(); }
|
||||
|
||||
void set_bounding_boxes_as_dirty() { m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; }
|
||||
|
||||
bool is_sla_support() const;
|
||||
bool is_sla_pad() const;
|
||||
|
||||
// Return an estimate of the memory consumed by this class.
|
||||
size_t cpu_memory_used() const {
|
||||
//FIXME what to do wih m_convex_hull?
|
||||
return sizeof(*this) - sizeof(this->indexed_vertex_array) + this->indexed_vertex_array.cpu_memory_used() + this->print_zs.capacity() * sizeof(coordf_t) + this->offsets.capacity() * sizeof(size_t);
|
||||
}
|
||||
// Return an estimate of the memory held by GPU vertex buffers.
|
||||
size_t gpu_memory_used() const { return this->indexed_vertex_array.gpu_memory_used(); }
|
||||
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
|
||||
};
|
||||
|
||||
typedef std::vector<GLVolume*> GLVolumePtrs;
|
||||
|
@ -461,30 +494,33 @@ public:
|
|||
~GLVolumeCollection() { clear(); };
|
||||
|
||||
std::vector<int> load_object(
|
||||
const ModelObject* model_object,
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
const std::vector<int>& instance_idxs,
|
||||
const std::string& color_by);
|
||||
const std::vector<int> &instance_idxs,
|
||||
const std::string &color_by,
|
||||
bool opengl_initialized);
|
||||
|
||||
int load_object_volume(
|
||||
const ModelObject* model_object,
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx,
|
||||
const std::string& color_by);
|
||||
const ModelObject *model_object,
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx,
|
||||
const std::string &color_by,
|
||||
bool opengl_initialized);
|
||||
|
||||
// Load SLA auxiliary GLVolumes (for support trees or pad).
|
||||
void load_object_auxiliary(
|
||||
const SLAPrintObject* print_object,
|
||||
const SLAPrintObject *print_object,
|
||||
int obj_idx,
|
||||
// pairs of <instance_idx, print_instance_idx>
|
||||
const std::vector<std::pair<size_t, size_t>>& instances,
|
||||
SLAPrintObjectStep milestone,
|
||||
// Timestamp of the last change of the milestone
|
||||
size_t timestamp);
|
||||
size_t timestamp,
|
||||
bool opengl_initialized);
|
||||
|
||||
int load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width);
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool size_unknown, float brim_width, bool opengl_initialized);
|
||||
|
||||
// Render the volumes by OpenGL.
|
||||
void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
|
||||
|
@ -492,7 +528,7 @@ public:
|
|||
// Finalize the initialization of the geometry & indices,
|
||||
// upload the geometry and indices to OpenGL VBO objects
|
||||
// and shrink the allocated data, possibly relasing it if it has been loaded into the VBOs.
|
||||
void finalize_geometry() { for (auto* v : volumes) v->finalize_geometry(); }
|
||||
void finalize_geometry(bool opengl_initialized) { for (auto* v : volumes) v->finalize_geometry(opengl_initialized); }
|
||||
// Release the geometry data assigned to the volumes.
|
||||
// If OpenGL VBOs were allocated, an OpenGL context has to be active to release them.
|
||||
void release_geometry() { for (auto *v : volumes) v->release_geometry(); }
|
||||
|
@ -520,6 +556,14 @@ public:
|
|||
// Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection
|
||||
std::vector<double> get_current_print_zs(bool active_only) const;
|
||||
|
||||
// Return an estimate of the memory consumed by this class.
|
||||
size_t cpu_memory_used() const;
|
||||
// Return an estimate of the memory held by GPU vertex buffers.
|
||||
size_t gpu_memory_used() const;
|
||||
size_t total_memory_used() const { return this->cpu_memory_used() + this->gpu_memory_used(); }
|
||||
// Return CPU, GPU and total memory log line.
|
||||
std::string log_memory_info() const;
|
||||
|
||||
private:
|
||||
GLVolumeCollection(const GLVolumeCollection &other);
|
||||
GLVolumeCollection& operator=(const GLVolumeCollection &);
|
||||
|
@ -537,6 +581,7 @@ public:
|
|||
GLModel();
|
||||
virtual ~GLModel();
|
||||
|
||||
// init() / init_from_file() shall be called with the OpenGL context active!
|
||||
bool init() { return on_init(); }
|
||||
bool init_from_file(const std::string& filename) { return on_init_from_file(filename); }
|
||||
|
||||
|
@ -566,7 +611,7 @@ protected:
|
|||
class GLArrow : public GLModel
|
||||
{
|
||||
protected:
|
||||
virtual bool on_init();
|
||||
bool on_init() override;
|
||||
};
|
||||
|
||||
class GLCurvedArrow : public GLModel
|
||||
|
@ -577,13 +622,13 @@ public:
|
|||
explicit GLCurvedArrow(unsigned int resolution);
|
||||
|
||||
protected:
|
||||
virtual bool on_init();
|
||||
bool on_init() override;
|
||||
};
|
||||
|
||||
class GLBed : public GLModel
|
||||
{
|
||||
protected:
|
||||
virtual bool on_init_from_file(const std::string& filename);
|
||||
bool on_init_from_file(const std::string& filename) override;
|
||||
};
|
||||
|
||||
class _3DScene
|
||||
|
|
|
@ -212,7 +212,7 @@ wxPanel* BedShapePanel::init_texture_panel()
|
|||
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
|
||||
if (lbl != nullptr)
|
||||
{
|
||||
wxString tooltip_text = (m_custom_texture == NONE) ? _(L("")) : _(m_custom_texture);
|
||||
wxString tooltip_text = (m_custom_texture == NONE) ? "" : _(m_custom_texture);
|
||||
wxToolTip* tooltip = lbl->GetToolTip();
|
||||
if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text))
|
||||
lbl->SetToolTip(tooltip_text);
|
||||
|
@ -280,7 +280,7 @@ wxPanel* BedShapePanel::init_model_panel()
|
|||
wxStaticText* lbl = dynamic_cast<wxStaticText*>(e.GetEventObject());
|
||||
if (lbl != nullptr)
|
||||
{
|
||||
wxString tooltip_text = (m_custom_model == NONE) ? _(L("")) : _(m_custom_model);
|
||||
wxString tooltip_text = (m_custom_model == NONE) ? "" : _(m_custom_model);
|
||||
wxToolTip* tooltip = lbl->GetToolTip();
|
||||
if ((tooltip == nullptr) || (tooltip->GetTip() != tooltip_text))
|
||||
lbl->SetToolTip(tooltip_text);
|
||||
|
|
|
@ -22,10 +22,10 @@ namespace Slic3r {
|
|||
namespace GUI {
|
||||
|
||||
const double Camera::DefaultDistance = 1000.0;
|
||||
double Camera::FrustrumMinZSize = 50.0;
|
||||
double Camera::FrustrumMinZRange = 50.0;
|
||||
double Camera::FrustrumMinNearZ = 100.0;
|
||||
double Camera::FrustrumZMargin = 10.0;
|
||||
double Camera::FovMinDeg = 0.5;
|
||||
double Camera::FovMaxDeg = 75.0;
|
||||
double Camera::MaxFovDeg = 60.0;
|
||||
|
||||
Camera::Camera()
|
||||
: phi(45.0f)
|
||||
|
@ -186,7 +186,8 @@ void Camera::apply_view_matrix() const
|
|||
|
||||
void Camera::apply_projection(const BoundingBoxf3& box) const
|
||||
{
|
||||
m_distance = DefaultDistance;
|
||||
set_distance(DefaultDistance);
|
||||
|
||||
double w = 0.0;
|
||||
double h = 0.0;
|
||||
|
||||
|
@ -194,15 +195,14 @@ void Camera::apply_projection(const BoundingBoxf3& box) const
|
|||
{
|
||||
m_frustrum_zs = calc_tight_frustrum_zs_around(box);
|
||||
|
||||
w = (double)m_viewport[2];
|
||||
h = (double)m_viewport[3];
|
||||
w = 0.5 * (double)m_viewport[2];
|
||||
h = 0.5 * (double)m_viewport[3];
|
||||
|
||||
double two_zoom = 2.0 * m_zoom;
|
||||
if (two_zoom != 0.0)
|
||||
if (m_zoom != 0.0)
|
||||
{
|
||||
double inv_two_zoom = 1.0 / two_zoom;
|
||||
w *= inv_two_zoom;
|
||||
h *= inv_two_zoom;
|
||||
double inv_zoom = 1.0 / m_zoom;
|
||||
w *= inv_zoom;
|
||||
h *= inv_zoom;
|
||||
}
|
||||
|
||||
switch (m_type)
|
||||
|
@ -226,21 +226,16 @@ void Camera::apply_projection(const BoundingBoxf3& box) const
|
|||
|
||||
if (m_type == Perspective)
|
||||
{
|
||||
double fov_rad = 2.0 * std::atan(h / m_frustrum_zs.first);
|
||||
double fov_deg = Geometry::rad2deg(fov_rad);
|
||||
double fov_deg = Geometry::rad2deg(2.0 * std::atan(h / m_frustrum_zs.first));
|
||||
|
||||
// adjust camera distance to keep fov in a limited range
|
||||
if (fov_deg > FovMaxDeg + 0.001)
|
||||
if (fov_deg > MaxFovDeg)
|
||||
{
|
||||
double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMaxDeg));
|
||||
m_distance += (new_near_z - m_frustrum_zs.first);
|
||||
apply_view_matrix();
|
||||
}
|
||||
else if (fov_deg < FovMinDeg - 0.001)
|
||||
{
|
||||
double new_near_z = h / ::tan(0.5 * Geometry::deg2rad(FovMinDeg));
|
||||
m_distance += (new_near_z - m_frustrum_zs.first);
|
||||
apply_view_matrix();
|
||||
double delta_z = h / ::tan(0.5 * Geometry::deg2rad(MaxFovDeg)) - m_frustrum_zs.first;
|
||||
if (delta_z > 0.001)
|
||||
set_distance(m_distance + delta_z);
|
||||
else
|
||||
break;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
@ -328,42 +323,50 @@ void Camera::debug_render() const
|
|||
|
||||
std::pair<double, double> Camera::calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const
|
||||
{
|
||||
std::pair<double, double> ret = std::make_pair(DBL_MAX, -DBL_MAX);
|
||||
std::pair<double, double> ret;
|
||||
|
||||
Vec3d bb_min = box.min;
|
||||
Vec3d bb_max = box.max;
|
||||
|
||||
// box vertices in world space
|
||||
std::vector<Vec3d> vertices;
|
||||
vertices.reserve(8);
|
||||
vertices.push_back(bb_min);
|
||||
vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2));
|
||||
vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2));
|
||||
vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2));
|
||||
vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2));
|
||||
vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2));
|
||||
vertices.push_back(bb_max);
|
||||
vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2));
|
||||
|
||||
// set the Z range in eye coordinates (negative Zs are in front of the camera)
|
||||
for (const Vec3d& v : vertices)
|
||||
while (true)
|
||||
{
|
||||
double z = -(m_view_matrix * v)(2);
|
||||
ret.first = std::min(ret.first, z);
|
||||
ret.second = std::max(ret.second, z);
|
||||
}
|
||||
ret = std::make_pair(DBL_MAX, -DBL_MAX);
|
||||
|
||||
// apply margin
|
||||
ret.first -= FrustrumZMargin;
|
||||
ret.second += FrustrumZMargin;
|
||||
// box vertices in world space
|
||||
std::vector<Vec3d> vertices;
|
||||
vertices.reserve(8);
|
||||
vertices.push_back(box.min);
|
||||
vertices.emplace_back(box.max(0), box.min(1), box.min(2));
|
||||
vertices.emplace_back(box.max(0), box.max(1), box.min(2));
|
||||
vertices.emplace_back(box.min(0), box.max(1), box.min(2));
|
||||
vertices.emplace_back(box.min(0), box.min(1), box.max(2));
|
||||
vertices.emplace_back(box.max(0), box.min(1), box.max(2));
|
||||
vertices.push_back(box.max);
|
||||
vertices.emplace_back(box.min(0), box.max(1), box.max(2));
|
||||
|
||||
// ensure min size
|
||||
if (ret.second - ret.first < FrustrumMinZSize)
|
||||
{
|
||||
double mid_z = 0.5 * (ret.first + ret.second);
|
||||
double half_size = 0.5 * FrustrumMinZSize;
|
||||
ret.first = mid_z - half_size;
|
||||
ret.second = mid_z + half_size;
|
||||
// set the Z range in eye coordinates (negative Zs are in front of the camera)
|
||||
for (const Vec3d& v : vertices)
|
||||
{
|
||||
double z = -(m_view_matrix * v)(2);
|
||||
ret.first = std::min(ret.first, z);
|
||||
ret.second = std::max(ret.second, z);
|
||||
}
|
||||
|
||||
// apply margin
|
||||
ret.first -= FrustrumZMargin;
|
||||
ret.second += FrustrumZMargin;
|
||||
|
||||
// ensure min size
|
||||
if (ret.second - ret.first < FrustrumMinZRange)
|
||||
{
|
||||
double mid_z = 0.5 * (ret.first + ret.second);
|
||||
double half_size = 0.5 * FrustrumMinZRange;
|
||||
ret.first = mid_z - half_size;
|
||||
ret.second = mid_z + half_size;
|
||||
}
|
||||
|
||||
if (ret.first >= FrustrumMinNearZ)
|
||||
break;
|
||||
|
||||
// ensure min Near Z
|
||||
set_distance(m_distance + FrustrumMinNearZ - ret.first);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -385,21 +388,19 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca
|
|||
Vec3d up = get_dir_up();
|
||||
Vec3d forward = get_dir_forward();
|
||||
|
||||
Vec3d bb_min = box.min;
|
||||
Vec3d bb_max = box.max;
|
||||
Vec3d bb_center = box.center();
|
||||
|
||||
// box vertices in world space
|
||||
std::vector<Vec3d> vertices;
|
||||
vertices.reserve(8);
|
||||
vertices.push_back(bb_min);
|
||||
vertices.emplace_back(bb_max(0), bb_min(1), bb_min(2));
|
||||
vertices.emplace_back(bb_max(0), bb_max(1), bb_min(2));
|
||||
vertices.emplace_back(bb_min(0), bb_max(1), bb_min(2));
|
||||
vertices.emplace_back(bb_min(0), bb_min(1), bb_max(2));
|
||||
vertices.emplace_back(bb_max(0), bb_min(1), bb_max(2));
|
||||
vertices.push_back(bb_max);
|
||||
vertices.emplace_back(bb_min(0), bb_max(1), bb_max(2));
|
||||
vertices.push_back(box.min);
|
||||
vertices.emplace_back(box.max(0), box.min(1), box.min(2));
|
||||
vertices.emplace_back(box.max(0), box.max(1), box.min(2));
|
||||
vertices.emplace_back(box.min(0), box.max(1), box.min(2));
|
||||
vertices.emplace_back(box.min(0), box.min(1), box.max(2));
|
||||
vertices.emplace_back(box.max(0), box.min(1), box.max(2));
|
||||
vertices.push_back(box.max);
|
||||
vertices.emplace_back(box.min(0), box.max(1), box.max(2));
|
||||
|
||||
double max_x = 0.0;
|
||||
double max_y = 0.0;
|
||||
|
@ -430,6 +431,12 @@ double Camera::calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int ca
|
|||
return std::min((double)canvas_w / (2.0 * max_x), (double)canvas_h / (2.0 * max_y));
|
||||
}
|
||||
|
||||
void Camera::set_distance(double distance) const
|
||||
{
|
||||
m_distance = distance;
|
||||
apply_view_matrix();
|
||||
}
|
||||
|
||||
} // GUI
|
||||
} // Slic3r
|
||||
|
||||
|
|
|
@ -10,10 +10,10 @@ namespace GUI {
|
|||
struct Camera
|
||||
{
|
||||
static const double DefaultDistance;
|
||||
static double FrustrumMinZSize;
|
||||
static double FrustrumMinZRange;
|
||||
static double FrustrumMinNearZ;
|
||||
static double FrustrumZMargin;
|
||||
static double FovMinDeg;
|
||||
static double FovMaxDeg;
|
||||
static double MaxFovDeg;
|
||||
|
||||
enum EType : unsigned char
|
||||
{
|
||||
|
@ -101,6 +101,7 @@ private:
|
|||
// the camera MUST be outside of the bounding box in eye coordinate of the given box
|
||||
std::pair<double, double> calc_tight_frustrum_zs_around(const BoundingBoxf3& box) const;
|
||||
double calc_zoom_to_bounding_box_factor(const BoundingBoxf3& box, int canvas_w, int canvas_h) const;
|
||||
void set_distance(double distance) const;
|
||||
};
|
||||
|
||||
} // GUI
|
||||
|
|
|
@ -393,6 +393,12 @@ void TextCtrl::set_value(const boost::any& value, bool change_event/* = false*/)
|
|||
else
|
||||
dynamic_cast<wxTextCtrl*>(window)->SetValue(boost::any_cast<wxString>(value));
|
||||
m_disable_change_event = false;
|
||||
|
||||
if (!change_event) {
|
||||
wxString ret_str = static_cast<wxTextCtrl*>(window)->GetValue();
|
||||
// update m_value to correct work of next value_was_changed()
|
||||
get_value_by_opt_type(ret_str);
|
||||
}
|
||||
}
|
||||
|
||||
void TextCtrl::set_last_meaningful_value()
|
||||
|
@ -410,7 +416,7 @@ void TextCtrl::set_na_value()
|
|||
boost::any& TextCtrl::get_value()
|
||||
{
|
||||
wxString ret_str = static_cast<wxTextCtrl*>(window)->GetValue();
|
||||
// modifies ret_string!
|
||||
// update m_value
|
||||
get_value_by_opt_type(ret_str);
|
||||
|
||||
return m_value;
|
||||
|
@ -905,7 +911,7 @@ boost::any& Choice::get_value()
|
|||
wxString ret_str = field->GetValue();
|
||||
|
||||
// options from right panel
|
||||
std::vector <std::string> right_panel_options{ "support", "scale_unit" };
|
||||
std::vector <std::string> right_panel_options{ "support", "pad", "scale_unit" };
|
||||
for (auto rp_option: right_panel_options)
|
||||
if (m_opt_id == rp_option)
|
||||
return m_value = boost::any(ret_str);
|
||||
|
|
|
@ -354,7 +354,7 @@ bool FirmwareDialog::priv::check_model_id()
|
|||
// Therefore, regretably, so far the check cannot be used and we just return true here.
|
||||
// TODO: Rewrite Serial using more platform-native code.
|
||||
return true;
|
||||
|
||||
|
||||
// if (hex_file.model_id.empty()) {
|
||||
// // No data to check against, assume it's ok
|
||||
// return true;
|
||||
|
|
|
@ -1234,10 +1234,9 @@ bool GLCanvas3D::init()
|
|||
return false;
|
||||
}
|
||||
|
||||
// // on linux the gl context is not valid until the canvas is not shown on screen
|
||||
// // we defer the geometry finalization of volumes until the first call to render()
|
||||
// if (!m_volumes.empty())
|
||||
// m_volumes.finalize_geometry();
|
||||
// on linux the gl context is not valid until the canvas is not shown on screen
|
||||
// we defer the geometry finalization of volumes until the first call to render()
|
||||
m_volumes.finalize_geometry(true);
|
||||
|
||||
if (m_gizmos.is_enabled() && !m_gizmos.init())
|
||||
std::cout << "Unable to initialize gizmos: please, check that all the required textures are available" << std::endl;
|
||||
|
@ -1320,6 +1319,26 @@ void GLCanvas3D::toggle_model_objects_visibility(bool visible, const ModelObject
|
|||
_set_warning_texture(WarningTexture::SomethingNotShown, false);
|
||||
}
|
||||
|
||||
void GLCanvas3D::update_instance_printable_state_for_object(const size_t obj_idx)
|
||||
{
|
||||
ModelObject* model_object = m_model->objects[obj_idx];
|
||||
for (int inst_idx = 0; inst_idx < model_object->instances.size(); inst_idx++)
|
||||
{
|
||||
ModelInstance* instance = model_object->instances[inst_idx];
|
||||
|
||||
for (GLVolume* volume : m_volumes.volumes)
|
||||
{
|
||||
if ((volume->object_idx() == obj_idx) && (volume->instance_idx() == inst_idx))
|
||||
volume->printable = instance->printable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas3D::update_instance_printable_state_for_objects(std::vector<size_t>& object_idxs)
|
||||
{
|
||||
for (size_t obj_idx : object_idxs)
|
||||
update_instance_printable_state_for_object(obj_idx);
|
||||
}
|
||||
|
||||
void GLCanvas3D::set_config(const DynamicPrintConfig* config)
|
||||
{
|
||||
|
@ -1529,7 +1548,7 @@ void GLCanvas3D::render()
|
|||
}
|
||||
|
||||
m_camera.apply_view_matrix();
|
||||
m_camera.apply_projection(_max_bounding_box(true));
|
||||
m_camera.apply_projection(_max_bounding_box(true, true));
|
||||
|
||||
GLfloat position_cam[4] = { 1.0f, 0.0f, 1.0f, 0.0f };
|
||||
glsafe(::glLightfv(GL_LIGHT1, GL_POSITION, position_cam));
|
||||
|
@ -1691,7 +1710,7 @@ std::vector<int> GLCanvas3D::load_object(const ModelObject& model_object, int ob
|
|||
instance_idxs.push_back(i);
|
||||
}
|
||||
}
|
||||
return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by);
|
||||
return m_volumes.load_object(&model_object, obj_idx, instance_idxs, m_color_by, m_initialized);
|
||||
}
|
||||
|
||||
std::vector<int> GLCanvas3D::load_object(const Model& model, int obj_idx)
|
||||
|
@ -1879,7 +1898,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id);
|
||||
if (it->new_geometry()) {
|
||||
// New volume.
|
||||
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by);
|
||||
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by, m_initialized);
|
||||
m_volumes.volumes.back()->geometry_id = key.geometry_id;
|
||||
update_object_list = true;
|
||||
} else {
|
||||
|
@ -1952,7 +1971,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
|
||||
for (size_t istep = 0; istep < sla_steps.size(); ++istep)
|
||||
if (!instances[istep].empty())
|
||||
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
|
||||
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp, m_initialized);
|
||||
}
|
||||
|
||||
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
|
||||
|
@ -1992,7 +2011,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
|||
depth = (900.f/w) * (float)(extruders_count - 1);
|
||||
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
|
||||
1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
||||
brim_spacing * 4.5f);
|
||||
brim_spacing * 4.5f, m_initialized);
|
||||
if (volume_idx_wipe_tower_old != -1)
|
||||
map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new;
|
||||
}
|
||||
|
@ -2110,8 +2129,7 @@ void GLCanvas3D::load_sla_preview()
|
|||
if ((m_canvas != nullptr) && (print != nullptr))
|
||||
{
|
||||
_set_current();
|
||||
// Reload the SLA support structures into GLVolumes.
|
||||
this->reload_scene(true, true);
|
||||
_load_sla_shells();
|
||||
_update_sla_shells_outside_state();
|
||||
_show_warning_texture_if_needed(WarningTexture::SlaSupportsOutside);
|
||||
}
|
||||
|
@ -2906,7 +2924,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
&& m_gizmos.get_current_type() != GLGizmosManager::SlaSupports) // disable context menu when the gizmo is open
|
||||
{
|
||||
// forces the selection of the volume
|
||||
m_selection.add(volume_idx);
|
||||
/* m_selection.add(volume_idx); // #et_FIXME_if_needed
|
||||
* To avoid extra "Add-Selection" snapshots,
|
||||
* call add() with check_for_already_contained=true
|
||||
* */
|
||||
m_selection.add(volume_idx, true, true);
|
||||
m_gizmos.refresh_on_off_state();
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_OBJECT_SELECT));
|
||||
m_gizmos.update_data();
|
||||
|
@ -2929,7 +2951,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
else if (evt.Moving())
|
||||
{
|
||||
m_mouse.position = pos.cast<double>();
|
||||
std::string tooltip = L("");
|
||||
std::string tooltip = "";
|
||||
|
||||
if (tooltip.empty())
|
||||
tooltip = m_gizmos.get_tooltip();
|
||||
|
@ -3217,7 +3239,7 @@ void GLCanvas3D::do_flatten(const Vec3d& normal, const std::string& snapshot_typ
|
|||
wxGetApp().plater()->take_snapshot(_(snapshot_type));
|
||||
|
||||
m_selection.flattening_rotate(normal);
|
||||
do_rotate(L("")); // avoid taking another snapshot
|
||||
do_rotate(""); // avoid taking another snapshot
|
||||
}
|
||||
|
||||
void GLCanvas3D::do_mirror(const std::string& snapshot_type)
|
||||
|
@ -3273,7 +3295,7 @@ void GLCanvas3D::do_mirror(const std::string& snapshot_type)
|
|||
void GLCanvas3D::set_camera_zoom(double zoom)
|
||||
{
|
||||
const Size& cnv_size = get_canvas_size();
|
||||
m_camera.set_zoom(zoom, _max_bounding_box(false), cnv_size.get_width(), cnv_size.get_height());
|
||||
m_camera.set_zoom(zoom, _max_bounding_box(false, false), cnv_size.get_width(), cnv_size.get_height());
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
|
@ -3620,14 +3642,14 @@ bool GLCanvas3D::_init_undoredo_toolbar()
|
|||
std::string curr_additional_tooltip;
|
||||
m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip);
|
||||
|
||||
std::string new_additional_tooltip = L("");
|
||||
std::string new_additional_tooltip = "";
|
||||
if (can_undo)
|
||||
wxGetApp().plater()->undo_redo_topmost_string_getter(true, new_additional_tooltip);
|
||||
|
||||
if (new_additional_tooltip != curr_additional_tooltip)
|
||||
{
|
||||
m_undoredo_toolbar.set_additional_tooltip(id, new_additional_tooltip);
|
||||
set_tooltip(L(""));
|
||||
set_tooltip("");
|
||||
}
|
||||
return can_undo;
|
||||
};
|
||||
|
@ -3649,14 +3671,14 @@ bool GLCanvas3D::_init_undoredo_toolbar()
|
|||
std::string curr_additional_tooltip;
|
||||
m_undoredo_toolbar.get_additional_tooltip(id, curr_additional_tooltip);
|
||||
|
||||
std::string new_additional_tooltip = L("");
|
||||
std::string new_additional_tooltip = "";
|
||||
if (can_redo)
|
||||
wxGetApp().plater()->undo_redo_topmost_string_getter(false, new_additional_tooltip);
|
||||
|
||||
if (new_additional_tooltip != curr_additional_tooltip)
|
||||
{
|
||||
m_undoredo_toolbar.set_additional_tooltip(id, new_additional_tooltip);
|
||||
set_tooltip(L(""));
|
||||
set_tooltip("");
|
||||
}
|
||||
return can_redo;
|
||||
};
|
||||
|
@ -3699,9 +3721,20 @@ void GLCanvas3D::_resize(unsigned int w, unsigned int h)
|
|||
m_dirty = false;
|
||||
}
|
||||
|
||||
BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_bed_model) const
|
||||
BoundingBoxf3 GLCanvas3D::_max_bounding_box(bool include_gizmos, bool include_bed_model) const
|
||||
{
|
||||
BoundingBoxf3 bb = volumes_bounding_box();
|
||||
|
||||
// The following is a workaround for gizmos not being taken in account when calculating the tight camera frustrum
|
||||
// A better solution would ask the gizmo manager for the bounding box of the current active gizmo, if any
|
||||
if (include_gizmos && m_gizmos.is_running())
|
||||
{
|
||||
BoundingBoxf3 sel_bb = m_selection.get_bounding_box();
|
||||
Vec3d sel_bb_center = sel_bb.center();
|
||||
Vec3d extend_by = sel_bb.max_size() * Vec3d::Ones();
|
||||
bb.merge(BoundingBoxf3(sel_bb_center - extend_by, sel_bb_center + extend_by));
|
||||
}
|
||||
|
||||
bb.merge(m_bed.get_bounding_box(include_bed_model));
|
||||
return bb;
|
||||
}
|
||||
|
@ -3737,6 +3770,7 @@ void GLCanvas3D::_picking_pass() const
|
|||
// Better to use software ray - casting on a bounding - box hierarchy.
|
||||
|
||||
if (m_multisample_allowed)
|
||||
// This flag is often ignored by NVIDIA drivers if rendering into a screen buffer.
|
||||
glsafe(::glDisable(GL_MULTISAMPLE));
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
@ -3766,7 +3800,9 @@ void GLCanvas3D::_picking_pass() const
|
|||
if (inside)
|
||||
{
|
||||
glsafe(::glReadPixels(m_mouse.position(0), cnv_size.get_height() - m_mouse.position(1) - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, (void*)color));
|
||||
volume_id = color[0] + (color[1] << 8) + (color[2] << 16);
|
||||
if (picking_checksum_alpha_channel(color[0], color[1], color[2]) == color[3])
|
||||
// Only non-interpolated colors are valid, those have their lowest three bits zeroed.
|
||||
volume_id = color[0] + (color[1] << 8) + (color[2] << 16);
|
||||
}
|
||||
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
|
||||
{
|
||||
|
@ -3789,6 +3825,7 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
|
|||
if (m_picking_enabled)
|
||||
{
|
||||
if (m_multisample_allowed)
|
||||
// This flag is often ignored by NVIDIA drivers if rendering into a screen buffer.
|
||||
glsafe(::glDisable(GL_MULTISAMPLE));
|
||||
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
@ -3814,6 +3851,8 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
|
|||
struct Pixel
|
||||
{
|
||||
std::array<GLubyte, 4> data;
|
||||
// Only non-interpolated colors are valid, those have their lowest three bits zeroed.
|
||||
bool valid() const { return picking_checksum_alpha_channel(data[0], data[1], data[2]) == data[3]; }
|
||||
int id() const { return data[0] + (data[1] << 8) + (data[2] << 16); }
|
||||
};
|
||||
|
||||
|
@ -3824,17 +3863,15 @@ void GLCanvas3D::_rectangular_selection_picking_pass() const
|
|||
tbb::parallel_for(tbb::blocked_range<size_t>(0, frame.size(), (size_t)width),
|
||||
[this, &frame, &idxs, &mutex](const tbb::blocked_range<size_t>& range) {
|
||||
for (size_t i = range.begin(); i < range.end(); ++i)
|
||||
{
|
||||
int volume_id = frame[i].id();
|
||||
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size()))
|
||||
{
|
||||
mutex.lock();
|
||||
idxs.insert(volume_id);
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
if (frame[i].valid()) {
|
||||
int volume_id = frame[i].id();
|
||||
if ((0 <= volume_id) && (volume_id < (int)m_volumes.volumes.size())) {
|
||||
mutex.lock();
|
||||
idxs.insert(volume_id);
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
});
|
||||
#else
|
||||
std::vector<GLubyte> frame(4 * px_count);
|
||||
glsafe(::glReadPixels(left, top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (void*)frame.data()));
|
||||
|
@ -4013,42 +4050,27 @@ void GLCanvas3D::_render_volumes_for_picking() const
|
|||
// do not cull backfaces to show broken geometry, if any
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
glsafe(::glEnableClientState(GL_VERTEX_ARRAY));
|
||||
glsafe(::glEnableClientState(GL_NORMAL_ARRAY));
|
||||
|
||||
const Transform3d& view_matrix = m_camera.get_view_matrix();
|
||||
GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, GLVolumeCollection::Opaque, view_matrix);
|
||||
for (const GLVolumeWithIdAndZ& volume : to_render)
|
||||
{
|
||||
// Object picking mode. Render the object with a color encoding the object index.
|
||||
unsigned int r = (volume.second.first & 0x000000FF) >> 0;
|
||||
unsigned int g = (volume.second.first & 0x0000FF00) >> 8;
|
||||
unsigned int b = (volume.second.first & 0x00FF0000) >> 16;
|
||||
glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255));
|
||||
|
||||
if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries))
|
||||
volume.first->render();
|
||||
}
|
||||
|
||||
to_render = volumes_to_render(m_volumes.volumes, GLVolumeCollection::Transparent, view_matrix);
|
||||
for (const GLVolumeWithIdAndZ& volume : to_render)
|
||||
{
|
||||
// Object picking mode. Render the object with a color encoding the object index.
|
||||
unsigned int r = (volume.second.first & 0x000000FF) >> 0;
|
||||
unsigned int g = (volume.second.first & 0x0000FF00) >> 8;
|
||||
unsigned int b = (volume.second.first & 0x00FF0000) >> 16;
|
||||
glsafe(::glColor3f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255));
|
||||
|
||||
if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries))
|
||||
volume.first->render();
|
||||
}
|
||||
for (size_t type = 0; type < 2; ++ type) {
|
||||
GLVolumeWithIdAndZList to_render = volumes_to_render(m_volumes.volumes, (type == 0) ? GLVolumeCollection::Opaque : GLVolumeCollection::Transparent, view_matrix);
|
||||
for (const GLVolumeWithIdAndZ& volume : to_render)
|
||||
if (!volume.first->disabled && ((volume.first->composite_id.volume_id >= 0) || m_render_sla_auxiliaries)) {
|
||||
// Object picking mode. Render the object with a color encoding the object index.
|
||||
unsigned int id = volume.second.first;
|
||||
unsigned int r = (id & (0x000000FF << 0)) << 0;
|
||||
unsigned int g = (id & (0x000000FF << 8)) >> 8;
|
||||
unsigned int b = (id & (0x000000FF << 16)) >> 16;
|
||||
unsigned int a = picking_checksum_alpha_channel(r, g, b);
|
||||
glsafe(::glColor4f((GLfloat)r * INV_255, (GLfloat)g * INV_255, (GLfloat)b * INV_255, (GLfloat)a * INV_255));
|
||||
volume.first->render();
|
||||
}
|
||||
}
|
||||
|
||||
glsafe(::glDisableClientState(GL_NORMAL_ARRAY));
|
||||
glsafe(::glDisableClientState(GL_VERTEX_ARRAY));
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
||||
glsafe(::glEnable(GL_CULL_FACE));
|
||||
}
|
||||
|
@ -4511,6 +4533,7 @@ void GLCanvas3D::_load_print_toolpaths()
|
|||
|
||||
_3DScene::extrusionentity_to_verts(print->skirt(), print_zs[i], Point(0, 0), volume);
|
||||
}
|
||||
volume.indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
}
|
||||
|
||||
void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, const std::vector<std::string>& str_tool_colors, const std::vector<double>& color_print_values)
|
||||
|
@ -4576,7 +4599,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
std::sort(ctxt.layers.begin(), ctxt.layers.end(), [](const Layer *l1, const Layer *l2) { return l1->print_z < l2->print_z; });
|
||||
|
||||
// Maximum size of an allocation block: 32MB / sizeof(float)
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start";
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - start" << m_volumes.log_memory_info() << log_memory_info();
|
||||
|
||||
//FIXME Improve the heuristics for a grain size.
|
||||
size_t grain_size = std::max(ctxt.layers.size() / 16, size_t(1));
|
||||
|
@ -4682,16 +4705,22 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
|
|||
}
|
||||
}
|
||||
}
|
||||
for (GLVolume *vol : vols)
|
||||
// Ideally one would call vol->indexed_vertex_array.finalize() here to move the buffers to the OpenGL driver,
|
||||
// but this code runs in parallel and the OpenGL driver is not thread safe.
|
||||
vol->indexed_vertex_array.shrink_to_fit();
|
||||
});
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results";
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
|
||||
// Remove empty volumes from the newly added volumes.
|
||||
m_volumes.volumes.erase(
|
||||
std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(),
|
||||
[](const GLVolume *volume) { return volume->empty(); }),
|
||||
m_volumes.volumes.end());
|
||||
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i)
|
||||
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end";
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading print object toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
||||
}
|
||||
|
||||
void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_tool_colors)
|
||||
|
@ -4748,7 +4777,7 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
|
|||
ctxt.wipe_tower_angle = ctxt.print->config().wipe_tower_rotation_angle.value/180.f * PI;
|
||||
ctxt.wipe_tower_pos = Vec2f(ctxt.print->config().wipe_tower_x.value, ctxt.print->config().wipe_tower_y.value);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start";
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - start" << m_volumes.log_memory_info() << log_memory_info();
|
||||
|
||||
//FIXME Improve the heuristics for a grain size.
|
||||
size_t n_items = print->wipe_tower_data().tool_changes.size() + (ctxt.priming.empty() ? 0 : 1);
|
||||
|
@ -4846,16 +4875,20 @@ void GLCanvas3D::_load_wipe_tower_toolpaths(const std::vector<std::string>& str_
|
|||
vol_new.indexed_vertex_array.reserve(ctxt.alloc_size_reserve());
|
||||
}
|
||||
}
|
||||
for (GLVolume *vol : vols)
|
||||
vol->indexed_vertex_array.shrink_to_fit();
|
||||
});
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results";
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - finalizing results" << m_volumes.log_memory_info() << log_memory_info();
|
||||
// Remove empty volumes from the newly added volumes.
|
||||
m_volumes.volumes.erase(
|
||||
std::remove_if(m_volumes.volumes.begin() + volumes_cnt_initial, m_volumes.volumes.end(),
|
||||
[](const GLVolume *volume) { return volume->empty(); }),
|
||||
m_volumes.volumes.end());
|
||||
for (size_t i = volumes_cnt_initial; i < m_volumes.volumes.size(); ++i)
|
||||
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end";
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading wipe tower toolpaths in parallel - end" << m_volumes.log_memory_info() << log_memory_info();
|
||||
}
|
||||
|
||||
static inline int hex_digit_to_int(const char c)
|
||||
|
@ -4868,6 +4901,8 @@ static inline int hex_digit_to_int(const char c)
|
|||
|
||||
void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - start" << m_volumes.log_memory_info() << log_memory_info();
|
||||
|
||||
// helper functions to select data in dependence of the extrusion view type
|
||||
struct Helper
|
||||
{
|
||||
|
@ -4983,6 +5018,8 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
|||
if (filters.empty())
|
||||
return;
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - create volumes" << m_volumes.log_memory_info() << log_memory_info();
|
||||
|
||||
// creates a new volume for each filter
|
||||
for (Filter& filter : filters)
|
||||
{
|
||||
|
@ -5013,6 +5050,8 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
|||
}
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - populate volumes" << m_volumes.log_memory_info() << log_memory_info();
|
||||
|
||||
// populates volumes
|
||||
for (const GCodePreviewData::Extrusion::Layer& layer : preview_data.extrusion.layers)
|
||||
{
|
||||
|
@ -5030,6 +5069,12 @@ void GLCanvas3D::_load_gcode_extrusion_paths(const GCodePreviewData& preview_dat
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// finalize volumes and sends geometry to gpu
|
||||
for (size_t i = initial_volumes_count; i < m_volumes.volumes.size(); ++i)
|
||||
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << "Loading G-code extrusion paths - end" << m_volumes.log_memory_info() << log_memory_info();
|
||||
}
|
||||
|
||||
void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data, const std::vector<float>& tool_colors)
|
||||
|
@ -5074,6 +5119,10 @@ void GLCanvas3D::_load_gcode_travel_paths(const GCodePreviewData& preview_data,
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
// finalize volumes and sends geometry to gpu
|
||||
for (size_t i = initial_volumes_count; i < m_volumes.volumes.size(); ++i)
|
||||
m_volumes.volumes[i]->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
}
|
||||
|
||||
bool GLCanvas3D::_travel_paths_by_type(const GCodePreviewData& preview_data)
|
||||
|
@ -5302,6 +5351,7 @@ void GLCanvas3D::_load_gcode_retractions(const GCodePreviewData& preview_data)
|
|||
|
||||
_3DScene::point3_to_verts(position.position, position.width, position.height, *volume);
|
||||
}
|
||||
volume->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5329,6 +5379,7 @@ void GLCanvas3D::_load_gcode_unretractions(const GCodePreviewData& preview_data)
|
|||
|
||||
_3DScene::point3_to_verts(position.position, position.width, position.height, *volume);
|
||||
}
|
||||
volume->indexed_vertex_array.finalize_geometry(m_initialized);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5354,7 +5405,7 @@ void GLCanvas3D::_load_fff_shells()
|
|||
instance_ids[i] = i;
|
||||
}
|
||||
|
||||
m_volumes.load_object(model_obj, object_id, instance_ids, "object");
|
||||
m_volumes.load_object(model_obj, object_id, instance_ids, "object", m_initialized);
|
||||
|
||||
++object_id;
|
||||
}
|
||||
|
@ -5376,11 +5427,63 @@ void GLCanvas3D::_load_fff_shells()
|
|||
if (!print->is_step_done(psWipeTower))
|
||||
depth = (900.f/config.wipe_tower_width) * (float)(extruders_count - 1);
|
||||
m_volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, depth, max_z, config.wipe_tower_rotation_angle,
|
||||
!print->is_step_done(psWipeTower), brim_spacing * 4.5f);
|
||||
!print->is_step_done(psWipeTower), brim_spacing * 4.5f, m_initialized);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// While it looks like we can call
|
||||
// this->reload_scene(true, true)
|
||||
// the two functions are quite different:
|
||||
// 1) This function only loads objects, for which the step slaposSliceSupports already finished. Therefore objects outside of the print bed never load.
|
||||
// 2) This function loads object mesh with the relative scaling correction (the "relative_correction" parameter) was applied,
|
||||
// therefore the mesh may be slightly larger or smaller than the mesh shown in the 3D scene.
|
||||
void GLCanvas3D::_load_sla_shells()
|
||||
{
|
||||
const SLAPrint* print = this->sla_print();
|
||||
if (print->objects().empty())
|
||||
// nothing to render, return
|
||||
return;
|
||||
|
||||
auto add_volume = [this](const SLAPrintObject &object, int volume_id, const SLAPrintObject::Instance& instance,
|
||||
const TriangleMesh &mesh, const float color[4], bool outside_printer_detection_enabled) {
|
||||
m_volumes.volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume& v = *m_volumes.volumes.back();
|
||||
v.indexed_vertex_array.load_mesh(mesh);
|
||||
v.indexed_vertex_array.finalize_geometry(this->m_initialized);
|
||||
v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled;
|
||||
v.composite_id.volume_id = volume_id;
|
||||
v.set_instance_offset(unscale(instance.shift(0), instance.shift(1), 0));
|
||||
v.set_instance_rotation(Vec3d(0.0, 0.0, (double)instance.rotation));
|
||||
v.set_instance_mirror(X, object.is_left_handed() ? -1. : 1.);
|
||||
v.set_convex_hull(mesh.convex_hull_3d());
|
||||
};
|
||||
|
||||
// adds objects' volumes
|
||||
for (const SLAPrintObject* obj : print->objects())
|
||||
if (obj->is_step_done(slaposSliceSupports)) {
|
||||
unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size();
|
||||
for (const SLAPrintObject::Instance& instance : obj->instances()) {
|
||||
add_volume(*obj, 0, instance, obj->transformed_mesh(), GLVolume::MODEL_COLOR[0], true);
|
||||
// Set the extruder_id and volume_id to achieve the same color as in the 3D scene when
|
||||
// through the update_volumes_colors_by_extruder() call.
|
||||
m_volumes.volumes.back()->extruder_id = obj->model_object()->volumes.front()->extruder_id();
|
||||
if (obj->is_step_done(slaposSupportTree) && obj->has_mesh(slaposSupportTree))
|
||||
add_volume(*obj, -int(slaposSupportTree), instance, obj->support_mesh(), GLVolume::SLA_SUPPORT_COLOR, true);
|
||||
if (obj->is_step_done(slaposBasePool) && obj->has_mesh(slaposBasePool))
|
||||
add_volume(*obj, -int(slaposBasePool), instance, obj->pad_mesh(), GLVolume::SLA_PAD_COLOR, false);
|
||||
}
|
||||
double shift_z = obj->get_current_elevation();
|
||||
for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) {
|
||||
GLVolume& v = *m_volumes.volumes[i];
|
||||
// apply shift z
|
||||
v.set_sla_shift_z(shift_z);
|
||||
}
|
||||
}
|
||||
|
||||
update_volumes_colors_by_extruder();
|
||||
}
|
||||
|
||||
void GLCanvas3D::_update_gcode_volumes_visibility(const GCodePreviewData& preview_data)
|
||||
{
|
||||
unsigned int size = (unsigned int)m_gcode_preview_volume_index.first_volumes.size();
|
||||
|
|
|
@ -482,6 +482,8 @@ public:
|
|||
|
||||
void toggle_sla_auxiliaries_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
|
||||
void toggle_model_objects_visibility(bool visible, const ModelObject* mo = nullptr, int instance_idx = -1);
|
||||
void update_instance_printable_state_for_object(size_t obj_idx);
|
||||
void update_instance_printable_state_for_objects(std::vector<size_t>& object_idxs);
|
||||
|
||||
void set_config(const DynamicPrintConfig* config);
|
||||
void set_process(BackgroundSlicingProcess* process);
|
||||
|
@ -652,7 +654,7 @@ private:
|
|||
bool _set_current();
|
||||
void _resize(unsigned int w, unsigned int h);
|
||||
|
||||
BoundingBoxf3 _max_bounding_box(bool include_bed_model) const;
|
||||
BoundingBoxf3 _max_bounding_box(bool include_gizmos, bool include_bed_model) const;
|
||||
|
||||
void _zoom_to_box(const BoundingBoxf3& box);
|
||||
|
||||
|
@ -721,6 +723,8 @@ private:
|
|||
void _load_gcode_unretractions(const GCodePreviewData& preview_data);
|
||||
// generates objects and wipe tower geometry
|
||||
void _load_fff_shells();
|
||||
// Load SLA objects and support structures for objects, for which the slaposSliceSupports step has been finished.
|
||||
void _load_sla_shells();
|
||||
// sets gcode geometry visibility according to user selection
|
||||
void _update_gcode_volumes_visibility(const GCodePreviewData& preview_data);
|
||||
void _update_toolpath_volumes_outside_state();
|
||||
|
|
|
@ -290,7 +290,21 @@ GLCanvas3D* GLCanvas3DManager::get_canvas(wxGLCanvas* canvas)
|
|||
|
||||
wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent)
|
||||
{
|
||||
int attribList[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 24, WX_GL_SAMPLE_BUFFERS, GL_TRUE, WX_GL_SAMPLES, 4, 0 };
|
||||
int attribList[] = {
|
||||
WX_GL_RGBA,
|
||||
WX_GL_DOUBLEBUFFER,
|
||||
// RGB channels each should be allocated with 8 bit depth. One should almost certainly get these bit depths by default.
|
||||
WX_GL_MIN_RED, 8,
|
||||
WX_GL_MIN_GREEN, 8,
|
||||
WX_GL_MIN_BLUE, 8,
|
||||
// Requesting an 8 bit alpha channel. Interestingly, the NVIDIA drivers would most likely work with some alpha plane, but glReadPixels would not return
|
||||
// the alpha channel on NVIDIA if not requested when the GL context is created.
|
||||
WX_GL_MIN_ALPHA, 8,
|
||||
WX_GL_DEPTH_SIZE, 24,
|
||||
WX_GL_SAMPLE_BUFFERS, GL_TRUE,
|
||||
WX_GL_SAMPLES, 4,
|
||||
0
|
||||
};
|
||||
|
||||
if (s_multisample == MS_Unknown)
|
||||
{
|
||||
|
@ -300,7 +314,7 @@ wxGLCanvas* GLCanvas3DManager::create_wxglcanvas(wxWindow *parent)
|
|||
}
|
||||
|
||||
if (! can_multisample())
|
||||
attribList[4] = 0;
|
||||
attribList[12] = 0;
|
||||
|
||||
return new wxGLCanvas(parent, wxID_ANY, attribList, wxDefaultPosition, wxDefaultSize, wxWANTS_CHARS);
|
||||
}
|
||||
|
|
|
@ -27,49 +27,57 @@ namespace GUI {
|
|||
|
||||
void GLTexture::Compressor::reset()
|
||||
{
|
||||
if (m_is_compressing)
|
||||
{
|
||||
// force compression completion, if any
|
||||
if (m_thread.joinable()) {
|
||||
m_abort_compressing = true;
|
||||
// wait for compression completion, if any
|
||||
while (m_is_compressing) {}
|
||||
}
|
||||
|
||||
m_levels.clear();
|
||||
}
|
||||
|
||||
void GLTexture::Compressor::add_level(unsigned int w, unsigned int h, const std::vector<unsigned char>& data)
|
||||
{
|
||||
m_levels.emplace_back(w, h, data);
|
||||
m_thread.join();
|
||||
m_levels.clear();
|
||||
m_num_levels_compressed = 0;
|
||||
m_abort_compressing = false;
|
||||
}
|
||||
assert(m_levels.empty());
|
||||
assert(m_abort_compressing == false);
|
||||
assert(m_num_levels_compressed == 0);
|
||||
}
|
||||
|
||||
void GLTexture::Compressor::start_compressing()
|
||||
{
|
||||
std::thread t(&GLTexture::Compressor::compress, this);
|
||||
t.detach();
|
||||
// The worker thread should be stopped already.
|
||||
assert(! m_thread.joinable());
|
||||
assert(! m_levels.empty());
|
||||
assert(m_abort_compressing == false);
|
||||
assert(m_num_levels_compressed == 0);
|
||||
if (! m_levels.empty()) {
|
||||
std::thread thrd(&GLTexture::Compressor::compress, this);
|
||||
m_thread = std::move(thrd);
|
||||
}
|
||||
}
|
||||
|
||||
bool GLTexture::Compressor::unsent_compressed_data_available() const
|
||||
{
|
||||
for (const Level& level : m_levels)
|
||||
{
|
||||
if (!level.sent_to_gpu && level.compressed)
|
||||
if (m_levels.empty())
|
||||
return false;
|
||||
// Querying the atomic m_num_levels_compressed value synchronizes processor caches, so that the dat of m_levels modified by the worker thread are accessible to the calling thread.
|
||||
unsigned int num_compressed = m_num_levels_compressed;
|
||||
for (unsigned int i = 0; i < num_compressed; ++ i)
|
||||
if (! m_levels[i].sent_to_gpu && ! m_levels[i].compressed_data.empty())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLTexture::Compressor::send_compressed_data_to_gpu()
|
||||
{
|
||||
// this method should be called inside the main thread of Slicer or a new OpenGL context (sharing resources) would be needed
|
||||
if (m_levels.empty())
|
||||
return;
|
||||
|
||||
glsafe(::glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, m_texture.m_id));
|
||||
for (int i = 0; i < (int)m_levels.size(); ++i)
|
||||
// Querying the atomic m_num_levels_compressed value synchronizes processor caches, so that the dat of m_levels modified by the worker thread are accessible to the calling thread.
|
||||
int num_compressed = (int)m_num_levels_compressed;
|
||||
for (int i = 0; i < num_compressed; ++ i)
|
||||
{
|
||||
Level& level = m_levels[i];
|
||||
if (!level.sent_to_gpu && level.compressed)
|
||||
if (! level.sent_to_gpu && ! level.compressed_data.empty())
|
||||
{
|
||||
glsafe(::glCompressedTexSubImage2D(GL_TEXTURE_2D, (GLint)i, 0, 0, (GLsizei)level.w, (GLsizei)level.h, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, (GLsizei)level.compressed_data.size(), (const GLvoid*)level.compressed_data.data()));
|
||||
glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, i));
|
||||
|
@ -77,29 +85,21 @@ void GLTexture::Compressor::send_compressed_data_to_gpu()
|
|||
level.sent_to_gpu = true;
|
||||
// we are done with the compressed data, we can discard it
|
||||
level.compressed_data.clear();
|
||||
level.compressed = false;
|
||||
}
|
||||
}
|
||||
glsafe(::glBindTexture(GL_TEXTURE_2D, 0));
|
||||
}
|
||||
|
||||
bool GLTexture::Compressor::all_compressed_data_sent_to_gpu() const
|
||||
{
|
||||
for (const Level& level : m_levels)
|
||||
{
|
||||
if (!level.sent_to_gpu)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (num_compressed == (unsigned int)m_levels.size())
|
||||
// Finalize the worker thread, close it.
|
||||
this->reset();
|
||||
}
|
||||
|
||||
void GLTexture::Compressor::compress()
|
||||
{
|
||||
// reference: https://github.com/Cyan4973/RygsDXTc
|
||||
|
||||
m_is_compressing = true;
|
||||
m_abort_compressing = false;
|
||||
assert(m_num_levels_compressed == 0);
|
||||
assert(m_abort_compressing == false);
|
||||
|
||||
for (Level& level : m_levels)
|
||||
{
|
||||
|
@ -115,11 +115,8 @@ void GLTexture::Compressor::compress()
|
|||
|
||||
// we are done with the source data, we can discard it
|
||||
level.src_data.clear();
|
||||
level.compressed = true;
|
||||
++ m_num_levels_compressed;
|
||||
}
|
||||
|
||||
m_is_compressing = false;
|
||||
m_abort_compressing = false;
|
||||
}
|
||||
|
||||
GLTexture::Quad_UVs GLTexture::FullTextureUVs = { { 0.0f, 1.0f }, { 1.0f, 1.0f }, { 1.0f, 0.0f }, { 0.0f, 0.0f } };
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#ifndef slic3r_GLTexture_hpp_
|
||||
#define slic3r_GLTexture_hpp_
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
class wxImage;
|
||||
|
||||
|
@ -19,30 +21,34 @@ namespace GUI {
|
|||
unsigned int h;
|
||||
std::vector<unsigned char> src_data;
|
||||
std::vector<unsigned char> compressed_data;
|
||||
bool compressed;
|
||||
bool sent_to_gpu;
|
||||
|
||||
Level(unsigned int w, unsigned int h, const std::vector<unsigned char>& data) : w(w), h(h), src_data(data), compressed(false), sent_to_gpu(false) {}
|
||||
Level(unsigned int w, unsigned int h, const std::vector<unsigned char>& data) : w(w), h(h), src_data(data), sent_to_gpu(false) {}
|
||||
};
|
||||
|
||||
GLTexture& m_texture;
|
||||
std::vector<Level> m_levels;
|
||||
bool m_is_compressing;
|
||||
bool m_abort_compressing;
|
||||
std::thread m_thread;
|
||||
// Does the caller want the background thread to stop?
|
||||
// This atomic also works as a memory barrier for synchronizing the cancel event with the worker thread.
|
||||
std::atomic<bool> m_abort_compressing;
|
||||
// How many levels were compressed since the start of the background processing thread?
|
||||
// This atomic also works as a memory barrier for synchronizing results of the worker thread with the calling thread.
|
||||
std::atomic<unsigned int> m_num_levels_compressed;
|
||||
|
||||
public:
|
||||
explicit Compressor(GLTexture& texture) : m_texture(texture), m_is_compressing(false), m_abort_compressing(false) {}
|
||||
explicit Compressor(GLTexture& texture) : m_texture(texture), m_abort_compressing(false), m_num_levels_compressed(0) {}
|
||||
~Compressor() { reset(); }
|
||||
|
||||
void reset();
|
||||
|
||||
void add_level(unsigned int w, unsigned int h, const std::vector<unsigned char>& data);
|
||||
void add_level(unsigned int w, unsigned int h, const std::vector<unsigned char>& data) { m_levels.emplace_back(w, h, data); }
|
||||
|
||||
void start_compressing();
|
||||
|
||||
bool unsent_compressed_data_available() const;
|
||||
void send_compressed_data_to_gpu();
|
||||
bool all_compressed_data_sent_to_gpu() const;
|
||||
bool all_compressed_data_sent_to_gpu() const { return m_levels.empty(); }
|
||||
|
||||
private:
|
||||
void compress();
|
||||
|
|
|
@ -173,7 +173,8 @@ bool GUI_App::on_init_inner()
|
|||
wxCHECK_MSG(wxDirExists(resources_dir), false,
|
||||
wxString::Format("Resources path does not exist or is not a directory: %s", resources_dir));
|
||||
|
||||
SetAppName(SLIC3R_APP_KEY);
|
||||
//SetAppName(SLIC3R_APP_KEY);
|
||||
SetAppName(SLIC3R_APP_KEY "-alpha");
|
||||
SetAppDisplayName(SLIC3R_APP_NAME);
|
||||
|
||||
// Enable this to get the default Win32 COMCTRL32 behavior of static boxes.
|
||||
|
@ -986,6 +987,7 @@ wxString GUI_App::current_language_code_safe() const
|
|||
language_code = language_code.substr(0, idx_underscore);
|
||||
const std::map<wxString, wxString> mapping {
|
||||
{ "cs", "cs_CZ", },
|
||||
{ "sk", "cs_CZ", },
|
||||
{ "de", "de_DE", },
|
||||
{ "es", "es_ES", },
|
||||
{ "fr", "fr_FR", },
|
||||
|
|
|
@ -186,7 +186,18 @@ ObjectList::ObjectList(wxWindow* parent) :
|
|||
|
||||
Bind(wxCUSTOMEVT_LAST_VOLUME_IS_DELETED, [this](wxCommandEvent& e) { last_volume_is_deleted(e.GetInt()); });
|
||||
|
||||
Bind(wxEVT_SIZE, ([this](wxSizeEvent &e) { this->EnsureVisible(this->GetCurrentItem()); e.Skip(); }));
|
||||
Bind(wxEVT_SIZE, ([this](wxSizeEvent &e) {
|
||||
#ifdef __WXGTK__
|
||||
// On GTK, the EnsureVisible call is postponed to Idle processing (see wxDataViewCtrl::m_ensureVisibleDefered).
|
||||
// So the postponed EnsureVisible() call is planned for an item, which may not exist at the Idle processing time, if this wxEVT_SIZE
|
||||
// event is succeeded by a delete of the currently active item. We are trying our luck by postponing the wxEVT_SIZE triggered EnsureVisible(),
|
||||
// which seems to be working as of now.
|
||||
this->CallAfter([this](){ this->EnsureVisible(this->GetCurrentItem()); });
|
||||
#else
|
||||
this->EnsureVisible(this->GetCurrentItem());
|
||||
#endif
|
||||
e.Skip();
|
||||
}));
|
||||
}
|
||||
|
||||
ObjectList::~ObjectList()
|
||||
|
@ -212,16 +223,20 @@ void ObjectList::create_objects_ctrl()
|
|||
EnableDropTarget(wxDF_UNICODETEXT);
|
||||
#endif // wxUSE_DRAG_AND_DROP && wxUSE_UNICODE
|
||||
|
||||
// column 0(Icon+Text) of the view control:
|
||||
// column ItemName(Icon+Text) of the view control:
|
||||
// And Icon can be consisting of several bitmaps
|
||||
AppendColumn(new wxDataViewColumn(_(L("Name")), new BitmapTextRenderer(),
|
||||
0, 20*wxGetApp().em_unit()/*200*/, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
|
||||
colName, 20*wxGetApp().em_unit()/*200*/, wxALIGN_LEFT, wxDATAVIEW_COL_RESIZABLE));
|
||||
|
||||
// column 1 of the view control:
|
||||
// column PrintableProperty (Icon) of the view control:
|
||||
AppendBitmapColumn(" ", colPrint, wxDATAVIEW_CELL_INERT, int(2 * wxGetApp().em_unit()),
|
||||
wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
|
||||
|
||||
// column Extruder of the view control:
|
||||
AppendColumn(create_objects_list_extruder_column(4));
|
||||
|
||||
// column 2 of the view control:
|
||||
AppendBitmapColumn(" ", 2, wxDATAVIEW_CELL_INERT, int(2.5 * wxGetApp().em_unit())/*25*/,
|
||||
// column ItemEditing of the view control:
|
||||
AppendBitmapColumn("Editing", colEditing, wxDATAVIEW_CELL_INERT, int(2.5 * wxGetApp().em_unit())/*25*/,
|
||||
wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
|
||||
}
|
||||
|
||||
|
@ -321,7 +336,7 @@ void ObjectList::set_tooltip_for_item(const wxPoint& pt)
|
|||
return;
|
||||
}
|
||||
|
||||
if (col->GetTitle() == " " && GetSelectedItemsCount()<2)
|
||||
if (col->GetTitle() == _(L("Editing")) && GetSelectedItemsCount()<2)
|
||||
GetMainWindow()->SetToolTip(_(L("Right button click the icon to change the object settings")));
|
||||
else if (col->GetTitle() == _("Name"))
|
||||
{
|
||||
|
@ -377,7 +392,7 @@ wxDataViewColumn* ObjectList::create_objects_list_extruder_column(int extruders_
|
|||
choices.Add(wxString::Format("%d", i));
|
||||
wxDataViewChoiceRenderer *c =
|
||||
new wxDataViewChoiceRenderer(choices, wxDATAVIEW_CELL_EDITABLE, wxALIGN_CENTER_HORIZONTAL);
|
||||
wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, 1,
|
||||
wxDataViewColumn* column = new wxDataViewColumn(_(L("Extruder")), c, colExtruder,
|
||||
8*wxGetApp().em_unit()/*80*/, wxALIGN_CENTER_HORIZONTAL, wxDATAVIEW_COL_RESIZABLE);
|
||||
return column;
|
||||
}
|
||||
|
@ -397,7 +412,7 @@ void ObjectList::update_extruder_values_for_items(const int max_extruder)
|
|||
else
|
||||
extruder = wxString::Format("%d", object->config.option<ConfigOptionInt>("extruder")->value);
|
||||
|
||||
m_objects_model->SetValue(extruder, item, 1);
|
||||
m_objects_model->SetValue(extruder, item, colExtruder);
|
||||
|
||||
if (object->volumes.size() > 1) {
|
||||
for (auto id = 0; id < object->volumes.size(); id++) {
|
||||
|
@ -409,7 +424,7 @@ void ObjectList::update_extruder_values_for_items(const int max_extruder)
|
|||
else
|
||||
extruder = wxString::Format("%d", object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value);
|
||||
|
||||
m_objects_model->SetValue(extruder, item, 1);
|
||||
m_objects_model->SetValue(extruder, item, colExtruder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -421,7 +436,7 @@ void ObjectList::update_objects_list_extruder_column(int extruders_count)
|
|||
if (printer_technology() == ptSLA)
|
||||
extruders_count = 1;
|
||||
|
||||
wxDataViewChoiceRenderer* ch_render = dynamic_cast<wxDataViewChoiceRenderer*>(GetColumn(1)->GetRenderer());
|
||||
wxDataViewChoiceRenderer* ch_render = dynamic_cast<wxDataViewChoiceRenderer*>(GetColumn(colExtruder)->GetRenderer());
|
||||
if (ch_render->GetChoices().GetCount() - 1 == extruders_count)
|
||||
return;
|
||||
|
||||
|
@ -430,21 +445,21 @@ void ObjectList::update_objects_list_extruder_column(int extruders_count)
|
|||
if (m_objects && extruders_count > 1)
|
||||
update_extruder_values_for_items(extruders_count);
|
||||
|
||||
// delete old 2nd column
|
||||
DeleteColumn(GetColumn(1));
|
||||
// insert new created 3rd column
|
||||
InsertColumn(1, create_objects_list_extruder_column(extruders_count));
|
||||
// delete old extruder column
|
||||
DeleteColumn(GetColumn(colExtruder));
|
||||
// insert new created extruder column
|
||||
InsertColumn(colExtruder, create_objects_list_extruder_column(extruders_count));
|
||||
// set show/hide for this column
|
||||
set_extruder_column_hidden(extruders_count <= 1);
|
||||
//a workaround for a wrong last column width updating under OSX
|
||||
GetColumn(2)->SetWidth(25);
|
||||
GetColumn(colEditing)->SetWidth(25);
|
||||
|
||||
m_prevent_update_extruder_in_config = false;
|
||||
}
|
||||
|
||||
void ObjectList::set_extruder_column_hidden(const bool hide) const
|
||||
{
|
||||
GetColumn(1)->SetHidden(hide);
|
||||
GetColumn(colExtruder)->SetHidden(hide);
|
||||
}
|
||||
|
||||
void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
|
||||
|
@ -471,7 +486,7 @@ void ObjectList::update_extruder_in_config(const wxDataViewItem& item)
|
|||
}
|
||||
|
||||
wxVariant variant;
|
||||
m_objects_model->GetValue(variant, item, 1);
|
||||
m_objects_model->GetValue(variant, item, colExtruder);
|
||||
const wxString selection = variant.GetString();
|
||||
|
||||
if (!m_config || selection.empty())
|
||||
|
@ -734,21 +749,21 @@ void ObjectList::OnContextMenu(wxDataViewEvent&)
|
|||
wxDataViewColumn* col;
|
||||
const wxPoint pt = get_mouse_position_in_control();
|
||||
HitTest(pt, item, col);
|
||||
if (!item)
|
||||
#ifdef __WXOSX__ // temporary workaround for OSX
|
||||
// after Yosemite OS X version, HitTest return undefined item
|
||||
item = GetSelection();
|
||||
if (item)
|
||||
show_context_menu();
|
||||
else
|
||||
printf("undefined item\n");
|
||||
return;
|
||||
#else
|
||||
return;
|
||||
// after Yosemite OS X version, HitTest return undefined item
|
||||
if (!item) item = GetSelection();
|
||||
#endif // __WXOSX__
|
||||
|
||||
if (!item) {
|
||||
printf("undefined item\n");
|
||||
return;
|
||||
}
|
||||
|
||||
const wxString title = col->GetTitle();
|
||||
|
||||
if (title == " ")
|
||||
toggle_printable_state(item);
|
||||
else if (title == _("Editing"))
|
||||
show_context_menu();
|
||||
else if (title == _("Name"))
|
||||
{
|
||||
|
@ -1013,6 +1028,11 @@ const std::vector<std::string>& ObjectList::get_options_for_bundle(const wxStrin
|
|||
return empty;
|
||||
}
|
||||
|
||||
static bool improper_category(const std::string& category, const int extruders_cnt)
|
||||
{
|
||||
return category.empty() || (extruders_cnt == 1 && (category == "Extruders" || category == "Wipe options" ));
|
||||
}
|
||||
|
||||
void ObjectList::get_options_menu(settings_menu_hierarchy& settings_menu, const bool is_part)
|
||||
{
|
||||
auto options = get_options(is_part);
|
||||
|
@ -1024,8 +1044,8 @@ void ObjectList::get_options_menu(settings_menu_hierarchy& settings_menu, const
|
|||
{
|
||||
auto const opt = config.def()->get(option);
|
||||
auto category = opt->category;
|
||||
if (category.empty() ||
|
||||
(category == "Extruders" && extruders_cnt == 1)) continue;
|
||||
if (improper_category(category, extruders_cnt))
|
||||
continue;
|
||||
|
||||
const std::string& label = !opt->full_label.empty() ? opt->full_label : opt->label;
|
||||
std::pair<std::string, std::string> option_label(option, label);
|
||||
|
@ -1370,6 +1390,13 @@ wxMenuItem* ObjectList::append_menu_item_instance_to_object(wxMenu* menu, wxWind
|
|||
[this](wxCommandEvent&) { split_instances(); }, "", menu, [](){return wxGetApp().plater()->can_set_instance_to_object(); }, parent);
|
||||
}
|
||||
|
||||
wxMenuItem* ObjectList::append_menu_item_printable(wxMenu* menu, wxWindow* parent)
|
||||
{
|
||||
return append_menu_check_item(menu, wxID_ANY, _(L("Printable")), "", [this](wxCommandEvent&) {
|
||||
wxGetApp().plater()->canvas3D()->get_selection().toggle_instance_printable_state();
|
||||
}, menu);
|
||||
}
|
||||
|
||||
void ObjectList::append_menu_items_osx(wxMenu* menu)
|
||||
{
|
||||
append_menu_item(menu, wxID_ANY, _(L("Rename")), "",
|
||||
|
@ -1537,7 +1564,7 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu)
|
|||
const int extruders_cnt = extruders_count();
|
||||
|
||||
for (auto& it : bundle) {
|
||||
if (it.first.empty() || it.first == "Extruders" && extruders_cnt == 1)
|
||||
if (improper_category(it.first, extruders_cnt))
|
||||
continue;
|
||||
|
||||
append_menu_item(menu, wxID_ANY, _(it.first), "",
|
||||
|
@ -1550,7 +1577,7 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu)
|
|||
m_freq_settings_fff : m_freq_settings_sla;
|
||||
|
||||
for (auto& it : bundle_quick) {
|
||||
if (it.first.empty() || it.first == "Extruders" && extruders_cnt == 1)
|
||||
if (improper_category(it.first, extruders_cnt))
|
||||
continue;
|
||||
|
||||
append_menu_item(menu, wxID_ANY, wxString::Format(_(L("Quick Add Settings (%s)")), _(it.first)), "",
|
||||
|
@ -1589,6 +1616,9 @@ void ObjectList::load_subobject(ModelVolumeType type)
|
|||
|
||||
|
||||
changed_object(obj_idx);
|
||||
if (type == ModelVolumeType::MODEL_PART)
|
||||
// update printable state on canvas
|
||||
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t)obj_idx);
|
||||
|
||||
wxDataViewItem sel_item;
|
||||
for (const auto& volume : volumes_info )
|
||||
|
@ -1712,6 +1742,9 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
|
|||
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||
|
||||
changed_object(obj_idx);
|
||||
if (type == ModelVolumeType::MODEL_PART)
|
||||
// update printable state on canvas
|
||||
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t)obj_idx);
|
||||
|
||||
const auto object_item = m_objects_model->GetTopParent(GetSelection());
|
||||
select_item(m_objects_model->AddVolumeChild(object_item, name, type,
|
||||
|
@ -1755,7 +1788,19 @@ void ObjectList::del_subobject_item(wxDataViewItem& item)
|
|||
if (type & itVolume && (*m_objects)[obj_idx]->get_mesh_errors_count() == 0)
|
||||
m_objects_model->DeleteWarningIcon(m_objects_model->GetParent(item));
|
||||
|
||||
// If last two Instances of object is selected, show the message about impossible action
|
||||
bool show_msg = false;
|
||||
if (type & itInstance) {
|
||||
wxDataViewItemArray instances;
|
||||
m_objects_model->GetChildren(m_objects_model->GetParent(item), instances);
|
||||
if (instances.Count() == 2 && IsSelected(instances[0]) && IsSelected(instances[1]))
|
||||
show_msg = true;
|
||||
}
|
||||
|
||||
m_objects_model->Delete(item);
|
||||
|
||||
if (show_msg)
|
||||
Slic3r::GUI::show_error(nullptr, _(L("Last instance of an object cannot be deleted.")));
|
||||
}
|
||||
|
||||
void ObjectList::del_settings_from_config(const wxDataViewItem& parent_item)
|
||||
|
@ -1838,7 +1883,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
|
|||
if (vol->is_model_part())
|
||||
++solid_cnt;
|
||||
if (volume->is_model_part() && solid_cnt == 1) {
|
||||
Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last solid part from object.")));
|
||||
Slic3r::GUI::show_error(nullptr, _(L("From Object List You can't delete the last solid part from object.")));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1857,7 +1902,7 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
|
|||
}
|
||||
else if (type == itInstance) {
|
||||
if (object->instances.size() == 1) {
|
||||
Slic3r::GUI::show_error(nullptr, _(L("You can't delete the last intance from object.")));
|
||||
Slic3r::GUI::show_error(nullptr, _(L("Last instance of an object cannot be deleted.")));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2172,7 +2217,7 @@ SettingsBundle ObjectList::get_item_settings_bundle(const DynamicPrintConfig* co
|
|||
for (auto& opt_key : opt_keys)
|
||||
{
|
||||
auto category = config->def()->get(opt_key)->category;
|
||||
if (category.empty() || (category == "Extruders" && extruders_cnt == 1))
|
||||
if (improper_category(category, extruders_cnt))
|
||||
continue;
|
||||
|
||||
std::vector< std::string > new_category;
|
||||
|
@ -2243,7 +2288,17 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed)
|
|||
|
||||
// add instances to the object, if it has those
|
||||
if (model_object->instances.size()>1)
|
||||
increase_object_instances(obj_idx, model_object->instances.size());
|
||||
{
|
||||
std::vector<bool> print_idicator(model_object->instances.size());
|
||||
for (int i = 0; i < model_object->instances.size(); ++i)
|
||||
print_idicator[i] = model_object->instances[i]->is_printable();
|
||||
|
||||
const wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx);
|
||||
m_objects_model->AddInstanceChild(object_item, print_idicator);
|
||||
Expand(m_objects_model->GetInstanceRootItem(object_item));
|
||||
}
|
||||
else
|
||||
m_objects_model->SetPrintableState(model_object->instances[0]->is_printable() ? piPrintable : piUnprintable, obj_idx);
|
||||
|
||||
// add settings to the object, if it has those
|
||||
add_settings_item(item, &model_object->config);
|
||||
|
@ -2325,7 +2380,7 @@ void ObjectList::delete_from_model_and_list(const std::vector<ItemForDelete>& it
|
|||
(*m_objects)[item->obj_idx]->config.has("extruder"))
|
||||
{
|
||||
const wxString extruder = wxString::Format("%d", (*m_objects)[item->obj_idx]->config.option<ConfigOptionInt>("extruder")->value);
|
||||
m_objects_model->SetValue(extruder, m_objects_model->GetItemById(item->obj_idx), 1);
|
||||
m_objects_model->SetValue(extruder, m_objects_model->GetItemById(item->obj_idx), colExtruder);
|
||||
}
|
||||
wxGetApp().plater()->canvas3D()->ensure_on_bed(item->obj_idx);
|
||||
}
|
||||
|
@ -2404,6 +2459,8 @@ void ObjectList::remove()
|
|||
|
||||
for (auto& item : sels)
|
||||
{
|
||||
if (m_objects_model->InvalidItem(item)) // item can be deleted for this moment (like last 2 Instances or Volumes)
|
||||
continue;
|
||||
if (m_objects_model->GetParent(item) == wxDataViewItem(0))
|
||||
delete_from_model_and_list(itObject, m_objects_model->GetIdByItem(item), -1);
|
||||
else {
|
||||
|
@ -2442,13 +2499,13 @@ void ObjectList::del_layer_range(const t_layer_height_range& range)
|
|||
select_item(selectable_item);
|
||||
}
|
||||
|
||||
double get_min_layer_height(const int extruder_idx)
|
||||
static 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)
|
||||
static 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);
|
||||
|
@ -2585,6 +2642,9 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay
|
|||
ranges[new_range] = config;
|
||||
|
||||
wxDataViewItem root_item = m_objects_model->GetLayerRootItem(m_objects_model->GetItemById(obj_idx));
|
||||
// To avoid update selection after deleting of a selected item (under GTK)
|
||||
// set m_prevent_list_events to true
|
||||
m_prevent_list_events = true;
|
||||
m_objects_model->DeleteChildren(root_item);
|
||||
|
||||
if (root_item.IsOk())
|
||||
|
@ -2835,6 +2895,9 @@ void ObjectList::update_selections_on_canvas()
|
|||
wxDataViewItemArray sels;
|
||||
GetSelections(sels);
|
||||
|
||||
// clear selection before adding new elements
|
||||
selection.clear(); //OR remove_all()?
|
||||
|
||||
for (auto item : sels)
|
||||
{
|
||||
add_to_selection(item, selection, instance_idx, mode);
|
||||
|
@ -3150,33 +3213,6 @@ void ObjectList::last_volume_is_deleted(const int obj_idx)
|
|||
volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||
}
|
||||
|
||||
/* #lm_FIXME_delete_after_testing
|
||||
void ObjectList::update_settings_items()
|
||||
{
|
||||
m_prevent_canvas_selection_update = true;
|
||||
wxDataViewItemArray sel;
|
||||
GetSelections(sel); // stash selection
|
||||
|
||||
wxDataViewItemArray items;
|
||||
m_objects_model->GetChildren(wxDataViewItem(0), items);
|
||||
|
||||
for (auto& item : items) {
|
||||
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) &&
|
||||
sel.Index(settings_item) != wxNOT_FOUND) {
|
||||
sel.Remove(settings_item);
|
||||
}
|
||||
}
|
||||
|
||||
// restore selection:
|
||||
SetSelections(sel);
|
||||
m_prevent_canvas_selection_update = false;
|
||||
}
|
||||
*/
|
||||
void ObjectList::update_and_show_object_settings_item()
|
||||
{
|
||||
const wxDataViewItem item = GetSelection();
|
||||
|
@ -3311,7 +3347,8 @@ void ObjectList::instances_to_separated_object(const int obj_idx, const std::set
|
|||
}
|
||||
|
||||
// Add new object to the object_list
|
||||
add_object_to_list(m_objects->size() - 1);
|
||||
const size_t new_obj_indx = static_cast<size_t>(m_objects->size() - 1);
|
||||
add_object_to_list(new_obj_indx);
|
||||
|
||||
for (std::set<int>::const_reverse_iterator it = inst_idxs.rbegin(); it != inst_idxs.rend(); ++it)
|
||||
{
|
||||
|
@ -3319,12 +3356,17 @@ void ObjectList::instances_to_separated_object(const int obj_idx, const std::set
|
|||
del_subobject_from_object(obj_idx, *it, itInstance);
|
||||
delete_instance_from_list(obj_idx, *it);
|
||||
}
|
||||
|
||||
// update printable state for new volumes on canvas3D
|
||||
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object(new_obj_indx);
|
||||
}
|
||||
|
||||
void ObjectList::instances_to_separated_objects(const int obj_idx)
|
||||
{
|
||||
const int inst_cnt = (*m_objects)[obj_idx]->instances.size();
|
||||
|
||||
std::vector<size_t> object_idxs;
|
||||
|
||||
for (int i = inst_cnt-1; i > 0 ; i--)
|
||||
{
|
||||
// create new object from initial
|
||||
|
@ -3338,12 +3380,17 @@ void ObjectList::instances_to_separated_objects(const int obj_idx)
|
|||
}
|
||||
|
||||
// Add new object to the object_list
|
||||
add_object_to_list(m_objects->size() - 1);
|
||||
const size_t new_obj_indx = static_cast<size_t>(m_objects->size() - 1);
|
||||
add_object_to_list(new_obj_indx);
|
||||
object_idxs.push_back(new_obj_indx);
|
||||
|
||||
// delete current instance from the initial object
|
||||
del_subobject_from_object(obj_idx, i, itInstance);
|
||||
delete_instance_from_list(obj_idx, i);
|
||||
}
|
||||
|
||||
// update printable state for new volumes on canvas3D
|
||||
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(object_idxs);
|
||||
}
|
||||
|
||||
void ObjectList::split_instances()
|
||||
|
@ -3398,7 +3445,7 @@ void ObjectList::rename_item()
|
|||
|
||||
// The icon can't be edited so get its old value and reuse it.
|
||||
wxVariant valueOld;
|
||||
m_objects_model->GetValue(valueOld, item, 0);
|
||||
m_objects_model->GetValue(valueOld, item, colName);
|
||||
|
||||
DataViewBitmapText bmpText;
|
||||
bmpText << valueOld;
|
||||
|
@ -3408,7 +3455,7 @@ void ObjectList::rename_item()
|
|||
|
||||
wxVariant value;
|
||||
value << bmpText;
|
||||
m_objects_model->SetValue(value, item, 0);
|
||||
m_objects_model->SetValue(value, item, colName);
|
||||
m_objects_model->ItemChanged(item);
|
||||
|
||||
update_name_in_model(item);
|
||||
|
@ -3449,9 +3496,10 @@ void ObjectList::msw_rescale()
|
|||
// update min size !!! A width of control shouldn't be a wxDefaultCoord
|
||||
SetMinSize(wxSize(1, 15 * em));
|
||||
|
||||
GetColumn(0)->SetWidth(19 * em);
|
||||
GetColumn(1)->SetWidth( 8 * em);
|
||||
GetColumn(2)->SetWidth( 2 * em);
|
||||
GetColumn(colName)->SetWidth(19 * em);
|
||||
GetColumn(colPrint)->SetWidth( 2 * em);
|
||||
GetColumn(colExtruder)->SetWidth( 8 * em);
|
||||
GetColumn(colEditing)->SetWidth( 2 * em);
|
||||
|
||||
// rescale all icons, used by ObjectList
|
||||
msw_rescale_icons();
|
||||
|
@ -3472,18 +3520,18 @@ void ObjectList::msw_rescale()
|
|||
|
||||
void ObjectList::ItemValueChanged(wxDataViewEvent &event)
|
||||
{
|
||||
if (event.GetColumn() == 0)
|
||||
if (event.GetColumn() == colName)
|
||||
update_name_in_model(event.GetItem());
|
||||
else if (event.GetColumn() == 1)
|
||||
else if (event.GetColumn() == colExtruder)
|
||||
update_extruder_in_config(event.GetItem());
|
||||
}
|
||||
|
||||
void ObjectList::OnEditingDone(wxDataViewEvent &event)
|
||||
{
|
||||
if (event.GetColumn() != 0)
|
||||
if (event.GetColumn() != colName)
|
||||
return;
|
||||
|
||||
const auto renderer = dynamic_cast<BitmapTextRenderer*>(GetColumn(0)->GetRenderer());
|
||||
const auto renderer = dynamic_cast<BitmapTextRenderer*>(GetColumn(colName)->GetRenderer());
|
||||
|
||||
if (renderer->WasCanceled())
|
||||
wxTheApp->CallAfter([this]{
|
||||
|
@ -3565,7 +3613,7 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const
|
|||
/* We can change extruder for Object/Volume only.
|
||||
* So, if Instance is selected, get its Object item and change it
|
||||
*/
|
||||
m_objects_model->SetValue(extruder_str, type & itInstance ? m_objects_model->GetTopParent(item) : item, 1);
|
||||
m_objects_model->SetValue(extruder_str, type & itInstance ? m_objects_model->GetTopParent(item) : item, colExtruder);
|
||||
|
||||
const int obj_idx = type & itObject ? m_objects_model->GetIdByItem(item) :
|
||||
m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
|
||||
|
@ -3588,18 +3636,69 @@ void ObjectList::update_after_undo_redo()
|
|||
m_objects_model->DeleteAll();
|
||||
|
||||
size_t obj_idx = 0;
|
||||
std::vector<size_t> obj_idxs;
|
||||
obj_idxs.reserve(m_objects->size());
|
||||
while (obj_idx < m_objects->size()) {
|
||||
add_object_to_list(obj_idx, false);
|
||||
obj_idxs.push_back(obj_idx);
|
||||
++obj_idx;
|
||||
}
|
||||
|
||||
#ifndef __WXOSX__
|
||||
// selection_changed();
|
||||
#endif /* __WXOSX__ */
|
||||
|
||||
update_selections();
|
||||
|
||||
m_prevent_canvas_selection_update = false;
|
||||
|
||||
// update printable states on canvas
|
||||
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_objects(obj_idxs);
|
||||
// update scene
|
||||
wxGetApp().plater()->update();
|
||||
}
|
||||
|
||||
void ObjectList::update_printable_state(int obj_idx, int instance_idx)
|
||||
{
|
||||
ModelObject* object = (*m_objects)[obj_idx];
|
||||
|
||||
const PrintIndicator printable = object->instances[instance_idx]->printable ? piPrintable : piUnprintable;
|
||||
if (object->instances.size() == 1)
|
||||
instance_idx = -1;
|
||||
|
||||
m_objects_model->SetPrintableState(printable, obj_idx, instance_idx);
|
||||
}
|
||||
|
||||
void ObjectList::toggle_printable_state(wxDataViewItem item)
|
||||
{
|
||||
const ItemType type = m_objects_model->GetItemType(item);
|
||||
if (!(type&(itObject|itInstance/*|itVolume*/)))
|
||||
return;
|
||||
|
||||
if (type & itObject)
|
||||
{
|
||||
const int obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||
ModelObject* object = (*m_objects)[obj_idx];
|
||||
|
||||
// get object's printable and change it
|
||||
const bool printable = !m_objects_model->IsPrintable(item);
|
||||
|
||||
const wxString snapshot_text = wxString::Format("%s %s",
|
||||
printable ? _(L("Set Printable")) : _(L("Set Unprintable")),
|
||||
object->name);
|
||||
take_snapshot(snapshot_text);
|
||||
|
||||
// set printable value for all instances in object
|
||||
for (auto inst : object->instances)
|
||||
inst->printable = printable;
|
||||
|
||||
// update printable state on canvas
|
||||
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t)obj_idx);
|
||||
|
||||
// update printable state in ObjectList
|
||||
m_objects_model->SetObjectPrintableState(printable ? piPrintable : piUnprintable , item);
|
||||
}
|
||||
else
|
||||
wxGetApp().plater()->canvas3D()->get_selection().toggle_instance_printable_state();
|
||||
|
||||
// update scene
|
||||
wxGetApp().plater()->update();
|
||||
}
|
||||
|
||||
ModelObject* ObjectList::object(const int obj_idx) const
|
||||
|
@ -3611,4 +3710,4 @@ ModelObject* ObjectList::object(const int obj_idx) const
|
|||
}
|
||||
|
||||
} //namespace GUI
|
||||
} //namespace Slic3r
|
||||
} //namespace Slic3r
|
||||
|
|
|
@ -225,6 +225,7 @@ public:
|
|||
wxMenuItem* append_menu_item_settings(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_printable(wxMenu* menu, wxWindow* parent);
|
||||
void append_menu_items_osx(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_fix_through_netfabb(wxMenu* menu);
|
||||
void append_menu_item_export_stl(wxMenu* menu) const ;
|
||||
|
@ -348,6 +349,9 @@ public:
|
|||
void msw_rescale();
|
||||
|
||||
void update_after_undo_redo();
|
||||
//update printable state for item from objects model
|
||||
void update_printable_state(int obj_idx, int instance_idx);
|
||||
void toggle_printable_state(wxDataViewItem item);
|
||||
|
||||
private:
|
||||
#ifdef __WXOSX__
|
||||
|
|
|
@ -176,6 +176,7 @@ Preview::Preview(
|
|||
, m_checkbox_retractions(nullptr)
|
||||
, m_checkbox_unretractions(nullptr)
|
||||
, m_checkbox_shells(nullptr)
|
||||
, m_checkbox_legend(nullptr)
|
||||
, m_config(config)
|
||||
, m_process(process)
|
||||
, m_gcode_preview_data(gcode_preview_data)
|
||||
|
@ -252,6 +253,9 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
|
|||
m_checkbox_unretractions = new wxCheckBox(this, wxID_ANY, _(L("Unretractions")));
|
||||
m_checkbox_shells = new wxCheckBox(this, wxID_ANY, _(L("Shells")));
|
||||
|
||||
m_checkbox_legend = new wxCheckBox(this, wxID_ANY, _(L("Legend")));
|
||||
m_checkbox_legend->SetValue(true);
|
||||
|
||||
wxBoxSizer* top_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
top_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0);
|
||||
top_sizer->Add(m_double_slider_sizer, 0, wxEXPAND, 0);
|
||||
|
@ -270,6 +274,8 @@ bool Preview::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view
|
|||
bottom_sizer->Add(m_checkbox_unretractions, 0, wxEXPAND | wxALL, 5);
|
||||
bottom_sizer->AddSpacer(10);
|
||||
bottom_sizer->Add(m_checkbox_shells, 0, wxEXPAND | wxALL, 5);
|
||||
bottom_sizer->AddSpacer(20);
|
||||
bottom_sizer->Add(m_checkbox_legend, 0, wxEXPAND | wxALL, 5);
|
||||
|
||||
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(top_sizer, 1, wxALL | wxEXPAND, 0);
|
||||
|
@ -442,6 +448,7 @@ void Preview::bind_event_handlers()
|
|||
m_checkbox_retractions->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_retractions, this);
|
||||
m_checkbox_unretractions->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_unretractions, this);
|
||||
m_checkbox_shells->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_shells, this);
|
||||
m_checkbox_legend->Bind(wxEVT_CHECKBOX, &Preview::on_checkbox_legend, this);
|
||||
}
|
||||
|
||||
void Preview::unbind_event_handlers()
|
||||
|
@ -453,6 +460,7 @@ void Preview::unbind_event_handlers()
|
|||
m_checkbox_retractions->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_retractions, this);
|
||||
m_checkbox_unretractions->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_unretractions, this);
|
||||
m_checkbox_shells->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_shells, this);
|
||||
m_checkbox_legend->Unbind(wxEVT_CHECKBOX, &Preview::on_checkbox_legend, this);
|
||||
}
|
||||
|
||||
void Preview::show_hide_ui_elements(const std::string& what)
|
||||
|
@ -464,6 +472,7 @@ void Preview::show_hide_ui_elements(const std::string& what)
|
|||
m_checkbox_retractions->Enable(enable);
|
||||
m_checkbox_unretractions->Enable(enable);
|
||||
m_checkbox_shells->Enable(enable);
|
||||
m_checkbox_legend->Enable(enable);
|
||||
|
||||
enable = (what != "none");
|
||||
m_label_view_type->Enable(enable);
|
||||
|
@ -476,6 +485,7 @@ void Preview::show_hide_ui_elements(const std::string& what)
|
|||
m_checkbox_retractions->Show(visible);
|
||||
m_checkbox_unretractions->Show(visible);
|
||||
m_checkbox_shells->Show(visible);
|
||||
m_checkbox_legend->Show(visible);
|
||||
m_label_view_type->Show(visible);
|
||||
m_choice_view_type->Show(visible);
|
||||
}
|
||||
|
@ -542,6 +552,12 @@ void Preview::on_checkbox_shells(wxCommandEvent& evt)
|
|||
refresh_print();
|
||||
}
|
||||
|
||||
void Preview::on_checkbox_legend(wxCommandEvent& evt)
|
||||
{
|
||||
m_canvas->enable_legend_texture(m_checkbox_legend->IsChecked());
|
||||
m_canvas_widget->Refresh();
|
||||
}
|
||||
|
||||
void Preview::update_view_type()
|
||||
{
|
||||
const DynamicPrintConfig& config = wxGetApp().preset_bundle->project_config;
|
||||
|
@ -702,6 +718,11 @@ void Preview::update_double_slider_from_canvas(wxKeyEvent& event)
|
|||
m_slider->SetHigherValue(new_pos);
|
||||
if (event.ShiftDown() || m_slider->is_one_layer()) m_slider->SetLowerValue(m_slider->GetHigherValue());
|
||||
}
|
||||
else if (key == 'L') {
|
||||
m_checkbox_legend->SetValue(!m_checkbox_legend->GetValue());
|
||||
auto evt = wxCommandEvent();
|
||||
on_checkbox_legend(evt);
|
||||
}
|
||||
else if (key == 'S')
|
||||
m_slider->ChangeOneLayerLock();
|
||||
else
|
||||
|
|
|
@ -80,6 +80,7 @@ class Preview : public wxPanel
|
|||
wxCheckBox* m_checkbox_retractions;
|
||||
wxCheckBox* m_checkbox_unretractions;
|
||||
wxCheckBox* m_checkbox_shells;
|
||||
wxCheckBox* m_checkbox_legend;
|
||||
|
||||
DynamicPrintConfig* m_config;
|
||||
BackgroundSlicingProcess* m_process;
|
||||
|
@ -147,6 +148,7 @@ private:
|
|||
void on_checkbox_retractions(wxCommandEvent& evt);
|
||||
void on_checkbox_unretractions(wxCommandEvent& evt);
|
||||
void on_checkbox_shells(wxCommandEvent& evt);
|
||||
void on_checkbox_legend(wxCommandEvent& evt);
|
||||
|
||||
// Create/Update/Reset double slider on 3dPreview
|
||||
void create_double_slider();
|
||||
|
|
|
@ -29,19 +29,21 @@ GLGizmoBase::Grabber::Grabber()
|
|||
color[0] = 1.0f;
|
||||
color[1] = 1.0f;
|
||||
color[2] = 1.0f;
|
||||
color[3] = 1.0f;
|
||||
}
|
||||
|
||||
void GLGizmoBase::Grabber::render(bool hover, float size) const
|
||||
{
|
||||
float render_color[3];
|
||||
float render_color[4];
|
||||
if (hover)
|
||||
{
|
||||
render_color[0] = 1.0f - color[0];
|
||||
render_color[1] = 1.0f - color[1];
|
||||
render_color[2] = 1.0f - color[2];
|
||||
render_color[3] = color[3];
|
||||
}
|
||||
else
|
||||
::memcpy((void*)render_color, (const void*)color, 3 * sizeof(float));
|
||||
::memcpy((void*)render_color, (const void*)color, 4 * sizeof(float));
|
||||
|
||||
render(size, render_color, true);
|
||||
}
|
||||
|
@ -63,7 +65,7 @@ void GLGizmoBase::Grabber::render(float size, const float* render_color, bool us
|
|||
if (use_lighting)
|
||||
glsafe(::glEnable(GL_LIGHTING));
|
||||
|
||||
glsafe(::glColor3fv(render_color));
|
||||
glsafe(::glColor4fv(render_color));
|
||||
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
|
@ -144,9 +146,9 @@ GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, u
|
|||
, m_dragging(false)
|
||||
, m_imgui(wxGetApp().imgui())
|
||||
{
|
||||
::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 3 * sizeof(float));
|
||||
::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 3 * sizeof(float));
|
||||
::memcpy((void*)m_highlight_color, (const void*)DEFAULT_HIGHLIGHT_COLOR, 3 * sizeof(float));
|
||||
::memcpy((void*)m_base_color, (const void*)DEFAULT_BASE_COLOR, 4 * sizeof(float));
|
||||
::memcpy((void*)m_drag_color, (const void*)DEFAULT_DRAG_COLOR, 4 * sizeof(float));
|
||||
::memcpy((void*)m_highlight_color, (const void*)DEFAULT_HIGHLIGHT_COLOR, 4 * sizeof(float));
|
||||
}
|
||||
|
||||
void GLGizmoBase::set_hover_id(int id)
|
||||
|
@ -161,7 +163,7 @@ void GLGizmoBase::set_hover_id(int id)
|
|||
void GLGizmoBase::set_highlight_color(const float* color)
|
||||
{
|
||||
if (color != nullptr)
|
||||
::memcpy((void*)m_highlight_color, (const void*)color, 3 * sizeof(float));
|
||||
::memcpy((void*)m_highlight_color, (const void*)color, 4 * sizeof(float));
|
||||
}
|
||||
|
||||
void GLGizmoBase::enable_grabber(unsigned int id)
|
||||
|
@ -210,7 +212,7 @@ void GLGizmoBase::update(const UpdateData& data)
|
|||
on_update(data);
|
||||
}
|
||||
|
||||
std::array<float, 3> GLGizmoBase::picking_color_component(unsigned int id) const
|
||||
std::array<float, 4> GLGizmoBase::picking_color_component(unsigned int id) const
|
||||
{
|
||||
static const float INV_255 = 1.0f / 255.0f;
|
||||
|
||||
|
@ -220,9 +222,12 @@ std::array<float, 3> GLGizmoBase::picking_color_component(unsigned int id) const
|
|||
id -= m_group_id;
|
||||
|
||||
// color components are encoded to match the calculation of volume_id made into GLCanvas3D::_picking_pass()
|
||||
return std::array<float, 3> { (float)((id >> 0) & 0xff) * INV_255, // red
|
||||
(float)((id >> 8) & 0xff) * INV_255, // green
|
||||
(float)((id >> 16) & 0xff) * INV_255 }; // blue
|
||||
return std::array<float, 4> {
|
||||
float((id >> 0) & 0xff) * INV_255, // red
|
||||
float((id >> 8) & 0xff) * INV_255, // green
|
||||
float((id >> 16) & 0xff) * INV_255, // blue
|
||||
float(picking_checksum_alpha_channel(id & 0xff, (id >> 8) & 0xff, (id >> 16) & 0xff))* INV_255 // checksum for validating against unwanted alpha blending and multi sampling
|
||||
};
|
||||
}
|
||||
|
||||
void GLGizmoBase::render_grabbers(const BoundingBoxf3& box) const
|
||||
|
@ -247,10 +252,11 @@ void GLGizmoBase::render_grabbers_for_picking(const BoundingBoxf3& box) const
|
|||
{
|
||||
if (m_grabbers[i].enabled)
|
||||
{
|
||||
std::array<float, 3> color = picking_color_component(i);
|
||||
std::array<float, 4> color = picking_color_component(i);
|
||||
m_grabbers[i].color[0] = color[0];
|
||||
m_grabbers[i].color[1] = color[1];
|
||||
m_grabbers[i].color[2] = color[2];
|
||||
m_grabbers[i].color[3] = color[3];
|
||||
m_grabbers[i].render_for_picking(mean_size);
|
||||
}
|
||||
}
|
||||
|
@ -267,5 +273,20 @@ std::string GLGizmoBase::format(float value, unsigned int decimals) const
|
|||
return Slic3r::string_printf("%.*f", decimals, value);
|
||||
}
|
||||
|
||||
// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components
|
||||
// were not interpolated by alpha blending or multi sampling.
|
||||
unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue)
|
||||
{
|
||||
// 8 bit hash for the color
|
||||
unsigned char b = ((((37 * red) + green) & 0x0ff) * 37 + blue) & 0x0ff;
|
||||
// Increase enthropy by a bit reversal
|
||||
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
||||
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
||||
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
||||
// Flip every second bit to increase the enthropy even more.
|
||||
b ^= 0x55;
|
||||
return b;
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -21,11 +21,11 @@ class ModelObject;
|
|||
|
||||
namespace GUI {
|
||||
|
||||
static const float DEFAULT_BASE_COLOR[3] = { 0.625f, 0.625f, 0.625f };
|
||||
static const float DEFAULT_DRAG_COLOR[3] = { 1.0f, 1.0f, 1.0f };
|
||||
static const float DEFAULT_HIGHLIGHT_COLOR[3] = { 1.0f, 0.38f, 0.0f };
|
||||
static const float AXES_COLOR[3][3] = { { 0.75f, 0.0f, 0.0f }, { 0.0f, 0.75f, 0.0f }, { 0.0f, 0.0f, 0.75f } };
|
||||
static const float CONSTRAINED_COLOR[3] = { 0.5f, 0.5f, 0.5f };
|
||||
static const float DEFAULT_BASE_COLOR[4] = { 0.625f, 0.625f, 0.625f, 1.0f };
|
||||
static const float DEFAULT_DRAG_COLOR[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
static const float DEFAULT_HIGHLIGHT_COLOR[4] = { 1.0f, 0.38f, 0.0f, 1.0f };
|
||||
static const float AXES_COLOR[][4] = { { 0.75f, 0.0f, 0.0f, 1.0f }, { 0.0f, 0.75f, 0.0f, 1.0f }, { 0.0f, 0.0f, 0.75f, 1.0f } };
|
||||
static const float CONSTRAINED_COLOR[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
||||
|
||||
|
||||
|
||||
|
@ -48,7 +48,7 @@ protected:
|
|||
|
||||
Vec3d center;
|
||||
Vec3d angles;
|
||||
float color[3];
|
||||
float color[4];
|
||||
bool enabled;
|
||||
bool dragging;
|
||||
|
||||
|
@ -94,9 +94,9 @@ protected:
|
|||
unsigned int m_sprite_id;
|
||||
int m_hover_id;
|
||||
bool m_dragging;
|
||||
float m_base_color[3];
|
||||
float m_drag_color[3];
|
||||
float m_highlight_color[3];
|
||||
float m_base_color[4];
|
||||
float m_drag_color[4];
|
||||
float m_highlight_color[4];
|
||||
mutable std::vector<Grabber> m_grabbers;
|
||||
ImGuiWrapper* m_imgui;
|
||||
|
||||
|
@ -166,7 +166,7 @@ protected:
|
|||
|
||||
// Returns the picking color for the given id, based on the BASE_ID constant
|
||||
// No check is made for clashing with other picking color (i.e. GLVolumes)
|
||||
std::array<float, 3> picking_color_component(unsigned int id) const;
|
||||
std::array<float, 4> picking_color_component(unsigned int id) const;
|
||||
void render_grabbers(const BoundingBoxf3& box) const;
|
||||
void render_grabbers(float size) const;
|
||||
void render_grabbers_for_picking(const BoundingBoxf3& box) const;
|
||||
|
@ -175,6 +175,10 @@ protected:
|
|||
std::string format(float value, unsigned int decimals) const;
|
||||
};
|
||||
|
||||
// Produce an alpha channel checksum for the red green blue components. The alpha channel may then be used to verify, whether the rgb components
|
||||
// were not interpolated by alpha blending or multi sampling.
|
||||
extern unsigned char picking_checksum_alpha_channel(unsigned char red, unsigned char green, unsigned char blue);
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace GUI {
|
|||
|
||||
const double GLGizmoCut::Offset = 10.0;
|
||||
const double GLGizmoCut::Margin = 20.0;
|
||||
const std::array<float, 3> GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0 };
|
||||
const std::array<float, 4> GLGizmoCut::GrabberColor = { 1.0, 0.5, 0.0, 1.0 };
|
||||
|
||||
GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
|
|
|
@ -11,7 +11,7 @@ class GLGizmoCut : public GLGizmoBase
|
|||
{
|
||||
static const double Offset;
|
||||
static const double Margin;
|
||||
static const std::array<float, 3> GrabberColor;
|
||||
static const std::array<float, 4> GrabberColor;
|
||||
|
||||
mutable double m_cut_z;
|
||||
double m_start_z;
|
||||
|
|
|
@ -115,7 +115,7 @@ void GLGizmoFlatten::on_render_for_picking() const
|
|||
const_cast<GLGizmoFlatten*>(this)->update_planes();
|
||||
for (int i = 0; i < (int)m_planes.size(); ++i)
|
||||
{
|
||||
glsafe(::glColor3fv(picking_color_component(i).data()));
|
||||
glsafe(::glColor4fv(picking_color_component(i).data()));
|
||||
::glBegin(GL_POLYGON);
|
||||
for (const Vec3d& vertex : m_planes[i].vertices)
|
||||
{
|
||||
|
|
|
@ -104,15 +104,15 @@ void GLGizmoMove3D::on_render() const
|
|||
|
||||
// x axis
|
||||
m_grabbers[0].center = Vec3d(box.max(0) + Offset, center(1), center(2));
|
||||
::memcpy((void*)m_grabbers[0].color, (const void*)&AXES_COLOR[0], 3 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[0].color, (const void*)&AXES_COLOR[0], 4 * sizeof(float));
|
||||
|
||||
// y axis
|
||||
m_grabbers[1].center = Vec3d(center(0), box.max(1) + Offset, center(2));
|
||||
::memcpy((void*)m_grabbers[1].color, (const void*)&AXES_COLOR[1], 3 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[1].color, (const void*)&AXES_COLOR[1], 4 * sizeof(float));
|
||||
|
||||
// z axis
|
||||
m_grabbers[2].center = Vec3d(center(0), center(1), box.max(2) + Offset);
|
||||
::memcpy((void*)m_grabbers[2].color, (const void*)&AXES_COLOR[2], 3 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[2].color, (const void*)&AXES_COLOR[2], 4 * sizeof(float));
|
||||
|
||||
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
|
||||
|
||||
|
@ -123,7 +123,7 @@ void GLGizmoMove3D::on_render() const
|
|||
{
|
||||
if (m_grabbers[i].enabled)
|
||||
{
|
||||
glsafe(::glColor3fv(AXES_COLOR[i]));
|
||||
glsafe(::glColor4fv(AXES_COLOR[i]));
|
||||
::glBegin(GL_LINES);
|
||||
::glVertex3dv(center.data());
|
||||
::glVertex3dv(m_grabbers[i].center.data());
|
||||
|
@ -142,7 +142,7 @@ void GLGizmoMove3D::on_render() const
|
|||
else
|
||||
{
|
||||
// draw axis
|
||||
glsafe(::glColor3fv(AXES_COLOR[m_hover_id]));
|
||||
glsafe(::glColor4fv(AXES_COLOR[m_hover_id]));
|
||||
::glBegin(GL_LINES);
|
||||
::glVertex3dv(center.data());
|
||||
::glVertex3dv(m_grabbers[m_hover_id].center.data());
|
||||
|
@ -220,19 +220,20 @@ void GLGizmoMove3D::render_grabber_extension(Axis axis, const BoundingBoxf3& box
|
|||
float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0);
|
||||
double size = m_dragging ? (double)m_grabbers[axis].get_dragging_half_size(mean_size) : (double)m_grabbers[axis].get_half_size(mean_size);
|
||||
|
||||
float color[3];
|
||||
::memcpy((void*)color, (const void*)m_grabbers[axis].color, 3 * sizeof(float));
|
||||
float color[4];
|
||||
::memcpy((void*)color, (const void*)m_grabbers[axis].color, 4 * sizeof(float));
|
||||
if (!picking && (m_hover_id != -1))
|
||||
{
|
||||
color[0] = 1.0f - color[0];
|
||||
color[1] = 1.0f - color[1];
|
||||
color[2] = 1.0f - color[2];
|
||||
color[3] = color[3];
|
||||
}
|
||||
|
||||
if (!picking)
|
||||
glsafe(::glEnable(GL_LIGHTING));
|
||||
|
||||
glsafe(::glColor3fv(color));
|
||||
glsafe(::glColor4fv(color));
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslated(m_grabbers[axis].center(0), m_grabbers[axis].center(1), m_grabbers[axis].center(2)));
|
||||
if (axis == X)
|
||||
|
|
|
@ -155,7 +155,7 @@ void GLGizmoRotate::on_render() const
|
|||
transform_to_local(selection);
|
||||
|
||||
glsafe(::glLineWidth((m_hover_id != -1) ? 2.0f : 1.5f));
|
||||
glsafe(::glColor3fv((m_hover_id != -1) ? m_drag_color : m_highlight_color));
|
||||
glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color : m_highlight_color));
|
||||
|
||||
render_circle();
|
||||
|
||||
|
@ -166,7 +166,7 @@ void GLGizmoRotate::on_render() const
|
|||
render_reference_radius();
|
||||
}
|
||||
|
||||
glsafe(::glColor3fv(m_highlight_color));
|
||||
glsafe(::glColor4fv(m_highlight_color));
|
||||
|
||||
if (m_hover_id != -1)
|
||||
render_angle();
|
||||
|
@ -287,14 +287,14 @@ void GLGizmoRotate::render_grabber(const BoundingBoxf3& box) const
|
|||
m_grabbers[0].center = Vec3d(::cos(m_angle) * grabber_radius, ::sin(m_angle) * grabber_radius, 0.0);
|
||||
m_grabbers[0].angles(2) = m_angle;
|
||||
|
||||
glsafe(::glColor3fv((m_hover_id != -1) ? m_drag_color : m_highlight_color));
|
||||
glsafe(::glColor4fv((m_hover_id != -1) ? m_drag_color : m_highlight_color));
|
||||
|
||||
::glBegin(GL_LINES);
|
||||
::glVertex3f(0.0f, 0.0f, 0.0f);
|
||||
::glVertex3dv(m_grabbers[0].center.data());
|
||||
glsafe(::glEnd());
|
||||
|
||||
::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 3 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[0].color, (const void*)m_highlight_color, 4 * sizeof(float));
|
||||
render_grabbers(box);
|
||||
}
|
||||
|
||||
|
@ -306,8 +306,8 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick
|
|||
float mean_size = (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0);
|
||||
double size = m_dragging ? (double)m_grabbers[0].get_dragging_half_size(mean_size) : (double)m_grabbers[0].get_half_size(mean_size);
|
||||
|
||||
float color[3];
|
||||
::memcpy((void*)color, (const void*)m_grabbers[0].color, 3 * sizeof(float));
|
||||
float color[4];
|
||||
::memcpy((void*)color, (const void*)m_grabbers[0].color, 4 * sizeof(float));
|
||||
if (!picking && (m_hover_id != -1))
|
||||
{
|
||||
color[0] = 1.0f - color[0];
|
||||
|
@ -318,7 +318,7 @@ void GLGizmoRotate::render_grabber_extension(const BoundingBoxf3& box, bool pick
|
|||
if (!picking)
|
||||
glsafe(::glEnable(GL_LIGHTING));
|
||||
|
||||
glsafe(::glColor3fv(color));
|
||||
glsafe(::glColor4fv(color));
|
||||
glsafe(::glPushMatrix());
|
||||
glsafe(::glTranslated(m_grabbers[0].center(0), m_grabbers[0].center(1), m_grabbers[0].center(2)));
|
||||
glsafe(::glRotated(Geometry::rad2deg(m_angle), 0.0, 0.0, 1.0));
|
||||
|
|
|
@ -172,20 +172,20 @@ void GLGizmoScale3D::on_render() const
|
|||
// x axis
|
||||
m_grabbers[0].center = m_transform * Vec3d(m_box.min(0), center(1), center(2)) - offset_x;
|
||||
m_grabbers[1].center = m_transform * Vec3d(m_box.max(0), center(1), center(2)) + offset_x;
|
||||
::memcpy((void*)m_grabbers[0].color, (ctrl_down && (m_hover_id == 1)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 3 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[1].color, (ctrl_down && (m_hover_id == 0)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 3 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[0].color, (ctrl_down && (m_hover_id == 1)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 4 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[1].color, (ctrl_down && (m_hover_id == 0)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[0], 4 * sizeof(float));
|
||||
|
||||
// y axis
|
||||
m_grabbers[2].center = m_transform * Vec3d(center(0), m_box.min(1), center(2)) - offset_y;
|
||||
m_grabbers[3].center = m_transform * Vec3d(center(0), m_box.max(1), center(2)) + offset_y;
|
||||
::memcpy((void*)m_grabbers[2].color, (ctrl_down && (m_hover_id == 3)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 3 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[3].color, (ctrl_down && (m_hover_id == 2)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 3 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[2].color, (ctrl_down && (m_hover_id == 3)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 4 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[3].color, (ctrl_down && (m_hover_id == 2)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[1], 4 * sizeof(float));
|
||||
|
||||
// z axis
|
||||
m_grabbers[4].center = m_transform * Vec3d(center(0), center(1), m_box.min(2)) - offset_z;
|
||||
m_grabbers[5].center = m_transform * Vec3d(center(0), center(1), m_box.max(2)) + offset_z;
|
||||
::memcpy((void*)m_grabbers[4].color, (ctrl_down && (m_hover_id == 5)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 3 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[5].color, (ctrl_down && (m_hover_id == 4)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 3 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[4].color, (ctrl_down && (m_hover_id == 5)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 4 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[5].color, (ctrl_down && (m_hover_id == 4)) ? (const void*)CONSTRAINED_COLOR : (const void*)&AXES_COLOR[2], 4 * sizeof(float));
|
||||
|
||||
// uniform
|
||||
m_grabbers[6].center = m_transform * Vec3d(m_box.min(0), m_box.min(1), center(2)) - offset_x - offset_y;
|
||||
|
@ -194,7 +194,7 @@ void GLGizmoScale3D::on_render() const
|
|||
m_grabbers[9].center = m_transform * Vec3d(m_box.min(0), m_box.max(1), center(2)) - offset_x + offset_y;
|
||||
for (int i = 6; i < 10; ++i)
|
||||
{
|
||||
::memcpy((void*)m_grabbers[i].color, (const void*)m_highlight_color, 3 * sizeof(float));
|
||||
::memcpy((void*)m_grabbers[i].color, (const void*)m_highlight_color, 4 * sizeof(float));
|
||||
}
|
||||
|
||||
// sets grabbers orientation
|
||||
|
@ -214,20 +214,20 @@ void GLGizmoScale3D::on_render() const
|
|||
// draw connections
|
||||
if (m_grabbers[0].enabled && m_grabbers[1].enabled)
|
||||
{
|
||||
glsafe(::glColor3fv(m_grabbers[0].color));
|
||||
glsafe(::glColor4fv(m_grabbers[0].color));
|
||||
render_grabbers_connection(0, 1);
|
||||
}
|
||||
if (m_grabbers[2].enabled && m_grabbers[3].enabled)
|
||||
{
|
||||
glsafe(::glColor3fv(m_grabbers[2].color));
|
||||
glsafe(::glColor4fv(m_grabbers[2].color));
|
||||
render_grabbers_connection(2, 3);
|
||||
}
|
||||
if (m_grabbers[4].enabled && m_grabbers[5].enabled)
|
||||
{
|
||||
glsafe(::glColor3fv(m_grabbers[4].color));
|
||||
glsafe(::glColor4fv(m_grabbers[4].color));
|
||||
render_grabbers_connection(4, 5);
|
||||
}
|
||||
glsafe(::glColor3fv(m_base_color));
|
||||
glsafe(::glColor4fv(m_base_color));
|
||||
render_grabbers_connection(6, 7);
|
||||
render_grabbers_connection(7, 8);
|
||||
render_grabbers_connection(8, 9);
|
||||
|
@ -238,7 +238,7 @@ void GLGizmoScale3D::on_render() const
|
|||
else if ((m_hover_id == 0) || (m_hover_id == 1))
|
||||
{
|
||||
// draw connection
|
||||
glsafe(::glColor3fv(m_grabbers[0].color));
|
||||
glsafe(::glColor4fv(m_grabbers[0].color));
|
||||
render_grabbers_connection(0, 1);
|
||||
// draw grabbers
|
||||
m_grabbers[0].render(true, grabber_mean_size);
|
||||
|
@ -247,7 +247,7 @@ void GLGizmoScale3D::on_render() const
|
|||
else if ((m_hover_id == 2) || (m_hover_id == 3))
|
||||
{
|
||||
// draw connection
|
||||
glsafe(::glColor3fv(m_grabbers[2].color));
|
||||
glsafe(::glColor4fv(m_grabbers[2].color));
|
||||
render_grabbers_connection(2, 3);
|
||||
// draw grabbers
|
||||
m_grabbers[2].render(true, grabber_mean_size);
|
||||
|
@ -256,7 +256,7 @@ void GLGizmoScale3D::on_render() const
|
|||
else if ((m_hover_id == 4) || (m_hover_id == 5))
|
||||
{
|
||||
// draw connection
|
||||
glsafe(::glColor3fv(m_grabbers[4].color));
|
||||
glsafe(::glColor4fv(m_grabbers[4].color));
|
||||
render_grabbers_connection(4, 5);
|
||||
// draw grabbers
|
||||
m_grabbers[4].render(true, grabber_mean_size);
|
||||
|
@ -265,7 +265,7 @@ void GLGizmoScale3D::on_render() const
|
|||
else if (m_hover_id >= 6)
|
||||
{
|
||||
// draw connection
|
||||
glsafe(::glColor3fv(m_drag_color));
|
||||
glsafe(::glColor4fv(m_drag_color));
|
||||
render_grabbers_connection(6, 7);
|
||||
render_grabbers_connection(7, 8);
|
||||
render_grabbers_connection(8, 9);
|
||||
|
|
|
@ -286,7 +286,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
|||
glsafe(::glTranslated(0.0, 0.0, m_z_shift));
|
||||
glsafe(::glMultMatrixd(instance_matrix.data()));
|
||||
|
||||
float render_color[3];
|
||||
float render_color[4];
|
||||
size_t cache_size = m_editing_mode ? m_editing_cache.size() : m_normal_cache.size();
|
||||
for (size_t i = 0; i < cache_size; ++i)
|
||||
{
|
||||
|
@ -298,12 +298,14 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
|||
|
||||
// First decide about the color of the point.
|
||||
if (picking) {
|
||||
std::array<float, 3> color = picking_color_component(i);
|
||||
std::array<float, 4> color = picking_color_component(i);
|
||||
render_color[0] = color[0];
|
||||
render_color[1] = color[1];
|
||||
render_color[2] = color[2];
|
||||
render_color[3] = color[3];
|
||||
}
|
||||
else {
|
||||
render_color[3] = 1.f;
|
||||
if ((m_hover_id == i && m_editing_mode)) { // ignore hover state unless editing mode is active
|
||||
render_color[0] = 0.f;
|
||||
render_color[1] = 1.0f;
|
||||
|
@ -320,7 +322,7 @@ void GLGizmoSlaSupports::render_points(const Selection& selection, bool picking)
|
|||
for (unsigned char i=0; i<3; ++i) render_color[i] = 0.5f;
|
||||
}
|
||||
}
|
||||
glsafe(::glColor3fv(render_color));
|
||||
glsafe(::glColor4fv(render_color));
|
||||
float render_color_emissive[4] = { 0.5f * render_color[0], 0.5f * render_color[1], 0.5f * render_color[2], 1.f};
|
||||
glsafe(::glMaterialfv(GL_FRONT, GL_EMISSION, render_color_emissive));
|
||||
|
||||
|
@ -422,9 +424,9 @@ void GLGizmoSlaSupports::update_mesh()
|
|||
|
||||
|
||||
|
||||
// Unprojects the mouse position on the mesh and return the hit point and normal of the facet.
|
||||
// The function throws if no intersection if found.
|
||||
std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos)
|
||||
// Unprojects the mouse position on the mesh and saves hit point and normal of the facet into pos_and_normal
|
||||
// Return false if no intersection was found, true otherwise.
|
||||
bool GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal)
|
||||
{
|
||||
// if the gizmo doesn't have the V, F structures for igl, calculate them first:
|
||||
if (m_its == nullptr)
|
||||
|
@ -457,7 +459,7 @@ std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse
|
|||
MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
|
||||
MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3),
|
||||
point1.cast<float>(), (point2-point1).cast<float>(), hits))
|
||||
throw std::invalid_argument("unproject_on_mesh(): No intersection found.");
|
||||
return false; // no intersection found
|
||||
|
||||
std::sort(hits.begin(), hits.end(), [](const igl::Hit& a, const igl::Hit& b) { return a.t < b.t; });
|
||||
|
||||
|
@ -481,14 +483,12 @@ std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse
|
|||
if (i==hits.size() || (hits.size()-i) % 2 != 0) {
|
||||
// All hits are either clipped, or there is an odd number of unclipped
|
||||
// hits - meaning the nearest must be from inside the mesh.
|
||||
throw std::invalid_argument("unproject_on_mesh(): No intersection found.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate and return both the point and the facet normal.
|
||||
return std::make_pair(
|
||||
result,
|
||||
a.cross(b)
|
||||
);
|
||||
pos_and_normal = std::make_pair(result, a.cross(b));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Following function is called from GLCanvas3D to inform the gizmo about a mouse/keyboard event.
|
||||
|
@ -526,16 +526,15 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous
|
|||
|
||||
// If there is some selection, don't add new point and deselect everything instead.
|
||||
if (m_selection_empty) {
|
||||
try {
|
||||
std::pair<Vec3f, Vec3f> pos_and_normal = unproject_on_mesh(mouse_position); // don't create anything if this throws
|
||||
std::pair<Vec3f, Vec3f> pos_and_normal;
|
||||
if (unproject_on_mesh(mouse_position, pos_and_normal)) { // we got an intersection
|
||||
wxGetApp().plater()->take_snapshot(_(L("Add support point")));
|
||||
m_editing_cache.emplace_back(sla::SupportPoint(pos_and_normal.first, m_new_point_head_diameter/2.f, false), false, pos_and_normal.second);
|
||||
m_parent.set_as_dirty();
|
||||
m_wait_for_up_event = true;
|
||||
}
|
||||
catch (...) { // not clicked on object
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
select_point(NoPoints);
|
||||
|
@ -739,10 +738,8 @@ void GLGizmoSlaSupports::on_update(const UpdateData& data)
|
|||
else {
|
||||
if (m_hover_id != -1 && (! m_editing_cache[m_hover_id].support_point.is_new_island || !m_lock_unique_islands)) {
|
||||
std::pair<Vec3f, Vec3f> pos_and_normal;
|
||||
try {
|
||||
pos_and_normal = unproject_on_mesh(data.mouse_pos.cast<double>());
|
||||
}
|
||||
catch (...) { return; }
|
||||
if (! unproject_on_mesh(data.mouse_pos.cast<double>(), pos_and_normal))
|
||||
return;
|
||||
m_editing_cache[m_hover_id].support_point.pos = pos_and_normal.first;
|
||||
m_editing_cache[m_hover_id].support_point.is_new_island = false;
|
||||
m_editing_cache[m_hover_id].normal = pos_and_normal.second;
|
||||
|
@ -1448,4 +1445,4 @@ SlaGizmoHelpDialog::SlaGizmoHelpDialog()
|
|||
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -32,7 +32,7 @@ private:
|
|||
int m_active_instance = -1;
|
||||
float m_active_instance_bb_radius; // to cache the bb
|
||||
mutable float m_z_shift = 0.f;
|
||||
std::pair<Vec3f, Vec3f> unproject_on_mesh(const Vec2d& mouse_pos);
|
||||
bool unproject_on_mesh(const Vec2d& mouse_pos, std::pair<Vec3f, Vec3f>& pos_and_normal);
|
||||
|
||||
const float RenderPointScale = 1.f;
|
||||
|
||||
|
|
|
@ -354,7 +354,7 @@ bool ImGuiWrapper::undo_redo_list(const ImVec2& size, const bool is_undo, bool (
|
|||
ImGui::Selectable(item_text, i < hovered);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(item_text);
|
||||
ImGui::SetTooltip("%s", item_text);
|
||||
hovered = i;
|
||||
is_hovered = true;
|
||||
}
|
||||
|
|
|
@ -6,23 +6,23 @@
|
|||
#include "GUI_App.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
KBShortcutsDialog::KBShortcutsDialog()
|
||||
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Keyboard Shortcuts")),
|
||||
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("Keyboard Shortcuts")),
|
||||
wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER)
|
||||
{
|
||||
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// logo
|
||||
m_logo_bmp = ScalableBitmap(this, "PrusaSlicer_32px.png", 32);
|
||||
|
||||
// fonts
|
||||
const wxFont& font = wxGetApp().normal_font();
|
||||
const wxFont& bold_font = wxGetApp().bold_font();
|
||||
const wxFont& bold_font = wxGetApp().bold_font();
|
||||
SetFont(font);
|
||||
|
||||
wxFont head_font = bold_font;
|
||||
|
@ -78,17 +78,17 @@ KBShortcutsDialog::KBShortcutsDialog()
|
|||
grid_sizer->Add(description, -1, wxALIGN_CENTRE_VERTICAL);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
wxStdDialogButtonSizer* buttons = this->CreateStdDialogButtonSizer(wxOK);
|
||||
|
||||
this->SetEscapeId(wxID_OK);
|
||||
this->Bind(wxEVT_BUTTON, &KBShortcutsDialog::onCloseDialog, this, wxID_OK);
|
||||
main_sizer->Add(buttons, 0, wxEXPAND | wxRIGHT | wxBOTTOM, 15);
|
||||
|
||||
|
||||
this->Bind(wxEVT_LEFT_DOWN, &KBShortcutsDialog::onCloseDialog, this);
|
||||
|
||||
SetSizer(main_sizer);
|
||||
main_sizer->SetSizeHints(this);
|
||||
SetSizer(main_sizer);
|
||||
main_sizer->SetSizeHints(this);
|
||||
}
|
||||
|
||||
void KBShortcutsDialog::fill_shortcuts()
|
||||
|
@ -132,6 +132,7 @@ void KBShortcutsDialog::fill_shortcuts()
|
|||
plater_shortcuts.reserve(20);
|
||||
|
||||
plater_shortcuts.push_back(Shortcut("A", L("Arrange")));
|
||||
plater_shortcuts.push_back(Shortcut("Shift+A", L("Arrange selection")));
|
||||
plater_shortcuts.push_back(Shortcut(ctrl+"A", L("Select All objects")));
|
||||
plater_shortcuts.push_back(Shortcut("Del", L("Delete selected")));
|
||||
plater_shortcuts.push_back(Shortcut(ctrl+"Del", L("Delete All")));
|
||||
|
@ -163,10 +164,10 @@ void KBShortcutsDialog::fill_shortcuts()
|
|||
|
||||
// Shortcuts gizmo_shortcuts;
|
||||
// gizmo_shortcuts.reserve(2);
|
||||
//
|
||||
//
|
||||
// gizmo_shortcuts.push_back(Shortcut("Shift+", L("Press to snap by 5% in Gizmo Scale\n or by 1mm in Gizmo Move")));
|
||||
// gizmo_shortcuts.push_back(Shortcut(alt, L("Press to scale or rotate selected objects around their own center")));
|
||||
//
|
||||
//
|
||||
// m_full_shortcuts.push_back(std::make_pair(_(L("Gizmo Shortcuts")), std::make_pair(gizmo_shortcuts, 1)));
|
||||
|
||||
|
||||
|
@ -177,6 +178,7 @@ void KBShortcutsDialog::fill_shortcuts()
|
|||
preview_shortcuts.push_back(Shortcut(L("Arrow Down"), L("Lower Layer")));
|
||||
preview_shortcuts.push_back(Shortcut("U", L("Upper Layer")));
|
||||
preview_shortcuts.push_back(Shortcut("D", L("Lower Layer")));
|
||||
preview_shortcuts.push_back(Shortcut("L", L("Show/Hide (L)egend")));
|
||||
|
||||
m_full_shortcuts.push_back(std::make_pair(_(L("Preview Shortcuts")), std::make_pair(preview_shortcuts, szLeft)));
|
||||
|
||||
|
|
|
@ -279,6 +279,18 @@ bool MainFrame::can_export_gcode() const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MainFrame::can_send_gcode() const
|
||||
{
|
||||
if (m_plater == nullptr)
|
||||
return false;
|
||||
|
||||
if (m_plater->model().objects.empty())
|
||||
return false;
|
||||
|
||||
const auto print_host_opt = wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionString>("print_host");
|
||||
return print_host_opt != nullptr && !print_host_opt->value.empty();
|
||||
}
|
||||
|
||||
bool MainFrame::can_slice() const
|
||||
{
|
||||
bool bg_proc = wxGetApp().app_config->get("background_processing") == "1";
|
||||
|
@ -451,6 +463,10 @@ void MainFrame::init_menubar()
|
|||
[this](wxCommandEvent&) { if (m_plater) m_plater->export_gcode(); }, menu_icon("export_gcode"), nullptr,
|
||||
[this](){return can_export_gcode(); }, this);
|
||||
m_changeable_menu_items.push_back(item_export_gcode);
|
||||
wxMenuItem* item_send_gcode = append_menu_item(export_menu, wxID_ANY, _(L("S&end G-code")) + dots +"\tCtrl+Shift+G", _(L("Send to print current plate as G-code")),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->send_gcode(); }, menu_icon("export_gcode"), nullptr,
|
||||
[this](){return can_send_gcode(); }, this);
|
||||
m_changeable_menu_items.push_back(item_send_gcode);
|
||||
export_menu->AppendSeparator();
|
||||
append_menu_item(export_menu, wxID_ANY, _(L("Export plate as &STL")) + dots, _(L("Export current plate as STL")),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->export_stl(); }, menu_icon("export_plater"), nullptr,
|
||||
|
@ -689,7 +705,8 @@ void MainFrame::update_menubar()
|
|||
{
|
||||
const bool is_fff = plater()->printer_technology() == ptFFF;
|
||||
|
||||
m_changeable_menu_items[miExport] ->SetItemLabel((is_fff ? _(L("Export &G-code")) : _(L("Export")) ) + dots + "\tCtrl+G");
|
||||
m_changeable_menu_items[miExport] ->SetItemLabel((is_fff ? _(L("Export &G-code")) : _(L("E&xport")) ) + dots + "\tCtrl+G");
|
||||
m_changeable_menu_items[miSend] ->SetItemLabel((is_fff ? _(L("S&end G-code")) : _(L("S&end to print"))) + dots + "\tCtrl+Shift+G");
|
||||
|
||||
m_changeable_menu_items[miMaterialTab] ->SetItemLabel((is_fff ? _(L("&Filament Settings Tab")) : _(L("Mate&rial Settings Tab"))) + "\tCtrl+3");
|
||||
m_changeable_menu_items[miMaterialTab] ->SetBitmap(create_scaled_bitmap(this, menu_icon(is_fff ? "spool": "resin")));
|
||||
|
|
|
@ -67,6 +67,7 @@ class MainFrame : public DPIFrame
|
|||
bool can_export_model() const;
|
||||
bool can_export_supports() const;
|
||||
bool can_export_gcode() const;
|
||||
bool can_send_gcode() const;
|
||||
bool can_slice() const;
|
||||
bool can_change_view() const;
|
||||
bool can_select() const;
|
||||
|
@ -79,6 +80,7 @@ class MainFrame : public DPIFrame
|
|||
enum MenuItems
|
||||
{ // FFF SLA
|
||||
miExport = 0, // Export G-code Export
|
||||
miSend, // Send G-code Send to print
|
||||
miMaterialTab, // Filament Settings Material Settings
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -162,11 +162,11 @@ VendorProfile VendorProfile::from_ini(const ptree &tree, const boost::filesystem
|
|||
if (from_pre_map != pre_family_model_map.end()) { model.family = from_pre_map->second; }
|
||||
}
|
||||
#if 0
|
||||
// Remove SLA printers from the initial alpha.
|
||||
if (model.technology == ptSLA)
|
||||
continue;
|
||||
// Remove SLA printers from the initial alpha.
|
||||
if (model.technology == ptSLA)
|
||||
continue;
|
||||
#endif
|
||||
section.second.get<std::string>("variants", "");
|
||||
section.second.get<std::string>("variants", "");
|
||||
const auto variants_field = section.second.get<std::string>("variants", "");
|
||||
std::vector<std::string> variants;
|
||||
if (Slic3r::unescape_strings_cstyle(variants_field, variants)) {
|
||||
|
@ -209,7 +209,7 @@ const std::string& Preset::suffix_modified()
|
|||
|
||||
void Preset::update_suffix_modified()
|
||||
{
|
||||
g_suffix_modified = (" (" + _(L("modified")) + ")").ToUTF8().data();
|
||||
g_suffix_modified = (" (" + _(L("modified")) + ")").ToUTF8().data();
|
||||
}
|
||||
// Remove an optional "(modified)" suffix from a name.
|
||||
// This converts a UI name to a unique preset identifier.
|
||||
|
@ -224,8 +224,8 @@ void Preset::set_num_extruders(DynamicPrintConfig &config, unsigned int num_extr
|
|||
{
|
||||
const auto &defaults = FullPrintConfig::defaults();
|
||||
for (const std::string &key : Preset::nozzle_options()) {
|
||||
if (key == "default_filament_profile")
|
||||
continue;
|
||||
if (key == "default_filament_profile")
|
||||
continue;
|
||||
auto *opt = config.option(key, false);
|
||||
assert(opt != nullptr);
|
||||
assert(opt->is_vector());
|
||||
|
@ -247,8 +247,8 @@ void Preset::normalize(DynamicPrintConfig &config)
|
|||
size_t n = (nozzle_diameter == nullptr) ? 1 : nozzle_diameter->values.size();
|
||||
const auto &defaults = FullPrintConfig::defaults();
|
||||
for (const std::string &key : Preset::filament_options()) {
|
||||
if (key == "compatible_prints" || key == "compatible_printers")
|
||||
continue;
|
||||
if (key == "compatible_prints" || key == "compatible_printers")
|
||||
continue;
|
||||
auto *opt = config.option(key, false);
|
||||
/*assert(opt != nullptr);
|
||||
assert(opt->is_vector());*/
|
||||
|
@ -307,7 +307,7 @@ bool Preset::is_compatible_with_print(const Preset &active_print) const
|
|||
}
|
||||
}
|
||||
return this->is_default || active_print.name.empty() || ! has_compatible_prints ||
|
||||
std::find(compatible_prints->values.begin(), compatible_prints->values.end(), active_print.name) !=
|
||||
std::find(compatible_prints->values.begin(), compatible_prints->values.end(), active_print.name) !=
|
||||
compatible_prints->values.end();
|
||||
}
|
||||
|
||||
|
@ -326,7 +326,7 @@ bool Preset::is_compatible_with_printer(const Preset &active_printer, const Dyna
|
|||
}
|
||||
}
|
||||
return this->is_default || active_printer.name.empty() || ! has_compatible_printers ||
|
||||
std::find(compatible_printers->values.begin(), compatible_printers->values.end(), active_printer.name) !=
|
||||
std::find(compatible_printers->values.begin(), compatible_printers->values.end(), active_printer.name) !=
|
||||
compatible_printers->values.end();
|
||||
}
|
||||
|
||||
|
@ -334,9 +334,9 @@ bool Preset::is_compatible_with_printer(const Preset &active_printer) const
|
|||
{
|
||||
DynamicPrintConfig config;
|
||||
config.set_key_value("printer_preset", new ConfigOptionString(active_printer.name));
|
||||
const ConfigOption *opt = active_printer.config.option("nozzle_diameter");
|
||||
if (opt)
|
||||
config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast<const ConfigOptionFloats*>(opt)->values.size()));
|
||||
const ConfigOption *opt = active_printer.config.option("nozzle_diameter");
|
||||
if (opt)
|
||||
config.set_key_value("num_extruders", new ConfigOptionInt((int)static_cast<const ConfigOptionFloats*>(opt)->values.size()));
|
||||
return this->is_compatible_with_printer(active_printer, &config);
|
||||
}
|
||||
|
||||
|
@ -358,40 +358,40 @@ void Preset::set_visible_from_appconfig(const AppConfig &app_config)
|
|||
}
|
||||
|
||||
const std::vector<std::string>& Preset::print_options()
|
||||
{
|
||||
{
|
||||
static std::vector<std::string> s_opts {
|
||||
"layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "top_solid_layers", "bottom_solid_layers",
|
||||
"extra_perimeters", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs",
|
||||
"layer_height", "first_layer_height", "perimeters", "spiral_vase", "slice_closing_radius", "top_solid_layers", "bottom_solid_layers",
|
||||
"extra_perimeters", "ensure_vertical_shell_thickness", "avoid_crossing_perimeters", "thin_walls", "overhangs",
|
||||
"seam_position", "external_perimeters_first", "fill_density", "fill_pattern", "top_fill_pattern", "bottom_fill_pattern",
|
||||
"infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle",
|
||||
"solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first", "max_print_speed",
|
||||
"max_volumetric_speed",
|
||||
"infill_every_layers", "infill_only_where_needed", "solid_infill_every_layers", "fill_angle", "bridge_angle",
|
||||
"solid_infill_below_area", "only_retract_when_crossing_perimeters", "infill_first", "max_print_speed",
|
||||
"max_volumetric_speed",
|
||||
#ifdef HAS_PRESSURE_EQUALIZER
|
||||
"max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
|
||||
"max_volumetric_extrusion_rate_slope_positive", "max_volumetric_extrusion_rate_slope_negative",
|
||||
#endif /* HAS_PRESSURE_EQUALIZER */
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed", "infill_speed", "solid_infill_speed",
|
||||
"top_solid_infill_speed", "support_material_speed", "support_material_xy_spacing", "support_material_interface_speed",
|
||||
"bridge_speed", "gap_fill_speed", "travel_speed", "first_layer_speed", "perimeter_acceleration", "infill_acceleration",
|
||||
"bridge_speed", "gap_fill_speed", "travel_speed", "first_layer_speed", "perimeter_acceleration", "infill_acceleration",
|
||||
"bridge_acceleration", "first_layer_acceleration", "default_acceleration", "skirts", "skirt_distance", "skirt_height",
|
||||
"min_skirt_length", "brim_width", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
|
||||
"raft_layers", "support_material_pattern", "support_material_with_sheath", "support_material_spacing",
|
||||
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers",
|
||||
"support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_contact_distance",
|
||||
"support_material_buildplate_only", "dont_support_bridges", "notes", "complete_objects", "extruder_clearance_radius",
|
||||
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder",
|
||||
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
|
||||
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
|
||||
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
||||
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects",
|
||||
"min_skirt_length", "brim_width", "support_material", "support_material_auto", "support_material_threshold", "support_material_enforce_layers",
|
||||
"raft_layers", "support_material_pattern", "support_material_with_sheath", "support_material_spacing",
|
||||
"support_material_synchronize_layers", "support_material_angle", "support_material_interface_layers",
|
||||
"support_material_interface_spacing", "support_material_interface_contact_loops", "support_material_contact_distance",
|
||||
"support_material_buildplate_only", "dont_support_bridges", "notes", "complete_objects", "extruder_clearance_radius",
|
||||
"extruder_clearance_height", "gcode_comments", "gcode_label_objects", "output_filename_format", "post_process", "perimeter_extruder",
|
||||
"infill_extruder", "solid_infill_extruder", "support_material_extruder", "support_material_interface_extruder",
|
||||
"ooze_prevention", "standby_temperature_delta", "interface_shells", "extrusion_width", "first_layer_extrusion_width",
|
||||
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
||||
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects",
|
||||
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
|
||||
"wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "single_extruder_multi_material_priming",
|
||||
"wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "single_extruder_multi_material_priming",
|
||||
"compatible_printers", "compatible_printers_condition", "inherits"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& Preset::filament_options()
|
||||
{
|
||||
{
|
||||
static std::vector<std::string> s_opts {
|
||||
"filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed",
|
||||
"extrusion_multiplier", "filament_density", "filament_cost", "filament_loading_speed", "filament_loading_speed_start", "filament_load_time",
|
||||
|
@ -401,16 +401,16 @@ const std::vector<std::string>& Preset::filament_options()
|
|||
"max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed",
|
||||
"start_filament_gcode", "end_filament_gcode",
|
||||
// Retract overrides
|
||||
"filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel",
|
||||
"filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe",
|
||||
// Profile compatibility
|
||||
"filament_retract_length", "filament_retract_lift", "filament_retract_lift_above", "filament_retract_lift_below", "filament_retract_speed", "filament_deretract_speed", "filament_retract_restart_extra", "filament_retract_before_travel",
|
||||
"filament_retract_layer_change", "filament_wipe", "filament_retract_before_wipe",
|
||||
// Profile compatibility
|
||||
"compatible_prints", "compatible_prints_condition", "compatible_printers", "compatible_printers_condition", "inherits"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& Preset::printer_options()
|
||||
{
|
||||
{
|
||||
static std::vector<std::string> s_opts;
|
||||
if (s_opts.empty()) {
|
||||
s_opts = {
|
||||
|
@ -420,20 +420,20 @@ const std::vector<std::string>& Preset::printer_options()
|
|||
"host_type", "print_host", "printhost_apikey", "printhost_cafile",
|
||||
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
||||
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
|
||||
"cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "max_print_height",
|
||||
"cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "max_print_height",
|
||||
"default_print_profile", "inherits",
|
||||
"remaining_times", "silent_mode", "machine_max_acceleration_extruding", "machine_max_acceleration_retracting",
|
||||
"machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e",
|
||||
"machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
|
||||
"machine_min_extruding_rate", "machine_min_travel_rate",
|
||||
"machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e"
|
||||
"machine_max_acceleration_x", "machine_max_acceleration_y", "machine_max_acceleration_z", "machine_max_acceleration_e",
|
||||
"machine_max_feedrate_x", "machine_max_feedrate_y", "machine_max_feedrate_z", "machine_max_feedrate_e",
|
||||
"machine_min_extruding_rate", "machine_min_travel_rate",
|
||||
"machine_max_jerk_x", "machine_max_jerk_y", "machine_max_jerk_z", "machine_max_jerk_e"
|
||||
};
|
||||
s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
|
||||
}
|
||||
return s_opts;
|
||||
}
|
||||
|
||||
// The following nozzle options of a printer profile will be adjusted to match the size
|
||||
// The following nozzle options of a printer profile will be adjusted to match the size
|
||||
// of the nozzle_diameter vector.
|
||||
const std::vector<std::string>& Preset::nozzle_options()
|
||||
{
|
||||
|
@ -442,14 +442,14 @@ const std::vector<std::string>& Preset::nozzle_options()
|
|||
"nozzle_diameter", "min_layer_height", "max_layer_height", "extruder_offset",
|
||||
"retract_length", "retract_lift", "retract_lift_above", "retract_lift_below", "retract_speed", "deretract_speed",
|
||||
"retract_before_wipe", "retract_restart_extra", "retract_before_travel", "wipe",
|
||||
"retract_layer_change", "retract_length_toolchange", "retract_restart_extra_toolchange", "extruder_colour",
|
||||
"retract_layer_change", "retract_length_toolchange", "retract_restart_extra_toolchange", "extruder_colour",
|
||||
"default_filament_profile"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& Preset::sla_print_options()
|
||||
{
|
||||
{
|
||||
static std::vector<std::string> s_opts;
|
||||
if (s_opts.empty()) {
|
||||
s_opts = {
|
||||
|
@ -477,16 +477,17 @@ const std::vector<std::string>& Preset::sla_print_options()
|
|||
"pad_wall_thickness",
|
||||
"pad_wall_height",
|
||||
"pad_max_merge_distance",
|
||||
"pad_edge_radius",
|
||||
// "pad_edge_radius",
|
||||
"pad_wall_slope",
|
||||
"pad_object_gap",
|
||||
"pad_zero_elevation",
|
||||
"pad_object_connector_stride",
|
||||
"pad_object_connector_width",
|
||||
"pad_object_connector_penetration",
|
||||
"output_filename_format",
|
||||
"output_filename_format",
|
||||
"default_sla_print_profile",
|
||||
"compatible_printers",
|
||||
"compatible_printers_condition",
|
||||
"compatible_printers_condition",
|
||||
"inherits"
|
||||
};
|
||||
}
|
||||
|
@ -494,7 +495,7 @@ const std::vector<std::string>& Preset::sla_print_options()
|
|||
}
|
||||
|
||||
const std::vector<std::string>& Preset::sla_material_options()
|
||||
{
|
||||
{
|
||||
static std::vector<std::string> s_opts;
|
||||
if (s_opts.empty()) {
|
||||
s_opts = {
|
||||
|
@ -503,7 +504,7 @@ const std::vector<std::string>& Preset::sla_material_options()
|
|||
"material_correction",
|
||||
"material_notes",
|
||||
"default_sla_material_profile",
|
||||
"compatible_prints", "compatible_prints_condition",
|
||||
"compatible_prints", "compatible_prints_condition",
|
||||
"compatible_printers", "compatible_printers_condition", "inherits"
|
||||
};
|
||||
}
|
||||
|
@ -511,7 +512,7 @@ const std::vector<std::string>& Preset::sla_material_options()
|
|||
}
|
||||
|
||||
const std::vector<std::string>& Preset::sla_printer_options()
|
||||
{
|
||||
{
|
||||
static std::vector<std::string> s_opts;
|
||||
if (s_opts.empty()) {
|
||||
s_opts = {
|
||||
|
@ -539,7 +540,7 @@ PresetCollection::PresetCollection(Preset::Type type, const std::vector<std::str
|
|||
m_idx_selected(0),
|
||||
m_bitmap_main_frame(new wxBitmap),
|
||||
m_bitmap_add(new wxBitmap),
|
||||
m_bitmap_cache(new GUI::BitmapCache)
|
||||
m_bitmap_cache(new GUI::BitmapCache)
|
||||
{
|
||||
// Insert just the default preset.
|
||||
this->add_default_preset(keys, defaults, default_name);
|
||||
|
@ -552,8 +553,8 @@ PresetCollection::~PresetCollection()
|
|||
m_bitmap_main_frame = nullptr;
|
||||
delete m_bitmap_add;
|
||||
m_bitmap_add = nullptr;
|
||||
delete m_bitmap_cache;
|
||||
m_bitmap_cache = nullptr;
|
||||
delete m_bitmap_cache;
|
||||
m_bitmap_cache = nullptr;
|
||||
}
|
||||
|
||||
void PresetCollection::reset(bool delete_files)
|
||||
|
@ -575,8 +576,8 @@ void PresetCollection::add_default_preset(const std::vector<std::string> &keys,
|
|||
{
|
||||
// Insert just the default preset.
|
||||
m_presets.emplace_back(Preset(this->type(), preset_name, true));
|
||||
m_presets.back().config.apply_only(defaults, keys.empty() ? defaults.keys() : keys);
|
||||
m_presets.back().loaded = true;
|
||||
m_presets.back().config.apply_only(defaults, keys.empty() ? defaults.keys() : keys);
|
||||
m_presets.back().loaded = true;
|
||||
++ m_num_default_presets;
|
||||
}
|
||||
|
||||
|
@ -584,13 +585,13 @@ void PresetCollection::add_default_preset(const std::vector<std::string> &keys,
|
|||
// Throws an exception on error.
|
||||
void PresetCollection::load_presets(const std::string &dir_path, const std::string &subdir)
|
||||
{
|
||||
boost::filesystem::path dir = boost::filesystem::canonical(boost::filesystem::path(dir_path) / subdir).make_preferred();
|
||||
m_dir_path = dir.string();
|
||||
boost::filesystem::path dir = boost::filesystem::canonical(boost::filesystem::path(dir_path) / subdir).make_preferred();
|
||||
m_dir_path = dir.string();
|
||||
std::string errors_cummulative;
|
||||
// Store the loaded presets into a new vector, otherwise the binary search for already existing presets would be broken.
|
||||
// (see the "Preset already present, not loading" message).
|
||||
std::deque<Preset> presets_loaded;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
|
||||
// Store the loaded presets into a new vector, otherwise the binary search for already existing presets would be broken.
|
||||
// (see the "Preset already present, not loading" message).
|
||||
std::deque<Preset> presets_loaded;
|
||||
for (auto &dir_entry : boost::filesystem::directory_iterator(dir))
|
||||
if (Slic3r::is_ini_file(dir_entry)) {
|
||||
std::string name = dir_entry.path().filename().string();
|
||||
// Remove the .ini suffix.
|
||||
|
@ -609,28 +610,28 @@ void PresetCollection::load_presets(const std::string &dir_path, const std::stri
|
|||
DynamicPrintConfig config;
|
||||
config.load_from_ini(preset.file);
|
||||
// Find a default preset for the config. The PrintPresetCollection provides different default preset based on the "printer_technology" field.
|
||||
const Preset &default_preset = this->default_preset_for(config);
|
||||
const Preset &default_preset = this->default_preset_for(config);
|
||||
preset.config = default_preset.config;
|
||||
preset.config.apply(std::move(config));
|
||||
Preset::normalize(preset.config);
|
||||
// Report configuration fields, which are misplaced into a wrong group.
|
||||
std::string incorrect_keys = Preset::remove_invalid_keys(config, default_preset.config);
|
||||
std::string incorrect_keys = Preset::remove_invalid_keys(config, default_preset.config);
|
||||
if (! incorrect_keys.empty())
|
||||
BOOST_LOG_TRIVIAL(error) << "Error in a preset file: The preset \"" <<
|
||||
preset.file << "\" contains the following incorrect keys: " << incorrect_keys << ", which were removed";
|
||||
preset.loaded = true;
|
||||
} catch (const std::ifstream::failure &err) {
|
||||
throw std::runtime_error(std::string("The selected preset cannot be loaded: ") + preset.file + "\n\tReason: " + err.what());
|
||||
throw std::runtime_error(std::string("The selected preset cannot be loaded: ") + preset.file + "\n\tReason: " + err.what());
|
||||
} catch (const std::runtime_error &err) {
|
||||
throw std::runtime_error(std::string("Failed loading the preset file: ") + preset.file + "\n\tReason: " + err.what());
|
||||
throw std::runtime_error(std::string("Failed loading the preset file: ") + preset.file + "\n\tReason: " + err.what());
|
||||
}
|
||||
presets_loaded.emplace_back(preset);
|
||||
presets_loaded.emplace_back(preset);
|
||||
} catch (const std::runtime_error &err) {
|
||||
errors_cummulative += err.what();
|
||||
errors_cummulative += "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
m_presets.insert(m_presets.end(), std::make_move_iterator(presets_loaded.begin()), std::make_move_iterator(presets_loaded.end()));
|
||||
m_presets.insert(m_presets.end(), std::make_move_iterator(presets_loaded.begin()), std::make_move_iterator(presets_loaded.end()));
|
||||
std::sort(m_presets.begin() + m_num_default_presets, m_presets.end());
|
||||
this->select_preset(first_visible_idx());
|
||||
if (! errors_cummulative.empty())
|
||||
|
@ -651,8 +652,8 @@ static bool profile_print_params_same(const DynamicPrintConfig &cfg1, const Dyna
|
|||
t_config_option_keys diff = cfg1.diff(cfg2);
|
||||
// Following keys are used by the UI, not by the slicing core, therefore they are not important
|
||||
// when comparing profiles for equality. Ignore them.
|
||||
for (const char *key : { "compatible_prints", "compatible_prints_condition",
|
||||
"compatible_printers", "compatible_printers_condition", "inherits",
|
||||
for (const char *key : { "compatible_prints", "compatible_prints_condition",
|
||||
"compatible_printers", "compatible_printers_condition", "inherits",
|
||||
"print_settings_id", "filament_settings_id", "sla_print_settings_id", "sla_material_settings_id", "printer_settings_id",
|
||||
"printer_model", "printer_variant", "default_print_profile", "default_filament_profile", "default_sla_print_profile", "default_sla_material_profile",
|
||||
"printhost_apikey", "printhost_cafile" })
|
||||
|
@ -663,7 +664,7 @@ static bool profile_print_params_same(const DynamicPrintConfig &cfg1, const Dyna
|
|||
|
||||
// Load a preset from an already parsed config file, insert it into the sorted sequence of presets
|
||||
// and select it, losing previous modifications.
|
||||
// In case
|
||||
// In case
|
||||
Preset& PresetCollection::load_external_preset(
|
||||
// Path to the profile source file (a G-code, an AMF or 3MF file, a config file)
|
||||
const std::string &path,
|
||||
|
@ -681,7 +682,7 @@ Preset& PresetCollection::load_external_preset(
|
|||
cfg.apply_only(config, cfg.keys(), true);
|
||||
// Is there a preset already loaded with the name stored inside the config?
|
||||
std::deque<Preset>::iterator it = this->find_preset_internal(original_name);
|
||||
bool found = it != m_presets.end() && it->name == original_name;
|
||||
bool found = it != m_presets.end() && it->name == original_name;
|
||||
if (found && profile_print_params_same(it->config, cfg)) {
|
||||
// The preset exists and it matches the values stored inside config.
|
||||
if (select)
|
||||
|
@ -706,7 +707,7 @@ Preset& PresetCollection::load_external_preset(
|
|||
suffix = " (" + std::to_string(idx) + ")";
|
||||
} else {
|
||||
if (idx == 0)
|
||||
suffix = " (" + original_name + ")";
|
||||
suffix = " (" + original_name + ")";
|
||||
else
|
||||
suffix = " (" + original_name + "-" + std::to_string(idx) + ")";
|
||||
}
|
||||
|
@ -751,8 +752,8 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string
|
|||
|
||||
void PresetCollection::save_current_preset(const std::string &new_name)
|
||||
{
|
||||
// 1) Find the preset with a new_name or create a new one,
|
||||
// initialize it with the edited config.
|
||||
// 1) Find the preset with a new_name or create a new one,
|
||||
// initialize it with the edited config.
|
||||
auto it = this->find_preset_internal(new_name);
|
||||
if (it != m_presets.end() && it->name == new_name) {
|
||||
// Preset with the same name found.
|
||||
|
@ -762,15 +763,15 @@ void PresetCollection::save_current_preset(const std::string &new_name)
|
|||
return;
|
||||
// Overwriting an existing preset.
|
||||
preset.config = std::move(m_edited_preset.config);
|
||||
// The newly saved preset will be activated -> make it visible.
|
||||
preset.is_visible = true;
|
||||
// The newly saved preset will be activated -> make it visible.
|
||||
preset.is_visible = true;
|
||||
} else {
|
||||
// Creating a new preset.
|
||||
Preset &preset = *m_presets.insert(it, m_edited_preset);
|
||||
Preset &preset = *m_presets.insert(it, m_edited_preset);
|
||||
std::string &inherits = preset.inherits();
|
||||
std::string old_name = preset.name;
|
||||
preset.name = new_name;
|
||||
preset.file = this->path_from_name(new_name);
|
||||
preset.file = this->path_from_name(new_name);
|
||||
preset.vendor = nullptr;
|
||||
if (preset.is_system) {
|
||||
// Inheriting from a system preset.
|
||||
|
@ -779,30 +780,30 @@ void PresetCollection::save_current_preset(const std::string &new_name)
|
|||
// Inheriting from a user preset. Link the new preset to the old preset.
|
||||
// inherits = old_name;
|
||||
} else {
|
||||
// Inherited from a user preset. Just maintain the "inherited" flag,
|
||||
// Inherited from a user preset. Just maintain the "inherited" flag,
|
||||
// meaning it will inherit from either the system preset, or the inherited user preset.
|
||||
}
|
||||
preset.is_default = false;
|
||||
preset.is_system = false;
|
||||
preset.is_external = false;
|
||||
// The newly saved preset will be activated -> make it visible.
|
||||
preset.is_visible = true;
|
||||
}
|
||||
// 2) Activate the saved preset.
|
||||
this->select_preset_by_name(new_name, true);
|
||||
// 2) Store the active preset to disk.
|
||||
this->get_selected_preset().save();
|
||||
// The newly saved preset will be activated -> make it visible.
|
||||
preset.is_visible = true;
|
||||
}
|
||||
// 2) Activate the saved preset.
|
||||
this->select_preset_by_name(new_name, true);
|
||||
// 2) Store the active preset to disk.
|
||||
this->get_selected_preset().save();
|
||||
}
|
||||
|
||||
bool PresetCollection::delete_current_preset()
|
||||
{
|
||||
const Preset &selected = this->get_selected_preset();
|
||||
if (selected.is_default)
|
||||
return false;
|
||||
if (! selected.is_external && ! selected.is_system) {
|
||||
// Erase the preset file.
|
||||
boost::nowide::remove(selected.file.c_str());
|
||||
}
|
||||
if (selected.is_default)
|
||||
return false;
|
||||
if (! selected.is_external && ! selected.is_system) {
|
||||
// Erase the preset file.
|
||||
boost::nowide::remove(selected.file.c_str());
|
||||
}
|
||||
// Remove the preset from the list.
|
||||
m_presets.erase(m_presets.begin() + m_idx_selected);
|
||||
// Find the next visible preset.
|
||||
|
@ -810,9 +811,9 @@ bool PresetCollection::delete_current_preset()
|
|||
if (new_selected_idx < m_presets.size())
|
||||
for (; new_selected_idx < m_presets.size() && ! m_presets[new_selected_idx].is_visible; ++ new_selected_idx) ;
|
||||
if (new_selected_idx == m_presets.size())
|
||||
for (--new_selected_idx; new_selected_idx > 0 && !m_presets[new_selected_idx].is_visible; --new_selected_idx);
|
||||
for (--new_selected_idx; new_selected_idx > 0 && !m_presets[new_selected_idx].is_visible; --new_selected_idx);
|
||||
this->select_preset(new_selected_idx);
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PresetCollection::load_bitmap_default(wxWindow *window, const std::string &file_name)
|
||||
|
@ -836,18 +837,18 @@ const Preset* PresetCollection::get_selected_preset_parent() const
|
|||
return nullptr;
|
||||
// const std::string &inherits = this->get_edited_preset().inherits();
|
||||
// if (inherits.empty())
|
||||
// return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
|
||||
// return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
|
||||
|
||||
std::string inherits = this->get_edited_preset().inherits();
|
||||
if (inherits.empty())
|
||||
{
|
||||
if (this->get_selected_preset().is_system || this->get_selected_preset().is_default)
|
||||
if (this->get_selected_preset().is_system || this->get_selected_preset().is_default)
|
||||
return &this->get_selected_preset();
|
||||
if (this->get_selected_preset().is_external)
|
||||
return nullptr;
|
||||
|
||||
|
||||
inherits = m_type != Preset::Type::TYPE_PRINTER ? "- default -" :
|
||||
this->get_edited_preset().printer_technology() == ptFFF ?
|
||||
this->get_edited_preset().printer_technology() == ptFFF ?
|
||||
"- default FFF -" : "- default SLA -" ;
|
||||
}
|
||||
|
||||
|
@ -859,14 +860,14 @@ const Preset* PresetCollection::get_preset_parent(const Preset& child) const
|
|||
{
|
||||
const std::string &inherits = child.inherits();
|
||||
if (inherits.empty())
|
||||
// return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
|
||||
return nullptr;
|
||||
// return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
|
||||
return nullptr;
|
||||
const Preset* preset = this->find_preset(inherits, false);
|
||||
return (preset == nullptr/* || preset->is_default */|| preset->is_external) ? nullptr : preset;
|
||||
}
|
||||
|
||||
const std::string& PresetCollection::get_suffix_modified() {
|
||||
return g_suffix_modified;
|
||||
return g_suffix_modified;
|
||||
}
|
||||
|
||||
// Return a preset by its name. If the preset is active, a temporary copy is returned.
|
||||
|
@ -876,7 +877,7 @@ Preset* PresetCollection::find_preset(const std::string &name, bool first_visibl
|
|||
Preset key(m_type, name, false);
|
||||
auto it = this->find_preset_internal(name);
|
||||
// Ensure that a temporary copy is returned if the preset found is currently selected.
|
||||
return (it != m_presets.end() && it->name == key.name) ? &this->preset(it - m_presets.begin()) :
|
||||
return (it != m_presets.end() && it->name == key.name) ? &this->preset(it - m_presets.begin()) :
|
||||
first_visible_if_not_found ? &this->first_visible() : nullptr;
|
||||
}
|
||||
|
||||
|
@ -896,9 +897,9 @@ void PresetCollection::set_default_suppressed(bool default_suppressed)
|
|||
{
|
||||
if (m_default_suppressed != default_suppressed) {
|
||||
m_default_suppressed = default_suppressed;
|
||||
bool default_visible = ! default_suppressed || m_idx_selected < m_num_default_presets;
|
||||
for (size_t i = 0; i < m_num_default_presets; ++ i)
|
||||
m_presets[i].is_visible = default_visible;
|
||||
bool default_visible = ! default_suppressed || m_idx_selected < m_num_default_presets;
|
||||
for (size_t i = 0; i < m_num_default_presets; ++ i)
|
||||
m_presets[i].is_visible = default_visible;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -931,7 +932,7 @@ size_t PresetCollection::update_compatible_internal(const Preset &active_printer
|
|||
//void PresetCollection::delete_current_preset();
|
||||
|
||||
// Update the wxChoice UI component from this list of presets.
|
||||
// Hide the
|
||||
// Hide the
|
||||
void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui)
|
||||
{
|
||||
if (ui == nullptr)
|
||||
|
@ -940,12 +941,12 @@ void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui)
|
|||
// Otherwise fill in the list from scratch.
|
||||
ui->Freeze();
|
||||
ui->Clear();
|
||||
size_t selected_preset_item = 0;
|
||||
size_t selected_preset_item = 0;
|
||||
|
||||
const Preset &selected_preset = this->get_selected_preset();
|
||||
// Show wide icons if the currently selected preset is not compatible with the current printer,
|
||||
// and draw a red flag in front of the selected preset.
|
||||
bool wide_icons = ! selected_preset.is_compatible && m_bitmap_incompatible != nullptr;
|
||||
const Preset &selected_preset = this->get_selected_preset();
|
||||
// Show wide icons if the currently selected preset is not compatible with the current printer,
|
||||
// and draw a red flag in front of the selected preset.
|
||||
bool wide_icons = ! selected_preset.is_compatible && m_bitmap_incompatible != nullptr;
|
||||
|
||||
/* It's supposed that standard size of an icon is 16px*16px for 100% scaled display.
|
||||
* So set sizes for solid_colored icons used for filament preset
|
||||
|
@ -957,87 +958,87 @@ void PresetCollection::update_platter_ui(GUI::PresetComboBox *ui)
|
|||
const int thin_space_icon_width = 4 * scale_f + 0.5f;
|
||||
const int wide_space_icon_width = 6 * scale_f + 0.5f;
|
||||
|
||||
std::map<wxString, wxBitmap*> nonsys_presets;
|
||||
wxString selected = "";
|
||||
if (!this->m_presets.front().is_visible)
|
||||
std::map<wxString, wxBitmap*> nonsys_presets;
|
||||
wxString selected = "";
|
||||
if (!this->m_presets.front().is_visible)
|
||||
ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap));
|
||||
for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++ i) {
|
||||
for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++ i) {
|
||||
const Preset &preset = this->m_presets[i];
|
||||
if (! preset.is_visible || (! preset.is_compatible && i != m_idx_selected))
|
||||
continue;
|
||||
std::string bitmap_key = "";
|
||||
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
|
||||
// to the filament color image.
|
||||
if (wide_icons)
|
||||
bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
|
||||
bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
|
||||
wxBitmap *bmp = m_bitmap_cache->find(bitmap_key);
|
||||
if (bmp == nullptr) {
|
||||
// Create the bitmap with color bars.
|
||||
std::vector<wxBitmap> bmps;
|
||||
if (wide_icons)
|
||||
// Paint a red flag for incompatible presets.
|
||||
bmps.emplace_back(preset.is_compatible ? m_bitmap_cache->mkclear(icon_width, icon_height) : *m_bitmap_incompatible);
|
||||
// Paint the color bars.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(thin_space_icon_width, icon_height));
|
||||
bmps.emplace_back(*m_bitmap_main_frame);
|
||||
// Paint a lock at the system presets.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(wide_space_icon_width, icon_height));
|
||||
bmps.emplace_back((preset.is_system || preset.is_default) ? *m_bitmap_lock : m_bitmap_cache->mkclear(icon_width, icon_height));
|
||||
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
|
||||
}
|
||||
std::string bitmap_key = "";
|
||||
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
|
||||
// to the filament color image.
|
||||
if (wide_icons)
|
||||
bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
|
||||
bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
|
||||
wxBitmap *bmp = m_bitmap_cache->find(bitmap_key);
|
||||
if (bmp == nullptr) {
|
||||
// Create the bitmap with color bars.
|
||||
std::vector<wxBitmap> bmps;
|
||||
if (wide_icons)
|
||||
// Paint a red flag for incompatible presets.
|
||||
bmps.emplace_back(preset.is_compatible ? m_bitmap_cache->mkclear(icon_width, icon_height) : *m_bitmap_incompatible);
|
||||
// Paint the color bars.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(thin_space_icon_width, icon_height));
|
||||
bmps.emplace_back(*m_bitmap_main_frame);
|
||||
// Paint a lock at the system presets.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(wide_space_icon_width, icon_height));
|
||||
bmps.emplace_back((preset.is_system || preset.is_default) ? *m_bitmap_lock : m_bitmap_cache->mkclear(icon_width, icon_height));
|
||||
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
|
||||
}
|
||||
|
||||
if (preset.is_default || preset.is_system) {
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
|
||||
(bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
if (i == m_idx_selected)
|
||||
selected_preset_item = ui->GetCount() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), bmp/*preset.is_compatible*/);
|
||||
if (i == m_idx_selected)
|
||||
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str());
|
||||
}
|
||||
if (i + 1 == m_num_default_presets)
|
||||
if (preset.is_default || preset.is_system) {
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
|
||||
(bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
if (i == m_idx_selected)
|
||||
selected_preset_item = ui->GetCount() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), bmp/*preset.is_compatible*/);
|
||||
if (i == m_idx_selected)
|
||||
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str());
|
||||
}
|
||||
if (i + 1 == m_num_default_presets)
|
||||
ui->set_label_marker(ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap));
|
||||
}
|
||||
if (!nonsys_presets.empty())
|
||||
{
|
||||
}
|
||||
if (!nonsys_presets.empty())
|
||||
{
|
||||
ui->set_label_marker(ui->Append(PresetCollection::separator(L("User presets")), wxNullBitmap));
|
||||
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
|
||||
ui->Append(it->first, *it->second);
|
||||
if (it->first == selected)
|
||||
selected_preset_item = ui->GetCount() - 1;
|
||||
}
|
||||
}
|
||||
if (m_type == Preset::TYPE_PRINTER) {
|
||||
std::string bitmap_key = "";
|
||||
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
|
||||
// to the filament color image.
|
||||
if (wide_icons)
|
||||
bitmap_key += "wide,";
|
||||
bitmap_key += "add_printer";
|
||||
wxBitmap *bmp = m_bitmap_cache->find(bitmap_key);
|
||||
if (bmp == nullptr) {
|
||||
// Create the bitmap with color bars.
|
||||
std::vector<wxBitmap> bmps;
|
||||
if (wide_icons)
|
||||
// Paint a red flag for incompatible presets.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(icon_width, icon_height));
|
||||
// Paint the color bars.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(thin_space_icon_width, icon_height));
|
||||
bmps.emplace_back(*m_bitmap_main_frame);
|
||||
// Paint a lock at the system presets.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(wide_space_icon_width, icon_height));
|
||||
bmps.emplace_back(m_bitmap_add ? *m_bitmap_add : wxNullBitmap);
|
||||
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
|
||||
}
|
||||
ui->set_label_marker(ui->Append(PresetCollection::separator(L("Add a new printer")), *bmp), GUI::PresetComboBox::LABEL_ITEM_CONFIG_WIZARD);
|
||||
}
|
||||
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
|
||||
ui->Append(it->first, *it->second);
|
||||
if (it->first == selected)
|
||||
selected_preset_item = ui->GetCount() - 1;
|
||||
}
|
||||
}
|
||||
if (m_type == Preset::TYPE_PRINTER) {
|
||||
std::string bitmap_key = "";
|
||||
// If the filament preset is not compatible and there is a "red flag" icon loaded, show it left
|
||||
// to the filament color image.
|
||||
if (wide_icons)
|
||||
bitmap_key += "wide,";
|
||||
bitmap_key += "add_printer";
|
||||
wxBitmap *bmp = m_bitmap_cache->find(bitmap_key);
|
||||
if (bmp == nullptr) {
|
||||
// Create the bitmap with color bars.
|
||||
std::vector<wxBitmap> bmps;
|
||||
if (wide_icons)
|
||||
// Paint a red flag for incompatible presets.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(icon_width, icon_height));
|
||||
// Paint the color bars.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(thin_space_icon_width, icon_height));
|
||||
bmps.emplace_back(*m_bitmap_main_frame);
|
||||
// Paint a lock at the system presets.
|
||||
bmps.emplace_back(m_bitmap_cache->mkclear(wide_space_icon_width, icon_height));
|
||||
bmps.emplace_back(m_bitmap_add ? *m_bitmap_add : wxNullBitmap);
|
||||
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
|
||||
}
|
||||
ui->set_label_marker(ui->Append(PresetCollection::separator(L("Add a new printer")), *bmp), GUI::PresetComboBox::LABEL_ITEM_CONFIG_WIZARD);
|
||||
}
|
||||
|
||||
ui->SetSelection(selected_preset_item);
|
||||
ui->SetToolTip(ui->GetString(selected_preset_item));
|
||||
ui->SetSelection(selected_preset_item);
|
||||
ui->SetToolTip(ui->GetString(selected_preset_item));
|
||||
ui->check_selection();
|
||||
ui->Thaw();
|
||||
|
||||
|
@ -1052,7 +1053,7 @@ size_t PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompati
|
|||
return 0;
|
||||
ui->Freeze();
|
||||
ui->Clear();
|
||||
size_t selected_preset_item = 0;
|
||||
size_t selected_preset_item = 0;
|
||||
|
||||
/* It's supposed that standard size of an icon is 16px*16px for 100% scaled display.
|
||||
* So set sizes for solid_colored(empty) icons used for preset
|
||||
|
@ -1062,52 +1063,52 @@ size_t PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompati
|
|||
const int icon_height = 16 * scale_f + 0.5f;
|
||||
const int icon_width = 16 * scale_f + 0.5f;
|
||||
|
||||
std::map<wxString, wxBitmap*> nonsys_presets;
|
||||
wxString selected = "";
|
||||
if (!this->m_presets.front().is_visible)
|
||||
ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap);
|
||||
for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++i) {
|
||||
std::map<wxString, wxBitmap*> nonsys_presets;
|
||||
wxString selected = "";
|
||||
if (!this->m_presets.front().is_visible)
|
||||
ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap);
|
||||
for (size_t i = this->m_presets.front().is_visible ? 0 : m_num_default_presets; i < this->m_presets.size(); ++i) {
|
||||
const Preset &preset = this->m_presets[i];
|
||||
if (! preset.is_visible || (! show_incompatible && ! preset.is_compatible && i != m_idx_selected))
|
||||
continue;
|
||||
std::string bitmap_key = "tab";
|
||||
bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
|
||||
bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
|
||||
wxBitmap *bmp = m_bitmap_cache->find(bitmap_key);
|
||||
if (bmp == nullptr) {
|
||||
// Create the bitmap with color bars.
|
||||
std::vector<wxBitmap> bmps;
|
||||
const wxBitmap* tmp_bmp = preset.is_compatible ? m_bitmap_compatible : m_bitmap_incompatible;
|
||||
bmps.emplace_back((tmp_bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *tmp_bmp);
|
||||
// Paint a lock at the system presets.
|
||||
bmps.emplace_back((preset.is_system || preset.is_default) ? *m_bitmap_lock : m_bitmap_cache->mkclear(icon_width, icon_height));
|
||||
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
|
||||
}
|
||||
std::string bitmap_key = "tab";
|
||||
bitmap_key += preset.is_compatible ? ",cmpt" : ",ncmpt";
|
||||
bitmap_key += (preset.is_system || preset.is_default) ? ",syst" : ",nsyst";
|
||||
wxBitmap *bmp = m_bitmap_cache->find(bitmap_key);
|
||||
if (bmp == nullptr) {
|
||||
// Create the bitmap with color bars.
|
||||
std::vector<wxBitmap> bmps;
|
||||
const wxBitmap* tmp_bmp = preset.is_compatible ? m_bitmap_compatible : m_bitmap_incompatible;
|
||||
bmps.emplace_back((tmp_bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *tmp_bmp);
|
||||
// Paint a lock at the system presets.
|
||||
bmps.emplace_back((preset.is_system || preset.is_default) ? *m_bitmap_lock : m_bitmap_cache->mkclear(icon_width, icon_height));
|
||||
bmp = m_bitmap_cache->insert(bitmap_key, bmps);
|
||||
}
|
||||
|
||||
if (preset.is_default || preset.is_system) {
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
|
||||
(bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
if (i == m_idx_selected)
|
||||
selected_preset_item = ui->GetCount() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), bmp/*preset.is_compatible*/);
|
||||
if (i == m_idx_selected)
|
||||
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str());
|
||||
}
|
||||
if (i + 1 == m_num_default_presets)
|
||||
ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap);
|
||||
if (preset.is_default || preset.is_system) {
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
|
||||
(bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
if (i == m_idx_selected)
|
||||
selected_preset_item = ui->GetCount() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), bmp/*preset.is_compatible*/);
|
||||
if (i == m_idx_selected)
|
||||
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str());
|
||||
}
|
||||
if (i + 1 == m_num_default_presets)
|
||||
ui->Append(PresetCollection::separator(L("System presets")), wxNullBitmap);
|
||||
}
|
||||
if (!nonsys_presets.empty())
|
||||
{
|
||||
ui->Append(PresetCollection::separator(L("User presets")), wxNullBitmap);
|
||||
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
|
||||
ui->Append(it->first, *it->second);
|
||||
if (it->first == selected)
|
||||
selected_preset_item = ui->GetCount() - 1;
|
||||
}
|
||||
}
|
||||
if (!nonsys_presets.empty())
|
||||
{
|
||||
ui->Append(PresetCollection::separator(L("User presets")), wxNullBitmap);
|
||||
for (std::map<wxString, wxBitmap*>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
|
||||
ui->Append(it->first, *it->second);
|
||||
if (it->first == selected)
|
||||
selected_preset_item = ui->GetCount() - 1;
|
||||
}
|
||||
}
|
||||
if (m_type == Preset::TYPE_PRINTER) {
|
||||
wxBitmap *bmp = m_bitmap_cache->find("add_printer_tab");
|
||||
if (bmp == nullptr) {
|
||||
|
@ -1119,10 +1120,10 @@ size_t PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompati
|
|||
}
|
||||
ui->Append(PresetCollection::separator("Add a new printer"), *bmp);
|
||||
}
|
||||
ui->SetSelection(selected_preset_item);
|
||||
ui->SetToolTip(ui->GetString(selected_preset_item));
|
||||
ui->SetSelection(selected_preset_item);
|
||||
ui->SetToolTip(ui->GetString(selected_preset_item));
|
||||
ui->Thaw();
|
||||
return selected_preset_item;
|
||||
return selected_preset_item;
|
||||
}
|
||||
|
||||
// Update a dirty floag of the current preset, update the labels of the UI component accordingly.
|
||||
|
@ -1142,11 +1143,11 @@ bool PresetCollection::update_dirty_ui(wxBitmapComboBox *ui)
|
|||
const Preset *preset = this->find_preset(preset_name, false);
|
||||
// The old_label could be the "----- system presets ------" or the "------- user presets --------" separator.
|
||||
// assert(preset != nullptr);
|
||||
if (preset != nullptr) {
|
||||
std::string new_label = preset->is_dirty ? preset->name + g_suffix_modified : preset->name;
|
||||
if (old_label != new_label)
|
||||
ui->SetString(ui_id, wxString::FromUTF8(new_label.c_str()));
|
||||
}
|
||||
if (preset != nullptr) {
|
||||
std::string new_label = preset->is_dirty ? preset->name + g_suffix_modified : preset->name;
|
||||
if (old_label != new_label)
|
||||
ui->SetString(ui_id, wxString::FromUTF8(new_label.c_str()));
|
||||
}
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
// wxWidgets on OSX do not upload the text of the combo box line automatically.
|
||||
|
@ -1159,15 +1160,15 @@ bool PresetCollection::update_dirty_ui(wxBitmapComboBox *ui)
|
|||
template<class T>
|
||||
void add_correct_opts_to_diff(const std::string &opt_key, t_config_option_keys& vec, const ConfigBase &other, const ConfigBase &this_c)
|
||||
{
|
||||
const T* opt_init = static_cast<const T*>(other.option(opt_key));
|
||||
const T* opt_cur = static_cast<const T*>(this_c.option(opt_key));
|
||||
int opt_init_max_id = opt_init->values.size() - 1;
|
||||
for (int i = 0; i < opt_cur->values.size(); i++)
|
||||
{
|
||||
int init_id = i <= opt_init_max_id ? i : 0;
|
||||
if (opt_cur->values[i] != opt_init->values[init_id])
|
||||
vec.emplace_back(opt_key + "#" + std::to_string(i));
|
||||
}
|
||||
const T* opt_init = static_cast<const T*>(other.option(opt_key));
|
||||
const T* opt_cur = static_cast<const T*>(this_c.option(opt_key));
|
||||
int opt_init_max_id = opt_init->values.size() - 1;
|
||||
for (int i = 0; i < opt_cur->values.size(); i++)
|
||||
{
|
||||
int init_id = i <= opt_init_max_id ? i : 0;
|
||||
if (opt_cur->values[i] != opt_init->values[init_id])
|
||||
vec.emplace_back(opt_key + "#" + std::to_string(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Use deep_diff to correct return of changed options, considering individual options for each extruder.
|
||||
|
@ -1201,10 +1202,10 @@ inline t_config_option_keys deep_diff(const ConfigBase &config_this, const Confi
|
|||
std::vector<std::string> PresetCollection::dirty_options(const Preset *edited, const Preset *reference, const bool deep_compare /*= false*/)
|
||||
{
|
||||
std::vector<std::string> changed;
|
||||
if (edited != nullptr && reference != nullptr) {
|
||||
if (edited != nullptr && reference != nullptr) {
|
||||
changed = deep_compare ?
|
||||
deep_diff(edited->config, reference->config) :
|
||||
reference->config.diff(edited->config);
|
||||
deep_diff(edited->config, reference->config) :
|
||||
reference->config.diff(edited->config);
|
||||
// The "compatible_printers" option key is handled differently from the others:
|
||||
// It is not mandatory. If the key is missing, it means it is compatible with any printer.
|
||||
// If the key exists and it is empty, it means it is compatible with no printer.
|
||||
|
@ -1227,19 +1228,19 @@ Preset& PresetCollection::select_preset(size_t idx)
|
|||
idx = first_visible_idx();
|
||||
m_idx_selected = idx;
|
||||
m_edited_preset = m_presets[idx];
|
||||
bool default_visible = ! m_default_suppressed || m_idx_selected < m_num_default_presets;
|
||||
for (size_t i = 0; i < m_num_default_presets; ++i)
|
||||
m_presets[i].is_visible = default_visible;
|
||||
bool default_visible = ! m_default_suppressed || m_idx_selected < m_num_default_presets;
|
||||
for (size_t i = 0; i < m_num_default_presets; ++i)
|
||||
m_presets[i].is_visible = default_visible;
|
||||
return m_presets[idx];
|
||||
}
|
||||
|
||||
bool PresetCollection::select_preset_by_name(const std::string &name_w_suffix, bool force)
|
||||
{
|
||||
{
|
||||
std::string name = Preset::remove_suffix_modified(name_w_suffix);
|
||||
// 1) Try to find the preset by its name.
|
||||
auto it = this->find_preset_internal(name);
|
||||
size_t idx = 0;
|
||||
if (it != m_presets.end() && it->name == name && it->is_visible)
|
||||
if (it != m_presets.end() && it->name == name && it->is_visible)
|
||||
// Preset found by its name and it is visible.
|
||||
idx = it - m_presets.begin();
|
||||
else {
|
||||
|
@ -1262,11 +1263,11 @@ bool PresetCollection::select_preset_by_name(const std::string &name_w_suffix, b
|
|||
}
|
||||
|
||||
bool PresetCollection::select_preset_by_name_strict(const std::string &name)
|
||||
{
|
||||
{
|
||||
// 1) Try to find the preset by its name.
|
||||
auto it = this->find_preset_internal(name);
|
||||
size_t idx = (size_t)-1;
|
||||
if (it != m_presets.end() && it->name == name && it->is_visible)
|
||||
if (it != m_presets.end() && it->name == name && it->is_visible)
|
||||
// Preset found by its name.
|
||||
idx = it - m_presets.begin();
|
||||
// 2) Select the new preset.
|
||||
|
@ -1333,9 +1334,9 @@ std::vector<std::string> PresetCollection::system_preset_names() const
|
|||
++ num;
|
||||
std::vector<std::string> out;
|
||||
out.reserve(num);
|
||||
for (const Preset &preset : m_presets)
|
||||
if (preset.is_system)
|
||||
out.emplace_back(preset.name);
|
||||
for (const Preset &preset : m_presets)
|
||||
if (preset.is_system)
|
||||
out.emplace_back(preset.name);
|
||||
std::sort(out.begin(), out.end());
|
||||
return out;
|
||||
}
|
||||
|
@ -1343,7 +1344,7 @@ std::vector<std::string> PresetCollection::system_preset_names() const
|
|||
// Generate a file path from a profile name. Add the ".ini" suffix if it is missing.
|
||||
std::string PresetCollection::path_from_name(const std::string &new_name) const
|
||||
{
|
||||
std::string file_name = boost::iends_with(new_name, ".ini") ? new_name : (new_name + ".ini");
|
||||
std::string file_name = boost::iends_with(new_name, ".ini") ? new_name : (new_name + ".ini");
|
||||
return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string();
|
||||
}
|
||||
|
||||
|
@ -1354,13 +1355,13 @@ void PresetCollection::clear_bitmap_cache()
|
|||
|
||||
wxString PresetCollection::separator(const std::string &label)
|
||||
{
|
||||
return wxString::FromUTF8(PresetCollection::separator_head()) + _(label) + wxString::FromUTF8(PresetCollection::separator_tail());
|
||||
return wxString::FromUTF8(PresetCollection::separator_head()) + _(label) + wxString::FromUTF8(PresetCollection::separator_tail());
|
||||
}
|
||||
|
||||
const Preset& PrinterPresetCollection::default_preset_for(const DynamicPrintConfig &config) const
|
||||
{
|
||||
const Preset& PrinterPresetCollection::default_preset_for(const DynamicPrintConfig &config) const
|
||||
{
|
||||
const ConfigOptionEnumGeneric *opt_printer_technology = config.opt<ConfigOptionEnumGeneric>("printer_technology");
|
||||
return this->default_preset((opt_printer_technology == nullptr || opt_printer_technology->value == ptFFF) ? 0 : 1);
|
||||
return this->default_preset((opt_printer_technology == nullptr || opt_printer_technology->value == ptFFF) ? 0 : 1);
|
||||
}
|
||||
|
||||
const Preset* PrinterPresetCollection::find_by_model_id(const std::string &model_id) const
|
||||
|
|
|
@ -100,6 +100,7 @@ void Selection::set_volumes(GLVolumePtrs* volumes)
|
|||
update_valid();
|
||||
}
|
||||
|
||||
// Init shall be called from the OpenGL render function, so that the OpenGL context is initialized!
|
||||
bool Selection::init()
|
||||
{
|
||||
if (!m_arrow.init())
|
||||
|
@ -1461,6 +1462,39 @@ std::vector<unsigned int> Selection::get_unselected_volume_idxs_from(const std::
|
|||
return idxs;
|
||||
}
|
||||
|
||||
void Selection::toggle_instance_printable_state()
|
||||
{
|
||||
int instance_idx = get_instance_idx();
|
||||
if (instance_idx == -1)
|
||||
return;
|
||||
|
||||
int obj_idx = get_object_idx();
|
||||
if ((0 <= obj_idx) && (obj_idx < (int)m_model->objects.size()))
|
||||
{
|
||||
ModelObject* model_object = m_model->objects[obj_idx];
|
||||
if ((0 <= instance_idx) && (instance_idx < (int)model_object->instances.size()))
|
||||
{
|
||||
ModelInstance* instance = model_object->instances[instance_idx];
|
||||
const bool printable = !instance->printable;
|
||||
|
||||
wxString snapshot_text = model_object->instances.size() == 1 ? wxString::Format("%s %s",
|
||||
printable ? _(L("Set Printable")) : _(L("Set Unprintable")), model_object->name) :
|
||||
printable ? _(L("Set Printable Instance")) : _(L("Set Unprintable Instance"));
|
||||
wxGetApp().plater()->take_snapshot(snapshot_text);
|
||||
|
||||
instance->printable = printable;
|
||||
|
||||
for (GLVolume* volume : *m_volumes)
|
||||
{
|
||||
if ((volume->object_idx() == obj_idx) && (volume->instance_idx() == instance_idx))
|
||||
volume->printable = instance->printable;
|
||||
}
|
||||
|
||||
wxGetApp().obj_list()->update_printable_state(obj_idx, instance_idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Selection::update_valid()
|
||||
{
|
||||
m_valid = (m_volumes != nullptr) && (m_model != nullptr);
|
||||
|
|
|
@ -336,6 +336,8 @@ public:
|
|||
// returns the list of idxs of the volumes contained in the given list but not in the selection
|
||||
std::vector<unsigned int> get_unselected_volume_idxs_from(const std::vector<unsigned int>& volume_idxs) const;
|
||||
|
||||
void toggle_instance_printable_state();
|
||||
|
||||
private:
|
||||
void update_valid();
|
||||
void update_type();
|
||||
|
|
|
@ -58,21 +58,19 @@ std::string get_mem_info(bool format_as_html)
|
|||
std::string b_end = format_as_html ? "</b>" : "";
|
||||
std::string line_end = format_as_html ? "<br>" : "\n";
|
||||
|
||||
const Slic3r::UndoRedo::Stack &stack = wxGetApp().plater()->undo_redo_stack_main();
|
||||
out << b_start << "RAM size reserved for the Undo / Redo stack [MB]: " << b_end << Slic3r::format_memsize_MB(stack.get_memory_limit()) << line_end;
|
||||
out << b_start << "RAM size occupied by the Undo / Redo stack [MB]: " << b_end << Slic3r::format_memsize_MB(stack.memsize()) << line_end << line_end;
|
||||
|
||||
#ifdef _WIN32
|
||||
HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, ::GetCurrentProcessId());
|
||||
if (hProcess != nullptr) {
|
||||
PROCESS_MEMORY_COUNTERS_EX pmc;
|
||||
if (GetProcessMemoryInfo(hProcess, (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)))
|
||||
out << b_start << "WorkingSet [MB]: " << b_end << format_memsize_MB(pmc.WorkingSetSize) << line_end
|
||||
<< b_start << "PrivateBytes [MB]: " << b_end << format_memsize_MB(pmc.PrivateUsage) << line_end
|
||||
<< b_start << "Pagefile(peak) [MB]: " << b_end << format_memsize_MB(pmc.PagefileUsage) << "(" << format_memsize_MB(pmc.PeakPagefileUsage) << ")" << line_end;
|
||||
CloseHandle(hProcess);
|
||||
std::string mem_info_str = log_memory_info(true);
|
||||
std::istringstream mem_info(mem_info_str);
|
||||
std::string value;
|
||||
while (std::getline(mem_info, value, ':')) {
|
||||
out << b_start << (value+": ") << b_end;
|
||||
std::getline(mem_info, value, ';');
|
||||
out << value << line_end;
|
||||
}
|
||||
#endif
|
||||
|
||||
const Slic3r::UndoRedo::Stack &stack = wxGetApp().plater()->undo_redo_stack_main();
|
||||
out << b_start << "RAM size reserved for the Undo / Redo stack: " << b_end << Slic3r::format_memsize_MB(stack.get_memory_limit()) << line_end;
|
||||
out << b_start << "RAM size occupied by the Undo / Redo stack: " << b_end << Slic3r::format_memsize_MB(stack.memsize()) << line_end << line_end;
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -218,7 +218,7 @@ protected:
|
|||
int m_em_unit;
|
||||
// To avoid actions with no-completed Tab
|
||||
bool m_complited { false };
|
||||
ConfigOptionMode m_mode = comSimple;
|
||||
ConfigOptionMode m_mode = comExpert; // to correct first Tab update_visibility() set mode to Expert
|
||||
|
||||
public:
|
||||
PresetBundle* m_preset_bundle;
|
||||
|
@ -340,6 +340,7 @@ class TabFilament : public Tab
|
|||
|
||||
void add_filament_overrides_page();
|
||||
void update_filament_overrides_page();
|
||||
void update_volumetric_flow_preset_hints();
|
||||
|
||||
std::map<std::string, wxCheckBox*> m_overrides_options;
|
||||
public:
|
||||
|
|
|
@ -157,6 +157,24 @@ wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string,
|
|||
return item;
|
||||
}
|
||||
|
||||
wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
|
||||
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler)
|
||||
{
|
||||
if (id == wxID_ANY)
|
||||
id = wxNewId();
|
||||
|
||||
wxMenuItem* item = menu->AppendCheckItem(id, string, description);
|
||||
|
||||
#ifdef __WXMSW__
|
||||
if (event_handler != nullptr && event_handler != menu)
|
||||
event_handler->Bind(wxEVT_MENU, cb, id);
|
||||
else
|
||||
#endif // __WXMSW__
|
||||
menu->Bind(wxEVT_MENU, cb, id);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
const unsigned int wxCheckListBoxComboPopup::DefaultWidth = 200;
|
||||
const unsigned int wxCheckListBoxComboPopup::DefaultHeight = 200;
|
||||
const unsigned int wxCheckListBoxComboPopup::DefaultItemHeight = 18;
|
||||
|
@ -432,6 +450,16 @@ wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in,
|
|||
// ObjectDataViewModelNode
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
void ObjectDataViewModelNode::init_container()
|
||||
{
|
||||
#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__
|
||||
}
|
||||
|
||||
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type) :
|
||||
m_parent(parent),
|
||||
m_type(type),
|
||||
|
@ -454,13 +482,8 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
|
|||
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__
|
||||
init_container();
|
||||
}
|
||||
|
||||
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
||||
|
@ -486,14 +509,8 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
|
|||
m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
|
||||
m_bmp = create_scaled_bitmap(nullptr, "edit_layers_some"); // 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();
|
||||
init_container();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
|
@ -512,6 +529,13 @@ void ObjectDataViewModelNode::set_action_icon()
|
|||
m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name); // FIXME: pass window ptr
|
||||
}
|
||||
|
||||
void ObjectDataViewModelNode::set_printable_icon(PrintIndicator printable)
|
||||
{
|
||||
m_printable = printable;
|
||||
m_printable_icon = m_printable == piUndef ? m_empty_bmp :
|
||||
create_scaled_bitmap(nullptr, m_printable == piPrintable ? "eye_open.png" : "eye_closed.png");
|
||||
}
|
||||
|
||||
Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr;
|
||||
void ObjectDataViewModelNode::update_settings_digest_bitmaps()
|
||||
{
|
||||
|
@ -565,17 +589,20 @@ bool ObjectDataViewModelNode::SetValue(const wxVariant& variant, unsigned col)
|
|||
{
|
||||
switch (col)
|
||||
{
|
||||
case 0: {
|
||||
case colPrint:
|
||||
m_printable_icon << variant;
|
||||
return true;
|
||||
case colName: {
|
||||
DataViewBitmapText data;
|
||||
data << variant;
|
||||
m_bmp = data.GetBitmap();
|
||||
m_name = data.GetText();
|
||||
return true; }
|
||||
case 1: {
|
||||
case colExtruder: {
|
||||
const wxString & val = variant.GetString();
|
||||
m_extruder = val == "0" ? _(L("default")) : val;
|
||||
return true; }
|
||||
case 2:
|
||||
case colEditing:
|
||||
m_action_icon << variant;
|
||||
return true;
|
||||
default:
|
||||
|
@ -735,26 +762,60 @@ static bool append_root_node(ObjectDataViewModelNode *parent_node,
|
|||
return false;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
|
||||
wxDataViewItem ObjectDataViewModel::AddRoot(const wxDataViewItem &parent_item, ItemType root_type)
|
||||
{
|
||||
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
if (!parent_node) return wxDataViewItem(0);
|
||||
|
||||
// get InstanceRoot node
|
||||
ObjectDataViewModelNode *inst_root_node { nullptr };
|
||||
ObjectDataViewModelNode *root_node { nullptr };
|
||||
const bool appended = append_root_node(parent_node, &root_node, root_type);
|
||||
if (!root_node) return wxDataViewItem(0);
|
||||
|
||||
const bool appended = append_root_node(parent_node, &inst_root_node, itInstanceRoot);
|
||||
const wxDataViewItem inst_root_item((void*)inst_root_node);
|
||||
if (!inst_root_node) return wxDataViewItem(0);
|
||||
const wxDataViewItem root_item((void*)root_node);
|
||||
|
||||
if (appended)
|
||||
ItemAdded(parent_item, inst_root_item);// notify control
|
||||
ItemAdded(parent_item, root_item);// notify control
|
||||
return root_item;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddInstanceRoot(const wxDataViewItem &parent_item)
|
||||
{
|
||||
return AddRoot(parent_item, itInstanceRoot);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
|
||||
{
|
||||
const std::vector<bool> print_indicator(num, true);
|
||||
|
||||
return wxDataViewItem((void*)AddInstanceChild(parent_item, print_indicator));
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem& parent_item,
|
||||
const std::vector<bool>& print_indicator)
|
||||
{
|
||||
const wxDataViewItem inst_root_item = AddInstanceRoot(parent_item);
|
||||
if (!inst_root_item) return wxDataViewItem(0);
|
||||
|
||||
ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID();
|
||||
|
||||
const bool just_created = inst_root_node->GetChildren().Count() == 0;
|
||||
|
||||
// Add instance nodes
|
||||
ObjectDataViewModelNode *instance_node = nullptr;
|
||||
size_t counter = 0;
|
||||
while (counter < num) {
|
||||
while (counter < print_indicator.size()) {
|
||||
instance_node = new ObjectDataViewModelNode(inst_root_node, itInstance);
|
||||
|
||||
// if InstanceRoot item is just created and start to adding Instances
|
||||
if (just_created && counter == 0) {
|
||||
ObjectDataViewModelNode* obj_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
// use object's printable state to first instance
|
||||
instance_node->set_printable_icon(obj_node->IsPrintable());
|
||||
}
|
||||
else
|
||||
instance_node->set_printable_icon(print_indicator[counter] ? piPrintable : piUnprintable);
|
||||
|
||||
inst_root_node->Append(instance_node);
|
||||
// notify control
|
||||
const wxDataViewItem instance_item((void*)instance_node);
|
||||
|
@ -762,25 +823,67 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
|
|||
++counter;
|
||||
}
|
||||
|
||||
// update object_node printable property
|
||||
UpdateObjectPrintable(parent_item);
|
||||
|
||||
return wxDataViewItem((void*)instance_node);
|
||||
}
|
||||
|
||||
void ObjectDataViewModel::UpdateObjectPrintable(wxDataViewItem parent_item)
|
||||
{
|
||||
const wxDataViewItem inst_root_item = GetInstanceRootItem(parent_item);
|
||||
if (!inst_root_item)
|
||||
return;
|
||||
|
||||
ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID();
|
||||
|
||||
const size_t child_cnt = inst_root_node->GetChildren().Count();
|
||||
PrintIndicator obj_pi = piUnprintable;
|
||||
for (size_t i=0; i < child_cnt; i++)
|
||||
if (inst_root_node->GetNthChild(i)->IsPrintable() & piPrintable) {
|
||||
obj_pi = piPrintable;
|
||||
break;
|
||||
}
|
||||
// and set printable state for object_node to piUndef
|
||||
ObjectDataViewModelNode* obj_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
obj_node->set_printable_icon(obj_pi);
|
||||
ItemChanged(parent_item);
|
||||
}
|
||||
|
||||
// update printable property for all instances from object
|
||||
void ObjectDataViewModel::UpdateInstancesPrintable(wxDataViewItem parent_item)
|
||||
{
|
||||
const wxDataViewItem inst_root_item = GetInstanceRootItem(parent_item);
|
||||
if (!inst_root_item)
|
||||
return;
|
||||
|
||||
ObjectDataViewModelNode* obj_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
const PrintIndicator obj_pi = obj_node->IsPrintable();
|
||||
|
||||
ObjectDataViewModelNode* inst_root_node = (ObjectDataViewModelNode*)inst_root_item.GetID();
|
||||
const size_t child_cnt = inst_root_node->GetChildren().Count();
|
||||
|
||||
for (size_t i=0; i < child_cnt; i++)
|
||||
{
|
||||
ObjectDataViewModelNode* inst_node = inst_root_node->GetNthChild(i);
|
||||
// and set printable state for object_node to piUndef
|
||||
inst_node->set_printable_icon(obj_pi);
|
||||
ItemChanged(wxDataViewItem((void*)inst_node));
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectDataViewModel::IsPrintable(const wxDataViewItem& item) const
|
||||
{
|
||||
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID();
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
return node->IsPrintable() == piPrintable;
|
||||
}
|
||||
|
||||
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;
|
||||
return AddRoot(parent_item, itLayerRoot);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item,
|
||||
|
@ -878,11 +981,13 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
|||
ItemDeleted(parent, item);
|
||||
|
||||
ObjectDataViewModelNode *last_instance_node = node_parent->GetNthChild(0);
|
||||
PrintIndicator last_instance_printable = last_instance_node->IsPrintable();
|
||||
node_parent->GetChildren().Remove(last_instance_node);
|
||||
delete last_instance_node;
|
||||
ItemDeleted(parent, wxDataViewItem(last_instance_node));
|
||||
|
||||
ObjectDataViewModelNode *obj_node = node_parent->GetParent();
|
||||
obj_node->set_printable_icon(last_instance_printable);
|
||||
obj_node->GetChildren().Remove(node_parent);
|
||||
delete node_parent;
|
||||
ret_item = wxDataViewItem(obj_node);
|
||||
|
@ -895,6 +1000,9 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
|||
return ret_item;
|
||||
}
|
||||
|
||||
if (node->m_type & itInstance)
|
||||
UpdateObjectPrintable(wxDataViewItem(node_parent->GetParent()));
|
||||
|
||||
// if there was last layer item, delete this one and layers root item
|
||||
if (node_parent->GetChildCount() == 0 && node_parent->m_type == itLayerRoot)
|
||||
{
|
||||
|
@ -1004,9 +1112,12 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par
|
|||
const int inst_cnt = inst_root_node->GetChildCount();
|
||||
const bool delete_inst_root_item = inst_cnt - num < 2 ? true : false;
|
||||
|
||||
PrintIndicator last_inst_printable = piUndef;
|
||||
|
||||
int stop = delete_inst_root_item ? 0 : inst_cnt - num;
|
||||
for (int i = inst_cnt - 1; i >= stop;--i) {
|
||||
ObjectDataViewModelNode *last_instance_node = inst_root_node->GetNthChild(i);
|
||||
if (i==0) last_inst_printable = last_instance_node->IsPrintable();
|
||||
inst_root_node->GetChildren().Remove(last_instance_node);
|
||||
delete last_instance_node;
|
||||
ItemDeleted(inst_root_item, wxDataViewItem(last_instance_node));
|
||||
|
@ -1015,13 +1126,18 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par
|
|||
if (delete_inst_root_item) {
|
||||
ret_item = parent_item;
|
||||
parent_node->GetChildren().Remove(inst_root_node);
|
||||
parent_node->set_printable_icon(last_inst_printable);
|
||||
ItemDeleted(parent_item, inst_root_item);
|
||||
ItemChanged(parent_item);
|
||||
#ifndef __WXGTK__
|
||||
if (parent_node->GetChildCount() == 0)
|
||||
parent_node->m_container = false;
|
||||
#endif //__WXGTK__
|
||||
}
|
||||
|
||||
// update object_node printable property
|
||||
UpdateObjectPrintable(parent_item);
|
||||
|
||||
return ret_item;
|
||||
}
|
||||
|
||||
|
@ -1325,6 +1441,18 @@ int ObjectDataViewModel::GetRowByItem(const wxDataViewItem& item) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
bool ObjectDataViewModel::InvalidItem(const wxDataViewItem& item)
|
||||
{
|
||||
if (!item)
|
||||
return true;
|
||||
|
||||
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID();
|
||||
if (!node || node->invalid())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxString ObjectDataViewModel::GetName(const wxDataViewItem &item) const
|
||||
{
|
||||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||
|
@ -1347,13 +1475,16 @@ void ObjectDataViewModel::GetValue(wxVariant &variant, const wxDataViewItem &ite
|
|||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||
switch (col)
|
||||
{
|
||||
case 0:
|
||||
case colPrint:
|
||||
variant << node->m_printable_icon;
|
||||
break;
|
||||
case colName:
|
||||
variant << DataViewBitmapText(node->m_name, node->m_bmp);
|
||||
break;
|
||||
case 1:
|
||||
case colExtruder:
|
||||
variant = node->m_extruder;
|
||||
break;
|
||||
case 2:
|
||||
case colEditing:
|
||||
variant << node->m_action_icon;
|
||||
break;
|
||||
default:
|
||||
|
@ -1416,7 +1547,7 @@ bool ObjectDataViewModel::IsEnabled(const wxDataViewItem &item, unsigned int col
|
|||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||
|
||||
// disable extruder selection for the non "itObject|itVolume" item
|
||||
return !(col == 1 && node->m_extruder.IsEmpty());
|
||||
return !(col == colExtruder && node->m_extruder.IsEmpty());
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetParent(const wxDataViewItem &item) const
|
||||
|
@ -1581,6 +1712,46 @@ void ObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const Slic3r
|
|||
ItemChanged(item);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::SetPrintableState(
|
||||
PrintIndicator printable,
|
||||
int obj_idx,
|
||||
int subobj_idx /* = -1*/,
|
||||
ItemType subobj_type/* = itInstance*/)
|
||||
{
|
||||
wxDataViewItem item = wxDataViewItem(0);
|
||||
if (subobj_idx < 0)
|
||||
item = GetItemById(obj_idx);
|
||||
else
|
||||
item = subobj_type&itInstance ? GetItemByInstanceId(obj_idx, subobj_idx) :
|
||||
GetItemByVolumeId(obj_idx, subobj_idx);
|
||||
|
||||
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)item.GetID();
|
||||
if (!node)
|
||||
return wxDataViewItem(0);
|
||||
node->set_printable_icon(printable);
|
||||
ItemChanged(item);
|
||||
|
||||
if (subobj_idx >= 0)
|
||||
UpdateObjectPrintable(GetItemById(obj_idx));
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::SetObjectPrintableState(
|
||||
PrintIndicator printable,
|
||||
wxDataViewItem obj_item)
|
||||
{
|
||||
ObjectDataViewModelNode* node = (ObjectDataViewModelNode*)obj_item.GetID();
|
||||
if (!node)
|
||||
return wxDataViewItem(0);
|
||||
node->set_printable_icon(printable);
|
||||
ItemChanged(obj_item);
|
||||
|
||||
UpdateInstancesPrintable(obj_item);
|
||||
|
||||
return obj_item;
|
||||
}
|
||||
|
||||
void ObjectDataViewModel::Rescale()
|
||||
{
|
||||
wxDataViewItemArray all_items;
|
||||
|
@ -1765,7 +1936,7 @@ bool BitmapTextRenderer::GetValueFromEditorCtrl(wxWindow* ctrl, wxVariant& value
|
|||
|
||||
// The icon can't be edited so get its old value and reuse it.
|
||||
wxVariant valueOld;
|
||||
GetView()->GetModel()->GetValue(valueOld, m_item, 0);
|
||||
GetView()->GetModel()->GetValue(valueOld, m_item, colName);
|
||||
|
||||
DataViewBitmapText bmpText;
|
||||
bmpText << valueOld;
|
||||
|
|
|
@ -44,6 +44,9 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin
|
|||
wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
|
||||
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler);
|
||||
|
||||
wxMenuItem* append_menu_check_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
|
||||
std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler);
|
||||
|
||||
class wxDialog;
|
||||
void edit_tooltip(wxString& tooltip);
|
||||
void msw_buttons_rescale(wxDialog* dlg, const int em_unit, const std::vector<int>& btn_ids);
|
||||
|
@ -173,6 +176,21 @@ enum ItemType {
|
|||
itLayer = 64,
|
||||
};
|
||||
|
||||
enum ColumnNumber
|
||||
{
|
||||
colName = 0, // item name
|
||||
colPrint , // printable property
|
||||
colExtruder , // extruder selection
|
||||
colEditing , // item editing
|
||||
};
|
||||
|
||||
enum PrintIndicator
|
||||
{
|
||||
piUndef = 0, // no print indicator
|
||||
piPrintable , // printable
|
||||
piUnprintable , // unprintable
|
||||
};
|
||||
|
||||
class ObjectDataViewModelNode;
|
||||
WX_DEFINE_ARRAY_PTR(ObjectDataViewModelNode*, MyObjectTreeModelNodePtrArray);
|
||||
|
||||
|
@ -192,6 +210,8 @@ class ObjectDataViewModelNode
|
|||
bool m_container = false;
|
||||
wxString m_extruder = "default";
|
||||
wxBitmap m_action_icon;
|
||||
PrintIndicator m_printable {piUndef};
|
||||
wxBitmap m_printable_icon;
|
||||
|
||||
std::string m_action_icon_name = "";
|
||||
Slic3r::ModelVolumeType m_volume_type;
|
||||
|
@ -204,15 +224,9 @@ public:
|
|||
m_type(itObject),
|
||||
m_extruder(extruder)
|
||||
{
|
||||
#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();
|
||||
}
|
||||
init_container();
|
||||
}
|
||||
|
||||
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
||||
const wxString& sub_obj_name,
|
||||
|
@ -226,14 +240,8 @@ public:
|
|||
m_extruder (extruder)
|
||||
{
|
||||
m_bmp = bmp;
|
||||
#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();
|
||||
init_container();
|
||||
}
|
||||
|
||||
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
||||
|
@ -258,10 +266,11 @@ public:
|
|||
#endif /* NDEBUG */
|
||||
}
|
||||
|
||||
bool IsContainer() const
|
||||
{
|
||||
return m_container;
|
||||
}
|
||||
void init_container();
|
||||
bool IsContainer() const
|
||||
{
|
||||
return m_container;
|
||||
}
|
||||
|
||||
ObjectDataViewModelNode* GetParent()
|
||||
{
|
||||
|
@ -313,9 +322,10 @@ public:
|
|||
const wxBitmap& GetBitmap() const { return m_bmp; }
|
||||
const wxString& GetName() const { return m_name; }
|
||||
ItemType GetType() const { return m_type; }
|
||||
void SetIdx(const int& idx);
|
||||
int GetIdx() const { return m_idx; }
|
||||
t_layer_height_range GetLayerRange() const { return m_layer_range; }
|
||||
void SetIdx(const int& idx);
|
||||
int GetIdx() const { return m_idx; }
|
||||
t_layer_height_range GetLayerRange() const { return m_layer_range; }
|
||||
PrintIndicator IsPrintable() const { return m_printable; }
|
||||
|
||||
// use this function only for childrens
|
||||
void AssignAllVal(ObjectDataViewModelNode& from_node)
|
||||
|
@ -347,6 +357,8 @@ public:
|
|||
|
||||
// Set action icons for node
|
||||
void set_action_icon();
|
||||
// Set printable icon for node
|
||||
void set_printable_icon(PrintIndicator printable);
|
||||
|
||||
void update_settings_digest_bitmaps();
|
||||
bool update_settings_digest(const std::vector<std::string>& categories);
|
||||
|
@ -356,6 +368,7 @@ public:
|
|||
#ifndef NDEBUG
|
||||
bool valid();
|
||||
#endif /* NDEBUG */
|
||||
bool invalid() const { return m_idx < -1; }
|
||||
|
||||
private:
|
||||
friend class ObjectDataViewModel;
|
||||
|
@ -391,6 +404,7 @@ public:
|
|||
const bool create_frst_child = true);
|
||||
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
|
||||
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
|
||||
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, const std::vector<bool>& print_indicator);
|
||||
wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
|
||||
wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item,
|
||||
const t_layer_height_range& layer_range,
|
||||
|
@ -418,6 +432,7 @@ public:
|
|||
void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
|
||||
int GetRowByItem(const wxDataViewItem& item) const;
|
||||
bool IsEmpty() { return m_objects.empty(); }
|
||||
bool InvalidItem(const wxDataViewItem& item);
|
||||
|
||||
// helper method for wxLog
|
||||
|
||||
|
@ -468,9 +483,17 @@ public:
|
|||
void UpdateSettingsDigest( const wxDataViewItem &item,
|
||||
const std::vector<std::string>& categories);
|
||||
|
||||
bool IsPrintable(const wxDataViewItem &item) const;
|
||||
void UpdateObjectPrintable(wxDataViewItem parent_item);
|
||||
void UpdateInstancesPrintable(wxDataViewItem parent_item);
|
||||
|
||||
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
|
||||
void SetWarningBitmap(wxBitmap* bitmap) { m_warning_bmp = bitmap; }
|
||||
void SetVolumeType(const wxDataViewItem &item, const Slic3r::ModelVolumeType type);
|
||||
wxDataViewItem SetPrintableState( PrintIndicator printable, int obj_idx,
|
||||
int subobj_idx = -1,
|
||||
ItemType subobj_type = itInstance);
|
||||
wxDataViewItem SetObjectPrintableState(PrintIndicator printable, wxDataViewItem obj_item);
|
||||
|
||||
void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; }
|
||||
// Rescale bitmaps for existing Items
|
||||
|
@ -480,6 +503,10 @@ public:
|
|||
const bool is_marked = false);
|
||||
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
|
||||
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
|
||||
|
||||
private:
|
||||
wxDataViewItem AddRoot(const wxDataViewItem& parent_item, const ItemType root_type);
|
||||
wxDataViewItem AddInstanceRoot(const wxDataViewItem& parent_item);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue