mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-26 10:11:10 -06:00
Merge branch 'master' into ys_overrides
This commit is contained in:
commit
8112d80fa2
159 changed files with 10096 additions and 5248 deletions
|
|
@ -81,6 +81,8 @@ set(SLIC3R_GUI_SOURCES
|
|||
GUI/GUI_ObjectManipulation.hpp
|
||||
GUI/GUI_ObjectSettings.cpp
|
||||
GUI/GUI_ObjectSettings.hpp
|
||||
GUI/GUI_ObjectLayers.cpp
|
||||
GUI/GUI_ObjectLayers.hpp
|
||||
GUI/LambdaObjectDialog.cpp
|
||||
GUI/LambdaObjectDialog.hpp
|
||||
GUI/Tab.cpp
|
||||
|
|
@ -146,6 +148,8 @@ set(SLIC3R_GUI_SOURCES
|
|||
Utils/PresetUpdater.hpp
|
||||
Utils/Time.cpp
|
||||
Utils/Time.hpp
|
||||
Utils/UndoRedo.cpp
|
||||
Utils/UndoRedo.hpp
|
||||
Utils/HexFile.cpp
|
||||
Utils/HexFile.hpp
|
||||
)
|
||||
|
|
@ -159,7 +163,7 @@ endif ()
|
|||
|
||||
add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
|
||||
|
||||
target_link_libraries(libslic3r_gui libslic3r avrdude imgui ${GLEW_LIBRARIES})
|
||||
target_link_libraries(libslic3r_gui libslic3r avrdude cereal imgui ${GLEW_LIBRARIES})
|
||||
if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY)
|
||||
add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE)
|
||||
endif ()
|
||||
|
|
|
|||
|
|
@ -274,8 +274,8 @@ void Bed3D::Axes::render_axis(double length) const
|
|||
|
||||
Bed3D::Bed3D()
|
||||
: m_type(Custom)
|
||||
, m_requires_canvas_update(false)
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
, m_requires_canvas_update(false)
|
||||
, m_vbo_id(0)
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
, m_scale_factor(1.0f)
|
||||
|
|
@ -330,12 +330,11 @@ Point Bed3D::point_projection(const Point& point) const
|
|||
}
|
||||
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
void Bed3D::render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_factor) const
|
||||
void Bed3D::render(GLCanvas3D* canvas, float theta, float scale_factor) const
|
||||
{
|
||||
m_scale_factor = scale_factor;
|
||||
|
||||
EType type = useVBOs ? m_type : Custom;
|
||||
switch (type)
|
||||
switch (m_type)
|
||||
{
|
||||
case MK2:
|
||||
{
|
||||
|
|
@ -361,7 +360,7 @@ void Bed3D::render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_fa
|
|||
}
|
||||
}
|
||||
#else
|
||||
void Bed3D::render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_factor) const
|
||||
void Bed3D::render(float theta, float scale_factor) const
|
||||
{
|
||||
m_scale_factor = scale_factor;
|
||||
|
||||
|
|
@ -372,17 +371,17 @@ void Bed3D::render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_fa
|
|||
{
|
||||
case MK2:
|
||||
{
|
||||
render_prusa(canvas, "mk2", theta, useVBOs);
|
||||
render_prusa("mk2", theta);
|
||||
break;
|
||||
}
|
||||
case MK3:
|
||||
{
|
||||
render_prusa(canvas, "mk3", theta, useVBOs);
|
||||
render_prusa("mk3", theta);
|
||||
break;
|
||||
}
|
||||
case SL1:
|
||||
{
|
||||
render_prusa(canvas, "sl1", theta, useVBOs);
|
||||
render_prusa("sl1", theta);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -546,7 +545,7 @@ void Bed3D::render_prusa(GLCanvas3D* canvas, const std::string &key, bool bottom
|
|||
if (!bottom)
|
||||
{
|
||||
filename = model_path + "_bed.stl";
|
||||
if ((m_model.get_filename() != filename) && m_model.init_from_file(filename, true)) {
|
||||
if ((m_model.get_filename() != filename) && m_model.init_from_file(filename)) {
|
||||
Vec3d offset = m_bounding_box.center() - Vec3d(0.0, 0.0, 0.5 * m_model.get_bounding_box().size()(2));
|
||||
if (key == "mk2")
|
||||
// hardcoded value to match the stl model
|
||||
|
|
@ -628,12 +627,12 @@ void Bed3D::render_prusa_shader(bool transparent) const
|
|||
if (position_id != -1)
|
||||
{
|
||||
glsafe(::glEnableVertexAttribArray(position_id));
|
||||
glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_position_offset()));
|
||||
glsafe(::glVertexAttribPointer(position_id, 3, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_position_offset()));
|
||||
}
|
||||
if (tex_coords_id != -1)
|
||||
{
|
||||
glsafe(::glEnableVertexAttribArray(tex_coords_id));
|
||||
glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)m_triangles.get_tex_coords_offset()));
|
||||
glsafe(::glVertexAttribPointer(tex_coords_id, 2, GL_FLOAT, GL_FALSE, stride, (GLvoid*)(intptr_t)m_triangles.get_tex_coords_offset()));
|
||||
}
|
||||
|
||||
glsafe(::glDrawArrays(GL_TRIANGLES, 0, (GLsizei)m_triangles.get_vertices_count()));
|
||||
|
|
@ -651,7 +650,7 @@ void Bed3D::render_prusa_shader(bool transparent) const
|
|||
}
|
||||
}
|
||||
#else
|
||||
void Bed3D::render_prusa(const std::string &key, float theta, bool useVBOs) const
|
||||
void Bed3D::render_prusa(const std::string& key, float theta) const
|
||||
{
|
||||
std::string tex_path = resources_dir() + "/icons/bed/" + key;
|
||||
|
||||
|
|
@ -677,7 +676,7 @@ void Bed3D::render_prusa(const std::string &key, float theta, bool useVBOs) cons
|
|||
std::string filename = tex_path + "_top.png";
|
||||
if ((m_top_texture.get_id() == 0) || (m_top_texture.get_source() != filename))
|
||||
{
|
||||
if (!m_top_texture.load_from_file(filename, true))
|
||||
if (!m_top_texture.load_from_file(filename, true, true))
|
||||
{
|
||||
render_custom();
|
||||
return;
|
||||
|
|
@ -694,7 +693,7 @@ void Bed3D::render_prusa(const std::string &key, float theta, bool useVBOs) cons
|
|||
filename = tex_path + "_bottom.png";
|
||||
if ((m_bottom_texture.get_id() == 0) || (m_bottom_texture.get_source() != filename))
|
||||
{
|
||||
if (!m_bottom_texture.load_from_file(filename, true))
|
||||
if (!m_bottom_texture.load_from_file(filename, true, true))
|
||||
{
|
||||
render_custom();
|
||||
return;
|
||||
|
|
@ -711,7 +710,7 @@ void Bed3D::render_prusa(const std::string &key, float theta, bool useVBOs) cons
|
|||
if (theta <= 90.0f)
|
||||
{
|
||||
filename = model_path + "_bed.stl";
|
||||
if ((m_model.get_filename() != filename) && m_model.init_from_file(filename, useVBOs)) {
|
||||
if ((m_model.get_filename() != filename) && m_model.init_from_file(filename)) {
|
||||
Vec3d offset = m_bounding_box.center() - Vec3d(0.0, 0.0, 0.5 * m_model.get_bounding_box().size()(2));
|
||||
if (key == "mk2")
|
||||
// hardcoded value to match the stl model
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@ public:
|
|||
const float* get_vertices_data() const;
|
||||
unsigned int get_vertices_data_size() const { return (unsigned int)m_vertices.size() * get_vertex_data_size(); }
|
||||
unsigned int get_vertex_data_size() const { return (unsigned int)(5 * sizeof(float)); }
|
||||
unsigned int get_position_offset() const { return 0; }
|
||||
unsigned int get_tex_coords_offset() const { return (unsigned int)(3 * sizeof(float)); }
|
||||
size_t get_position_offset() const { return 0; }
|
||||
size_t get_tex_coords_offset() const { return (size_t)(3 * sizeof(float)); }
|
||||
unsigned int get_vertices_count() const { return (unsigned int)m_vertices.size(); }
|
||||
#else
|
||||
const float* get_vertices() const { return m_vertices.data(); }
|
||||
|
|
@ -128,7 +128,11 @@ public:
|
|||
bool contains(const Point& point) const;
|
||||
Point point_projection(const Point& point) const;
|
||||
|
||||
void render(GLCanvas3D* canvas, float theta, bool useVBOs, float scale_factor) const;
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
void render(GLCanvas3D* canvas, float theta, float scale_factor) const;
|
||||
#else
|
||||
void render(float theta, float scale_factor) const;
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
void render_axes() const;
|
||||
|
||||
private:
|
||||
|
|
@ -140,7 +144,7 @@ private:
|
|||
void render_prusa(GLCanvas3D* canvas, const std::string& key, bool bottom) const;
|
||||
void render_prusa_shader(bool transparent) const;
|
||||
#else
|
||||
void render_prusa(const std::string &key, float theta, bool useVBOs) const;
|
||||
void render_prusa(const std::string& key, float theta) const;
|
||||
#endif // ENABLE_TEXTURES_FROM_SVG
|
||||
void render_custom() const;
|
||||
#if ENABLE_TEXTURES_FROM_SVG
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -56,7 +56,7 @@ public:
|
|||
vertices_and_normals_interleaved_VBO_id(0),
|
||||
triangle_indices_VBO_id(0),
|
||||
quad_indices_VBO_id(0)
|
||||
{ this->setup_sizes(); }
|
||||
{}
|
||||
GLIndexedVertexArray(const GLIndexedVertexArray &rhs) :
|
||||
vertices_and_normals_interleaved(rhs.vertices_and_normals_interleaved),
|
||||
triangle_indices(rhs.triangle_indices),
|
||||
|
|
@ -64,7 +64,7 @@ public:
|
|||
vertices_and_normals_interleaved_VBO_id(0),
|
||||
triangle_indices_VBO_id(0),
|
||||
quad_indices_VBO_id(0)
|
||||
{ this->setup_sizes(); }
|
||||
{}
|
||||
GLIndexedVertexArray(GLIndexedVertexArray &&rhs) :
|
||||
vertices_and_normals_interleaved(std::move(rhs.vertices_and_normals_interleaved)),
|
||||
triangle_indices(std::move(rhs.triangle_indices)),
|
||||
|
|
@ -72,7 +72,9 @@ public:
|
|||
vertices_and_normals_interleaved_VBO_id(0),
|
||||
triangle_indices_VBO_id(0),
|
||||
quad_indices_VBO_id(0)
|
||||
{ this->setup_sizes(); }
|
||||
{}
|
||||
|
||||
~GLIndexedVertexArray() { release_geometry(); }
|
||||
|
||||
GLIndexedVertexArray& operator=(const GLIndexedVertexArray &rhs)
|
||||
{
|
||||
|
|
@ -82,7 +84,10 @@ public:
|
|||
this->vertices_and_normals_interleaved = rhs.vertices_and_normals_interleaved;
|
||||
this->triangle_indices = rhs.triangle_indices;
|
||||
this->quad_indices = rhs.quad_indices;
|
||||
this->setup_sizes();
|
||||
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;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
|
@ -94,30 +99,32 @@ public:
|
|||
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->setup_sizes();
|
||||
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;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Vertices and their normals, interleaved to be used by void glInterleavedArrays(GL_N3F_V3F, 0, x)
|
||||
std::vector<float> vertices_and_normals_interleaved;
|
||||
std::vector<int> triangle_indices;
|
||||
std::vector<int> quad_indices;
|
||||
mutable std::vector<float> vertices_and_normals_interleaved;
|
||||
mutable std::vector<int> triangle_indices;
|
||||
mutable 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.
|
||||
size_t vertices_and_normals_interleaved_size;
|
||||
size_t triangle_indices_size;
|
||||
size_t quad_indices_size;
|
||||
size_t vertices_and_normals_interleaved_size{ 0 };
|
||||
size_t triangle_indices_size{ 0 };
|
||||
size_t quad_indices_size{ 0 };
|
||||
|
||||
// IDs of the Vertex Array Objects, into which the geometry has been loaded.
|
||||
// Zero if the VBOs are not used.
|
||||
unsigned int vertices_and_normals_interleaved_VBO_id;
|
||||
unsigned int triangle_indices_VBO_id;
|
||||
unsigned int quad_indices_VBO_id;
|
||||
// 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 };
|
||||
|
||||
void load_mesh_flat_shading(const TriangleMesh &mesh);
|
||||
void load_mesh_full_shading(const TriangleMesh &mesh);
|
||||
void load_mesh(const TriangleMesh &mesh, bool use_VBOs) { use_VBOs ? this->load_mesh_full_shading(mesh) : this->load_mesh_flat_shading(mesh); }
|
||||
void load_mesh(const TriangleMesh& mesh) { this->load_mesh_full_shading(mesh); }
|
||||
|
||||
inline bool has_VBOs() const { return vertices_and_normals_interleaved_VBO_id != 0; }
|
||||
|
||||
|
|
@ -128,6 +135,10 @@ public:
|
|||
}
|
||||
|
||||
inline void push_geometry(float x, float y, float z, float nx, float ny, float nz) {
|
||||
assert(this->vertices_and_normals_interleaved_VBO_id == 0);
|
||||
if (this->vertices_and_normals_interleaved_VBO_id != 0)
|
||||
return;
|
||||
|
||||
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);
|
||||
|
|
@ -136,6 +147,9 @@ public:
|
|||
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_size = this->vertices_and_normals_interleaved.size();
|
||||
m_bounding_box.merge(Vec3f(x, y, z).cast<double>());
|
||||
};
|
||||
|
||||
inline void push_geometry(double x, double y, double z, double nx, double ny, double nz) {
|
||||
|
|
@ -147,80 +161,66 @@ public:
|
|||
}
|
||||
|
||||
inline void push_triangle(int idx1, int idx2, int idx3) {
|
||||
assert(this->vertices_and_normals_interleaved_VBO_id == 0);
|
||||
if (this->vertices_and_normals_interleaved_VBO_id != 0)
|
||||
return;
|
||||
|
||||
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_size = this->triangle_indices.size();
|
||||
};
|
||||
|
||||
inline void push_quad(int idx1, int idx2, int idx3, int idx4) {
|
||||
assert(this->vertices_and_normals_interleaved_VBO_id == 0);
|
||||
if (this->vertices_and_normals_interleaved_VBO_id != 0)
|
||||
return;
|
||||
|
||||
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_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(bool use_VBOs);
|
||||
void finalize_geometry() const;
|
||||
// Release the geometry data, release OpenGL VBOs.
|
||||
void release_geometry();
|
||||
// Render either using an immediate mode, or the VBOs.
|
||||
|
||||
void render() const;
|
||||
void render(const std::pair<size_t, size_t> &tverts_range, const std::pair<size_t, size_t> &qverts_range) const;
|
||||
void render(const std::pair<size_t, size_t>& tverts_range, const std::pair<size_t, size_t>& qverts_range) const;
|
||||
|
||||
// Is there any geometry data stored?
|
||||
bool empty() const { return vertices_and_normals_interleaved_size == 0; }
|
||||
|
||||
// Is this object indexed, or is it just a set of triangles?
|
||||
bool indexed() const { return ! this->empty() && this->triangle_indices_size + this->quad_indices_size > 0; }
|
||||
|
||||
void clear() {
|
||||
this->vertices_and_normals_interleaved.clear();
|
||||
this->triangle_indices.clear();
|
||||
this->quad_indices.clear();
|
||||
this->setup_sizes();
|
||||
this->m_bounding_box.reset();
|
||||
vertices_and_normals_interleaved_size = 0;
|
||||
triangle_indices_size = 0;
|
||||
quad_indices_size = 0;
|
||||
}
|
||||
|
||||
// Shrink the internal storage to tighly fit the data stored.
|
||||
void shrink_to_fit() {
|
||||
if (! this->has_VBOs())
|
||||
this->setup_sizes();
|
||||
void shrink_to_fit() const {
|
||||
this->vertices_and_normals_interleaved.shrink_to_fit();
|
||||
this->triangle_indices.shrink_to_fit();
|
||||
this->quad_indices.shrink_to_fit();
|
||||
}
|
||||
|
||||
BoundingBoxf3 bounding_box() const {
|
||||
BoundingBoxf3 bbox;
|
||||
if (! this->vertices_and_normals_interleaved.empty()) {
|
||||
bbox.defined = true;
|
||||
bbox.min(0) = bbox.max(0) = this->vertices_and_normals_interleaved[3];
|
||||
bbox.min(1) = bbox.max(1) = this->vertices_and_normals_interleaved[4];
|
||||
bbox.min(2) = bbox.max(2) = this->vertices_and_normals_interleaved[5];
|
||||
for (size_t i = 9; i < this->vertices_and_normals_interleaved.size(); i += 6) {
|
||||
const float *verts = this->vertices_and_normals_interleaved.data() + i;
|
||||
bbox.min(0) = std::min<coordf_t>(bbox.min(0), verts[0]);
|
||||
bbox.min(1) = std::min<coordf_t>(bbox.min(1), verts[1]);
|
||||
bbox.min(2) = std::min<coordf_t>(bbox.min(2), verts[2]);
|
||||
bbox.max(0) = std::max<coordf_t>(bbox.max(0), verts[0]);
|
||||
bbox.max(1) = std::max<coordf_t>(bbox.max(1), verts[1]);
|
||||
bbox.max(2) = std::max<coordf_t>(bbox.max(2), verts[2]);
|
||||
}
|
||||
}
|
||||
return bbox;
|
||||
}
|
||||
const BoundingBoxf3& bounding_box() const { return m_bounding_box; }
|
||||
|
||||
private:
|
||||
inline void setup_sizes() {
|
||||
vertices_and_normals_interleaved_size = this->vertices_and_normals_interleaved.size();
|
||||
triangle_indices_size = this->triangle_indices.size();
|
||||
quad_indices_size = this->quad_indices.size();
|
||||
}
|
||||
BoundingBoxf3 m_bounding_box;
|
||||
};
|
||||
|
||||
class GLVolume {
|
||||
|
|
@ -263,8 +263,6 @@ private:
|
|||
mutable bool m_transformed_convex_hull_bounding_box_dirty;
|
||||
|
||||
public:
|
||||
// Bounding box of this volume, in unscaled coordinates.
|
||||
BoundingBoxf3 bounding_box;
|
||||
// Color of the triangles / quads held by this volume.
|
||||
float color[4];
|
||||
// Color used to render this volume.
|
||||
|
|
@ -329,6 +327,9 @@ public:
|
|||
// Offset into qverts & tverts, or offsets into indices stored into an OpenGL name_index_buffer.
|
||||
std::vector<size_t> offsets;
|
||||
|
||||
// Bounding box of this volume, in unscaled coordinates.
|
||||
const BoundingBoxf3& bounding_box() const { return this->indexed_vertex_array.bounding_box(); }
|
||||
|
||||
void set_render_color(float r, float g, float b, float a);
|
||||
void set_render_color(const float* rgba, unsigned int size);
|
||||
// Sets render color in dependence of current state
|
||||
|
|
@ -409,16 +410,17 @@ public:
|
|||
BoundingBoxf3 transformed_convex_hull_bounding_box(const Transform3d &trafo) const;
|
||||
// caching variant
|
||||
const BoundingBoxf3& transformed_convex_hull_bounding_box() const;
|
||||
// convex hull
|
||||
const TriangleMesh* convex_hull() const { return m_convex_hull.get(); }
|
||||
|
||||
bool empty() const { return this->indexed_vertex_array.empty(); }
|
||||
bool indexed() const { return this->indexed_vertex_array.indexed(); }
|
||||
|
||||
void set_range(coordf_t low, coordf_t high);
|
||||
void render() const;
|
||||
void render_VBOs(int color_id, int detection_id, int worldmatrix_id) const;
|
||||
void render_legacy() const;
|
||||
|
||||
void finalize_geometry(bool use_VBOs) { this->indexed_vertex_array.finalize_geometry(use_VBOs); }
|
||||
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 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; }
|
||||
|
|
@ -459,42 +461,38 @@ 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,
|
||||
bool use_VBOs);
|
||||
const std::vector<int>& instance_idxs,
|
||||
const std::string& color_by);
|
||||
|
||||
int load_object_volume(
|
||||
const ModelObject *model_object,
|
||||
const ModelObject* model_object,
|
||||
int obj_idx,
|
||||
int volume_idx,
|
||||
int instance_idx,
|
||||
const std::string &color_by,
|
||||
bool use_VBOs);
|
||||
const std::string& color_by);
|
||||
|
||||
// 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,
|
||||
const std::vector<std::pair<size_t, size_t>>& instances,
|
||||
SLAPrintObjectStep milestone,
|
||||
// Timestamp of the last change of the milestone
|
||||
size_t timestamp,
|
||||
bool use_VBOs);
|
||||
size_t timestamp);
|
||||
|
||||
int load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs, 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);
|
||||
|
||||
// Render the volumes by OpenGL.
|
||||
void render_VBOs(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
|
||||
void render_legacy(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
|
||||
void render(ERenderType type, bool disable_cullface, const Transform3d& view_matrix, std::function<bool(const GLVolume&)> filter_func = std::function<bool(const GLVolume&)>()) const;
|
||||
|
||||
// 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(bool use_VBOs) { for (auto *v : volumes) v->finalize_geometry(use_VBOs); }
|
||||
void finalize_geometry() { for (auto* v : volumes) v->finalize_geometry(); }
|
||||
// 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(); }
|
||||
|
|
@ -533,17 +531,16 @@ class GLModel
|
|||
{
|
||||
protected:
|
||||
GLVolume m_volume;
|
||||
bool m_useVBOs;
|
||||
std::string m_filename;
|
||||
|
||||
public:
|
||||
GLModel();
|
||||
virtual ~GLModel();
|
||||
|
||||
bool init(bool useVBOs) { return on_init(useVBOs); }
|
||||
bool init_from_file(const std::string& filename, bool useVBOs) { return on_init_from_file(filename, useVBOs); }
|
||||
bool init() { return on_init(); }
|
||||
bool init_from_file(const std::string& filename) { return on_init_from_file(filename); }
|
||||
|
||||
void center_around(const Vec3d& center) { m_volume.set_volume_offset(center - m_volume.bounding_box.center()); }
|
||||
void center_around(const Vec3d& center) { m_volume.set_volume_offset(center - m_volume.bounding_box().center()); }
|
||||
void set_color(const float* color, unsigned int size);
|
||||
|
||||
const Vec3d& get_offset() const;
|
||||
|
|
@ -554,7 +551,7 @@ public:
|
|||
void set_scale(const Vec3d& scale);
|
||||
|
||||
const std::string& get_filename() const { return m_filename; }
|
||||
const BoundingBoxf3& get_bounding_box() const { return m_volume.bounding_box; }
|
||||
const BoundingBoxf3& get_bounding_box() const { return m_volume.bounding_box(); }
|
||||
const BoundingBoxf3& get_transformed_bounding_box() const { return m_volume.transformed_bounding_box(); }
|
||||
|
||||
void reset();
|
||||
|
|
@ -562,18 +559,14 @@ public:
|
|||
void render() const;
|
||||
|
||||
protected:
|
||||
virtual bool on_init(bool useVBOs) { return false; }
|
||||
virtual bool on_init_from_file(const std::string& filename, bool useVBOs) { return false; }
|
||||
|
||||
private:
|
||||
void render_VBOs() const;
|
||||
void render_legacy() const;
|
||||
virtual bool on_init() { return false; }
|
||||
virtual bool on_init_from_file(const std::string& filename) { return false; }
|
||||
};
|
||||
|
||||
class GLArrow : public GLModel
|
||||
{
|
||||
protected:
|
||||
virtual bool on_init(bool useVBOs);
|
||||
virtual bool on_init();
|
||||
};
|
||||
|
||||
class GLCurvedArrow : public GLModel
|
||||
|
|
@ -584,13 +577,13 @@ public:
|
|||
explicit GLCurvedArrow(unsigned int resolution);
|
||||
|
||||
protected:
|
||||
virtual bool on_init(bool useVBOs);
|
||||
virtual bool on_init();
|
||||
};
|
||||
|
||||
class GLBed : public GLModel
|
||||
{
|
||||
protected:
|
||||
virtual bool on_init_from_file(const std::string& filename, bool useVBOs);
|
||||
virtual bool on_init_from_file(const std::string& filename);
|
||||
};
|
||||
|
||||
class _3DScene
|
||||
|
|
|
|||
|
|
@ -229,6 +229,33 @@ std::string AppConfig::get_last_dir() const
|
|||
return std::string();
|
||||
}
|
||||
|
||||
std::vector<std::string> AppConfig::get_recent_projects() const
|
||||
{
|
||||
std::vector<std::string> ret;
|
||||
const auto it = m_storage.find("recent_projects");
|
||||
if (it != m_storage.end())
|
||||
{
|
||||
for (const std::map<std::string, std::string>::value_type& item : it->second)
|
||||
{
|
||||
ret.push_back(item.second);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void AppConfig::set_recent_projects(const std::vector<std::string>& recent_projects)
|
||||
{
|
||||
auto it = m_storage.find("recent_projects");
|
||||
if (it == m_storage.end())
|
||||
it = m_storage.insert(std::map<std::string, std::map<std::string, std::string>>::value_type("recent_projects", std::map<std::string, std::string>())).first;
|
||||
|
||||
it->second.clear();
|
||||
for (unsigned int i = 0; i < (unsigned int)recent_projects.size(); ++i)
|
||||
{
|
||||
it->second[std::to_string(i + 1)] = recent_projects[i];
|
||||
}
|
||||
}
|
||||
|
||||
void AppConfig::update_config_dir(const std::string &dir)
|
||||
{
|
||||
this->set("recent", "config_directory", dir);
|
||||
|
|
|
|||
|
|
@ -122,6 +122,9 @@ public:
|
|||
// Does the config file exist?
|
||||
static bool exists();
|
||||
|
||||
std::vector<std::string> get_recent_projects() const;
|
||||
void set_recent_projects(const std::vector<std::string>& recent_projects);
|
||||
|
||||
private:
|
||||
// Map of section, name -> value
|
||||
std::map<std::string, std::map<std::string, std::string>> m_storage;
|
||||
|
|
|
|||
|
|
@ -53,15 +53,12 @@ void BedShapeDialog::on_dpi_changed(const wxRect &suggested_rect)
|
|||
|
||||
void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
||||
{
|
||||
// on_change(nullptr);
|
||||
|
||||
auto box = new wxStaticBox(this, wxID_ANY, _(L("Shape")));
|
||||
auto sbsizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
auto sbsizer = new wxStaticBoxSizer(wxVERTICAL, this, _(L("Shape")));
|
||||
|
||||
// shape options
|
||||
m_shape_options_book = new wxChoicebook(this, wxID_ANY, wxDefaultPosition,
|
||||
wxSize(25*wxGetApp().em_unit(), -1), wxCHB_TOP);
|
||||
sbsizer->Add(m_shape_options_book);
|
||||
sbsizer->Add(m_shape_options_book);
|
||||
|
||||
auto optgroup = init_shape_options_page(_(L("Rectangular")));
|
||||
ConfigOptionDef def;
|
||||
|
|
@ -92,13 +89,15 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||
Line line{ "", "" };
|
||||
line.full_width = 1;
|
||||
line.widget = [this](wxWindow* parent) {
|
||||
auto btn = new wxButton(parent, wxID_ANY, _(L("Load shape from STL...")), wxDefaultPosition, wxDefaultSize);
|
||||
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(btn);
|
||||
auto shape_btn = new wxButton(parent, wxID_ANY, _(L("Load shape from STL...")));
|
||||
wxSizer* shape_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
shape_sizer->Add(shape_btn, 1, wxEXPAND);
|
||||
|
||||
btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent e)
|
||||
{
|
||||
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(shape_sizer, 1, wxEXPAND);
|
||||
|
||||
shape_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
||||
{
|
||||
load_stl();
|
||||
}));
|
||||
|
||||
|
|
@ -106,8 +105,8 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||
};
|
||||
optgroup->append_line(line);
|
||||
|
||||
Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent e)
|
||||
{
|
||||
Bind(wxEVT_CHOICEBOOK_PAGE_CHANGED, ([this](wxCommandEvent& e)
|
||||
{
|
||||
update_shape();
|
||||
}));
|
||||
|
||||
|
|
@ -117,8 +116,8 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||
|
||||
// main sizer
|
||||
auto top_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
top_sizer->Add(sbsizer, 0, wxEXPAND | wxLeft | wxTOP | wxBOTTOM, 10);
|
||||
if (m_canvas)
|
||||
top_sizer->Add(sbsizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 10);
|
||||
if (m_canvas)
|
||||
top_sizer->Add(m_canvas, 1, wxEXPAND | wxALL, 10) ;
|
||||
|
||||
SetSizerAndFit(top_sizer);
|
||||
|
|
@ -135,8 +134,7 @@ void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
|||
// Create a panel for a rectangular / circular / custom bed shape.
|
||||
ConfigOptionsGroupShp BedShapePanel::init_shape_options_page(const wxString& title)
|
||||
{
|
||||
|
||||
auto panel = new wxPanel(m_shape_options_book);
|
||||
auto panel = new wxPanel(m_shape_options_book);
|
||||
ConfigOptionsGroupShp optgroup;
|
||||
optgroup = std::make_shared<ConfigOptionsGroup>(panel, _(L("Settings")));
|
||||
|
||||
|
|
|
|||
|
|
@ -113,11 +113,19 @@ wxString Field::get_tooltip_text(const wxString& default_string)
|
|||
wxString tooltip_text("");
|
||||
wxString tooltip = _(m_opt.tooltip);
|
||||
edit_tooltip(tooltip);
|
||||
|
||||
std::string opt_id = m_opt_id;
|
||||
auto hash_pos = opt_id.find("#");
|
||||
if (hash_pos != std::string::npos) {
|
||||
opt_id.replace(hash_pos, 1,"[");
|
||||
opt_id += "]";
|
||||
}
|
||||
|
||||
if (tooltip.length() > 0)
|
||||
tooltip_text = tooltip + "\n" + _(L("default value")) + "\t: " +
|
||||
(boost::iends_with(m_opt_id, "_gcode") ? "\n" : "") + default_string +
|
||||
(boost::iends_with(m_opt_id, "_gcode") ? "" : "\n") +
|
||||
_(L("parameter name")) + "\t: " + m_opt_id;
|
||||
(boost::iends_with(opt_id, "_gcode") ? "\n" : "") + default_string +
|
||||
(boost::iends_with(opt_id, "_gcode") ? "" : "\n") +
|
||||
_(L("parameter name")) + "\t: " + opt_id;
|
||||
|
||||
return tooltip_text;
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -12,6 +12,7 @@
|
|||
#include "Camera.hpp"
|
||||
#include "Selection.hpp"
|
||||
#include "Gizmos/GLGizmosManager.hpp"
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
|
|
@ -126,6 +127,8 @@ wxDECLARE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent);
|
|||
wxDECLARE_EVENT(EVT_GLCANVAS_RESETGIZMOS, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, wxKeyEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_EDIT_COLOR_CHANGE, wxKeyEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
|
||||
|
||||
class GLCanvas3D
|
||||
{
|
||||
|
|
@ -435,7 +438,8 @@ private:
|
|||
Shader m_shader;
|
||||
Mouse m_mouse;
|
||||
mutable GLGizmosManager m_gizmos;
|
||||
mutable GLToolbar m_toolbar;
|
||||
mutable GLToolbar m_main_toolbar;
|
||||
mutable GLToolbar m_undoredo_toolbar;
|
||||
ClippingPlane m_clipping_planes[2];
|
||||
mutable ClippingPlane m_camera_clipping_plane;
|
||||
bool m_use_clipping_planes;
|
||||
|
|
@ -452,7 +456,6 @@ private:
|
|||
// Screen is only refreshed from the OnIdle handler if it is dirty.
|
||||
bool m_dirty;
|
||||
bool m_initialized;
|
||||
bool m_use_VBOs;
|
||||
bool m_apply_zoom_to_volumes_filter;
|
||||
mutable std::vector<int> m_hover_volume_idxs;
|
||||
bool m_warning_texture_enabled;
|
||||
|
|
@ -485,6 +488,8 @@ private:
|
|||
RenderStats m_render_stats;
|
||||
#endif // ENABLE_RENDER_STATISTICS
|
||||
|
||||
int m_imgui_undo_redo_hovered_pos{ -1 };
|
||||
|
||||
public:
|
||||
GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar& view_toolbar);
|
||||
~GLCanvas3D();
|
||||
|
|
@ -494,7 +499,7 @@ public:
|
|||
wxGLCanvas* get_wxglcanvas() { return m_canvas; }
|
||||
const wxGLCanvas* get_wxglcanvas() const { return m_canvas; }
|
||||
|
||||
bool init(bool useVBOs);
|
||||
bool init();
|
||||
void post_event(wxEvent &&event);
|
||||
|
||||
void set_as_dirty();
|
||||
|
|
@ -513,6 +518,9 @@ public:
|
|||
const Selection& get_selection() const { return m_selection; }
|
||||
Selection& get_selection() { return m_selection; }
|
||||
|
||||
const GLGizmosManager& get_gizmos_manager() const { return m_gizmos; }
|
||||
GLGizmosManager& get_gizmos_manager() { return m_gizmos; }
|
||||
|
||||
void bed_shape_changed();
|
||||
|
||||
void set_clipping_plane(unsigned int id, const ClippingPlane& plane)
|
||||
|
|
@ -544,7 +552,8 @@ public:
|
|||
void enable_moving(bool enable);
|
||||
void enable_gizmos(bool enable);
|
||||
void enable_selection(bool enable);
|
||||
void enable_toolbar(bool enable);
|
||||
void enable_main_toolbar(bool enable);
|
||||
void enable_undoredo_toolbar(bool enable);
|
||||
void enable_dynamic_background(bool enable);
|
||||
void allow_multisample(bool allow);
|
||||
|
||||
|
|
@ -596,11 +605,12 @@ public:
|
|||
|
||||
void set_tooltip(const std::string& tooltip) const;
|
||||
|
||||
void do_move();
|
||||
void do_rotate();
|
||||
void do_scale();
|
||||
void do_flatten();
|
||||
void do_mirror();
|
||||
// the following methods add a snapshot to the undo/redo stack, unless the given string is empty
|
||||
void do_move(const std::string& snapshot_type);
|
||||
void do_rotate(const std::string& snapshot_type);
|
||||
void do_scale(const std::string& snapshot_type);
|
||||
void do_flatten(const Vec3d& normal, const std::string& snapshot_type);
|
||||
void do_mirror(const std::string& snapshot_type);
|
||||
|
||||
void set_camera_zoom(double zoom);
|
||||
|
||||
|
|
@ -608,6 +618,7 @@ public:
|
|||
void reset_all_gizmos() { m_gizmos.reset_all_states(); }
|
||||
|
||||
void handle_sidebar_focus_event(const std::string& opt_key, bool focus_on);
|
||||
void handle_layers_data_focus_event(const t_layer_height_range range, const EditorType type);
|
||||
|
||||
void update_ui_from_settings();
|
||||
|
||||
|
|
@ -635,10 +646,18 @@ public:
|
|||
void start_keeping_dirty() { m_keep_dirty = true; }
|
||||
void stop_keeping_dirty() { m_keep_dirty = false; }
|
||||
|
||||
unsigned int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); }
|
||||
void force_main_toolbar_left_action(unsigned int item_id) { m_main_toolbar.force_left_action(item_id, *this); }
|
||||
void force_main_toolbar_right_action(unsigned int item_id) { m_main_toolbar.force_right_action(item_id, *this); }
|
||||
void get_undoredo_toolbar_additional_tooltip(unsigned int item_id, std::string& text) { return m_undoredo_toolbar.get_additional_tooltip(item_id, text); }
|
||||
void set_undoredo_toolbar_additional_tooltip(unsigned int item_id, const std::string& text) { m_undoredo_toolbar.set_additional_tooltip(item_id, text); }
|
||||
|
||||
private:
|
||||
bool _is_shown_on_screen() const;
|
||||
|
||||
bool _init_toolbar();
|
||||
bool _init_toolbars();
|
||||
bool _init_main_toolbar();
|
||||
bool _init_undoredo_toolbar();
|
||||
|
||||
bool _set_current();
|
||||
void _resize(unsigned int w, unsigned int h);
|
||||
|
|
@ -665,13 +684,15 @@ private:
|
|||
void _render_volumes_for_picking() const;
|
||||
void _render_current_gizmo() const;
|
||||
void _render_gizmos_overlay() const;
|
||||
void _render_toolbar() const;
|
||||
void _render_main_toolbar() const;
|
||||
void _render_undoredo_toolbar() const;
|
||||
void _render_view_toolbar() const;
|
||||
#if ENABLE_SHOW_CAMERA_TARGET
|
||||
void _render_camera_target() const;
|
||||
#endif // ENABLE_SHOW_CAMERA_TARGET
|
||||
void _render_sla_slices() const;
|
||||
void _render_selection_sidebar_hints() const;
|
||||
void _render_undo_redo_stack(const bool is_undo, float pos_x);
|
||||
|
||||
void _update_volumes_hover_state() const;
|
||||
|
||||
|
|
@ -711,8 +732,6 @@ private:
|
|||
void _load_gcode_unretractions(const GCodePreviewData& preview_data);
|
||||
// generates objects and wipe tower geometry
|
||||
void _load_fff_shells();
|
||||
// generates objects geometry for sla
|
||||
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();
|
||||
|
|
@ -727,13 +746,11 @@ private:
|
|||
|
||||
bool _is_any_volume_outside() const;
|
||||
|
||||
#if !ENABLE_SVG_ICONS
|
||||
void _resize_toolbars() const;
|
||||
#endif // !ENABLE_SVG_ICONS
|
||||
|
||||
// updates the selection from the content of m_hover_volume_idxs
|
||||
void _update_selection_from_hover();
|
||||
|
||||
bool _deactivate_undo_redo_toolbar_items();
|
||||
|
||||
static std::vector<float> _parse_colors(const std::vector<std::string>& colors);
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -192,7 +192,6 @@ GLCanvas3DManager::GLInfo GLCanvas3DManager::s_gl_info;
|
|||
GLCanvas3DManager::GLCanvas3DManager()
|
||||
: m_context(nullptr)
|
||||
, m_gl_initialized(false)
|
||||
, m_use_VBOs(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -266,8 +265,6 @@ void GLCanvas3DManager::init_gl()
|
|||
if (!m_gl_initialized)
|
||||
{
|
||||
glewInit();
|
||||
const AppConfig* config = GUI::get_app_config();
|
||||
m_use_VBOs = s_gl_info.is_version_greater_or_equal_to(2, 0);
|
||||
m_gl_initialized = true;
|
||||
if (GLEW_EXT_texture_compression_s3tc)
|
||||
s_compressed_textures_supported = true;
|
||||
|
|
@ -323,7 +320,7 @@ bool GLCanvas3DManager::init(GLCanvas3D& canvas)
|
|||
if (!m_gl_initialized)
|
||||
init_gl();
|
||||
|
||||
return canvas.init(m_use_VBOs);
|
||||
return canvas.init();
|
||||
}
|
||||
|
||||
void GLCanvas3DManager::detect_multisample(int* attribList)
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ private:
|
|||
wxGLContext* m_context;
|
||||
static GLInfo s_gl_info;
|
||||
bool m_gl_initialized;
|
||||
bool m_use_VBOs;
|
||||
static EMultisampleState s_multisample;
|
||||
static bool s_compressed_textures_supported;
|
||||
|
||||
|
|
|
|||
|
|
@ -34,20 +34,25 @@ wxDEFINE_EVENT(EVT_GLVIEWTOOLBAR_PREVIEW, SimpleEvent);
|
|||
|
||||
const GLToolbarItem::ActionCallback GLToolbarItem::Default_Action_Callback = [](){};
|
||||
const GLToolbarItem::VisibilityCallback GLToolbarItem::Default_Visibility_Callback = []()->bool { return true; };
|
||||
const GLToolbarItem::EnabledStateCallback GLToolbarItem::Default_Enabled_State_Callback = []()->bool { return true; };
|
||||
const GLToolbarItem::EnablingCallback GLToolbarItem::Default_Enabling_Callback = []()->bool { return true; };
|
||||
const GLToolbarItem::RenderCallback GLToolbarItem::Default_Render_Callback = [](float, float, float, float){};
|
||||
|
||||
GLToolbarItem::Data::Option::Option()
|
||||
: toggable(false)
|
||||
, action_callback(Default_Action_Callback)
|
||||
, render_callback(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
GLToolbarItem::Data::Data()
|
||||
: name("")
|
||||
#if ENABLE_SVG_ICONS
|
||||
, icon_filename("")
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, tooltip("")
|
||||
, additional_tooltip("")
|
||||
, sprite_id(-1)
|
||||
, is_toggable(false)
|
||||
, visible(true)
|
||||
, action_callback(Default_Action_Callback)
|
||||
, visibility_callback(Default_Visibility_Callback)
|
||||
, enabled_state_callback(Default_Enabled_State_Callback)
|
||||
, enabling_callback(Default_Enabling_Callback)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -55,6 +60,7 @@ GLToolbarItem::GLToolbarItem(GLToolbarItem::EType type, const GLToolbarItem::Dat
|
|||
: m_type(type)
|
||||
, m_state(Normal)
|
||||
, m_data(data)
|
||||
, m_last_action_type(Undefined)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +76,7 @@ bool GLToolbarItem::update_visibility()
|
|||
|
||||
bool GLToolbarItem::update_enabled_state()
|
||||
{
|
||||
bool enabled = m_data.enabled_state_callback();
|
||||
bool enabled = m_data.enabling_callback();
|
||||
bool ret = (is_enabled() != enabled);
|
||||
if (ret)
|
||||
m_state = enabled ? GLToolbarItem::Normal : GLToolbarItem::Disabled;
|
||||
|
|
@ -81,6 +87,14 @@ bool GLToolbarItem::update_enabled_state()
|
|||
void GLToolbarItem::render(unsigned int tex_id, float left, float right, float bottom, float top, unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const
|
||||
{
|
||||
GLTexture::render_sub_texture(tex_id, left, right, bottom, top, get_uvs(tex_width, tex_height, icon_size));
|
||||
|
||||
if (is_pressed())
|
||||
{
|
||||
if ((m_last_action_type == Left) && m_data.left.can_render())
|
||||
m_data.left.render_callback(left, right, bottom, top);
|
||||
else if ((m_last_action_type == Right) && m_data.right.can_render())
|
||||
m_data.right.render_callback(left, right, bottom, top);
|
||||
}
|
||||
}
|
||||
|
||||
GLTexture::Quad_UVs GLToolbarItem::get_uvs(unsigned int tex_width, unsigned int tex_height, unsigned int icon_size) const
|
||||
|
|
@ -105,14 +119,6 @@ GLTexture::Quad_UVs GLToolbarItem::get_uvs(unsigned int tex_width, unsigned int
|
|||
return uvs;
|
||||
}
|
||||
|
||||
#if !ENABLE_SVG_ICONS
|
||||
ItemsIconsTexture::Metadata::Metadata()
|
||||
: filename("")
|
||||
, icon_size(0)
|
||||
{
|
||||
}
|
||||
#endif // !ENABLE_SVG_ICONS
|
||||
|
||||
BackgroundTexture::Metadata::Metadata()
|
||||
: filename("")
|
||||
, left(0)
|
||||
|
|
@ -122,44 +128,32 @@ BackgroundTexture::Metadata::Metadata()
|
|||
{
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
const float GLToolbar::Default_Icons_Size = 40.0f;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
GLToolbar::Layout::Layout()
|
||||
: type(Horizontal)
|
||||
, orientation(Center)
|
||||
, horizontal_orientation(HO_Center)
|
||||
, vertical_orientation(VO_Center)
|
||||
, top(0.0f)
|
||||
, left(0.0f)
|
||||
, border(0.0f)
|
||||
, separator_size(0.0f)
|
||||
, gap_size(0.0f)
|
||||
#if ENABLE_SVG_ICONS
|
||||
, icons_size(Default_Icons_Size)
|
||||
, scale(1.0f)
|
||||
#else
|
||||
, icons_scale(1.0f)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, width(0.0f)
|
||||
, height(0.0f)
|
||||
, dirty(true)
|
||||
{
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLToolbar::GLToolbar(GLToolbar::EType type, const std::string& name)
|
||||
#else
|
||||
GLToolbar::GLToolbar(GLToolbar::EType type)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
: m_type(type)
|
||||
#if ENABLE_SVG_ICONS
|
||||
, m_name(name)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_enabled(false)
|
||||
#if ENABLE_SVG_ICONS
|
||||
, m_icons_texture_dirty(true)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_tooltip("")
|
||||
, m_pressed_toggable_id(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -171,27 +165,13 @@ GLToolbar::~GLToolbar()
|
|||
}
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
bool GLToolbar::init(const BackgroundTexture::Metadata& background_texture)
|
||||
#else
|
||||
bool GLToolbar::init(const ItemsIconsTexture::Metadata& icons_texture, const BackgroundTexture::Metadata& background_texture)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
{
|
||||
#if ENABLE_SVG_ICONS
|
||||
if (m_background_texture.texture.get_id() != 0)
|
||||
return true;
|
||||
|
||||
std::string path = resources_dir() + "/icons/";
|
||||
bool res = false;
|
||||
#else
|
||||
if (m_icons_texture.texture.get_id() != 0)
|
||||
return true;
|
||||
|
||||
std::string path = resources_dir() + "/icons/";
|
||||
bool res = !icons_texture.filename.empty() && m_icons_texture.texture.load_from_file(path + icons_texture.filename, false);
|
||||
if (res)
|
||||
m_icons_texture.metadata = icons_texture;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
if (!background_texture.filename.empty())
|
||||
res = m_background_texture.texture.load_from_file(path + background_texture.filename, false, true);
|
||||
|
|
@ -213,16 +193,6 @@ void GLToolbar::set_layout_type(GLToolbar::Layout::EType type)
|
|||
m_layout.dirty = true;
|
||||
}
|
||||
|
||||
GLToolbar::Layout::EOrientation GLToolbar::get_layout_orientation() const
|
||||
{
|
||||
return m_layout.orientation;
|
||||
}
|
||||
|
||||
void GLToolbar::set_layout_orientation(GLToolbar::Layout::EOrientation orientation)
|
||||
{
|
||||
m_layout.orientation = orientation;
|
||||
}
|
||||
|
||||
void GLToolbar::set_position(float top, float left)
|
||||
{
|
||||
m_layout.top = top;
|
||||
|
|
@ -247,7 +217,6 @@ void GLToolbar::set_gap_size(float size)
|
|||
m_layout.dirty = true;
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
void GLToolbar::set_icons_size(float size)
|
||||
{
|
||||
if (m_layout.icons_size != size)
|
||||
|
|
@ -267,13 +236,6 @@ void GLToolbar::set_scale(float scale)
|
|||
m_icons_texture_dirty = true;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void GLToolbar::set_icons_scale(float scale)
|
||||
{
|
||||
m_layout.icons_scale = scale;
|
||||
m_layout.dirty = true;
|
||||
}
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
bool GLToolbar::is_enabled() const
|
||||
{
|
||||
|
|
@ -341,7 +303,7 @@ void GLToolbar::select_item(const std::string& name)
|
|||
|
||||
bool GLToolbar::is_item_pressed(const std::string& name) const
|
||||
{
|
||||
for (GLToolbarItem* item : m_items)
|
||||
for (const GLToolbarItem* item : m_items)
|
||||
{
|
||||
if (item->get_name() == name)
|
||||
return item->is_pressed();
|
||||
|
|
@ -352,7 +314,7 @@ bool GLToolbar::is_item_pressed(const std::string& name) const
|
|||
|
||||
bool GLToolbar::is_item_disabled(const std::string& name) const
|
||||
{
|
||||
for (GLToolbarItem* item : m_items)
|
||||
for (const GLToolbarItem* item : m_items)
|
||||
{
|
||||
if (item->get_name() == name)
|
||||
return item->is_disabled();
|
||||
|
|
@ -363,7 +325,7 @@ bool GLToolbar::is_item_disabled(const std::string& name) const
|
|||
|
||||
bool GLToolbar::is_item_visible(const std::string& name) const
|
||||
{
|
||||
for (GLToolbarItem* item : m_items)
|
||||
for (const GLToolbarItem* item : m_items)
|
||||
{
|
||||
if (item->get_name() == name)
|
||||
return item->is_visible();
|
||||
|
|
@ -372,11 +334,71 @@ bool GLToolbar::is_item_visible(const std::string& name) const
|
|||
return false;
|
||||
}
|
||||
|
||||
bool GLToolbar::is_any_item_pressed() const
|
||||
{
|
||||
for (const GLToolbarItem* item : m_items)
|
||||
{
|
||||
if (item->is_pressed())
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int GLToolbar::get_item_id(const std::string& name) const
|
||||
{
|
||||
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
|
||||
{
|
||||
if (m_items[i]->get_name() == name)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void GLToolbar::force_left_action(unsigned int item_id, GLCanvas3D& parent)
|
||||
{
|
||||
do_action(GLToolbarItem::Left, item_id, parent, false);
|
||||
}
|
||||
|
||||
void GLToolbar::force_right_action(unsigned int item_id, GLCanvas3D& parent)
|
||||
{
|
||||
do_action(GLToolbarItem::Right, item_id, parent, false);
|
||||
}
|
||||
|
||||
void GLToolbar::get_additional_tooltip(unsigned int item_id, std::string& text)
|
||||
{
|
||||
if (item_id < (unsigned int)m_items.size())
|
||||
{
|
||||
GLToolbarItem* item = m_items[item_id];
|
||||
if (item != nullptr)
|
||||
{
|
||||
text = item->get_additional_tooltip();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
text = L("");
|
||||
}
|
||||
|
||||
void GLToolbar::set_additional_tooltip(unsigned int item_id, const std::string& text)
|
||||
{
|
||||
if (item_id < (unsigned int)m_items.size())
|
||||
{
|
||||
GLToolbarItem* item = m_items[item_id];
|
||||
if (item != nullptr)
|
||||
item->set_additional_tooltip(text);
|
||||
}
|
||||
}
|
||||
|
||||
bool GLToolbar::update_items_state()
|
||||
{
|
||||
bool ret = false;
|
||||
ret |= update_items_visibility();
|
||||
ret |= update_items_enabled_state();
|
||||
if (!is_any_item_pressed())
|
||||
m_pressed_toggable_id = -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -385,10 +407,8 @@ void GLToolbar::render(const GLCanvas3D& parent) const
|
|||
if (!m_enabled || m_items.empty())
|
||||
return;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
if (m_icons_texture_dirty)
|
||||
generate_icons_texture();
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
switch (m_layout.type)
|
||||
{
|
||||
|
|
@ -400,6 +420,9 @@ void GLToolbar::render(const GLCanvas3D& parent) const
|
|||
|
||||
bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return false;
|
||||
|
||||
Vec2d mouse_pos((double)evt.GetX(), (double)evt.GetY());
|
||||
bool processed = false;
|
||||
|
||||
|
|
@ -430,7 +453,7 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
|||
if (item_id == -1)
|
||||
{
|
||||
// mouse is outside the toolbar
|
||||
m_tooltip = "";
|
||||
m_tooltip = L("");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -440,10 +463,11 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
|||
m_mouse_capture.left = true;
|
||||
m_mouse_capture.parent = &parent;
|
||||
processed = true;
|
||||
if ((item_id != -2) && !m_items[item_id]->is_separator())
|
||||
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Left)))
|
||||
{
|
||||
// mouse is inside an icon
|
||||
do_action((unsigned int)item_id, parent);
|
||||
do_action(GLToolbarItem::Left, (unsigned int)item_id, parent, true);
|
||||
parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
else if (evt.MiddleDown())
|
||||
|
|
@ -455,6 +479,13 @@ bool GLToolbar::on_mouse(wxMouseEvent& evt, GLCanvas3D& parent)
|
|||
{
|
||||
m_mouse_capture.right = true;
|
||||
m_mouse_capture.parent = &parent;
|
||||
processed = true;
|
||||
if ((item_id != -2) && !m_items[item_id]->is_separator() && ((m_pressed_toggable_id == -1) || (m_items[item_id]->get_last_action_type() == GLToolbarItem::Right)))
|
||||
{
|
||||
// mouse is inside an icon
|
||||
do_action(GLToolbarItem::Right, (unsigned int)item_id, parent, true);
|
||||
parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
else if (evt.LeftUp())
|
||||
processed = true;
|
||||
|
|
@ -492,20 +523,12 @@ float GLToolbar::get_width_horizontal() const
|
|||
|
||||
float GLToolbar::get_width_vertical() const
|
||||
{
|
||||
#if ENABLE_SVG_ICONS
|
||||
return (2.0f * m_layout.border + m_layout.icons_size) * m_layout.scale;
|
||||
#else
|
||||
return 2.0f * m_layout.border * m_layout.icons_scale + m_icons_texture.metadata.icon_size * m_layout.icons_scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
}
|
||||
|
||||
float GLToolbar::get_height_horizontal() const
|
||||
{
|
||||
#if ENABLE_SVG_ICONS
|
||||
return (2.0f * m_layout.border + m_layout.icons_size) * m_layout.scale;
|
||||
#else
|
||||
return 2.0f * m_layout.border * m_layout.icons_scale + m_icons_texture.metadata.icon_size * m_layout.icons_scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
}
|
||||
|
||||
float GLToolbar::get_height_vertical() const
|
||||
|
|
@ -515,7 +538,6 @@ float GLToolbar::get_height_vertical() const
|
|||
|
||||
float GLToolbar::get_main_size() const
|
||||
{
|
||||
#if ENABLE_SVG_ICONS
|
||||
float size = 2.0f * m_layout.border;
|
||||
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
|
||||
{
|
||||
|
|
@ -531,59 +553,64 @@ float GLToolbar::get_main_size() const
|
|||
if (m_items.size() > 1)
|
||||
size += ((float)m_items.size() - 1.0f) * m_layout.gap_size;
|
||||
|
||||
size *= m_layout.scale;
|
||||
#else
|
||||
float size = 2.0f * m_layout.border * m_layout.icons_scale;
|
||||
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
|
||||
{
|
||||
if (!m_items[i]->is_visible())
|
||||
continue;
|
||||
|
||||
if (m_items[i]->is_separator())
|
||||
size += m_layout.separator_size * m_layout.icons_scale;
|
||||
else
|
||||
size += (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale;
|
||||
}
|
||||
|
||||
if (m_items.size() > 1)
|
||||
size += ((float)m_items.size() - 1.0f) * m_layout.gap_size * m_layout.icons_scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
return size;
|
||||
return size * m_layout.scale;
|
||||
}
|
||||
|
||||
void GLToolbar::do_action(unsigned int item_id, GLCanvas3D& parent)
|
||||
void GLToolbar::do_action(GLToolbarItem::EActionType type, unsigned int item_id, GLCanvas3D& parent, bool check_hover)
|
||||
{
|
||||
if (item_id < (unsigned int)m_items.size())
|
||||
if ((m_pressed_toggable_id == -1) || (m_pressed_toggable_id == item_id))
|
||||
{
|
||||
GLToolbarItem* item = m_items[item_id];
|
||||
if ((item != nullptr) && !item->is_separator() && item->is_hovered())
|
||||
if (item_id < (unsigned int)m_items.size())
|
||||
{
|
||||
if (item->is_toggable())
|
||||
GLToolbarItem* item = m_items[item_id];
|
||||
if ((item != nullptr) && !item->is_separator() && (!check_hover || item->is_hovered()))
|
||||
{
|
||||
GLToolbarItem::EState state = item->get_state();
|
||||
if (state == GLToolbarItem::Hover)
|
||||
item->set_state(GLToolbarItem::HoverPressed);
|
||||
else if (state == GLToolbarItem::HoverPressed)
|
||||
item->set_state(GLToolbarItem::Hover);
|
||||
|
||||
parent.render();
|
||||
item->do_action();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_type == Radio)
|
||||
select_item(item->get_name());
|
||||
else
|
||||
item->set_state(GLToolbarItem::HoverPressed);
|
||||
|
||||
parent.render();
|
||||
item->do_action();
|
||||
if ((m_type == Normal) && (item->get_state() != GLToolbarItem::Disabled))
|
||||
if (((type == GLToolbarItem::Right) && item->is_right_toggable()) ||
|
||||
((type == GLToolbarItem::Left) && item->is_left_toggable()))
|
||||
{
|
||||
// the item may get disabled during the action, if not, set it back to hover state
|
||||
item->set_state(GLToolbarItem::Hover);
|
||||
GLToolbarItem::EState state = item->get_state();
|
||||
if (state == GLToolbarItem::Hover)
|
||||
item->set_state(GLToolbarItem::HoverPressed);
|
||||
else if (state == GLToolbarItem::HoverPressed)
|
||||
item->set_state(GLToolbarItem::Hover);
|
||||
else if (state == GLToolbarItem::Pressed)
|
||||
item->set_state(GLToolbarItem::Normal);
|
||||
else if (state == GLToolbarItem::Normal)
|
||||
item->set_state(GLToolbarItem::Pressed);
|
||||
|
||||
m_pressed_toggable_id = item->is_pressed() ? item_id : -1;
|
||||
item->reset_last_action_type();
|
||||
|
||||
parent.render();
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
case GLToolbarItem::Left: { item->do_left_action(); break; }
|
||||
case GLToolbarItem::Right: { item->do_right_action(); break; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_type == Radio)
|
||||
select_item(item->get_name());
|
||||
else
|
||||
item->set_state(item->is_hovered() ? GLToolbarItem::HoverPressed : GLToolbarItem::Pressed);
|
||||
|
||||
item->reset_last_action_type();
|
||||
parent.render();
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
case GLToolbarItem::Left: { item->do_left_action(); break; }
|
||||
case GLToolbarItem::Right: { item->do_right_action(); break; }
|
||||
}
|
||||
|
||||
if ((m_type == Normal) && (item->get_state() != GLToolbarItem::Disabled))
|
||||
{
|
||||
// the item may get disabled during the action, if not, set it back to hover state
|
||||
item->set_state(GLToolbarItem::Hover);
|
||||
parent.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -593,7 +620,7 @@ void GLToolbar::do_action(unsigned int item_id, GLCanvas3D& parent)
|
|||
std::string GLToolbar::update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return "";
|
||||
return L("");
|
||||
|
||||
switch (m_layout.type)
|
||||
{
|
||||
|
|
@ -609,20 +636,12 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC
|
|||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
#if ENABLE_SVG_ICONS
|
||||
float factor = m_layout.scale * inv_zoom;
|
||||
#else
|
||||
float factor = m_layout.icons_scale * inv_zoom;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
float scaled_icons_size = m_layout.icons_size * factor;
|
||||
#else
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
|
|
@ -650,7 +669,15 @@ std::string GLToolbar::update_hover_state_horizontal(const Vec2d& mouse_pos, GLC
|
|||
GLToolbarItem::EState state = item->get_state();
|
||||
bool inside = (left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top);
|
||||
if (inside)
|
||||
{
|
||||
tooltip = item->get_tooltip();
|
||||
if (!item->is_pressed())
|
||||
{
|
||||
const std::string& additional_tooltip = item->get_additional_tooltip();
|
||||
if (!additional_tooltip.empty())
|
||||
tooltip += L("\n") + additional_tooltip;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
|
|
@ -714,20 +741,12 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan
|
|||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
#if ENABLE_SVG_ICONS
|
||||
float factor = m_layout.scale * inv_zoom;
|
||||
#else
|
||||
float factor = m_layout.icons_scale * inv_zoom;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
float scaled_icons_size = m_layout.icons_size * factor;
|
||||
#else
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
|
|
@ -754,7 +773,15 @@ std::string GLToolbar::update_hover_state_vertical(const Vec2d& mouse_pos, GLCan
|
|||
GLToolbarItem::EState state = item->get_state();
|
||||
bool inside = (left <= (float)scaled_mouse_pos(0)) && ((float)scaled_mouse_pos(0) <= right) && (bottom <= (float)scaled_mouse_pos(1)) && ((float)scaled_mouse_pos(1) <= top);
|
||||
if (inside)
|
||||
{
|
||||
tooltip = item->get_tooltip();
|
||||
if (!item->is_pressed())
|
||||
{
|
||||
const std::string& additional_tooltip = item->get_additional_tooltip();
|
||||
if (!additional_tooltip.empty())
|
||||
tooltip += L("\n") + additional_tooltip;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
|
|
@ -831,20 +858,12 @@ int GLToolbar::contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3
|
|||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
#if ENABLE_SVG_ICONS
|
||||
float factor = m_layout.scale * inv_zoom;
|
||||
#else
|
||||
float factor = m_layout.icons_scale * inv_zoom;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
float scaled_icons_size = m_layout.icons_size * factor;
|
||||
#else
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
|
|
@ -914,20 +933,12 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D&
|
|||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
#if ENABLE_SVG_ICONS
|
||||
float factor = m_layout.scale * inv_zoom;
|
||||
#else
|
||||
float factor = m_layout.icons_scale * inv_zoom;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
Size cnv_size = parent.get_canvas_size();
|
||||
Vec2d scaled_mouse_pos((mouse_pos(0) - 0.5 * (double)cnv_size.get_width()) * inv_zoom, (0.5 * (double)cnv_size.get_height() - mouse_pos(1)) * inv_zoom);
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
float scaled_icons_size = m_layout.icons_size * factor;
|
||||
#else
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
|
|
@ -991,36 +1002,95 @@ int GLToolbar::contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D&
|
|||
return -1;
|
||||
}
|
||||
|
||||
void GLToolbar::render_background(float left, float top, float right, float bottom, float border) const
|
||||
{
|
||||
unsigned int tex_id = m_background_texture.texture.get_id();
|
||||
float tex_width = (float)m_background_texture.texture.get_width();
|
||||
float tex_height = (float)m_background_texture.texture.get_height();
|
||||
if ((tex_id != 0) && (tex_width > 0) && (tex_height > 0))
|
||||
{
|
||||
float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f;
|
||||
float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f;
|
||||
|
||||
float internal_left = left + border;
|
||||
float internal_right = right - border;
|
||||
float internal_top = top - border;
|
||||
float internal_bottom = bottom + border;
|
||||
|
||||
float left_uv = 0.0f;
|
||||
float right_uv = 1.0f;
|
||||
float top_uv = 1.0f;
|
||||
float bottom_uv = 0.0f;
|
||||
|
||||
float internal_left_uv = (float)m_background_texture.metadata.left * inv_tex_width;
|
||||
float internal_right_uv = 1.0f - (float)m_background_texture.metadata.right * inv_tex_width;
|
||||
float internal_top_uv = 1.0f - (float)m_background_texture.metadata.top * inv_tex_height;
|
||||
float internal_bottom_uv = (float)m_background_texture.metadata.bottom * inv_tex_height;
|
||||
|
||||
// top-left corner
|
||||
if ((m_layout.horizontal_orientation == Layout::HO_Left) || (m_layout.vertical_orientation == Layout::VO_Top))
|
||||
GLTexture::render_sub_texture(tex_id, left, internal_left, internal_top, top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
else
|
||||
GLTexture::render_sub_texture(tex_id, left, internal_left, internal_top, top, { { left_uv, internal_top_uv }, { internal_left_uv, internal_top_uv }, { internal_left_uv, top_uv }, { left_uv, top_uv } });
|
||||
|
||||
// top edge
|
||||
if (m_layout.vertical_orientation == Layout::VO_Top)
|
||||
GLTexture::render_sub_texture(tex_id, internal_left, internal_right, internal_top, top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
else
|
||||
GLTexture::render_sub_texture(tex_id, internal_left, internal_right, internal_top, top, { { internal_left_uv, internal_top_uv }, { internal_right_uv, internal_top_uv }, { internal_right_uv, top_uv }, { internal_left_uv, top_uv } });
|
||||
|
||||
// top-right corner
|
||||
if ((m_layout.horizontal_orientation == Layout::HO_Right) || (m_layout.vertical_orientation == Layout::VO_Top))
|
||||
GLTexture::render_sub_texture(tex_id, internal_right, right, internal_top, top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
else
|
||||
GLTexture::render_sub_texture(tex_id, internal_right, right, internal_top, top, { { internal_right_uv, internal_top_uv }, { right_uv, internal_top_uv }, { right_uv, top_uv }, { internal_right_uv, top_uv } });
|
||||
|
||||
// center-left edge
|
||||
if (m_layout.horizontal_orientation == Layout::HO_Left)
|
||||
GLTexture::render_sub_texture(tex_id, left, internal_left, internal_bottom, internal_top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
else
|
||||
GLTexture::render_sub_texture(tex_id, left, internal_left, internal_bottom, internal_top, { { left_uv, internal_bottom_uv }, { internal_left_uv, internal_bottom_uv }, { internal_left_uv, internal_top_uv }, { left_uv, internal_top_uv } });
|
||||
|
||||
// center
|
||||
GLTexture::render_sub_texture(tex_id, internal_left, internal_right, internal_bottom, internal_top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
|
||||
// center-right edge
|
||||
if (m_layout.horizontal_orientation == Layout::HO_Right)
|
||||
GLTexture::render_sub_texture(tex_id, internal_right, right, internal_bottom, internal_top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
else
|
||||
GLTexture::render_sub_texture(tex_id, internal_right, right, internal_bottom, internal_top, { { internal_right_uv, internal_bottom_uv }, { right_uv, internal_bottom_uv }, { right_uv, internal_top_uv }, { internal_right_uv, internal_top_uv } });
|
||||
|
||||
// bottom-left corner
|
||||
if ((m_layout.horizontal_orientation == Layout::HO_Left) || (m_layout.vertical_orientation == Layout::VO_Bottom))
|
||||
GLTexture::render_sub_texture(tex_id, left, internal_left, bottom, internal_bottom, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
else
|
||||
GLTexture::render_sub_texture(tex_id, left, internal_left, bottom, internal_bottom, { { left_uv, bottom_uv }, { internal_left_uv, bottom_uv }, { internal_left_uv, internal_bottom_uv }, { left_uv, internal_bottom_uv } });
|
||||
|
||||
// bottom edge
|
||||
if (m_layout.vertical_orientation == Layout::VO_Bottom)
|
||||
GLTexture::render_sub_texture(tex_id, internal_left, internal_right, bottom, internal_bottom, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
else
|
||||
GLTexture::render_sub_texture(tex_id, internal_left, internal_right, bottom, internal_bottom, { { internal_left_uv, bottom_uv }, { internal_right_uv, bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_left_uv, internal_bottom_uv } });
|
||||
|
||||
// bottom-right corner
|
||||
if ((m_layout.horizontal_orientation == Layout::HO_Right) || (m_layout.vertical_orientation == Layout::VO_Bottom))
|
||||
GLTexture::render_sub_texture(tex_id, internal_right, right, bottom, internal_bottom, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
else
|
||||
GLTexture::render_sub_texture(tex_id, internal_right, right, bottom, internal_bottom, { { internal_right_uv, bottom_uv }, { right_uv, bottom_uv }, { right_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv } });
|
||||
}
|
||||
}
|
||||
|
||||
void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
|
||||
{
|
||||
#if ENABLE_SVG_ICONS
|
||||
unsigned int tex_id = m_icons_texture.get_id();
|
||||
int tex_width = m_icons_texture.get_width();
|
||||
int tex_height = m_icons_texture.get_height();
|
||||
#else
|
||||
unsigned int tex_id = m_icons_texture.texture.get_id();
|
||||
int tex_width = m_icons_texture.texture.get_width();
|
||||
int tex_height = m_icons_texture.texture.get_height();
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
#if !ENABLE_SVG_ICONS
|
||||
if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0))
|
||||
return;
|
||||
#endif // !ENABLE_SVG_ICONS
|
||||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
#if ENABLE_SVG_ICONS
|
||||
float factor = inv_zoom * m_layout.scale;
|
||||
#else
|
||||
float factor = inv_zoom * m_layout.icons_scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
float scaled_icons_size = m_layout.icons_size * factor;
|
||||
#else
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * factor;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
|
|
@ -1035,96 +1105,13 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
|
|||
float right = left + scaled_width;
|
||||
float bottom = top - scaled_height;
|
||||
|
||||
// renders background
|
||||
unsigned int bg_tex_id = m_background_texture.texture.get_id();
|
||||
float bg_tex_width = (float)m_background_texture.texture.get_width();
|
||||
float bg_tex_height = (float)m_background_texture.texture.get_height();
|
||||
if ((bg_tex_id != 0) && (bg_tex_width > 0) && (bg_tex_height > 0))
|
||||
{
|
||||
float inv_bg_tex_width = (bg_tex_width != 0.0f) ? 1.0f / bg_tex_width : 0.0f;
|
||||
float inv_bg_tex_height = (bg_tex_height != 0.0f) ? 1.0f / bg_tex_height : 0.0f;
|
||||
|
||||
float bg_uv_left = 0.0f;
|
||||
float bg_uv_right = 1.0f;
|
||||
float bg_uv_top = 1.0f;
|
||||
float bg_uv_bottom = 0.0f;
|
||||
|
||||
float bg_left = left;
|
||||
float bg_right = right;
|
||||
float bg_top = top;
|
||||
float bg_bottom = bottom;
|
||||
float bg_width = right - left;
|
||||
float bg_height = top - bottom;
|
||||
float bg_min_size = std::min(bg_width, bg_height);
|
||||
|
||||
float bg_uv_i_left = (float)m_background_texture.metadata.left * inv_bg_tex_width;
|
||||
float bg_uv_i_right = 1.0f - (float)m_background_texture.metadata.right * inv_bg_tex_width;
|
||||
float bg_uv_i_top = 1.0f - (float)m_background_texture.metadata.top * inv_bg_tex_height;
|
||||
float bg_uv_i_bottom = (float)m_background_texture.metadata.bottom * inv_bg_tex_height;
|
||||
|
||||
float bg_i_left = bg_left + scaled_border;
|
||||
float bg_i_right = bg_right - scaled_border;
|
||||
float bg_i_top = bg_top - scaled_border;
|
||||
float bg_i_bottom = bg_bottom + scaled_border;
|
||||
|
||||
switch (m_layout.orientation)
|
||||
{
|
||||
case Layout::Top:
|
||||
{
|
||||
bg_uv_top = bg_uv_i_top;
|
||||
bg_i_top = bg_top;
|
||||
break;
|
||||
}
|
||||
case Layout::Bottom:
|
||||
{
|
||||
bg_uv_bottom = bg_uv_i_bottom;
|
||||
bg_i_bottom = bg_bottom;
|
||||
break;
|
||||
}
|
||||
case Layout::Center:
|
||||
{
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if ((m_layout.border > 0) && (bg_uv_top != bg_uv_i_top))
|
||||
{
|
||||
if (bg_uv_left != bg_uv_i_left)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_i_top, bg_top, { { bg_uv_left, bg_uv_i_top }, { bg_uv_i_left, bg_uv_i_top }, { bg_uv_i_left, bg_uv_top }, { bg_uv_left, bg_uv_top } });
|
||||
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_left, bg_i_right, bg_i_top, bg_top, { { bg_uv_i_left, bg_uv_i_top }, { bg_uv_i_right, bg_uv_i_top }, { bg_uv_i_right, bg_uv_top }, { bg_uv_i_left, bg_uv_top } });
|
||||
|
||||
if (bg_uv_right != bg_uv_i_right)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_right, bg_right, bg_i_top, bg_top, { { bg_uv_i_right, bg_uv_i_top }, { bg_uv_right, bg_uv_i_top }, { bg_uv_right, bg_uv_top }, { bg_uv_i_right, bg_uv_top } });
|
||||
}
|
||||
|
||||
if ((m_layout.border > 0) && (bg_uv_left != bg_uv_i_left))
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_i_bottom, bg_i_top, { { bg_uv_left, bg_uv_i_bottom }, { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_i_left, bg_uv_i_top }, { bg_uv_left, bg_uv_i_top } });
|
||||
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_left, bg_i_right, bg_i_bottom, bg_i_top, { { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_i_right, bg_uv_i_bottom }, { bg_uv_i_right, bg_uv_i_top }, { bg_uv_i_left, bg_uv_i_top } });
|
||||
|
||||
if ((m_layout.border > 0) && (bg_uv_right != bg_uv_i_right))
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_right, bg_right, bg_i_bottom, bg_i_top, { { bg_uv_i_right, bg_uv_i_bottom }, { bg_uv_right, bg_uv_i_bottom }, { bg_uv_right, bg_uv_i_top }, { bg_uv_i_right, bg_uv_i_top } });
|
||||
|
||||
if ((m_layout.border > 0) && (bg_uv_bottom != bg_uv_i_bottom))
|
||||
{
|
||||
if (bg_uv_left != bg_uv_i_left)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_bottom, bg_i_bottom, { { bg_uv_left, bg_uv_bottom }, { bg_uv_i_left, bg_uv_bottom }, { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_left, bg_uv_i_bottom } });
|
||||
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_left, bg_i_right, bg_bottom, bg_i_bottom, { { bg_uv_i_left, bg_uv_bottom }, { bg_uv_i_right, bg_uv_bottom }, { bg_uv_i_right, bg_uv_i_bottom }, { bg_uv_i_left, bg_uv_i_bottom } });
|
||||
|
||||
if (bg_uv_right != bg_uv_i_right)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_right, bg_right, bg_bottom, bg_i_bottom, { { bg_uv_i_right, bg_uv_bottom }, { bg_uv_right, bg_uv_bottom }, { bg_uv_right, bg_uv_i_bottom }, { bg_uv_i_right, bg_uv_i_bottom } });
|
||||
}
|
||||
}
|
||||
render_background(left, top, right, bottom, scaled_border);
|
||||
|
||||
left += scaled_border;
|
||||
top -= scaled_border;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0))
|
||||
return;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
// renders icons
|
||||
for (const GLToolbarItem* item : m_items)
|
||||
|
|
@ -1136,11 +1123,7 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
|
|||
left += separator_stride;
|
||||
else
|
||||
{
|
||||
#if ENABLE_SVG_ICONS
|
||||
item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale));
|
||||
#else
|
||||
item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, m_icons_texture.metadata.icon_size);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
left += icon_stride;
|
||||
}
|
||||
}
|
||||
|
|
@ -1148,34 +1131,15 @@ void GLToolbar::render_horizontal(const GLCanvas3D& parent) const
|
|||
|
||||
void GLToolbar::render_vertical(const GLCanvas3D& parent) const
|
||||
{
|
||||
#if ENABLE_SVG_ICONS
|
||||
unsigned int tex_id = m_icons_texture.get_id();
|
||||
int tex_width = m_icons_texture.get_width();
|
||||
int tex_height = m_icons_texture.get_height();
|
||||
#else
|
||||
unsigned int tex_id = m_icons_texture.texture.get_id();
|
||||
int tex_width = m_icons_texture.texture.get_width();
|
||||
int tex_height = m_icons_texture.texture.get_height();
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
#if !ENABLE_SVG_ICONS
|
||||
if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0))
|
||||
return;
|
||||
#endif // !ENABLE_SVG_ICONS
|
||||
|
||||
float zoom = (float)parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
#if ENABLE_SVG_ICONS
|
||||
float factor = inv_zoom * m_layout.scale;
|
||||
#else
|
||||
float factor = inv_zoom * m_layout.icons_scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
float scaled_icons_size = m_layout.icons_size * factor;
|
||||
#else
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_layout.icons_scale * factor;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
float scaled_separator_size = m_layout.separator_size * factor;
|
||||
float scaled_gap_size = m_layout.gap_size * factor;
|
||||
float scaled_border = m_layout.border * factor;
|
||||
|
|
@ -1190,96 +1154,13 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const
|
|||
float right = left + scaled_width;
|
||||
float bottom = top - scaled_height;
|
||||
|
||||
// renders background
|
||||
unsigned int bg_tex_id = m_background_texture.texture.get_id();
|
||||
float bg_tex_width = (float)m_background_texture.texture.get_width();
|
||||
float bg_tex_height = (float)m_background_texture.texture.get_height();
|
||||
if ((bg_tex_id != 0) && (bg_tex_width > 0) && (bg_tex_height > 0))
|
||||
{
|
||||
float inv_bg_tex_width = (bg_tex_width != 0.0f) ? 1.0f / bg_tex_width : 0.0f;
|
||||
float inv_bg_tex_height = (bg_tex_height != 0.0f) ? 1.0f / bg_tex_height : 0.0f;
|
||||
|
||||
float bg_uv_left = 0.0f;
|
||||
float bg_uv_right = 1.0f;
|
||||
float bg_uv_top = 1.0f;
|
||||
float bg_uv_bottom = 0.0f;
|
||||
|
||||
float bg_left = left;
|
||||
float bg_right = right;
|
||||
float bg_top = top;
|
||||
float bg_bottom = bottom;
|
||||
float bg_width = right - left;
|
||||
float bg_height = top - bottom;
|
||||
float bg_min_size = std::min(bg_width, bg_height);
|
||||
|
||||
float bg_uv_i_left = (float)m_background_texture.metadata.left * inv_bg_tex_width;
|
||||
float bg_uv_i_right = 1.0f - (float)m_background_texture.metadata.right * inv_bg_tex_width;
|
||||
float bg_uv_i_top = 1.0f - (float)m_background_texture.metadata.top * inv_bg_tex_height;
|
||||
float bg_uv_i_bottom = (float)m_background_texture.metadata.bottom * inv_bg_tex_height;
|
||||
|
||||
float bg_i_left = bg_left + scaled_border;
|
||||
float bg_i_right = bg_right - scaled_border;
|
||||
float bg_i_top = bg_top - scaled_border;
|
||||
float bg_i_bottom = bg_bottom + scaled_border;
|
||||
|
||||
switch (m_layout.orientation)
|
||||
{
|
||||
case Layout::Left:
|
||||
{
|
||||
bg_uv_left = bg_uv_i_left;
|
||||
bg_i_left = bg_left;
|
||||
break;
|
||||
}
|
||||
case Layout::Right:
|
||||
{
|
||||
bg_uv_right = bg_uv_i_right;
|
||||
bg_i_right = bg_right;
|
||||
break;
|
||||
}
|
||||
case Layout::Center:
|
||||
{
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
if ((m_layout.border > 0) && (bg_uv_top != bg_uv_i_top))
|
||||
{
|
||||
if (bg_uv_left != bg_uv_i_left)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_i_top, bg_top, { { bg_uv_left, bg_uv_i_top }, { bg_uv_i_left, bg_uv_i_top }, { bg_uv_i_left, bg_uv_top }, { bg_uv_left, bg_uv_top } });
|
||||
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_left, bg_i_right, bg_i_top, bg_top, { { bg_uv_i_left, bg_uv_i_top }, { bg_uv_i_right, bg_uv_i_top }, { bg_uv_i_right, bg_uv_top }, { bg_uv_i_left, bg_uv_top } });
|
||||
|
||||
if (bg_uv_right != bg_uv_i_right)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_right, bg_right, bg_i_top, bg_top, { { bg_uv_i_right, bg_uv_i_top }, { bg_uv_right, bg_uv_i_top }, { bg_uv_right, bg_uv_top }, { bg_uv_i_right, bg_uv_top } });
|
||||
}
|
||||
|
||||
if ((m_layout.border > 0) && (bg_uv_left != bg_uv_i_left))
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_i_bottom, bg_i_top, { { bg_uv_left, bg_uv_i_bottom }, { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_i_left, bg_uv_i_top }, { bg_uv_left, bg_uv_i_top } });
|
||||
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_left, bg_i_right, bg_i_bottom, bg_i_top, { { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_i_right, bg_uv_i_bottom }, { bg_uv_i_right, bg_uv_i_top }, { bg_uv_i_left, bg_uv_i_top } });
|
||||
|
||||
if ((m_layout.border > 0) && (bg_uv_right != bg_uv_i_right))
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_right, bg_right, bg_i_bottom, bg_i_top, { { bg_uv_i_right, bg_uv_i_bottom }, { bg_uv_right, bg_uv_i_bottom }, { bg_uv_right, bg_uv_i_top }, { bg_uv_i_right, bg_uv_i_top } });
|
||||
|
||||
if ((m_layout.border > 0) && (bg_uv_bottom != bg_uv_i_bottom))
|
||||
{
|
||||
if (bg_uv_left != bg_uv_i_left)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_bottom, bg_i_bottom, { { bg_uv_left, bg_uv_bottom }, { bg_uv_i_left, bg_uv_bottom }, { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_left, bg_uv_i_bottom } });
|
||||
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_left, bg_i_right, bg_bottom, bg_i_bottom, { { bg_uv_i_left, bg_uv_bottom }, { bg_uv_i_right, bg_uv_bottom }, { bg_uv_i_right, bg_uv_i_bottom }, { bg_uv_i_left, bg_uv_i_bottom } });
|
||||
|
||||
if (bg_uv_right != bg_uv_i_right)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_right, bg_right, bg_bottom, bg_i_bottom, { { bg_uv_i_right, bg_uv_bottom }, { bg_uv_right, bg_uv_bottom }, { bg_uv_right, bg_uv_i_bottom }, { bg_uv_i_right, bg_uv_i_bottom } });
|
||||
}
|
||||
}
|
||||
render_background(left, top, right, bottom, scaled_border);
|
||||
|
||||
left += scaled_border;
|
||||
top -= scaled_border;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
if ((tex_id == 0) || (tex_width <= 0) || (tex_height <= 0))
|
||||
return;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
// renders icons
|
||||
for (const GLToolbarItem* item : m_items)
|
||||
|
|
@ -1291,17 +1172,12 @@ void GLToolbar::render_vertical(const GLCanvas3D& parent) const
|
|||
top -= separator_stride;
|
||||
else
|
||||
{
|
||||
#if ENABLE_SVG_ICONS
|
||||
item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, (unsigned int)(m_layout.icons_size * m_layout.scale));
|
||||
#else
|
||||
item->render(tex_id, left, left + scaled_icons_size, top - scaled_icons_size, top, (unsigned int)tex_width, (unsigned int)tex_height, m_icons_texture.metadata.icon_size);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
top -= icon_stride;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
bool GLToolbar::generate_icons_texture() const
|
||||
{
|
||||
std::string path = resources_dir() + "/icons/";
|
||||
|
|
@ -1337,7 +1213,6 @@ bool GLToolbar::generate_icons_texture() const
|
|||
|
||||
return res;
|
||||
}
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
bool GLToolbar::update_items_visibility()
|
||||
{
|
||||
|
|
@ -1371,9 +1246,15 @@ bool GLToolbar::update_items_enabled_state()
|
|||
{
|
||||
bool ret = false;
|
||||
|
||||
for (GLToolbarItem* item : m_items)
|
||||
for (unsigned int i = 0; i < (unsigned int)m_items.size(); ++i)
|
||||
{
|
||||
GLToolbarItem* item = m_items[i];
|
||||
ret |= item->update_enabled_state();
|
||||
if (item->is_enabled() && (m_pressed_toggable_id != -1) && (m_pressed_toggable_id != i))
|
||||
{
|
||||
ret = true;
|
||||
item->set_state(GLToolbarItem::Disabled);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ class GLToolbarItem
|
|||
public:
|
||||
typedef std::function<void()> ActionCallback;
|
||||
typedef std::function<bool()> VisibilityCallback;
|
||||
typedef std::function<bool()> EnabledStateCallback;
|
||||
typedef std::function<bool()> EnablingCallback;
|
||||
typedef std::function<void(float, float, float, float)> RenderCallback;
|
||||
|
||||
enum EType : unsigned char
|
||||
{
|
||||
|
|
@ -45,6 +46,14 @@ public:
|
|||
Num_Types
|
||||
};
|
||||
|
||||
enum EActionType : unsigned char
|
||||
{
|
||||
Undefined,
|
||||
Left,
|
||||
Right,
|
||||
Num_Action_Types
|
||||
};
|
||||
|
||||
enum EState : unsigned char
|
||||
{
|
||||
Normal,
|
||||
|
|
@ -57,29 +66,43 @@ public:
|
|||
|
||||
struct Data
|
||||
{
|
||||
struct Option
|
||||
{
|
||||
bool toggable;
|
||||
ActionCallback action_callback;
|
||||
RenderCallback render_callback;
|
||||
|
||||
Option();
|
||||
|
||||
bool can_render() const { return toggable && (render_callback != nullptr); }
|
||||
};
|
||||
|
||||
std::string name;
|
||||
#if ENABLE_SVG_ICONS
|
||||
std::string icon_filename;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
std::string tooltip;
|
||||
std::string additional_tooltip;
|
||||
unsigned int sprite_id;
|
||||
bool is_toggable;
|
||||
// mouse left click
|
||||
Option left;
|
||||
// mouse right click
|
||||
Option right;
|
||||
bool visible;
|
||||
ActionCallback action_callback;
|
||||
VisibilityCallback visibility_callback;
|
||||
EnabledStateCallback enabled_state_callback;
|
||||
EnablingCallback enabling_callback;
|
||||
|
||||
Data();
|
||||
};
|
||||
|
||||
static const ActionCallback Default_Action_Callback;
|
||||
static const VisibilityCallback Default_Visibility_Callback;
|
||||
static const EnabledStateCallback Default_Enabled_State_Callback;
|
||||
static const EnablingCallback Default_Enabling_Callback;
|
||||
static const RenderCallback Default_Render_Callback;
|
||||
|
||||
private:
|
||||
EType m_type;
|
||||
EState m_state;
|
||||
Data m_data;
|
||||
EActionType m_last_action_type;
|
||||
|
||||
public:
|
||||
GLToolbarItem(EType type, const Data& data);
|
||||
|
|
@ -88,22 +111,30 @@ public:
|
|||
void set_state(EState state) { m_state = state; }
|
||||
|
||||
const std::string& get_name() const { return m_data.name; }
|
||||
#if ENABLE_SVG_ICONS
|
||||
const std::string& get_icon_filename() const { return m_data.icon_filename; }
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
const std::string& get_tooltip() const { return m_data.tooltip; }
|
||||
const std::string& get_additional_tooltip() const { return m_data.additional_tooltip; }
|
||||
void set_additional_tooltip(const std::string& text) { m_data.additional_tooltip = text; }
|
||||
|
||||
void do_action() { m_data.action_callback(); }
|
||||
void do_left_action() { m_last_action_type = Left; m_data.left.action_callback(); }
|
||||
void do_right_action() { m_last_action_type = Right; m_data.right.action_callback(); }
|
||||
|
||||
bool is_enabled() const { return m_state != Disabled; }
|
||||
bool is_disabled() const { return m_state == Disabled; }
|
||||
bool is_hovered() const { return (m_state == Hover) || (m_state == HoverPressed); }
|
||||
bool is_pressed() const { return (m_state == Pressed) || (m_state == HoverPressed); }
|
||||
|
||||
bool is_toggable() const { return m_data.is_toggable; }
|
||||
bool is_visible() const { return m_data.visible; }
|
||||
bool is_separator() const { return m_type == Separator; }
|
||||
|
||||
bool is_left_toggable() const { return m_data.left.toggable; }
|
||||
bool is_right_toggable() const { return m_data.right.toggable; }
|
||||
|
||||
bool has_left_render_callback() const { return m_data.left.render_callback != nullptr; }
|
||||
bool has_right_render_callback() const { return m_data.right.render_callback != nullptr; }
|
||||
|
||||
EActionType get_last_action_type() const { return m_last_action_type; }
|
||||
void reset_last_action_type() { m_last_action_type = Undefined; }
|
||||
|
||||
// returns true if the state changes
|
||||
bool update_visibility();
|
||||
// returns true if the state changes
|
||||
|
|
@ -118,27 +149,6 @@ private:
|
|||
friend class GLToolbar;
|
||||
};
|
||||
|
||||
#if !ENABLE_SVG_ICONS
|
||||
// items icon textures are assumed to be square and all with the same size in pixels, no internal check is done
|
||||
// icons are layed-out into the texture starting from the top-left corner in the same order as enum GLToolbarItem::EState
|
||||
// from left to right
|
||||
struct ItemsIconsTexture
|
||||
{
|
||||
struct Metadata
|
||||
{
|
||||
// path of the file containing the icons' texture
|
||||
std::string filename;
|
||||
// size of the square icons, in pixels
|
||||
unsigned int icon_size;
|
||||
|
||||
Metadata();
|
||||
};
|
||||
|
||||
GLTexture texture;
|
||||
Metadata metadata;
|
||||
};
|
||||
#endif // !ENABLE_SVG_ICONS
|
||||
|
||||
struct BackgroundTexture
|
||||
{
|
||||
struct Metadata
|
||||
|
|
@ -164,9 +174,7 @@ struct BackgroundTexture
|
|||
class GLToolbar
|
||||
{
|
||||
public:
|
||||
#if ENABLE_SVG_ICONS
|
||||
static const float Default_Icons_Size;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
enum EType : unsigned char
|
||||
{
|
||||
|
|
@ -184,29 +192,32 @@ public:
|
|||
Num_Types
|
||||
};
|
||||
|
||||
enum EOrientation : unsigned int
|
||||
enum EHorizontalOrientation : unsigned char
|
||||
{
|
||||
Top,
|
||||
Bottom,
|
||||
Left,
|
||||
Right,
|
||||
Center,
|
||||
Num_Locations
|
||||
HO_Left,
|
||||
HO_Center,
|
||||
HO_Right,
|
||||
Num_Horizontal_Orientations
|
||||
};
|
||||
|
||||
enum EVerticalOrientation : unsigned char
|
||||
{
|
||||
VO_Top,
|
||||
VO_Center,
|
||||
VO_Bottom,
|
||||
Num_Vertical_Orientations
|
||||
};
|
||||
|
||||
EType type;
|
||||
EOrientation orientation;
|
||||
EHorizontalOrientation horizontal_orientation;
|
||||
EVerticalOrientation vertical_orientation;
|
||||
float top;
|
||||
float left;
|
||||
float border;
|
||||
float separator_size;
|
||||
float gap_size;
|
||||
#if ENABLE_SVG_ICONS
|
||||
float icons_size;
|
||||
float scale;
|
||||
#else
|
||||
float icons_scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
float width;
|
||||
float height;
|
||||
|
|
@ -219,16 +230,10 @@ private:
|
|||
typedef std::vector<GLToolbarItem*> ItemsList;
|
||||
|
||||
EType m_type;
|
||||
#if ENABLE_SVG_ICONS
|
||||
std::string m_name;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
bool m_enabled;
|
||||
#if ENABLE_SVG_ICONS
|
||||
mutable GLTexture m_icons_texture;
|
||||
mutable bool m_icons_texture_dirty;
|
||||
#else
|
||||
ItemsIconsTexture m_icons_texture;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
BackgroundTexture m_background_texture;
|
||||
mutable Layout m_layout;
|
||||
|
||||
|
|
@ -249,36 +254,27 @@ private:
|
|||
|
||||
MouseCapture m_mouse_capture;
|
||||
std::string m_tooltip;
|
||||
unsigned int m_pressed_toggable_id;
|
||||
|
||||
public:
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLToolbar(EType type, const std::string& name);
|
||||
#else
|
||||
explicit GLToolbar(EType type);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
~GLToolbar();
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
bool init(const BackgroundTexture::Metadata& background_texture);
|
||||
#else
|
||||
bool init(const ItemsIconsTexture::Metadata& icons_texture, const BackgroundTexture::Metadata& background_texture);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
Layout::EType get_layout_type() const;
|
||||
void set_layout_type(Layout::EType type);
|
||||
Layout::EOrientation get_layout_orientation() const;
|
||||
void set_layout_orientation(Layout::EOrientation orientation);
|
||||
Layout::EHorizontalOrientation get_horizontal_orientation() const { return m_layout.horizontal_orientation; }
|
||||
void set_horizontal_orientation(Layout::EHorizontalOrientation orientation) { m_layout.horizontal_orientation = orientation; }
|
||||
Layout::EVerticalOrientation get_vertical_orientation() const { return m_layout.vertical_orientation; }
|
||||
void set_vertical_orientation(Layout::EVerticalOrientation orientation) { m_layout.vertical_orientation = orientation; }
|
||||
|
||||
void set_position(float top, float left);
|
||||
void set_border(float border);
|
||||
void set_separator_size(float size);
|
||||
void set_gap_size(float size);
|
||||
#if ENABLE_SVG_ICONS
|
||||
void set_icons_size(float size);
|
||||
void set_scale(float scale);
|
||||
#else
|
||||
void set_icons_scale(float scale);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
bool is_enabled() const;
|
||||
void set_enabled(bool enable);
|
||||
|
|
@ -295,8 +291,17 @@ public:
|
|||
bool is_item_disabled(const std::string& name) const;
|
||||
bool is_item_visible(const std::string& name) const;
|
||||
|
||||
bool is_any_item_pressed() const;
|
||||
|
||||
unsigned int get_item_id(const std::string& name) const;
|
||||
|
||||
void force_left_action(unsigned int item_id, GLCanvas3D& parent);
|
||||
void force_right_action(unsigned int item_id, GLCanvas3D& parent);
|
||||
|
||||
const std::string& get_tooltip() const { return m_tooltip; }
|
||||
|
||||
void get_additional_tooltip(unsigned int item_id, std::string& text);
|
||||
void set_additional_tooltip(unsigned int item_id, const std::string& text);
|
||||
|
||||
// returns true if any item changed its state
|
||||
bool update_items_state();
|
||||
|
|
@ -312,7 +317,7 @@ private:
|
|||
float get_height_horizontal() const;
|
||||
float get_height_vertical() const;
|
||||
float get_main_size() const;
|
||||
void do_action(unsigned int item_id, GLCanvas3D& parent);
|
||||
void do_action(GLToolbarItem::EActionType type, unsigned int item_id, GLCanvas3D& parent, bool check_hover);
|
||||
std::string update_hover_state(const Vec2d& mouse_pos, GLCanvas3D& parent);
|
||||
std::string update_hover_state_horizontal(const Vec2d& mouse_pos, GLCanvas3D& parent);
|
||||
std::string update_hover_state_vertical(const Vec2d& mouse_pos, GLCanvas3D& parent);
|
||||
|
|
@ -321,12 +326,11 @@ private:
|
|||
int contains_mouse_horizontal(const Vec2d& mouse_pos, const GLCanvas3D& parent) const;
|
||||
int contains_mouse_vertical(const Vec2d& mouse_pos, const GLCanvas3D& parent) const;
|
||||
|
||||
void render_background(float left, float top, float right, float bottom, float border) const;
|
||||
void render_horizontal(const GLCanvas3D& parent) const;
|
||||
void render_vertical(const GLCanvas3D& parent) const;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
bool generate_icons_texture() const;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
// returns true if any item changed its state
|
||||
bool update_items_visibility();
|
||||
|
|
|
|||
|
|
@ -135,8 +135,7 @@ void config_wizard(int reason)
|
|||
|
||||
wxGetApp().load_current_presets();
|
||||
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA &&
|
||||
wxGetApp().obj_list()->has_multi_part_objects())
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA && model_has_multi_part_objects(wxGetApp().model()))
|
||||
{
|
||||
show_info(nullptr,
|
||||
_(L("It's impossible to print multi-part object(s) with SLA technology.")) + "\n\n" +
|
||||
|
|
|
|||
|
|
@ -534,7 +534,7 @@ void GUI_App::persist_window_geometry(wxTopLevelWindow *window, bool default_max
|
|||
});
|
||||
}
|
||||
|
||||
void GUI_App::load_project(wxWindow *parent, wxString& input_file)
|
||||
void GUI_App::load_project(wxWindow *parent, wxString& input_file) const
|
||||
{
|
||||
input_file.Clear();
|
||||
wxFileDialog dialog(parent ? parent : GetTopWindow(),
|
||||
|
|
@ -546,7 +546,7 @@ void GUI_App::load_project(wxWindow *parent, wxString& input_file)
|
|||
input_file = dialog.GetPath();
|
||||
}
|
||||
|
||||
void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files)
|
||||
void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const
|
||||
{
|
||||
input_files.Clear();
|
||||
wxFileDialog dialog(parent ? parent : GetTopWindow(),
|
||||
|
|
@ -854,7 +854,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
|||
|
||||
// This is called when closing the application, when loading a config file or when starting the config wizard
|
||||
// to notify the user whether he is aware that some preset changes will be lost.
|
||||
bool GUI_App::check_unsaved_changes()
|
||||
bool GUI_App::check_unsaved_changes(const wxString &header)
|
||||
{
|
||||
wxString dirty;
|
||||
PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology();
|
||||
|
|
@ -868,8 +868,12 @@ bool GUI_App::check_unsaved_changes()
|
|||
// No changes, the application may close or reload presets.
|
||||
return true;
|
||||
// Ask the user.
|
||||
wxString message;
|
||||
if (! header.empty())
|
||||
message = header + "\n\n";
|
||||
message += _(L("The presets on the following tabs were modified")) + ": " + dirty + "\n\n" + _(L("Discard changes and continue anyway?"));
|
||||
wxMessageDialog dialog(mainframe,
|
||||
_(L("The presets on the following tabs were modified")) + ": " + dirty + "\n\n" + _(L("Discard changes and continue anyway?")),
|
||||
message,
|
||||
wxString(SLIC3R_APP_NAME) + " - " + _(L("Unsaved Presets")),
|
||||
wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT);
|
||||
return dialog.ShowModal() == wxID_YES;
|
||||
|
|
@ -934,14 +938,19 @@ ObjectList* GUI_App::obj_list()
|
|||
return sidebar().obj_list();
|
||||
}
|
||||
|
||||
ObjectLayers* GUI_App::obj_layers()
|
||||
{
|
||||
return sidebar().obj_layers();
|
||||
}
|
||||
|
||||
Plater* GUI_App::plater()
|
||||
{
|
||||
return plater_;
|
||||
}
|
||||
|
||||
ModelObjectPtrs* GUI_App::model_objects()
|
||||
Model& GUI_App::model()
|
||||
{
|
||||
return &plater_->model().objects;
|
||||
return plater_->model();
|
||||
}
|
||||
|
||||
wxNotebook* GUI_App::tab_panel() const
|
||||
|
|
|
|||
|
|
@ -121,8 +121,8 @@ public:
|
|||
void recreate_GUI();
|
||||
void system_info();
|
||||
void keyboard_shortcuts();
|
||||
void load_project(wxWindow *parent, wxString& input_file);
|
||||
void import_model(wxWindow *parent, wxArrayString& input_files);
|
||||
void load_project(wxWindow *parent, wxString& input_file) const;
|
||||
void import_model(wxWindow *parent, wxArrayString& input_files) const;
|
||||
static bool catch_error(std::function<void()> cb, const std::string& err);
|
||||
|
||||
void persist_window_geometry(wxTopLevelWindow *window, bool default_maximized = false);
|
||||
|
|
@ -139,7 +139,7 @@ public:
|
|||
void update_mode();
|
||||
|
||||
void add_config_menu(wxMenuBar *menu);
|
||||
bool check_unsaved_changes();
|
||||
bool check_unsaved_changes(const wxString &header = wxString());
|
||||
bool checked_tab(Tab* tab);
|
||||
void load_current_presets();
|
||||
|
||||
|
|
@ -156,8 +156,9 @@ public:
|
|||
ObjectManipulation* obj_manipul();
|
||||
ObjectSettings* obj_settings();
|
||||
ObjectList* obj_list();
|
||||
ObjectLayers* obj_layers();
|
||||
Plater* plater();
|
||||
std::vector<ModelObject*> *model_objects();
|
||||
Model& model();
|
||||
|
||||
AppConfig* app_config{ nullptr };
|
||||
PresetBundle* preset_bundle{ nullptr };
|
||||
|
|
|
|||
341
src/slic3r/GUI/GUI_ObjectLayers.cpp
Normal file
341
src/slic3r/GUI/GUI_ObjectLayers.cpp
Normal file
|
|
@ -0,0 +1,341 @@
|
|||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
|
||||
#include "OptionsGroup.hpp"
|
||||
#include "PresetBundle.hpp"
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include "I18N.hpp"
|
||||
|
||||
#include <wx/wupdlock.h>
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
namespace GUI
|
||||
{
|
||||
|
||||
ObjectLayers::ObjectLayers(wxWindow* parent) :
|
||||
OG_Settings(parent, true)
|
||||
{
|
||||
m_grid_sizer = new wxFlexGridSizer(3, 5, 5); // "Min Z", "Max Z", "Layer height" & buttons sizer
|
||||
m_grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
|
||||
|
||||
// Legend for object layers
|
||||
for (const std::string col : { "Min Z", "Max Z", "Layer height" }) {
|
||||
auto temp = new wxStaticText(m_parent, wxID_ANY, _(L(col)), wxDefaultPosition, /*size*/wxDefaultSize, wxST_ELLIPSIZE_MIDDLE);
|
||||
temp->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||
temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
temp->SetFont(wxGetApp().bold_font());
|
||||
|
||||
m_grid_sizer->Add(temp);
|
||||
}
|
||||
|
||||
m_og->sizer->Clear(true);
|
||||
m_og->sizer->Add(m_grid_sizer, 0, wxEXPAND | wxALL, wxOSX ? 0 : 5);
|
||||
|
||||
m_bmp_delete = ScalableBitmap(parent, "remove_copies"/*"cross"*/);
|
||||
m_bmp_add = ScalableBitmap(parent, "add_copies");
|
||||
}
|
||||
|
||||
void ObjectLayers::select_editor(LayerRangeEditor* editor, const bool is_last_edited_range)
|
||||
{
|
||||
if (is_last_edited_range && m_selection_type == editor->type()) {
|
||||
/* Workaround! Under OSX we should use CallAfter() for SetFocus() after LayerEditors "reorganizations",
|
||||
* because of selected control's strange behavior:
|
||||
* cursor is set to the control, but blue border - doesn't.
|
||||
* And as a result we couldn't edit this control.
|
||||
* */
|
||||
#ifdef __WXOSX__
|
||||
wxTheApp->CallAfter([editor]() {
|
||||
#endif
|
||||
editor->SetFocus();
|
||||
editor->SetInsertionPointEnd();
|
||||
#ifdef __WXOSX__
|
||||
});
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
wxSizer* ObjectLayers::create_layer(const t_layer_height_range& range)
|
||||
{
|
||||
const bool is_last_edited_range = range == m_selectable_range;
|
||||
|
||||
auto set_focus_data = [range, this](const EditorType type)
|
||||
{
|
||||
m_selectable_range = range;
|
||||
m_selection_type = type;
|
||||
};
|
||||
|
||||
auto update_focus_data = [range, this](const t_layer_height_range& new_range, EditorType type, bool enter_pressed)
|
||||
{
|
||||
// change selectable range for new one, if enter was pressed or if same range was selected
|
||||
if (enter_pressed || m_selectable_range == range)
|
||||
m_selectable_range = new_range;
|
||||
if (enter_pressed)
|
||||
m_selection_type = type;
|
||||
};
|
||||
|
||||
// Add control for the "Min Z"
|
||||
|
||||
auto editor = new LayerRangeEditor(this, double_to_string(range.first), etMinZ,
|
||||
set_focus_data, [range, update_focus_data, this](coordf_t min_z, bool enter_pressed)
|
||||
{
|
||||
if (fabs(min_z - range.first) < EPSILON) {
|
||||
m_selection_type = etUndef;
|
||||
return false;
|
||||
}
|
||||
|
||||
// data for next focusing
|
||||
coordf_t max_z = min_z < range.second ? range.second : min_z + 0.5;
|
||||
const t_layer_height_range& new_range = { min_z, max_z };
|
||||
update_focus_data(new_range, etMinZ, enter_pressed);
|
||||
|
||||
return wxGetApp().obj_list()->edit_layer_range(range, new_range);
|
||||
});
|
||||
|
||||
select_editor(editor, is_last_edited_range);
|
||||
m_grid_sizer->Add(editor);
|
||||
|
||||
// Add control for the "Max Z"
|
||||
|
||||
editor = new LayerRangeEditor(this, double_to_string(range.second), etMaxZ,
|
||||
set_focus_data, [range, update_focus_data, this](coordf_t max_z, bool enter_pressed)
|
||||
{
|
||||
if (fabs(max_z - range.second) < EPSILON || range.first > max_z) {
|
||||
m_selection_type = etUndef;
|
||||
return false; // LayersList would not be updated/recreated
|
||||
}
|
||||
|
||||
// data for next focusing
|
||||
const t_layer_height_range& new_range = { range.first, max_z };
|
||||
update_focus_data(new_range, etMaxZ, enter_pressed);
|
||||
|
||||
return wxGetApp().obj_list()->edit_layer_range(range, new_range);
|
||||
});
|
||||
|
||||
select_editor(editor, is_last_edited_range);
|
||||
m_grid_sizer->Add(editor);
|
||||
|
||||
// Add control for the "Layer height"
|
||||
|
||||
editor = new LayerRangeEditor(this,
|
||||
double_to_string(m_object->layer_config_ranges[range].option("layer_height")->getFloat()),
|
||||
etLayerHeight, set_focus_data, [range, this](coordf_t layer_height, bool)
|
||||
{
|
||||
return wxGetApp().obj_list()->edit_layer_range(range, layer_height);
|
||||
});
|
||||
|
||||
select_editor(editor, is_last_edited_range);
|
||||
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(editor);
|
||||
m_grid_sizer->Add(sizer);
|
||||
|
||||
return sizer;
|
||||
}
|
||||
|
||||
void ObjectLayers::create_layers_list()
|
||||
{
|
||||
for (const auto layer : m_object->layer_config_ranges)
|
||||
{
|
||||
const t_layer_height_range& range = layer.first;
|
||||
auto sizer = create_layer(range);
|
||||
|
||||
auto del_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_delete);
|
||||
del_btn->SetToolTip(_(L("Remove layer")));
|
||||
|
||||
sizer->Add(del_btn, 0, wxRIGHT | wxLEFT, em_unit(m_parent));
|
||||
|
||||
del_btn->Bind(wxEVT_BUTTON, [this, range](wxEvent &event) {
|
||||
wxGetApp().obj_list()->del_layer_range(range);
|
||||
});
|
||||
|
||||
auto add_btn = new ScalableButton(m_parent, wxID_ANY, m_bmp_add);
|
||||
add_btn->SetToolTip(_(L("Add layer")));
|
||||
|
||||
sizer->Add(add_btn, 0, wxRIGHT, em_unit(m_parent));
|
||||
|
||||
add_btn->Bind(wxEVT_BUTTON, [this, range](wxEvent &event) {
|
||||
wxGetApp().obj_list()->add_layer_range_after_current(range);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectLayers::update_layers_list()
|
||||
{
|
||||
ObjectList* objects_ctrl = wxGetApp().obj_list();
|
||||
if (objects_ctrl->multiple_selection()) return;
|
||||
|
||||
const auto item = objects_ctrl->GetSelection();
|
||||
if (!item) return;
|
||||
|
||||
const int obj_idx = objects_ctrl->get_selected_obj_idx();
|
||||
if (obj_idx < 0) return;
|
||||
|
||||
const ItemType type = objects_ctrl->GetModel()->GetItemType(item);
|
||||
if (!(type & (itLayerRoot | itLayer))) return;
|
||||
|
||||
m_object = objects_ctrl->object(obj_idx);
|
||||
if (!m_object || m_object->layer_config_ranges.empty()) return;
|
||||
|
||||
// Delete all controls from options group except of the legends
|
||||
|
||||
const int cols = m_grid_sizer->GetEffectiveColsCount();
|
||||
const int rows = m_grid_sizer->GetEffectiveRowsCount();
|
||||
for (int idx = cols*rows-1; idx >= cols; idx--) {
|
||||
wxSizerItem* t = m_grid_sizer->GetItem(idx);
|
||||
if (t->IsSizer())
|
||||
t->GetSizer()->Clear(true);
|
||||
else
|
||||
t->DeleteWindows();
|
||||
m_grid_sizer->Remove(idx);
|
||||
}
|
||||
|
||||
// Add new control according to the selected item
|
||||
|
||||
if (type & itLayerRoot)
|
||||
create_layers_list();
|
||||
else
|
||||
create_layer(objects_ctrl->GetModel()->GetLayerRangeByItem(item));
|
||||
|
||||
m_parent->Layout();
|
||||
}
|
||||
|
||||
void ObjectLayers::update_scene_from_editor_selection() const
|
||||
{
|
||||
// needed to show the visual hints in 3D scene
|
||||
wxGetApp().plater()->canvas3D()->handle_layers_data_focus_event(m_selectable_range, m_selection_type);
|
||||
}
|
||||
|
||||
void ObjectLayers::UpdateAndShow(const bool show)
|
||||
{
|
||||
if (show)
|
||||
update_layers_list();
|
||||
|
||||
OG_Settings::UpdateAndShow(show);
|
||||
}
|
||||
|
||||
void ObjectLayers::msw_rescale()
|
||||
{
|
||||
m_bmp_delete.msw_rescale();
|
||||
m_bmp_add.msw_rescale();
|
||||
}
|
||||
|
||||
void ObjectLayers::reset_selection()
|
||||
{
|
||||
m_selectable_range = { 0.0, 0.0 };
|
||||
m_selection_type = etLayerHeight;
|
||||
}
|
||||
|
||||
LayerRangeEditor::LayerRangeEditor( ObjectLayers* parent,
|
||||
const wxString& value,
|
||||
EditorType type,
|
||||
std::function<void(EditorType)> set_focus_data_fn,
|
||||
std::function<bool(coordf_t, bool enter_pressed)> edit_fn
|
||||
) :
|
||||
m_valid_value(value),
|
||||
m_type(type),
|
||||
m_set_focus_data(set_focus_data_fn),
|
||||
wxTextCtrl(parent->m_parent, wxID_ANY, value, wxDefaultPosition,
|
||||
wxSize(8 * em_unit(parent->m_parent), wxDefaultCoord), wxTE_PROCESS_ENTER)
|
||||
{
|
||||
this->SetFont(wxGetApp().normal_font());
|
||||
|
||||
this->Bind(wxEVT_TEXT_ENTER, [this, edit_fn](wxEvent&)
|
||||
{
|
||||
m_enter_pressed = true;
|
||||
// If LayersList wasn't updated/recreated, we can call wxEVT_KILL_FOCUS.Skip()
|
||||
if (m_type&etLayerHeight) {
|
||||
if (!edit_fn(get_value(), true))
|
||||
SetValue(m_valid_value);
|
||||
else
|
||||
m_valid_value = double_to_string(get_value());
|
||||
m_call_kill_focus = true;
|
||||
}
|
||||
else if (!edit_fn(get_value(), true)) {
|
||||
SetValue(m_valid_value);
|
||||
m_call_kill_focus = true;
|
||||
}
|
||||
}, this->GetId());
|
||||
|
||||
this->Bind(wxEVT_KILL_FOCUS, [this, edit_fn](wxFocusEvent& e)
|
||||
{
|
||||
if (!m_enter_pressed) {
|
||||
#ifndef __WXGTK__
|
||||
/* Update data for next editor selection.
|
||||
* But under GTK it lucks like there is no information about selected control at e.GetWindow(),
|
||||
* so we'll take it from wxEVT_LEFT_DOWN event
|
||||
* */
|
||||
LayerRangeEditor* new_editor = dynamic_cast<LayerRangeEditor*>(e.GetWindow());
|
||||
if (new_editor)
|
||||
new_editor->set_focus_data();
|
||||
#endif // not __WXGTK__
|
||||
// If LayersList wasn't updated/recreated, we should call e.Skip()
|
||||
if (m_type & etLayerHeight) {
|
||||
if (!edit_fn(get_value(), false))
|
||||
SetValue(m_valid_value);
|
||||
else
|
||||
m_valid_value = double_to_string(get_value());
|
||||
e.Skip();
|
||||
}
|
||||
else if (!edit_fn(get_value(), false)) {
|
||||
SetValue(m_valid_value);
|
||||
e.Skip();
|
||||
}
|
||||
}
|
||||
else if (m_call_kill_focus) {
|
||||
m_call_kill_focus = false;
|
||||
e.Skip();
|
||||
}
|
||||
}, this->GetId());
|
||||
|
||||
this->Bind(wxEVT_SET_FOCUS, [this, parent](wxFocusEvent& e)
|
||||
{
|
||||
set_focus_data();
|
||||
parent->update_scene_from_editor_selection();
|
||||
e.Skip();
|
||||
}, this->GetId());
|
||||
|
||||
#ifdef __WXGTK__ // Workaround! To take information about selectable range
|
||||
this->Bind(wxEVT_LEFT_DOWN, [this](wxEvent& e)
|
||||
{
|
||||
set_focus_data();
|
||||
e.Skip();
|
||||
}, this->GetId());
|
||||
#endif //__WXGTK__
|
||||
|
||||
this->Bind(wxEVT_CHAR, ([this](wxKeyEvent& event)
|
||||
{
|
||||
// select all text using Ctrl+A
|
||||
if (wxGetKeyState(wxKeyCode('A')) && wxGetKeyState(WXK_CONTROL))
|
||||
this->SetSelection(-1, -1); //select all
|
||||
event.Skip();
|
||||
}));
|
||||
}
|
||||
|
||||
coordf_t LayerRangeEditor::get_value()
|
||||
{
|
||||
wxString str = GetValue();
|
||||
|
||||
coordf_t layer_height;
|
||||
// Replace the first occurence of comma in decimal number.
|
||||
str.Replace(",", ".", false);
|
||||
if (str == ".")
|
||||
layer_height = 0.0;
|
||||
else
|
||||
{
|
||||
if (!str.ToCDouble(&layer_height) || layer_height < 0.0f)
|
||||
{
|
||||
show_error(m_parent, _(L("Invalid numeric input.")));
|
||||
SetValue(double_to_string(layer_height));
|
||||
}
|
||||
}
|
||||
|
||||
return layer_height;
|
||||
}
|
||||
|
||||
} //namespace GUI
|
||||
} //namespace Slic3r
|
||||
88
src/slic3r/GUI/GUI_ObjectLayers.hpp
Normal file
88
src/slic3r/GUI/GUI_ObjectLayers.hpp
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
#ifndef slic3r_GUI_ObjectLayers_hpp_
|
||||
#define slic3r_GUI_ObjectLayers_hpp_
|
||||
|
||||
#include "GUI_ObjectSettings.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
#ifdef __WXOSX__
|
||||
#include "../libslic3r/PrintConfig.hpp"
|
||||
#endif
|
||||
|
||||
class wxBoxSizer;
|
||||
|
||||
namespace Slic3r {
|
||||
class ModelObject;
|
||||
|
||||
namespace GUI {
|
||||
class ConfigOptionsGroup;
|
||||
|
||||
typedef double coordf_t;
|
||||
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||
|
||||
class ObjectLayers;
|
||||
|
||||
enum EditorType
|
||||
{
|
||||
etUndef = 0,
|
||||
etMinZ = 1,
|
||||
etMaxZ = 2,
|
||||
etLayerHeight = 4,
|
||||
};
|
||||
|
||||
class LayerRangeEditor : public wxTextCtrl
|
||||
{
|
||||
bool m_enter_pressed { false };
|
||||
bool m_call_kill_focus { false };
|
||||
wxString m_valid_value;
|
||||
EditorType m_type;
|
||||
|
||||
std::function<void(EditorType)> m_set_focus_data;
|
||||
|
||||
public:
|
||||
LayerRangeEditor( ObjectLayers* parent,
|
||||
const wxString& value = wxEmptyString,
|
||||
EditorType type = etUndef,
|
||||
std::function<void(EditorType)> set_focus_data_fn = [](EditorType) {;},
|
||||
std::function<bool(coordf_t, bool)> edit_fn = [](coordf_t, bool) {return false; }
|
||||
);
|
||||
~LayerRangeEditor() {}
|
||||
|
||||
EditorType type() const {return m_type;}
|
||||
void set_focus_data() const { m_set_focus_data(m_type);}
|
||||
|
||||
private:
|
||||
coordf_t get_value();
|
||||
};
|
||||
|
||||
class ObjectLayers : public OG_Settings
|
||||
{
|
||||
ScalableBitmap m_bmp_delete;
|
||||
ScalableBitmap m_bmp_add;
|
||||
ModelObject* m_object {nullptr};
|
||||
|
||||
wxFlexGridSizer* m_grid_sizer;
|
||||
t_layer_height_range m_selectable_range;
|
||||
EditorType m_selection_type {etUndef};
|
||||
|
||||
public:
|
||||
ObjectLayers(wxWindow* parent);
|
||||
~ObjectLayers() {}
|
||||
|
||||
void select_editor(LayerRangeEditor* editor, const bool is_last_edited_range);
|
||||
wxSizer* create_layer(const t_layer_height_range& range); // without_buttons
|
||||
void create_layers_list();
|
||||
void update_layers_list();
|
||||
|
||||
void update_scene_from_editor_selection() const;
|
||||
|
||||
void UpdateAndShow(const bool show) override;
|
||||
void msw_rescale();
|
||||
void reset_selection();
|
||||
void set_selectable_range(const t_layer_height_range& range) { m_selectable_range = range; }
|
||||
|
||||
friend class LayerRangeEditor;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif // slic3r_GUI_ObjectLayers_hpp_
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -26,13 +26,17 @@ enum class ModelVolumeType : int;
|
|||
// FIXME: broken build on mac os because of this is missing:
|
||||
typedef std::vector<std::string> t_config_option_keys;
|
||||
|
||||
typedef std::map<std::string, std::vector<std::string>> FreqSettingsBundle;
|
||||
typedef std::map<std::string, std::vector<std::string>> SettingsBundle;
|
||||
|
||||
// category -> vector ( option ; label )
|
||||
typedef std::map< std::string, std::vector< std::pair<std::string, std::string> > > settings_menu_hierarchy;
|
||||
|
||||
typedef std::vector<ModelVolume*> ModelVolumePtrs;
|
||||
|
||||
typedef double coordf_t;
|
||||
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||
typedef std::map<t_layer_height_range, DynamicPrintConfig> t_layer_config_ranges;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
wxDECLARE_EVENT(EVT_OBJ_LIST_OBJECT_SELECT, SimpleEvent);
|
||||
|
|
@ -64,9 +68,10 @@ class ObjectList : public wxDataViewCtrl
|
|||
{
|
||||
enum SELECTION_MODE
|
||||
{
|
||||
smUndef,
|
||||
smVolume,
|
||||
smInstance
|
||||
smUndef = 0,
|
||||
smVolume = 1,
|
||||
smInstance = 2,
|
||||
smLayer = 4
|
||||
} m_selection_mode {smUndef};
|
||||
|
||||
struct dragged_item_data
|
||||
|
|
@ -119,12 +124,17 @@ class ObjectList : public wxDataViewCtrl
|
|||
MenuWithSeparators m_menu_part;
|
||||
MenuWithSeparators m_menu_sla_object;
|
||||
MenuWithSeparators m_menu_instance;
|
||||
wxMenuItem* m_menu_item_split { nullptr };
|
||||
wxMenuItem* m_menu_item_split_part { nullptr };
|
||||
MenuWithSeparators m_menu_layer;
|
||||
wxMenuItem* m_menu_item_settings { nullptr };
|
||||
wxMenuItem* m_menu_item_split_instances { nullptr };
|
||||
|
||||
std::vector<wxBitmap*> m_bmp_vector;
|
||||
ObjectDataViewModel *m_objects_model{ nullptr };
|
||||
DynamicPrintConfig *m_config {nullptr};
|
||||
std::vector<ModelObject*> *m_objects{ nullptr };
|
||||
|
||||
std::vector<wxBitmap*> m_bmp_vector;
|
||||
|
||||
t_layer_config_ranges m_layer_config_ranges_cache;
|
||||
|
||||
int m_selected_object_id = -1;
|
||||
bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select()
|
||||
|
|
@ -142,8 +152,8 @@ class ObjectList : public wxDataViewCtrl
|
|||
wxDataViewItem m_last_selected_item {nullptr};
|
||||
|
||||
#if 0
|
||||
FreqSettingsBundle m_freq_settings_fff;
|
||||
FreqSettingsBundle m_freq_settings_sla;
|
||||
SettingsBundle m_freq_settings_fff;
|
||||
SettingsBundle m_freq_settings_sla;
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
|
@ -153,11 +163,11 @@ public:
|
|||
|
||||
std::map<std::string, wxBitmap> CATEGORY_ICON;
|
||||
|
||||
ObjectDataViewModel *m_objects_model{ nullptr };
|
||||
DynamicPrintConfig *m_config {nullptr};
|
||||
|
||||
std::vector<ModelObject*> *m_objects{ nullptr };
|
||||
ObjectDataViewModel* GetModel() const { return m_objects_model; }
|
||||
DynamicPrintConfig* config() const { return m_config; }
|
||||
std::vector<ModelObject*>* objects() const { return m_objects; }
|
||||
|
||||
ModelObject* object(const int obj_idx) const ;
|
||||
|
||||
void create_objects_ctrl();
|
||||
void create_popup_menus();
|
||||
|
|
@ -192,13 +202,19 @@ public:
|
|||
void key_event(wxKeyEvent& event);
|
||||
#endif /* __WXOSX__ */
|
||||
|
||||
void copy();
|
||||
void paste();
|
||||
void undo();
|
||||
void redo();
|
||||
|
||||
void get_settings_choice(const wxString& category_name);
|
||||
void get_freq_settings_choice(const wxString& bundle_name);
|
||||
void update_settings_item();
|
||||
void show_settings(const wxDataViewItem settings_item);
|
||||
|
||||
wxMenu* append_submenu_add_generic(wxMenu* menu, const ModelVolumeType type);
|
||||
void append_menu_items_add_volume(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_split(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_layers_editing(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_settings(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_change_type(wxMenu* menu);
|
||||
wxMenuItem* append_menu_item_instance_to_object(wxMenu* menu, wxWindow* parent);
|
||||
|
|
@ -222,10 +238,18 @@ public:
|
|||
void load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
|
||||
void del_object(const int obj_idx);
|
||||
void del_subobject_item(wxDataViewItem& item);
|
||||
void del_settings_from_config();
|
||||
void del_settings_from_config(const wxDataViewItem& parent_item);
|
||||
void del_instances_from_object(const int obj_idx);
|
||||
void del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range);
|
||||
void del_layers_from_object(const int obj_idx);
|
||||
bool del_subobject_from_object(const int obj_idx, const int idx, const int type);
|
||||
void split();
|
||||
void layers_editing();
|
||||
|
||||
wxDataViewItem add_layer_root_item(const wxDataViewItem obj_item);
|
||||
wxDataViewItem add_settings_item(wxDataViewItem parent_item, const DynamicPrintConfig* config);
|
||||
|
||||
DynamicPrintConfig get_default_layer_config(const int obj_idx);
|
||||
bool get_volume_by_item(const wxDataViewItem& item, ModelVolume*& volume);
|
||||
bool is_splittable();
|
||||
bool selected_instances_of_same_object();
|
||||
|
|
@ -235,12 +259,13 @@ public:
|
|||
wxBoxSizer* get_sizer() {return m_sizer;}
|
||||
int get_selected_obj_idx() const;
|
||||
DynamicPrintConfig& get_item_config(const wxDataViewItem& item) const;
|
||||
SettingsBundle get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_layers_range_settings);
|
||||
|
||||
void changed_object(const int obj_idx = -1) const;
|
||||
void part_selection_changed();
|
||||
|
||||
// Add object to the list
|
||||
void add_object_to_list(size_t obj_idx);
|
||||
void add_object_to_list(size_t obj_idx, bool call_selection_changed = true);
|
||||
// Delete object from the list
|
||||
void delete_object_from_list();
|
||||
void delete_object_from_list(const size_t obj_idx);
|
||||
|
|
@ -265,6 +290,14 @@ public:
|
|||
|
||||
// Remove objects/sub-object from the list
|
||||
void remove();
|
||||
void del_layer_range(const t_layer_height_range& range);
|
||||
void add_layer_range_after_current(const t_layer_height_range& current_range);
|
||||
void add_layer_item (const t_layer_height_range& range,
|
||||
const wxDataViewItem layers_item,
|
||||
const int layer_idx = -1);
|
||||
bool edit_layer_range(const t_layer_height_range& range, coordf_t layer_height);
|
||||
bool edit_layer_range(const t_layer_height_range& range,
|
||||
const t_layer_height_range& new_range);
|
||||
|
||||
void init_objects();
|
||||
bool multiple_selection() const ;
|
||||
|
|
@ -284,8 +317,10 @@ public:
|
|||
void change_part_type();
|
||||
|
||||
void last_volume_is_deleted(const int obj_idx);
|
||||
bool has_multi_part_objects();
|
||||
void update_settings_items();
|
||||
void update_and_show_object_settings_item();
|
||||
void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
|
||||
void update_object_list_by_printer_technology();
|
||||
void update_object_menu();
|
||||
|
||||
void instances_to_separated_object(const int obj_idx, const std::set<int>& inst_idx);
|
||||
|
|
@ -295,11 +330,15 @@ public:
|
|||
void fix_through_netfabb();
|
||||
void update_item_error_icon(const int obj_idx, int vol_idx) const ;
|
||||
|
||||
void fill_layer_config_ranges_cache();
|
||||
void paste_layers_into_list();
|
||||
void paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& volumes);
|
||||
void paste_objects_into_list(const std::vector<size_t>& object_idxs);
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
void update_after_undo_redo();
|
||||
|
||||
private:
|
||||
#ifdef __WXOSX__
|
||||
// void OnChar(wxKeyEvent& event);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,28 @@ namespace Slic3r
|
|||
namespace GUI
|
||||
{
|
||||
|
||||
|
||||
// Helper function to be used by drop to bed button. Returns lowest point of this
|
||||
// volume in world coordinate system.
|
||||
static double get_volume_min_z(const GLVolume* volume)
|
||||
{
|
||||
const Transform3f& world_matrix = volume->world_matrix().cast<float>();
|
||||
|
||||
// need to get the ModelVolume pointer
|
||||
const ModelObject* mo = wxGetApp().model().objects[volume->composite_id.object_id];
|
||||
const ModelVolume* mv = mo->volumes[volume->composite_id.volume_id];
|
||||
const TriangleMesh& hull = mv->get_convex_hull();
|
||||
|
||||
float min_z = std::numeric_limits<float>::max();
|
||||
for (const stl_facet& facet : hull.stl.facet_start) {
|
||||
for (int i = 0; i < 3; ++ i)
|
||||
min_z = std::min(min_z, Vec3f::UnitZ().dot(world_matrix * facet.vertex[i]));
|
||||
}
|
||||
return min_z;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static wxBitmapComboBox* create_word_local_combo(wxWindow *parent)
|
||||
{
|
||||
wxSize size(15 * wxGetApp().em_unit(), -1);
|
||||
|
|
@ -177,25 +199,24 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
m_mirror_bitmap_off = ScalableBitmap(parent, "mirroring_off.png");
|
||||
m_mirror_bitmap_hidden = ScalableBitmap(parent, "mirroring_transparent.png");
|
||||
|
||||
for (const std::string axis : { "x", "y", "z" }) {
|
||||
const std::string label = boost::algorithm::to_upper_copy(axis);
|
||||
def.set_default_value(new ConfigOptionString{ " " + label });
|
||||
Option option = Option(def, axis + "_axis_legend");
|
||||
|
||||
unsigned int axis_idx = (axis[0] - 'x'); // 0, 1 or 2
|
||||
static const char axes[] = { 'X', 'Y', 'Z' };
|
||||
for (size_t axis_idx = 0; axis_idx < sizeof(axes); axis_idx++) {
|
||||
const char label = axes[axis_idx];
|
||||
def.set_default_value(new ConfigOptionString{ std::string(" ") + label });
|
||||
Option option(def, std::string() + label + "_axis_legend");
|
||||
|
||||
// We will add a button to toggle mirroring to each axis:
|
||||
auto mirror_button = [=](wxWindow* parent) {
|
||||
auto mirror_button = [this, mirror_btn_width, axis_idx, label](wxWindow* parent) {
|
||||
wxSize btn_size(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width);
|
||||
auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off.png", wxEmptyString, btn_size, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW);
|
||||
btn->SetToolTip(wxString::Format(_(L("Toggle %s axis mirroring")), label));
|
||||
btn->SetToolTip(wxString::Format(_(L("Toggle %c axis mirroring")), (int)label));
|
||||
|
||||
m_mirror_buttons[axis_idx].first = btn;
|
||||
m_mirror_buttons[axis_idx].second = mbShown;
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(btn);
|
||||
|
||||
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
||||
btn->Bind(wxEVT_BUTTON, [this, axis_idx](wxCommandEvent &e) {
|
||||
Axis axis = (Axis)(axis_idx + X);
|
||||
if (m_mirror_buttons[axis_idx].second == mbHidden)
|
||||
return;
|
||||
|
|
@ -220,11 +241,11 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
|
||||
selection.synchronize_unselected_volumes();
|
||||
// Copy mirroring values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
|
||||
canvas->do_mirror();
|
||||
canvas->set_as_dirty();
|
||||
canvas->do_mirror(L("Set Mirror"));
|
||||
UpdateAndShow(true);
|
||||
});
|
||||
return sizer;
|
||||
|
||||
return sizer;
|
||||
};
|
||||
|
||||
option.side_widget = mirror_button;
|
||||
|
|
@ -258,13 +279,13 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
return btn;
|
||||
};
|
||||
// Add reset scale button
|
||||
auto reset_scale_button = [=](wxWindow* parent) {
|
||||
auto reset_scale_button = [this](wxWindow* parent) {
|
||||
auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
|
||||
btn->SetToolTip(_(L("Reset scale")));
|
||||
m_reset_scale_button = btn;
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(btn, wxBU_EXACTFIT);
|
||||
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
||||
btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) {
|
||||
change_scale_value(0, 100.);
|
||||
change_scale_value(1, 100.);
|
||||
change_scale_value(2, 100.);
|
||||
|
|
@ -275,13 +296,13 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
}
|
||||
else if (option_name == "Rotation") {
|
||||
// Add reset rotation button
|
||||
auto reset_rotation_button = [=](wxWindow* parent) {
|
||||
auto reset_rotation_button = [this](wxWindow* parent) {
|
||||
auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo"));
|
||||
btn->SetToolTip(_(L("Reset rotation")));
|
||||
m_reset_rotation_button = btn;
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(btn, wxBU_EXACTFIT);
|
||||
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
||||
btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) {
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
|
||||
|
|
@ -302,7 +323,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL);
|
||||
selection.synchronize_unselected_volumes();
|
||||
// Copy rotation values from GLVolumes into Model (ModelInstance / ModelVolume), trigger background processing.
|
||||
canvas->do_rotate();
|
||||
canvas->do_rotate(L("Set Rotation"));
|
||||
|
||||
UpdateAndShow(true);
|
||||
});
|
||||
|
|
@ -310,6 +331,34 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||
};
|
||||
line.append_widget(reset_rotation_button);
|
||||
}
|
||||
else if (option_name == "Position") {
|
||||
// Add drop to bed button
|
||||
auto drop_to_bed_button = [=](wxWindow* parent) {
|
||||
auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "drop_to_bed.png"));
|
||||
btn->SetToolTip(_(L("Drop to bed")));
|
||||
m_drop_to_bed_button = btn;
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(btn, wxBU_EXACTFIT);
|
||||
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
||||
// ???
|
||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||
Selection& selection = canvas->get_selection();
|
||||
|
||||
if (selection.is_single_volume() || selection.is_single_modifier()) {
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
|
||||
const Geometry::Transformation& instance_trafo = volume->get_instance_transformation();
|
||||
Vec3d diff = m_cache.position - instance_trafo.get_matrix(true).inverse() * Vec3d(0., 0., get_volume_min_z(volume));
|
||||
|
||||
change_position_value(0, diff.x());
|
||||
change_position_value(1, diff.y());
|
||||
change_position_value(2, diff.z());
|
||||
}
|
||||
});
|
||||
return sizer;
|
||||
};
|
||||
line.append_widget(drop_to_bed_button);
|
||||
}
|
||||
// Add empty bmp (Its size have to be equal to PrusaLockButton) in front of "Size" option to label alignment
|
||||
else if (option_name == "Size") {
|
||||
line.near_label_widget = [this](wxWindow* parent) {
|
||||
|
|
@ -417,7 +466,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
|||
m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.;
|
||||
} else {
|
||||
m_new_rotation = volume->get_instance_rotation() * (180. / M_PI);
|
||||
m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct((*wxGetApp().model_objects())[volume->object_idx()]->raw_mesh_bounding_box().size());
|
||||
m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
|
||||
m_new_scale = volume->get_instance_scaling_factor() * 100.;
|
||||
}
|
||||
|
||||
|
|
@ -441,7 +490,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
|||
m_new_position = volume->get_volume_offset();
|
||||
m_new_rotation = volume->get_volume_rotation() * (180. / M_PI);
|
||||
m_new_scale = volume->get_volume_scaling_factor() * 100.;
|
||||
m_new_size = volume->get_volume_transformation().get_scaling_factor().cwiseProduct(volume->bounding_box.size());
|
||||
m_new_size = volume->get_volume_transformation().get_scaling_factor().cwiseProduct(volume->bounding_box().size());
|
||||
m_new_enabled = true;
|
||||
}
|
||||
else if (obj_list->multiple_selection() || obj_list->is_selected(itInstanceRoot))
|
||||
|
|
@ -536,11 +585,13 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
|||
|
||||
bool show_rotation = false;
|
||||
bool show_scale = false;
|
||||
bool show_drop_to_bed = false;
|
||||
|
||||
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
Vec3d rotation;
|
||||
Vec3d scale;
|
||||
double min_z = 0.;
|
||||
|
||||
if (selection.is_single_full_instance()) {
|
||||
rotation = volume->get_instance_rotation();
|
||||
|
|
@ -549,14 +600,17 @@ void ObjectManipulation::update_reset_buttons_visibility()
|
|||
else {
|
||||
rotation = volume->get_volume_rotation();
|
||||
scale = volume->get_volume_scaling_factor();
|
||||
min_z = get_volume_min_z(volume);
|
||||
}
|
||||
show_rotation = !rotation.isApprox(Vec3d::Zero());
|
||||
show_scale = !scale.isApprox(Vec3d::Ones());
|
||||
show_drop_to_bed = (std::abs(min_z) > EPSILON);
|
||||
}
|
||||
|
||||
wxGetApp().CallAfter([this, show_rotation, show_scale]{
|
||||
wxGetApp().CallAfter([this, show_rotation, show_scale, show_drop_to_bed]{
|
||||
m_reset_rotation_button->Show(show_rotation);
|
||||
m_reset_scale_button->Show(show_scale);
|
||||
m_drop_to_bed_button->Show(show_drop_to_bed);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -655,7 +709,7 @@ void ObjectManipulation::change_position_value(int axis, double value)
|
|||
Selection& selection = canvas->get_selection();
|
||||
selection.start_dragging();
|
||||
selection.translate(position - m_cache.position, selection.requires_local_axes());
|
||||
canvas->do_move();
|
||||
canvas->do_move(L("Set Position"));
|
||||
|
||||
m_cache.position = position;
|
||||
m_cache.position_rounded(axis) = DBL_MAX;
|
||||
|
|
@ -686,7 +740,7 @@ void ObjectManipulation::change_rotation_value(int axis, double value)
|
|||
selection.rotate(
|
||||
(M_PI / 180.0) * (transformation_type.absolute() ? rotation : rotation - m_cache.rotation),
|
||||
transformation_type);
|
||||
canvas->do_rotate();
|
||||
canvas->do_rotate(L("Set Orientation"));
|
||||
|
||||
m_cache.rotation = rotation;
|
||||
m_cache.rotation_rounded(axis) = DBL_MAX;
|
||||
|
|
@ -721,11 +775,11 @@ void ObjectManipulation::change_size_value(int axis, double value)
|
|||
|
||||
Vec3d ref_size = m_cache.size;
|
||||
if (selection.is_single_volume() || selection.is_single_modifier())
|
||||
ref_size = selection.get_volume(*selection.get_volume_idxs().begin())->bounding_box.size();
|
||||
else if (selection.is_single_full_instance())
|
||||
ref_size = selection.get_volume(*selection.get_volume_idxs().begin())->bounding_box().size();
|
||||
else if (selection.is_single_full_instance())
|
||||
ref_size = m_world_coordinates ?
|
||||
selection.get_unscaled_instance_bounding_box().size() :
|
||||
(*wxGetApp().model_objects())[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size();
|
||||
wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size();
|
||||
|
||||
this->do_scale(axis, 100. * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2)));
|
||||
|
||||
|
|
@ -751,7 +805,7 @@ void ObjectManipulation::do_scale(int axis, const Vec3d &scale) const
|
|||
|
||||
selection.start_dragging();
|
||||
selection.scale(scaling_factor * 0.01, transformation_type);
|
||||
wxGetApp().plater()->canvas3D()->do_scale();
|
||||
wxGetApp().plater()->canvas3D()->do_scale(L("Set Scale"));
|
||||
}
|
||||
|
||||
void ObjectManipulation::on_change(t_config_option_key opt_key, const boost::any& value)
|
||||
|
|
@ -848,7 +902,7 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
|
|||
return;
|
||||
}
|
||||
// Bake the rotation into the meshes of the object.
|
||||
(*wxGetApp().model_objects())[volume->composite_id.object_id]->bake_xy_rotation_into_meshes(volume->composite_id.instance_id);
|
||||
wxGetApp().model().objects[volume->composite_id.object_id]->bake_xy_rotation_into_meshes(volume->composite_id.instance_id);
|
||||
// Update the 3D scene, selections etc.
|
||||
wxGetApp().plater()->update();
|
||||
// Recalculate cached values at this panel, refresh the screen.
|
||||
|
|
@ -869,6 +923,7 @@ void ObjectManipulation::msw_rescale()
|
|||
m_mirror_bitmap_hidden.msw_rescale();
|
||||
m_reset_scale_button->msw_rescale();
|
||||
m_reset_rotation_button->msw_rescale();
|
||||
m_drop_to_bed_button->msw_rescale();
|
||||
|
||||
get_og()->msw_rescale();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ class ObjectManipulation : public OG_Settings
|
|||
// Non-owning pointers to the reset buttons, so we can hide and show them.
|
||||
ScalableButton* m_reset_scale_button = nullptr;
|
||||
ScalableButton* m_reset_rotation_button = nullptr;
|
||||
ScalableButton* m_drop_to_bed_button = nullptr;
|
||||
|
||||
// Mirroring buttons and their current state
|
||||
enum MirrorButtonState {
|
||||
|
|
|
|||
|
|
@ -63,18 +63,28 @@ ObjectSettings::ObjectSettings(wxWindow* parent) :
|
|||
m_bmp_delete = ScalableBitmap(parent, "cross");
|
||||
}
|
||||
|
||||
void ObjectSettings::update_settings_list()
|
||||
bool ObjectSettings::update_settings_list()
|
||||
{
|
||||
m_settings_list_sizer->Clear(true);
|
||||
m_og_settings.resize(0);
|
||||
|
||||
auto objects_ctrl = wxGetApp().obj_list();
|
||||
auto objects_model = wxGetApp().obj_list()->m_objects_model;
|
||||
auto config = wxGetApp().obj_list()->m_config;
|
||||
auto objects_model = wxGetApp().obj_list()->GetModel();
|
||||
auto config = wxGetApp().obj_list()->config();
|
||||
|
||||
const auto item = objects_ctrl->GetSelection();
|
||||
if (item && !objects_ctrl->multiple_selection() &&
|
||||
config && objects_model->IsSettingsItem(item))
|
||||
{
|
||||
|
||||
if (!item || !objects_model->IsSettingsItem(item) || !config || objects_ctrl->multiple_selection())
|
||||
return false;
|
||||
|
||||
const bool is_layers_range_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itLayer;
|
||||
SettingsBundle cat_options = objects_ctrl->get_item_settings_bundle(config, is_layers_range_settings);
|
||||
|
||||
if (!cat_options.empty())
|
||||
{
|
||||
std::vector<std::string> categories;
|
||||
categories.reserve(cat_options.size());
|
||||
|
||||
auto extra_column = [config, this](wxWindow* parent, const Line& line)
|
||||
{
|
||||
auto opt_key = (line.get_options())[0].opt_id; //we assume that we have one option per line
|
||||
|
|
@ -94,85 +104,61 @@ void ObjectSettings::update_settings_list()
|
|||
return btn;
|
||||
};
|
||||
|
||||
std::map<std::string, std::vector<std::string>> cat_options;
|
||||
auto opt_keys = config->keys();
|
||||
objects_ctrl->update_opt_keys(opt_keys); // update options list according to print technology
|
||||
|
||||
m_og_settings.resize(0);
|
||||
std::vector<std::string> categories;
|
||||
if (!(opt_keys.size() == 1 && opt_keys[0] == "extruder"))// return;
|
||||
for (auto& cat : cat_options)
|
||||
{
|
||||
const int extruders_cnt = wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology() == ptSLA ? 1 :
|
||||
wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->values.size();
|
||||
if (cat.second.size() == 1 &&
|
||||
(cat.second[0] == "extruder" || is_layers_range_settings && cat.second[0] == "layer_height"))
|
||||
continue;
|
||||
|
||||
for (auto& opt_key : opt_keys) {
|
||||
auto category = config->def()->get(opt_key)->category;
|
||||
if (category.empty() ||
|
||||
(category == "Extruders" && extruders_cnt == 1)) continue;
|
||||
categories.push_back(cat.first);
|
||||
|
||||
std::vector< std::string > new_category;
|
||||
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
|
||||
optgroup->label_width = 15;
|
||||
optgroup->sidetext_width = 5.5;
|
||||
|
||||
auto& cat_opt = cat_options.find(category) == cat_options.end() ? new_category : cat_options.at(category);
|
||||
cat_opt.push_back(opt_key);
|
||||
if (cat_opt.size() == 1)
|
||||
cat_options[category] = cat_opt;
|
||||
}
|
||||
optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) {
|
||||
wxGetApp().obj_list()->changed_object(); };
|
||||
|
||||
for (auto& cat : cat_options) {
|
||||
if (cat.second.size() == 1 && cat.second[0] == "extruder")
|
||||
// call back for rescaling of the extracolumn control
|
||||
optgroup->rescale_extra_column_item = [this](wxWindow* win) {
|
||||
auto *ctrl = dynamic_cast<ScalableButton*>(win);
|
||||
if (ctrl == nullptr)
|
||||
return;
|
||||
ctrl->SetBitmap_(m_bmp_delete);
|
||||
};
|
||||
|
||||
const bool is_extruders_cat = cat.first == "Extruders";
|
||||
for (auto& opt : cat.second)
|
||||
{
|
||||
if (opt == "extruder" || is_layers_range_settings && opt == "layer_height")
|
||||
continue;
|
||||
|
||||
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
|
||||
optgroup->label_width = 15;
|
||||
optgroup->sidetext_width = 5.5;
|
||||
|
||||
optgroup->m_on_change = [](const t_config_option_key& opt_id, const boost::any& value) {
|
||||
wxGetApp().obj_list()->changed_object(); };
|
||||
|
||||
const bool is_extriders_cat = cat.first == "Extruders";
|
||||
for (auto& opt : cat.second)
|
||||
{
|
||||
if (opt == "extruder")
|
||||
continue;
|
||||
Option option = optgroup->get_option(opt);
|
||||
option.opt.width = 12;
|
||||
if (is_extriders_cat)
|
||||
option.opt.max = wxGetApp().extruders_cnt();
|
||||
optgroup->append_single_option_line(option);
|
||||
}
|
||||
optgroup->reload_config();
|
||||
m_settings_list_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0);
|
||||
|
||||
// call back for rescaling of the extracolumn control
|
||||
optgroup->rescale_extra_column_item = [this](wxWindow* win) {
|
||||
auto *ctrl = dynamic_cast<ScalableButton*>(win);
|
||||
if (ctrl == nullptr)
|
||||
return;
|
||||
ctrl->SetBitmap_(m_bmp_delete);
|
||||
};
|
||||
|
||||
m_og_settings.push_back(optgroup);
|
||||
|
||||
categories.push_back(cat.first);
|
||||
Option option = optgroup->get_option(opt);
|
||||
option.opt.width = 12;
|
||||
if (is_extruders_cat)
|
||||
option.opt.max = wxGetApp().extruders_edited_cnt();
|
||||
optgroup->append_single_option_line(option);
|
||||
}
|
||||
optgroup->reload_config();
|
||||
|
||||
m_settings_list_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0);
|
||||
m_og_settings.push_back(optgroup);
|
||||
}
|
||||
|
||||
if (m_og_settings.empty()) {
|
||||
objects_ctrl->select_item(objects_model->Delete(item));
|
||||
}
|
||||
else {
|
||||
if (!categories.empty())
|
||||
objects_model->UpdateSettingsDigest(item, categories);
|
||||
}
|
||||
}
|
||||
if (!categories.empty())
|
||||
objects_model->UpdateSettingsDigest(item, categories);
|
||||
}
|
||||
else
|
||||
{
|
||||
objects_ctrl->select_item(objects_model->Delete(item));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ObjectSettings::UpdateAndShow(const bool show)
|
||||
{
|
||||
if (show)
|
||||
update_settings_list();
|
||||
|
||||
OG_Settings::UpdateAndShow(show);
|
||||
OG_Settings::UpdateAndShow(show ? update_settings_list() : false);
|
||||
}
|
||||
|
||||
void ObjectSettings::msw_rescale()
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ public:
|
|||
ObjectSettings(wxWindow* parent);
|
||||
~ObjectSettings() {}
|
||||
|
||||
void update_settings_list();
|
||||
bool update_settings_list();
|
||||
void UpdateAndShow(const bool show) override;
|
||||
void msw_rescale();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -63,7 +63,8 @@ bool View3D::init(wxWindow* parent, Bed3D& bed, Camera& camera, GLToolbar& view_
|
|||
m_canvas->set_config(config);
|
||||
m_canvas->enable_gizmos(true);
|
||||
m_canvas->enable_selection(true);
|
||||
m_canvas->enable_toolbar(true);
|
||||
m_canvas->enable_main_toolbar(true);
|
||||
m_canvas->enable_undoredo_toolbar(true);
|
||||
|
||||
wxBoxSizer* main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(m_canvas_widget, 1, wxALL | wxEXPAND, 0);
|
||||
|
|
|
|||
|
|
@ -132,18 +132,13 @@ void GLGizmoBase::Grabber::render_face(float half_size) const
|
|||
glsafe(::glEnd());
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
|
||||
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
#else
|
||||
GLGizmoBase::GLGizmoBase(GLCanvas3D& parent, unsigned int sprite_id)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
: m_parent(parent)
|
||||
, m_group_id(-1)
|
||||
, m_state(Off)
|
||||
, m_shortcut_key(0)
|
||||
#if ENABLE_SVG_ICONS
|
||||
, m_icon_filename(icon_filename)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_sprite_id(sprite_id)
|
||||
, m_hover_id(-1)
|
||||
, m_dragging(false)
|
||||
|
|
@ -185,7 +180,7 @@ void GLGizmoBase::disable_grabber(unsigned int id)
|
|||
on_disable_grabber(id);
|
||||
}
|
||||
|
||||
void GLGizmoBase::start_dragging(const Selection& selection)
|
||||
void GLGizmoBase::start_dragging()
|
||||
{
|
||||
m_dragging = true;
|
||||
|
||||
|
|
@ -194,7 +189,7 @@ void GLGizmoBase::start_dragging(const Selection& selection)
|
|||
m_grabbers[i].dragging = (m_hover_id == i);
|
||||
}
|
||||
|
||||
on_start_dragging(selection);
|
||||
on_start_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoBase::stop_dragging()
|
||||
|
|
@ -209,10 +204,10 @@ void GLGizmoBase::stop_dragging()
|
|||
on_stop_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoBase::update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoBase::update(const UpdateData& data)
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
on_update(data, selection);
|
||||
on_update(data);
|
||||
}
|
||||
|
||||
std::array<float, 3> GLGizmoBase::picking_color_component(unsigned int id) const
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/Selection.hpp"
|
||||
|
||||
#include <cereal/archives/binary.hpp>
|
||||
|
||||
class wxWindow;
|
||||
class GLUquadric;
|
||||
|
|
@ -75,10 +76,10 @@ public:
|
|||
|
||||
struct UpdateData
|
||||
{
|
||||
const Linef3 mouse_ray;
|
||||
const Point* mouse_pos;
|
||||
const Linef3& mouse_ray;
|
||||
const Point& mouse_pos;
|
||||
|
||||
UpdateData(const Linef3& mouse_ray, const Point* mouse_pos = nullptr)
|
||||
UpdateData(const Linef3& mouse_ray, const Point& mouse_pos)
|
||||
: mouse_ray(mouse_ray), mouse_pos(mouse_pos)
|
||||
{}
|
||||
};
|
||||
|
|
@ -89,9 +90,7 @@ protected:
|
|||
int m_group_id;
|
||||
EState m_state;
|
||||
int m_shortcut_key;
|
||||
#if ENABLE_SVG_ICONS
|
||||
std::string m_icon_filename;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
unsigned int m_sprite_id;
|
||||
int m_hover_id;
|
||||
bool m_dragging;
|
||||
|
|
@ -102,15 +101,14 @@ protected:
|
|||
ImGuiWrapper* m_imgui;
|
||||
|
||||
public:
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoBase(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
#else
|
||||
GLGizmoBase(GLCanvas3D& parent, unsigned int sprite_id);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
virtual ~GLGizmoBase() {}
|
||||
|
||||
bool init() { return on_init(); }
|
||||
|
||||
void load(cereal::BinaryInputArchive& ar) { m_state = On; on_load(ar); }
|
||||
void save(cereal::BinaryOutputArchive& ar) const { on_save(ar); }
|
||||
|
||||
std::string get_name() const { return on_get_name(); }
|
||||
|
||||
int get_group_id() const { return m_group_id; }
|
||||
|
|
@ -122,11 +120,9 @@ public:
|
|||
int get_shortcut_key() const { return m_shortcut_key; }
|
||||
void set_shortcut_key(int key) { m_shortcut_key = key; }
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
const std::string& get_icon_filename() const { return m_icon_filename; }
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
bool is_activable(const Selection& selection) const { return on_is_activable(selection); }
|
||||
bool is_activable() const { return on_is_activable(); }
|
||||
bool is_selectable() const { return on_is_selectable(); }
|
||||
|
||||
unsigned int get_sprite_id() const { return m_sprite_id; }
|
||||
|
|
@ -139,32 +135,34 @@ public:
|
|||
void enable_grabber(unsigned int id);
|
||||
void disable_grabber(unsigned int id);
|
||||
|
||||
void start_dragging(const Selection& selection);
|
||||
void start_dragging();
|
||||
void stop_dragging();
|
||||
|
||||
bool is_dragging() const { return m_dragging; }
|
||||
|
||||
void update(const UpdateData& data, const Selection& selection);
|
||||
void update(const UpdateData& data);
|
||||
|
||||
void render(const Selection& selection) const { on_render(selection); }
|
||||
void render_for_picking(const Selection& selection) const { on_render_for_picking(selection); }
|
||||
void render_input_window(float x, float y, float bottom_limit, const Selection& selection) { on_render_input_window(x, y, bottom_limit, selection); }
|
||||
void render() const { on_render(); }
|
||||
void render_for_picking() const { on_render_for_picking(); }
|
||||
void render_input_window(float x, float y, float bottom_limit) { on_render_input_window(x, y, bottom_limit); }
|
||||
|
||||
protected:
|
||||
virtual bool on_init() = 0;
|
||||
virtual void on_load(cereal::BinaryInputArchive& ar) {}
|
||||
virtual void on_save(cereal::BinaryOutputArchive& ar) const {}
|
||||
virtual std::string on_get_name() const = 0;
|
||||
virtual void on_set_state() {}
|
||||
virtual void on_set_hover_id() {}
|
||||
virtual bool on_is_activable(const Selection& selection) const { return true; }
|
||||
virtual bool on_is_activable() const { return true; }
|
||||
virtual bool on_is_selectable() const { return true; }
|
||||
virtual void on_enable_grabber(unsigned int id) {}
|
||||
virtual void on_disable_grabber(unsigned int id) {}
|
||||
virtual void on_start_dragging(const Selection& selection) {}
|
||||
virtual void on_start_dragging() {}
|
||||
virtual void on_stop_dragging() {}
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection) = 0;
|
||||
virtual void on_render(const Selection& selection) const = 0;
|
||||
virtual void on_render_for_picking(const Selection& selection) const = 0;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection) {}
|
||||
virtual void on_update(const UpdateData& data) {}
|
||||
virtual void on_render() const = 0;
|
||||
virtual void on_render_for_picking() const = 0;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit) {}
|
||||
|
||||
// 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)
|
||||
|
|
|
|||
|
|
@ -19,13 +19,8 @@ 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 };
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
#else
|
||||
GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, sprite_id)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_cut_z(0.0)
|
||||
, m_max_z(0.0)
|
||||
, m_keep_upper(true)
|
||||
|
|
@ -33,7 +28,6 @@ GLGizmoCut::GLGizmoCut(GLCanvas3D& parent, unsigned int sprite_id)
|
|||
, m_rotate_lower(false)
|
||||
{}
|
||||
|
||||
|
||||
bool GLGizmoCut::on_init()
|
||||
{
|
||||
m_grabbers.emplace_back();
|
||||
|
|
@ -54,15 +48,18 @@ void GLGizmoCut::on_set_state()
|
|||
}
|
||||
}
|
||||
|
||||
bool GLGizmoCut::on_is_activable(const Selection& selection) const
|
||||
bool GLGizmoCut::on_is_activable() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
return selection.is_single_full_instance() && !selection.is_wipe_tower();
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoCut::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id == -1) { return; }
|
||||
if (m_hover_id == -1)
|
||||
return;
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
m_start_z = m_cut_z;
|
||||
update_max_z(selection);
|
||||
|
|
@ -71,19 +68,21 @@ void GLGizmoCut::on_start_dragging(const Selection& selection)
|
|||
m_drag_center(2) = m_cut_z;
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoCut::on_update(const UpdateData& data)
|
||||
{
|
||||
if (m_hover_id != -1) {
|
||||
set_cut_z(m_start_z + calc_projection(data.mouse_ray));
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render(const Selection& selection) const
|
||||
void GLGizmoCut::on_render() const
|
||||
{
|
||||
if (m_grabbers[0].dragging) {
|
||||
set_tooltip("Z: " + format(m_cut_z, 2));
|
||||
}
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
update_max_z(selection);
|
||||
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
|
|
@ -129,14 +128,13 @@ void GLGizmoCut::on_render(const Selection& selection) const
|
|||
m_grabbers[0].render(m_hover_id == 0, (float)((box.size()(0) + box.size()(1) + box.size()(2)) / 3.0));
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoCut::on_render_for_picking() const
|
||||
{
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
render_grabbers_for_picking(selection.get_bounding_box());
|
||||
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
|
||||
}
|
||||
|
||||
void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection)
|
||||
void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
const float approx_height = m_imgui->scaled(11.0f);
|
||||
y = std::min(y, bottom_limit - approx_height);
|
||||
|
|
@ -159,7 +157,7 @@ void GLGizmoCut::on_render_input_window(float x, float y, float bottom_limit, co
|
|||
m_imgui->end();
|
||||
|
||||
if (cut_clicked && (m_keep_upper || m_keep_lower)) {
|
||||
perform_cut(selection);
|
||||
perform_cut(m_parent.get_selection());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,22 +23,20 @@ class GLGizmoCut : public GLGizmoBase
|
|||
bool m_rotate_lower;
|
||||
|
||||
public:
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoCut(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
#else
|
||||
GLGizmoCut(GLCanvas3D& parent, unsigned int sprite_id);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
protected:
|
||||
virtual bool on_init();
|
||||
virtual void on_load(cereal::BinaryInputArchive& ar) { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); }
|
||||
virtual void on_save(cereal::BinaryOutputArchive& ar) const { ar(m_cut_z, m_keep_upper, m_keep_lower, m_rotate_lower); }
|
||||
virtual std::string on_get_name() const;
|
||||
virtual void on_set_state();
|
||||
virtual bool on_is_activable(const Selection& selection) const;
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection);
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection);
|
||||
virtual bool on_is_activable() const;
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_update(const UpdateData& data);
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit);
|
||||
|
||||
private:
|
||||
void update_max_z(const Selection& selection) const;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
#include "GLGizmoFlatten.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
|
||||
#include <numeric>
|
||||
|
||||
|
|
@ -9,13 +11,8 @@ namespace Slic3r {
|
|||
namespace GUI {
|
||||
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
#else
|
||||
GLGizmoFlatten::GLGizmoFlatten(GLCanvas3D& parent, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, sprite_id)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_normal(Vec3d::Zero())
|
||||
, m_starting_center(Vec3d::Zero())
|
||||
{
|
||||
|
|
@ -27,28 +24,46 @@ bool GLGizmoFlatten::on_init()
|
|||
return true;
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::on_set_state()
|
||||
{
|
||||
// m_model_object pointer can be invalid (for instance because of undo/redo action),
|
||||
// we should recover it from the object id
|
||||
m_model_object = nullptr;
|
||||
for (const auto mo : wxGetApp().model().objects) {
|
||||
if (mo->id() == m_model_object_id) {
|
||||
m_model_object = mo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_state == On && is_plane_update_necessary())
|
||||
update_planes();
|
||||
}
|
||||
|
||||
std::string GLGizmoFlatten::on_get_name() const
|
||||
{
|
||||
return (_(L("Place on face")) + " [F]").ToUTF8().data();
|
||||
}
|
||||
|
||||
bool GLGizmoFlatten::on_is_activable(const Selection& selection) const
|
||||
bool GLGizmoFlatten::on_is_activable() const
|
||||
{
|
||||
return selection.is_single_full_instance();
|
||||
return m_parent.get_selection().is_single_full_instance();
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoFlatten::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
{
|
||||
assert(m_planes_valid);
|
||||
m_normal = m_planes[m_hover_id].normal;
|
||||
m_starting_center = selection.get_bounding_box().center();
|
||||
m_starting_center = m_parent.get_selection().get_bounding_box().center();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::on_render(const Selection& selection) const
|
||||
void GLGizmoFlatten::on_render() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
|
@ -83,8 +98,10 @@ void GLGizmoFlatten::on_render(const Selection& selection) const
|
|||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoFlatten::on_render_for_picking() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
|
||||
|
|
@ -120,6 +137,7 @@ void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object)
|
|||
m_planes_valid = false;
|
||||
}
|
||||
m_model_object = model_object;
|
||||
m_model_object_id = model_object ? model_object->id() : 0;
|
||||
}
|
||||
|
||||
void GLGizmoFlatten::update_planes()
|
||||
|
|
|
|||
|
|
@ -31,17 +31,14 @@ private:
|
|||
bool m_planes_valid = false;
|
||||
mutable Vec3d m_starting_center;
|
||||
const ModelObject* m_model_object = nullptr;
|
||||
ObjectID m_model_object_id = 0;
|
||||
std::vector<const Transform3d*> instances_matrices;
|
||||
|
||||
void update_planes();
|
||||
bool is_plane_update_necessary() const;
|
||||
|
||||
public:
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoFlatten(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
#else
|
||||
GLGizmoFlatten(GLCanvas3D& parent, unsigned int sprite_id);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
void set_flattening_data(const ModelObject* model_object);
|
||||
Vec3d get_flattening_normal() const;
|
||||
|
|
@ -49,16 +46,11 @@ public:
|
|||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const;
|
||||
virtual bool on_is_activable(const Selection& selection) const;
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection) {}
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
virtual void on_set_state()
|
||||
{
|
||||
if (m_state == On && is_plane_update_necessary())
|
||||
update_planes();
|
||||
}
|
||||
virtual bool on_is_activable() const;
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
virtual void on_set_state() override;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
#include "GLGizmoMove.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
|
@ -10,13 +11,8 @@ namespace GUI {
|
|||
|
||||
const double GLGizmoMove3D::Offset = 10.0;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
#else
|
||||
GLGizmoMove3D::GLGizmoMove3D(GLCanvas3D& parent, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, sprite_id)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_displacement(Vec3d::Zero())
|
||||
, m_snap_step(1.0)
|
||||
, m_starting_drag_position(Vec3d::Zero())
|
||||
|
|
@ -52,12 +48,12 @@ std::string GLGizmoMove3D::on_get_name() const
|
|||
return (_(L("Move")) + " [M]").ToUTF8().data();
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoMove3D::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
{
|
||||
m_displacement = Vec3d::Zero();
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
|
||||
m_starting_drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting_box_center = box.center();
|
||||
m_starting_box_bottom_center = box.center();
|
||||
|
|
@ -70,7 +66,7 @@ void GLGizmoMove3D::on_stop_dragging()
|
|||
m_displacement = Vec3d::Zero();
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoMove3D::on_update(const UpdateData& data)
|
||||
{
|
||||
if (m_hover_id == 0)
|
||||
m_displacement(0) = calc_projection(data);
|
||||
|
|
@ -80,8 +76,10 @@ void GLGizmoMove3D::on_update(const UpdateData& data, const Selection& selection
|
|||
m_displacement(2) = calc_projection(data);
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_render(const Selection& selection) const
|
||||
void GLGizmoMove3D::on_render() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
bool show_position = selection.is_single_full_instance();
|
||||
const Vec3d& position = selection.get_bounding_box().center();
|
||||
|
||||
|
|
@ -157,20 +155,21 @@ void GLGizmoMove3D::on_render(const Selection& selection) const
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoMove3D::on_render_for_picking() const
|
||||
{
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
|
||||
render_grabbers_for_picking(box);
|
||||
render_grabber_extension(X, box, true);
|
||||
render_grabber_extension(Y, box, true);
|
||||
render_grabber_extension(Z, box, true);
|
||||
}
|
||||
|
||||
void GLGizmoMove3D::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection)
|
||||
{
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
void GLGizmoMove3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
bool show_position = selection.is_single_full_instance();
|
||||
const Vec3d& position = selection.get_bounding_box().center();
|
||||
|
||||
|
|
@ -183,8 +182,8 @@ void GLGizmoMove3D::on_render_input_window(float x, float y, float bottom_limit,
|
|||
m_imgui->input_vec3("", displacement, 100.0f, "%.2f");
|
||||
|
||||
m_imgui->end();
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
}
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
|
||||
double GLGizmoMove3D::calc_projection(const UpdateData& data) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,11 +22,7 @@ class GLGizmoMove3D : public GLGizmoBase
|
|||
GLUquadricObj* m_quadric;
|
||||
|
||||
public:
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoMove3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
#else
|
||||
GLGizmoMove3D(GLCanvas3D& parent, unsigned int sprite_id);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
virtual ~GLGizmoMove3D();
|
||||
|
||||
double get_snap_step(double step) const { return m_snap_step; }
|
||||
|
|
@ -37,12 +33,14 @@ public:
|
|||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const;
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_stop_dragging();
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection);
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection);
|
||||
virtual void on_update(const UpdateData& data);
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit);
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
|
||||
private:
|
||||
double calc_projection(const UpdateData& data) const;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
#include "GLGizmoRotate.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
|
@ -19,11 +20,7 @@ const unsigned int GLGizmoRotate::SnapRegionsCount = 8;
|
|||
const float GLGizmoRotate::GrabberOffset = 0.15f; // in percent of radius
|
||||
|
||||
GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis)
|
||||
#if ENABLE_SVG_ICONS
|
||||
: GLGizmoBase(parent, "", -1)
|
||||
#else
|
||||
: GLGizmoBase(parent, -1)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_axis(axis)
|
||||
, m_angle(0.0)
|
||||
, m_quadric(nullptr)
|
||||
|
|
@ -40,11 +37,7 @@ GLGizmoRotate::GLGizmoRotate(GLCanvas3D& parent, GLGizmoRotate::Axis axis)
|
|||
}
|
||||
|
||||
GLGizmoRotate::GLGizmoRotate(const GLGizmoRotate& other)
|
||||
#if ENABLE_SVG_ICONS
|
||||
: GLGizmoBase(other.m_parent, other.m_icon_filename, other.m_sprite_id)
|
||||
#else
|
||||
: GLGizmoBase(other.m_parent, other.m_sprite_id)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_axis(other.m_axis)
|
||||
, m_angle(other.m_angle)
|
||||
, m_quadric(nullptr)
|
||||
|
|
@ -80,9 +73,9 @@ bool GLGizmoRotate::on_init()
|
|||
return true;
|
||||
}
|
||||
|
||||
void GLGizmoRotate::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoRotate::on_start_dragging()
|
||||
{
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
const BoundingBoxf3& box = m_parent.get_selection().get_bounding_box();
|
||||
m_center = box.center();
|
||||
m_radius = Offset + box.radius();
|
||||
m_snap_coarse_in_radius = m_radius / 3.0f;
|
||||
|
|
@ -91,9 +84,9 @@ void GLGizmoRotate::on_start_dragging(const Selection& selection)
|
|||
m_snap_fine_out_radius = m_snap_fine_in_radius + m_radius * ScaleLongTooth;
|
||||
}
|
||||
|
||||
void GLGizmoRotate::on_update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoRotate::on_update(const UpdateData& data)
|
||||
{
|
||||
Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, selection));
|
||||
Vec2d mouse_pos = to_2d(mouse_position_in_local_plane(data.mouse_ray, m_parent.get_selection()));
|
||||
|
||||
Vec2d orig_dir = Vec2d::UnitX();
|
||||
Vec2d new_dir = mouse_pos.normalized();
|
||||
|
|
@ -126,11 +119,12 @@ void GLGizmoRotate::on_update(const UpdateData& data, const Selection& selection
|
|||
m_angle = theta;
|
||||
}
|
||||
|
||||
void GLGizmoRotate::on_render(const Selection& selection) const
|
||||
void GLGizmoRotate::on_render() const
|
||||
{
|
||||
if (!m_grabbers[0].enabled)
|
||||
return;
|
||||
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
const BoundingBoxf3& box = selection.get_bounding_box();
|
||||
|
||||
std::string axis;
|
||||
|
|
@ -183,8 +177,10 @@ void GLGizmoRotate::on_render(const Selection& selection) const
|
|||
glsafe(::glPopMatrix());
|
||||
}
|
||||
|
||||
void GLGizmoRotate::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoRotate::on_render_for_picking() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
glsafe(::glPushMatrix());
|
||||
|
|
@ -417,13 +413,8 @@ Vec3d GLGizmoRotate::mouse_position_in_local_plane(const Linef3& mouse_ray, cons
|
|||
return transform(mouse_ray, m).intersect_plane(0.0);
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
#else
|
||||
GLGizmoRotate3D::GLGizmoRotate3D(GLCanvas3D& parent, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, sprite_id)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
{
|
||||
m_gizmos.emplace_back(parent, GLGizmoRotate::X);
|
||||
m_gizmos.emplace_back(parent, GLGizmoRotate::Y);
|
||||
|
|
@ -458,10 +449,10 @@ std::string GLGizmoRotate3D::on_get_name() const
|
|||
return (_(L("Rotate")) + " [R]").ToUTF8().data();
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoRotate3D::on_start_dragging()
|
||||
{
|
||||
if ((0 <= m_hover_id) && (m_hover_id < 3))
|
||||
m_gizmos[m_hover_id].start_dragging(selection);
|
||||
m_gizmos[m_hover_id].start_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::on_stop_dragging()
|
||||
|
|
@ -470,23 +461,23 @@ void GLGizmoRotate3D::on_stop_dragging()
|
|||
m_gizmos[m_hover_id].stop_dragging();
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::on_render(const Selection& selection) const
|
||||
void GLGizmoRotate3D::on_render() const
|
||||
{
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
|
||||
if ((m_hover_id == -1) || (m_hover_id == 0))
|
||||
m_gizmos[X].render(selection);
|
||||
m_gizmos[X].render();
|
||||
|
||||
if ((m_hover_id == -1) || (m_hover_id == 1))
|
||||
m_gizmos[Y].render(selection);
|
||||
m_gizmos[Y].render();
|
||||
|
||||
if ((m_hover_id == -1) || (m_hover_id == 2))
|
||||
m_gizmos[Z].render(selection);
|
||||
m_gizmos[Z].render();
|
||||
}
|
||||
|
||||
void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection)
|
||||
{
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
Vec3d rotation(Geometry::rad2deg(m_gizmos[0].get_angle()), Geometry::rad2deg(m_gizmos[1].get_angle()), Geometry::rad2deg(m_gizmos[2].get_angle()));
|
||||
wxString label = _(L("Rotation (deg)"));
|
||||
|
||||
|
|
@ -495,8 +486,8 @@ void GLGizmoRotate3D::on_render_input_window(float x, float y, float bottom_limi
|
|||
m_imgui->begin(label, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
m_imgui->input_vec3("", rotation, 100.0f, "%.2f");
|
||||
m_imgui->end();
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
}
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -52,10 +52,10 @@ public:
|
|||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const { return ""; }
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection);
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_update(const UpdateData& data);
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
|
||||
private:
|
||||
void render_circle() const;
|
||||
|
|
@ -76,11 +76,7 @@ class GLGizmoRotate3D : public GLGizmoBase
|
|||
std::vector<GLGizmoRotate> m_gizmos;
|
||||
|
||||
public:
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoRotate3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
#else
|
||||
GLGizmoRotate3D(GLCanvas3D& parent, unsigned int sprite_id);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); }
|
||||
void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); }
|
||||
|
|
@ -102,7 +98,6 @@ protected:
|
|||
m_gizmos[i].set_hover_id((m_hover_id == i) ? 0 : -1);
|
||||
}
|
||||
}
|
||||
virtual bool on_is_activable(const Selection& selection) const { return true; }
|
||||
virtual void on_enable_grabber(unsigned int id)
|
||||
{
|
||||
if ((0 <= id) && (id < 3))
|
||||
|
|
@ -113,25 +108,26 @@ protected:
|
|||
if ((0 <= id) && (id < 3))
|
||||
m_gizmos[id].disable_grabber(0);
|
||||
}
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_stop_dragging();
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection)
|
||||
virtual void on_update(const UpdateData& data)
|
||||
{
|
||||
for (GLGizmoRotate& g : m_gizmos)
|
||||
{
|
||||
g.update(data, selection);
|
||||
g.update(data);
|
||||
}
|
||||
}
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const
|
||||
{
|
||||
for (const GLGizmoRotate& g : m_gizmos)
|
||||
{
|
||||
g.render_for_picking(selection);
|
||||
g.render_for_picking();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection);
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit);
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
|
||||
// Include GLGizmoBase.hpp before I18N.hpp as it includes some libigl code, which overrides our localization "L" macro.
|
||||
#include "GLGizmoScale.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
|
@ -13,13 +12,8 @@ namespace GUI {
|
|||
|
||||
const float GLGizmoScale3D::Offset = 5.0f;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
#else
|
||||
GLGizmoScale3D::GLGizmoScale3D(GLCanvas3D& parent, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, sprite_id)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_scale(Vec3d::Ones())
|
||||
, m_offset(Vec3d::Zero())
|
||||
, m_snap_step(0.05)
|
||||
|
|
@ -53,13 +47,18 @@ std::string GLGizmoScale3D::on_get_name() const
|
|||
return (_(L("Scale")) + " [S]").ToUTF8().data();
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_start_dragging(const Selection& selection)
|
||||
bool GLGizmoScale3D::on_is_activable() const
|
||||
{
|
||||
return !m_parent.get_selection().is_wipe_tower();
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1)
|
||||
{
|
||||
m_starting.drag_position = m_grabbers[m_hover_id].center;
|
||||
m_starting.ctrl_down = wxGetKeyState(WXK_CONTROL);
|
||||
m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : selection.get_bounding_box();
|
||||
m_starting.box = (m_starting.ctrl_down && (m_hover_id < 6)) ? m_box : m_parent.get_selection().get_bounding_box();
|
||||
|
||||
const Vec3d& center = m_starting.box.center();
|
||||
m_starting.pivots[0] = m_transform * Vec3d(m_starting.box.max(0), center(1), center(2));
|
||||
|
|
@ -71,7 +70,7 @@ void GLGizmoScale3D::on_start_dragging(const Selection& selection)
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoScale3D::on_update(const UpdateData& data)
|
||||
{
|
||||
if ((m_hover_id == 0) || (m_hover_id == 1))
|
||||
do_scale_along_axis(X, data);
|
||||
|
|
@ -83,8 +82,10 @@ void GLGizmoScale3D::on_update(const UpdateData& data, const Selection& selectio
|
|||
do_scale_uniform(data);
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_render(const Selection& selection) const
|
||||
void GLGizmoScale3D::on_render() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
bool single_instance = selection.is_single_full_instance();
|
||||
bool single_volume = selection.is_single_modifier() || selection.is_single_volume();
|
||||
bool single_selection = single_instance || single_volume;
|
||||
|
|
@ -136,7 +137,7 @@ void GLGizmoScale3D::on_render(const Selection& selection) const
|
|||
for (unsigned int idx : idxs)
|
||||
{
|
||||
const GLVolume* vol = selection.get_volume(idx);
|
||||
m_box.merge(vol->bounding_box.transformed(vol->get_volume_transformation().get_matrix()));
|
||||
m_box.merge(vol->bounding_box().transformed(vol->get_volume_transformation().get_matrix()));
|
||||
}
|
||||
|
||||
// gets transform from first selected volume
|
||||
|
|
@ -151,7 +152,7 @@ void GLGizmoScale3D::on_render(const Selection& selection) const
|
|||
else if (single_volume)
|
||||
{
|
||||
const GLVolume* v = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
m_box = v->bounding_box;
|
||||
m_box = v->bounding_box();
|
||||
m_transform = v->world_matrix();
|
||||
angles = Geometry::extract_euler_angles(m_transform);
|
||||
// consider rotation+mirror only components of the transform for offsets
|
||||
|
|
@ -277,16 +278,16 @@ void GLGizmoScale3D::on_render(const Selection& selection) const
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoScale3D::on_render_for_picking() const
|
||||
{
|
||||
glsafe(::glDisable(GL_DEPTH_TEST));
|
||||
|
||||
render_grabbers_for_picking(selection.get_bounding_box());
|
||||
render_grabbers_for_picking(m_parent.get_selection().get_bounding_box());
|
||||
}
|
||||
|
||||
void GLGizmoScale3D::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection)
|
||||
{
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
void GLGizmoScale3D::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
bool single_instance = selection.is_single_full_instance();
|
||||
wxString label = _(L("Scale (%)"));
|
||||
|
||||
|
|
@ -295,8 +296,8 @@ void GLGizmoScale3D::on_render_input_window(float x, float y, float bottom_limit
|
|||
m_imgui->begin(label, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
m_imgui->input_vec3("", m_scale * 100.f, 100.0f, "%.2f");
|
||||
m_imgui->end();
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
}
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
|
||||
void GLGizmoScale3D::render_grabbers_connection(unsigned int id_1, unsigned int id_2) const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,11 +32,7 @@ class GLGizmoScale3D : public GLGizmoBase
|
|||
StartingData m_starting;
|
||||
|
||||
public:
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoScale3D(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
#else
|
||||
GLGizmoScale3D(GLCanvas3D& parent, unsigned int sprite_id);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
double get_snap_step(double step) const { return m_snap_step; }
|
||||
void set_snap_step(double step) { m_snap_step = step; }
|
||||
|
|
@ -49,12 +45,14 @@ public:
|
|||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const;
|
||||
virtual bool on_is_activable(const Selection& selection) const { return !selection.is_wipe_tower(); }
|
||||
virtual void on_start_dragging(const Selection& selection);
|
||||
virtual void on_update(const UpdateData& data, const Selection& selection);
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection);
|
||||
virtual bool on_is_activable() const;
|
||||
virtual void on_start_dragging();
|
||||
virtual void on_update(const UpdateData& data);
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
#if !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit);
|
||||
#endif // !DISABLE_MOVE_ROTATE_SCALE_GIZMOS_IMGUI
|
||||
|
||||
private:
|
||||
void render_grabbers_connection(unsigned int id_1, unsigned int id_2) const;
|
||||
|
|
|
|||
|
|
@ -19,13 +19,8 @@
|
|||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, icon_filename, sprite_id)
|
||||
#else
|
||||
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent, unsigned int sprite_id)
|
||||
: GLGizmoBase(parent, sprite_id)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_quadric(nullptr)
|
||||
, m_its(nullptr)
|
||||
{
|
||||
|
|
@ -99,8 +94,10 @@ void GLGizmoSlaSupports::set_sla_support_data(ModelObject* model_object, const S
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::on_render(const Selection& selection) const
|
||||
void GLGizmoSlaSupports::on_render() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
// If current m_model_object does not match selection, ask GLCanvas3D to turn us off
|
||||
if (m_state == On
|
||||
&& (m_model_object != selection.get_model()->objects[selection.get_object_idx()]
|
||||
|
|
@ -109,6 +106,9 @@ void GLGizmoSlaSupports::on_render(const Selection& selection) const
|
|||
return;
|
||||
}
|
||||
|
||||
if (! m_its || ! m_mesh)
|
||||
const_cast<GLGizmoSlaSupports*>(this)->update_mesh();
|
||||
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
|
|
@ -257,8 +257,9 @@ void GLGizmoSlaSupports::render_clipping_plane(const Selection& selection) const
|
|||
}
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::on_render_for_picking(const Selection& selection) const
|
||||
void GLGizmoSlaSupports::on_render_for_picking() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
#if ENABLE_RENDER_PICKING_PASS
|
||||
m_z_shift = selection.get_volume(*selection.get_volume_idxs().begin())->get_sla_shift_z();
|
||||
#endif
|
||||
|
|
@ -384,23 +385,31 @@ bool GLGizmoSlaSupports::is_point_clipped(const Vec3d& point) const
|
|||
bool GLGizmoSlaSupports::is_mesh_update_necessary() const
|
||||
{
|
||||
return ((m_state == On) && (m_model_object != nullptr) && !m_model_object->instances.empty())
|
||||
&& ((m_model_object->id() != m_current_mesh_model_id) || m_its == nullptr);
|
||||
&& ((m_model_object->id() != m_current_mesh_object_id) || m_its == nullptr);
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::update_mesh()
|
||||
{
|
||||
if (! m_model_object)
|
||||
return;
|
||||
|
||||
wxBusyCursor wait;
|
||||
// this way we can use that mesh directly.
|
||||
// This mesh does not account for the possible Z up SLA offset.
|
||||
m_mesh = &m_model_object->volumes.front()->mesh();
|
||||
m_its = &m_mesh->its;
|
||||
m_current_mesh_model_id = m_model_object->id();
|
||||
m_editing_mode = false;
|
||||
|
||||
m_AABB.deinit();
|
||||
m_AABB.init(
|
||||
MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
|
||||
MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3));
|
||||
// If this is different mesh than last time or if the AABB tree is uninitialized, recalculate it.
|
||||
if (m_current_mesh_object_id != m_model_object->id() || (m_AABB.m_left == NULL && m_AABB.m_right == NULL))
|
||||
{
|
||||
m_AABB.deinit();
|
||||
m_AABB.init(
|
||||
MapMatrixXfUnaligned(m_its->vertices.front().data(), m_its->vertices.size(), 3),
|
||||
MapMatrixXiUnaligned(m_its->indices.front().data(), m_its->indices.size(), 3));
|
||||
}
|
||||
|
||||
m_current_mesh_object_id = m_model_object->id();
|
||||
m_editing_mode = false;
|
||||
}
|
||||
|
||||
// Unprojects the mouse position on the mesh and return the hit point and normal of the facet.
|
||||
|
|
@ -707,12 +716,12 @@ void GLGizmoSlaSupports::delete_selected_points(bool force)
|
|||
//m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::on_update(const UpdateData& data, const Selection& selection)
|
||||
void GLGizmoSlaSupports::on_update(const UpdateData& data)
|
||||
{
|
||||
if (m_editing_mode && m_hover_id != -1 && data.mouse_pos && (!m_editing_mode_cache[m_hover_id].support_point.is_new_island || !m_lock_unique_islands)) {
|
||||
if (m_editing_mode && m_hover_id != -1 && (!m_editing_mode_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(Vec2d((*data.mouse_pos)(0), (*data.mouse_pos)(1)));
|
||||
pos_and_normal = unproject_on_mesh(data.mouse_pos.cast<double>());
|
||||
}
|
||||
catch (...) { return; }
|
||||
m_editing_mode_cache[m_hover_id].support_point.pos = pos_and_normal.first;
|
||||
|
|
@ -827,7 +836,7 @@ void GLGizmoSlaSupports::make_line_segments() const
|
|||
*/
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_limit, const Selection& selection)
|
||||
void GLGizmoSlaSupports::on_render_input_window(float x, float y, float bottom_limit)
|
||||
{
|
||||
if (!m_model_object)
|
||||
return;
|
||||
|
|
@ -928,10 +937,12 @@ RENDER_AGAIN:
|
|||
}
|
||||
|
||||
if (value_changed) { // Update side panel
|
||||
wxTheApp->CallAfter([]() {
|
||||
wxGetApp().obj_settings()->UpdateAndShow(true);
|
||||
wxGetApp().obj_list()->update_settings_items();
|
||||
});
|
||||
/* wxTheApp->CallAfter([]() {
|
||||
* wxGetApp().obj_settings()->UpdateAndShow(true);
|
||||
* wxGetApp().obj_list()->update_settings_items();
|
||||
* });
|
||||
* #lm_FIXME_delete_after_testing */
|
||||
wxGetApp().obj_list()->update_and_show_object_settings_item();
|
||||
}
|
||||
|
||||
bool generate = m_imgui->button(m_desc.at("auto_generate"));
|
||||
|
|
@ -1005,11 +1016,13 @@ RENDER_AGAIN:
|
|||
m_parent.set_as_dirty();
|
||||
}
|
||||
|
||||
bool GLGizmoSlaSupports::on_is_activable(const Selection& selection) const
|
||||
bool GLGizmoSlaSupports::on_is_activable() const
|
||||
{
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() != ptSLA
|
||||
|| !selection.is_from_single_instance())
|
||||
return false;
|
||||
return false;
|
||||
|
||||
// Check that none of the selected volumes is outside. Only SLA auxiliaries (supports) are allowed outside.
|
||||
const Selection::IndicesList& list = selection.get_volume_idxs();
|
||||
|
|
@ -1032,53 +1045,72 @@ std::string GLGizmoSlaSupports::on_get_name() const
|
|||
|
||||
void GLGizmoSlaSupports::on_set_state()
|
||||
{
|
||||
if (m_state == On && m_old_state != On) { // the gizmo was just turned on
|
||||
if (is_mesh_update_necessary())
|
||||
update_mesh();
|
||||
|
||||
// we'll now reload support points:
|
||||
if (m_model_object)
|
||||
editing_mode_reload_cache();
|
||||
|
||||
m_parent.toggle_model_objects_visibility(false);
|
||||
if (m_model_object)
|
||||
m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
|
||||
|
||||
// Set default head diameter from config.
|
||||
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
|
||||
m_new_point_head_diameter = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value;
|
||||
// m_model_object pointer can be invalid (for instance because of undo/redo action),
|
||||
// we should recover it from the object id
|
||||
const ModelObject* old_model_object = m_model_object;
|
||||
m_model_object = nullptr;
|
||||
for (const auto mo : wxGetApp().model().objects) {
|
||||
if (mo->id() == m_current_mesh_object_id) {
|
||||
m_model_object = mo;
|
||||
break;
|
||||
}
|
||||
if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
|
||||
wxGetApp().CallAfter([this]() {
|
||||
// Following is called through CallAfter, because otherwise there was a problem
|
||||
// on OSX with the wxMessageDialog being shown several times when clicked into.
|
||||
if (m_model_object) {
|
||||
if (m_unsaved_changes) {
|
||||
wxMessageDialog dlg(GUI::wxGetApp().mainframe, _(L("Do you want to save your manually edited support points?")) + "\n",
|
||||
_(L("Save changes?")), wxICON_QUESTION | wxYES | wxNO);
|
||||
if (dlg.ShowModal() == wxID_YES)
|
||||
editing_mode_apply_changes();
|
||||
else
|
||||
editing_mode_discard_changes();
|
||||
}
|
||||
}
|
||||
|
||||
// If ModelObject pointer really changed, invalidate mesh and do everything
|
||||
// as if the gizmo was switched from Off state
|
||||
if (m_model_object == nullptr || old_model_object != m_model_object) {
|
||||
m_mesh = nullptr;
|
||||
m_its = nullptr;
|
||||
m_old_state = Off;
|
||||
}
|
||||
|
||||
if (m_state == On && m_old_state != On) { // the gizmo was just turned on
|
||||
if (is_mesh_update_necessary())
|
||||
update_mesh();
|
||||
|
||||
// we'll now reload support points:
|
||||
if (m_model_object)
|
||||
editing_mode_reload_cache();
|
||||
|
||||
m_parent.toggle_model_objects_visibility(false);
|
||||
if (m_model_object)
|
||||
m_parent.toggle_model_objects_visibility(true, m_model_object, m_active_instance);
|
||||
|
||||
// Set default head diameter from config.
|
||||
const DynamicPrintConfig& cfg = wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
|
||||
m_new_point_head_diameter = static_cast<const ConfigOptionFloat*>(cfg.option("support_head_front_diameter"))->value;
|
||||
}
|
||||
if (m_state == Off && m_old_state != Off) { // the gizmo was just turned Off
|
||||
wxGetApp().CallAfter([this]() {
|
||||
// Following is called through CallAfter, because otherwise there was a problem
|
||||
// on OSX with the wxMessageDialog being shown several times when clicked into.
|
||||
if (m_model_object) {
|
||||
if (m_unsaved_changes) {
|
||||
wxMessageDialog dlg(GUI::wxGetApp().mainframe, _(L("Do you want to save your manually edited support points?")) + "\n",
|
||||
_(L("Save changes?")), wxICON_QUESTION | wxYES | wxNO);
|
||||
if (dlg.ShowModal() == wxID_YES)
|
||||
editing_mode_apply_changes();
|
||||
else
|
||||
editing_mode_discard_changes();
|
||||
}
|
||||
m_parent.toggle_model_objects_visibility(true);
|
||||
m_editing_mode = false; // so it is not active next time the gizmo opens
|
||||
m_editing_mode_cache.clear();
|
||||
m_clipping_plane_distance = 0.f;
|
||||
// Release triangle mesh slicer and the AABB spatial search structure.
|
||||
m_AABB.deinit();
|
||||
m_its = nullptr;
|
||||
m_tms.reset();
|
||||
m_supports_tms.reset();
|
||||
});
|
||||
}
|
||||
m_old_state = m_state;
|
||||
}
|
||||
m_parent.toggle_model_objects_visibility(true);
|
||||
m_editing_mode = false; // so it is not active next time the gizmo opens
|
||||
m_editing_mode_cache.clear();
|
||||
m_clipping_plane_distance = 0.f;
|
||||
// Release triangle mesh slicer and the AABB spatial search structure.
|
||||
m_AABB.deinit();
|
||||
m_its = nullptr;
|
||||
m_tms.reset();
|
||||
m_supports_tms.reset();
|
||||
});
|
||||
}
|
||||
m_old_state = m_state;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::on_start_dragging(const Selection& selection)
|
||||
void GLGizmoSlaSupports::on_start_dragging()
|
||||
{
|
||||
if (m_hover_id != -1) {
|
||||
select_point(NoPoints);
|
||||
|
|
@ -1088,6 +1120,26 @@ void GLGizmoSlaSupports::on_start_dragging(const Selection& selection)
|
|||
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::on_load(cereal::BinaryInputArchive& ar)
|
||||
{
|
||||
ar(m_clipping_plane_distance,
|
||||
m_clipping_plane_normal,
|
||||
m_current_mesh_object_id
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::on_save(cereal::BinaryOutputArchive& ar) const
|
||||
{
|
||||
ar(m_clipping_plane_distance,
|
||||
m_clipping_plane_normal,
|
||||
m_current_mesh_object_id
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLGizmoSlaSupports::select_point(int i)
|
||||
{
|
||||
if (i == AllPoints || i == NoPoints) {
|
||||
|
|
@ -1144,6 +1196,7 @@ void GLGizmoSlaSupports::editing_mode_apply_changes()
|
|||
// If there are no changes, don't touch the front-end. The data in the cache could have been
|
||||
// taken from the backend and copying them to ModelObject would needlessly invalidate them.
|
||||
if (m_unsaved_changes) {
|
||||
wxGetApp().plater()->take_snapshot(_(L("Support points edit")));
|
||||
m_model_object->sla_points_status = sla::PointsStatus::UserModified;
|
||||
m_model_object->sla_support_points.clear();
|
||||
for (const CacheEntry& cache_entry : m_editing_mode_cache)
|
||||
|
|
@ -1202,6 +1255,7 @@ void GLGizmoSlaSupports::auto_generate()
|
|||
)), _(L("Warning")), wxICON_WARNING | wxYES | wxNO);
|
||||
|
||||
if (m_model_object->sla_points_status != sla::PointsStatus::UserModified || m_editing_mode_cache.empty() || dlg.ShowModal() == wxID_YES) {
|
||||
wxGetApp().plater()->take_snapshot(_(L("Autogenerate support points")));
|
||||
m_model_object->sla_support_points.clear();
|
||||
m_model_object->sla_points_status = sla::PointsStatus::Generating;
|
||||
m_editing_mode_cache.clear();
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
#include "libslic3r/SLAPrint.hpp"
|
||||
#include <wx/dialog.h>
|
||||
|
||||
#include <cereal/types/vector.hpp>
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
|
@ -26,7 +28,7 @@ class GLGizmoSlaSupports : public GLGizmoBase
|
|||
{
|
||||
private:
|
||||
ModelObject* m_model_object = nullptr;
|
||||
ModelID m_current_mesh_model_id = 0;
|
||||
ObjectID m_current_mesh_object_id = 0;
|
||||
int m_active_instance = -1;
|
||||
float m_active_instance_bb_radius; // to cache the bb
|
||||
mutable float m_z_shift = 0.f;
|
||||
|
|
@ -49,20 +51,25 @@ private:
|
|||
|
||||
class CacheEntry {
|
||||
public:
|
||||
CacheEntry() :
|
||||
support_point(sla::SupportPoint()), selected(false), normal(Vec3f::Zero()) {}
|
||||
|
||||
CacheEntry(const sla::SupportPoint& point, bool sel, const Vec3f& norm = Vec3f::Zero()) :
|
||||
support_point(point), selected(sel), normal(norm) {}
|
||||
|
||||
sla::SupportPoint support_point;
|
||||
bool selected; // whether the point is selected
|
||||
Vec3f normal;
|
||||
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar)
|
||||
{
|
||||
ar(support_point, selected, normal);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoSlaSupports(GLCanvas3D& parent, const std::string& icon_filename, unsigned int sprite_id);
|
||||
#else
|
||||
GLGizmoSlaSupports(GLCanvas3D& parent, unsigned int sprite_id);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
virtual ~GLGizmoSlaSupports();
|
||||
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down);
|
||||
|
|
@ -74,9 +81,9 @@ public:
|
|||
|
||||
private:
|
||||
bool on_init();
|
||||
void on_update(const UpdateData& data, const Selection& selection);
|
||||
virtual void on_render(const Selection& selection) const;
|
||||
virtual void on_render_for_picking(const Selection& selection) const;
|
||||
void on_update(const UpdateData& data);
|
||||
virtual void on_render() const;
|
||||
virtual void on_render_for_picking() const;
|
||||
|
||||
//void render_selection_rectangle() const;
|
||||
void render_points(const Selection& selection, bool picking = false) const;
|
||||
|
|
@ -137,12 +144,14 @@ protected:
|
|||
if ((int)m_editing_mode_cache.size() <= m_hover_id)
|
||||
m_hover_id = -1;
|
||||
}
|
||||
void on_start_dragging(const Selection& selection) override;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit, const Selection& selection) override;
|
||||
void on_start_dragging() override;
|
||||
virtual void on_render_input_window(float x, float y, float bottom_limit) override;
|
||||
|
||||
virtual std::string on_get_name() const;
|
||||
virtual bool on_is_activable(const Selection& selection) const;
|
||||
virtual bool on_is_activable() const;
|
||||
virtual bool on_is_selectable() const;
|
||||
virtual void on_load(cereal::BinaryInputArchive& ar) override;
|
||||
virtual void on_save(cereal::BinaryOutputArchive& ar) const override;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -12,51 +12,29 @@
|
|||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
const float GLGizmosManager::Default_Icons_Size = 64;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
const float GLGizmosManager::Default_Icons_Size = 64;
|
||||
|
||||
GLGizmosManager::GLGizmosManager()
|
||||
: m_enabled(false)
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmosManager::GLGizmosManager(GLCanvas3D& parent)
|
||||
: m_parent(parent)
|
||||
, m_enabled(false)
|
||||
, m_icons_texture_dirty(true)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_current(Undefined)
|
||||
#if ENABLE_SVG_ICONS
|
||||
, m_overlay_icons_size(Default_Icons_Size)
|
||||
, m_overlay_scale(1.0f)
|
||||
, m_overlay_border(5.0f)
|
||||
, m_overlay_gap_y(5.0f)
|
||||
, m_tooltip("")
|
||||
, m_serializing(false)
|
||||
{
|
||||
}
|
||||
#else
|
||||
{
|
||||
set_overlay_scale(1.0);
|
||||
}
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
GLGizmosManager::~GLGizmosManager()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
bool GLGizmosManager::init(GLCanvas3D& parent)
|
||||
bool GLGizmosManager::init()
|
||||
{
|
||||
#if !ENABLE_SVG_ICONS
|
||||
m_icons_texture.metadata.filename = "gizmos.png";
|
||||
m_icons_texture.metadata.icon_size = 64;
|
||||
|
||||
if (!m_icons_texture.metadata.filename.empty())
|
||||
{
|
||||
if (!m_icons_texture.texture.load_from_file(resources_dir() + "/icons/" + m_icons_texture.metadata.filename, false))
|
||||
{
|
||||
reset();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif // !ENABLE_SVG_ICONS
|
||||
|
||||
m_background_texture.metadata.filename = "toolbar_background.png";
|
||||
m_background_texture.metadata.left = 16;
|
||||
m_background_texture.metadata.top = 16;
|
||||
|
|
@ -72,11 +50,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
}
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
GLGizmoBase* gizmo = new GLGizmoMove3D(parent, "move.svg", 0);
|
||||
#else
|
||||
GLGizmoBase* gizmo = new GLGizmoMove3D(parent, 0);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
GLGizmoBase* gizmo = new GLGizmoMove3D(m_parent, "move.svg", 0);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
|
|
@ -85,11 +59,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
|
||||
m_gizmos.insert(GizmosMap::value_type(Move, gizmo));
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
gizmo = new GLGizmoScale3D(parent, "scale.svg", 1);
|
||||
#else
|
||||
gizmo = new GLGizmoScale3D(parent, 1);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
gizmo = new GLGizmoScale3D(m_parent, "scale.svg", 1);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
|
|
@ -98,11 +68,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
|
||||
m_gizmos.insert(GizmosMap::value_type(Scale, gizmo));
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
gizmo = new GLGizmoRotate3D(parent, "rotate.svg", 2);
|
||||
#else
|
||||
gizmo = new GLGizmoRotate3D(parent, 2);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
gizmo = new GLGizmoRotate3D(m_parent, "rotate.svg", 2);
|
||||
if (gizmo == nullptr)
|
||||
{
|
||||
reset();
|
||||
|
|
@ -117,11 +83,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
|
||||
m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo));
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
gizmo = new GLGizmoFlatten(parent, "place.svg", 3);
|
||||
#else
|
||||
gizmo = new GLGizmoFlatten(parent, 3);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
gizmo = new GLGizmoFlatten(m_parent, "place.svg", 3);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
|
|
@ -132,11 +94,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
|
||||
m_gizmos.insert(GizmosMap::value_type(Flatten, gizmo));
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
gizmo = new GLGizmoCut(parent, "cut.svg", 4);
|
||||
#else
|
||||
gizmo = new GLGizmoCut(parent, 4);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
gizmo = new GLGizmoCut(m_parent, "cut.svg", 4);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
|
|
@ -147,11 +105,7 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
|
||||
m_gizmos.insert(GizmosMap::value_type(Cut, gizmo));
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
gizmo = new GLGizmoSlaSupports(parent, "sla_supports.svg", 5);
|
||||
#else
|
||||
gizmo = new GLGizmoSlaSupports(parent, 5);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
gizmo = new GLGizmoSlaSupports(m_parent, "sla_supports.svg", 5);
|
||||
if (gizmo == nullptr)
|
||||
return false;
|
||||
|
||||
|
|
@ -165,7 +119,6 @@ bool GLGizmosManager::init(GLCanvas3D& parent)
|
|||
return true;
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
void GLGizmosManager::set_overlay_icon_size(float size)
|
||||
{
|
||||
if (m_overlay_icons_size != size)
|
||||
|
|
@ -174,29 +127,25 @@ void GLGizmosManager::set_overlay_icon_size(float size)
|
|||
m_icons_texture_dirty = true;
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
void GLGizmosManager::set_overlay_scale(float scale)
|
||||
{
|
||||
#if ENABLE_SVG_ICONS
|
||||
if (m_overlay_scale != scale)
|
||||
{
|
||||
m_overlay_scale = scale;
|
||||
m_icons_texture_dirty = true;
|
||||
}
|
||||
#else
|
||||
m_overlay_icons_scale = scale;
|
||||
m_overlay_border = 5.0f * scale;
|
||||
m_overlay_gap_y = 5.0f * scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
}
|
||||
|
||||
void GLGizmosManager::refresh_on_off_state(const Selection& selection)
|
||||
void GLGizmosManager::refresh_on_off_state()
|
||||
{
|
||||
if (m_serializing)
|
||||
return;
|
||||
|
||||
GizmosMap::iterator it = m_gizmos.find(m_current);
|
||||
if ((it != m_gizmos.end()) && (it->second != nullptr))
|
||||
{
|
||||
if (!it->second->is_activable(selection))
|
||||
if (!it->second->is_activable())
|
||||
{
|
||||
it->second->set_state(GLGizmoBase::Off);
|
||||
m_current = Undefined;
|
||||
|
|
@ -209,6 +158,9 @@ void GLGizmosManager::reset_all_states()
|
|||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
if (m_serializing)
|
||||
return;
|
||||
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if (it->second != nullptr)
|
||||
|
|
@ -248,22 +200,22 @@ void GLGizmosManager::enable_grabber(EType type, unsigned int id, bool enable)
|
|||
}
|
||||
}
|
||||
|
||||
void GLGizmosManager::update(const Linef3& mouse_ray, const Selection& selection, const Point* mouse_pos)
|
||||
void GLGizmosManager::update(const Linef3& mouse_ray, const Point& mouse_pos)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->update(GLGizmoBase::UpdateData(mouse_ray, mouse_pos), selection);
|
||||
curr->update(GLGizmoBase::UpdateData(mouse_ray, mouse_pos));
|
||||
}
|
||||
|
||||
void GLGizmosManager::update_data(GLCanvas3D& canvas)
|
||||
void GLGizmosManager::update_data()
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
const Selection& selection = canvas.get_selection();
|
||||
const Selection& selection = m_parent.get_selection();
|
||||
|
||||
bool is_wipe_tower = selection.is_wipe_tower();
|
||||
enable_grabber(Move, 2, !is_wipe_tower);
|
||||
|
|
@ -284,7 +236,7 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas)
|
|||
set_rotation(Vec3d::Zero());
|
||||
ModelObject* model_object = selection.get_model()->objects[selection.get_object_idx()];
|
||||
set_flattening_data(model_object);
|
||||
set_sla_support_data(model_object, selection);
|
||||
set_sla_support_data(model_object);
|
||||
}
|
||||
else if (selection.is_single_volume() || selection.is_single_modifier())
|
||||
{
|
||||
|
|
@ -292,7 +244,7 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas)
|
|||
set_scale(volume->get_volume_scaling_factor());
|
||||
set_rotation(Vec3d::Zero());
|
||||
set_flattening_data(nullptr);
|
||||
set_sla_support_data(nullptr, selection);
|
||||
set_sla_support_data(nullptr);
|
||||
}
|
||||
else if (is_wipe_tower)
|
||||
{
|
||||
|
|
@ -300,14 +252,14 @@ void GLGizmosManager::update_data(GLCanvas3D& canvas)
|
|||
set_scale(Vec3d::Ones());
|
||||
set_rotation(Vec3d(0., 0., (M_PI/180.) * dynamic_cast<const ConfigOptionFloat*>(config.option("wipe_tower_rotation_angle"))->value));
|
||||
set_flattening_data(nullptr);
|
||||
set_sla_support_data(nullptr, selection);
|
||||
set_sla_support_data(nullptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_scale(Vec3d::Ones());
|
||||
set_rotation(Vec3d::Zero());
|
||||
set_flattening_data(selection.is_from_single_object() ? selection.get_model()->objects[selection.get_object_idx()] : nullptr);
|
||||
set_sla_support_data(nullptr, selection);
|
||||
set_sla_support_data(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -320,9 +272,12 @@ bool GLGizmosManager::is_running() const
|
|||
return (curr != nullptr) ? (curr->get_state() == GLGizmoBase::On) : false;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::handle_shortcut(int key, const Selection& selection)
|
||||
bool GLGizmosManager::handle_shortcut(int key)
|
||||
{
|
||||
if (!m_enabled || selection.is_empty())
|
||||
if (!m_enabled)
|
||||
return false;
|
||||
|
||||
if (m_parent.get_selection().is_empty())
|
||||
return false;
|
||||
|
||||
EType old_current = m_current;
|
||||
|
|
@ -334,7 +289,7 @@ bool GLGizmosManager::handle_shortcut(int key, const Selection& selection)
|
|||
|
||||
int it_key = it->second->get_shortcut_key();
|
||||
|
||||
if (it->second->is_activable(selection) && ((it_key == key - 64) || (it_key == key - 96)))
|
||||
if (it->second->is_activable() && ((it_key == key - 64) || (it_key == key - 96)))
|
||||
{
|
||||
if ((it->second->get_state() == GLGizmoBase::On))
|
||||
{
|
||||
|
|
@ -370,14 +325,14 @@ bool GLGizmosManager::is_dragging() const
|
|||
return (curr != nullptr) ? curr->is_dragging() : false;
|
||||
}
|
||||
|
||||
void GLGizmosManager::start_dragging(const Selection& selection)
|
||||
void GLGizmosManager::start_dragging()
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->start_dragging(selection);
|
||||
curr->start_dragging();
|
||||
}
|
||||
|
||||
void GLGizmosManager::stop_dragging()
|
||||
|
|
@ -465,14 +420,14 @@ void GLGizmosManager::set_flattening_data(const ModelObject* model_object)
|
|||
reinterpret_cast<GLGizmoFlatten*>(it->second)->set_flattening_data(model_object);
|
||||
}
|
||||
|
||||
void GLGizmosManager::set_sla_support_data(ModelObject* model_object, const Selection& selection)
|
||||
void GLGizmosManager::set_sla_support_data(ModelObject* model_object)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
GizmosMap::const_iterator it = m_gizmos.find(SlaSupports);
|
||||
if (it != m_gizmos.end())
|
||||
reinterpret_cast<GLGizmoSlaSupports*>(it->second)->set_sla_support_data(model_object, selection);
|
||||
reinterpret_cast<GLGizmoSlaSupports*>(it->second)->set_sla_support_data(model_object, m_parent.get_selection());
|
||||
}
|
||||
|
||||
// Returns true if the gizmo used the event to do something, false otherwise.
|
||||
|
|
@ -501,40 +456,38 @@ ClippingPlane GLGizmosManager::get_sla_clipping_plane() const
|
|||
}
|
||||
|
||||
|
||||
void GLGizmosManager::render_current_gizmo(const Selection& selection) const
|
||||
void GLGizmosManager::render_current_gizmo() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->render(selection);
|
||||
curr->render();
|
||||
}
|
||||
|
||||
void GLGizmosManager::render_current_gizmo_for_picking_pass(const Selection& selection) const
|
||||
void GLGizmosManager::render_current_gizmo_for_picking_pass() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->render_for_picking(selection);
|
||||
curr->render_for_picking();
|
||||
}
|
||||
|
||||
void GLGizmosManager::render_overlay(const GLCanvas3D& canvas, const Selection& selection) const
|
||||
void GLGizmosManager::render_overlay() const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
if (m_icons_texture_dirty)
|
||||
generate_icons_texture();
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
do_render_overlay(canvas, selection);
|
||||
do_render_overlay();
|
||||
}
|
||||
|
||||
bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt, GLCanvas3D& canvas)
|
||||
bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt)
|
||||
{
|
||||
bool processed = false;
|
||||
|
||||
|
|
@ -547,14 +500,12 @@ bool GLGizmosManager::on_mouse_wheel(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
return processed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
||||
bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
||||
{
|
||||
Point pos(evt.GetX(), evt.GetY());
|
||||
Vec2d mouse_pos((double)evt.GetX(), (double)evt.GetY());
|
||||
|
||||
Selection& selection = canvas.get_selection();
|
||||
Selection& selection = m_parent.get_selection();
|
||||
int selected_object_idx = selection.get_object_idx();
|
||||
bool processed = false;
|
||||
|
||||
|
|
@ -570,7 +521,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
|
||||
// mouse anywhere
|
||||
if (evt.Moving())
|
||||
m_tooltip = update_hover_state(canvas, mouse_pos);
|
||||
m_tooltip = update_hover_state(mouse_pos);
|
||||
else if (evt.LeftUp())
|
||||
m_mouse_capture.left = false;
|
||||
else if (evt.MiddleUp())
|
||||
|
|
@ -581,7 +532,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
// if the button down was done on this toolbar, prevent from dragging into the scene
|
||||
processed = true;
|
||||
|
||||
if (!overlay_contains_mouse(canvas, mouse_pos))
|
||||
if (!overlay_contains_mouse(mouse_pos))
|
||||
{
|
||||
// mouse is outside the toolbar
|
||||
m_tooltip = "";
|
||||
|
|
@ -593,41 +544,40 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
processed = true;
|
||||
else if (!selection.is_empty() && grabber_contains_mouse())
|
||||
{
|
||||
update_data(canvas);
|
||||
update_data();
|
||||
selection.start_dragging();
|
||||
start_dragging(selection);
|
||||
start_dragging();
|
||||
|
||||
if (m_current == Flatten)
|
||||
{
|
||||
// Rotate the object so the normal points downward:
|
||||
selection.flattening_rotate(get_flattening_normal());
|
||||
canvas.do_flatten();
|
||||
m_parent.do_flatten(get_flattening_normal(), L("Gizmo-Place on Face"));
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
}
|
||||
|
||||
canvas.set_as_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
else if (evt.RightDown() && (selected_object_idx != -1) && (m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::RightDown))
|
||||
// event was taken care of by the SlaSupports gizmo
|
||||
processed = true;
|
||||
else if (evt.Dragging() && (canvas.get_move_volume_id() != -1) && (m_current == SlaSupports))
|
||||
// don't allow dragging objects with the Sla gizmo on
|
||||
else if (evt.Dragging() && (m_parent.get_move_volume_id() != -1) && (m_current == SlaSupports))
|
||||
// don't allow dragging objects with the Sla gizmo on
|
||||
processed = true;
|
||||
else if (evt.Dragging() && (m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()))
|
||||
{
|
||||
// the gizmo got the event and took some action, no need to do anything more here
|
||||
canvas.set_as_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.Dragging() && is_dragging())
|
||||
{
|
||||
if (!canvas.get_wxglcanvas()->HasCapture())
|
||||
canvas.get_wxglcanvas()->CaptureMouse();
|
||||
if (!m_parent.get_wxglcanvas()->HasCapture())
|
||||
m_parent.get_wxglcanvas()->CaptureMouse();
|
||||
|
||||
canvas.set_mouse_as_dragging();
|
||||
update(canvas.mouse_ray(pos), selection, &pos);
|
||||
m_parent.set_mouse_as_dragging();
|
||||
update(m_parent.mouse_ray(pos), pos);
|
||||
|
||||
switch (m_current)
|
||||
{
|
||||
|
|
@ -664,7 +614,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
break;
|
||||
}
|
||||
|
||||
canvas.set_as_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.LeftUp() && is_dragging())
|
||||
|
|
@ -673,18 +623,18 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
{
|
||||
case Move:
|
||||
{
|
||||
canvas.disable_regenerate_volumes();
|
||||
canvas.do_move();
|
||||
m_parent.disable_regenerate_volumes();
|
||||
m_parent.do_move(L("Gizmo-Move"));
|
||||
break;
|
||||
}
|
||||
case Scale:
|
||||
{
|
||||
canvas.do_scale();
|
||||
m_parent.do_scale(L("Gizmo-Scale"));
|
||||
break;
|
||||
}
|
||||
case Rotate:
|
||||
{
|
||||
canvas.do_rotate();
|
||||
m_parent.do_rotate(L("Gizmo-Rotate"));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -692,25 +642,25 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
}
|
||||
|
||||
stop_dragging();
|
||||
update_data(canvas);
|
||||
update_data();
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
// Let the platter know that the dragging finished, so a delayed refresh
|
||||
// of the scene with the background processing data should be performed.
|
||||
canvas.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED));
|
||||
// updates camera target constraints
|
||||
canvas.refresh_camera_scene_box();
|
||||
m_parent.refresh_camera_scene_box();
|
||||
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.LeftUp() && (m_current == SlaSupports) && !canvas.is_mouse_dragging())
|
||||
else if (evt.LeftUp() && (m_current == SlaSupports) && !m_parent.is_mouse_dragging())
|
||||
{
|
||||
// in case SLA gizmo is selected, we just pass the LeftUp event and stop processing - neither
|
||||
// object moving or selecting is suppressed in that case
|
||||
gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown());
|
||||
processed = true;
|
||||
}
|
||||
else if (evt.LeftUp() && (m_current == Flatten) && ((canvas.get_first_hover_volume_idx() != -1) || grabber_contains_mouse()))
|
||||
else if (evt.LeftUp() && (m_current == Flatten) && ((m_parent.get_first_hover_volume_idx() != -1) || grabber_contains_mouse()))
|
||||
{
|
||||
// to avoid to loose the selection when user clicks an object while the Flatten gizmo is active
|
||||
processed = true;
|
||||
|
|
@ -722,24 +672,24 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
if (evt.LeftDown() || evt.LeftDClick())
|
||||
{
|
||||
m_mouse_capture.left = true;
|
||||
m_mouse_capture.parent = &canvas;
|
||||
m_mouse_capture.parent = &m_parent;
|
||||
processed = true;
|
||||
if (!selection.is_empty())
|
||||
{
|
||||
update_on_off_state(canvas, mouse_pos, selection);
|
||||
update_data(canvas);
|
||||
canvas.set_as_dirty();
|
||||
update_on_off_state(mouse_pos);
|
||||
update_data();
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
else if (evt.MiddleDown())
|
||||
{
|
||||
m_mouse_capture.middle = true;
|
||||
m_mouse_capture.parent = &canvas;
|
||||
m_mouse_capture.parent = &m_parent;
|
||||
}
|
||||
else if (evt.RightDown())
|
||||
{
|
||||
m_mouse_capture.right = true;
|
||||
m_mouse_capture.parent = &canvas;
|
||||
m_mouse_capture.parent = &m_parent;
|
||||
}
|
||||
else if (evt.LeftUp())
|
||||
processed = true;
|
||||
|
|
@ -748,7 +698,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas)
|
|||
return processed;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::on_char(wxKeyEvent& evt, GLCanvas3D& canvas)
|
||||
bool GLGizmosManager::on_char(wxKeyEvent& evt)
|
||||
{
|
||||
// see include/wx/defs.h enum wxKeyCode
|
||||
int keyCode = evt.GetKeyCode();
|
||||
|
|
@ -856,20 +806,20 @@ bool GLGizmosManager::on_char(wxKeyEvent& evt, GLCanvas3D& canvas)
|
|||
|
||||
if (!processed && !evt.HasModifiers())
|
||||
{
|
||||
if (handle_shortcut(keyCode, canvas.get_selection()))
|
||||
if (handle_shortcut(keyCode))
|
||||
{
|
||||
update_data(canvas);
|
||||
update_data();
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (processed)
|
||||
canvas.set_as_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::on_key(wxKeyEvent& evt, GLCanvas3D& canvas)
|
||||
bool GLGizmosManager::on_key(wxKeyEvent& evt)
|
||||
{
|
||||
const int keyCode = evt.GetKeyCode();
|
||||
bool processed = false;
|
||||
|
|
@ -895,23 +845,29 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt, GLCanvas3D& canvas)
|
|||
}
|
||||
|
||||
// if (processed)
|
||||
// canvas.set_cursor(GLCanvas3D::Standard);
|
||||
// m_parent.set_cursor(GLCanvas3D::Standard);
|
||||
}
|
||||
else if (evt.GetEventType() == wxEVT_KEY_DOWN)
|
||||
{
|
||||
if ((m_current == SlaSupports) && ((keyCode == WXK_SHIFT) || (keyCode == WXK_ALT)) && reinterpret_cast<GLGizmoSlaSupports*>(get_current())->is_in_editing_mode())
|
||||
{
|
||||
// canvas.set_cursor(GLCanvas3D::Cross);
|
||||
// m_parent.set_cursor(GLCanvas3D::Cross);
|
||||
processed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (processed)
|
||||
canvas.set_as_dirty();
|
||||
m_parent.set_as_dirty();
|
||||
|
||||
return processed;
|
||||
}
|
||||
|
||||
void GLGizmosManager::update_after_undo_redo()
|
||||
{
|
||||
update_data();
|
||||
m_serializing = false;
|
||||
}
|
||||
|
||||
void GLGizmosManager::reset()
|
||||
{
|
||||
for (GizmosMap::value_type& gizmo : m_gizmos)
|
||||
|
|
@ -923,23 +879,73 @@ void GLGizmosManager::reset()
|
|||
m_gizmos.clear();
|
||||
}
|
||||
|
||||
void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selection& selection) const
|
||||
void GLGizmosManager::render_background(float left, float top, float right, float bottom, float border) const
|
||||
{
|
||||
unsigned int tex_id = m_background_texture.texture.get_id();
|
||||
float tex_width = (float)m_background_texture.texture.get_width();
|
||||
float tex_height = (float)m_background_texture.texture.get_height();
|
||||
if ((tex_id != 0) && (tex_width > 0) && (tex_height > 0))
|
||||
{
|
||||
float inv_tex_width = (tex_width != 0.0f) ? 1.0f / tex_width : 0.0f;
|
||||
float inv_tex_height = (tex_height != 0.0f) ? 1.0f / tex_height : 0.0f;
|
||||
|
||||
float internal_left = left + border;
|
||||
float internal_right = right - border;
|
||||
float internal_top = top - border;
|
||||
float internal_bottom = bottom + border;
|
||||
|
||||
float left_uv = 0.0f;
|
||||
float right_uv = 1.0f;
|
||||
float top_uv = 1.0f;
|
||||
float bottom_uv = 0.0f;
|
||||
|
||||
float internal_left_uv = (float)m_background_texture.metadata.left * inv_tex_width;
|
||||
float internal_right_uv = 1.0f - (float)m_background_texture.metadata.right * inv_tex_width;
|
||||
float internal_top_uv = 1.0f - (float)m_background_texture.metadata.top * inv_tex_height;
|
||||
float internal_bottom_uv = (float)m_background_texture.metadata.bottom * inv_tex_height;
|
||||
|
||||
// top-left corner
|
||||
GLTexture::render_sub_texture(tex_id, left, internal_left, internal_top, top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
|
||||
// top edge
|
||||
GLTexture::render_sub_texture(tex_id, internal_left, internal_right, internal_top, top, { { internal_left_uv, internal_top_uv }, { internal_right_uv, internal_top_uv }, { internal_right_uv, top_uv }, { internal_left_uv, top_uv } });
|
||||
|
||||
// top-right corner
|
||||
GLTexture::render_sub_texture(tex_id, internal_right, right, internal_top, top, { { internal_right_uv, internal_top_uv }, { right_uv, internal_top_uv }, { right_uv, top_uv }, { internal_right_uv, top_uv } });
|
||||
|
||||
// center-left edge
|
||||
GLTexture::render_sub_texture(tex_id, left, internal_left, internal_bottom, internal_top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
|
||||
// center
|
||||
GLTexture::render_sub_texture(tex_id, internal_left, internal_right, internal_bottom, internal_top, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
|
||||
// center-right edge
|
||||
GLTexture::render_sub_texture(tex_id, internal_right, right, internal_bottom, internal_top, { { internal_right_uv, internal_bottom_uv }, { right_uv, internal_bottom_uv }, { right_uv, internal_top_uv }, { internal_right_uv, internal_top_uv } });
|
||||
|
||||
// bottom-left corner
|
||||
GLTexture::render_sub_texture(tex_id, left, internal_left, bottom, internal_bottom, { { internal_left_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_right_uv, internal_top_uv }, { internal_left_uv, internal_top_uv } });
|
||||
|
||||
// bottom edge
|
||||
GLTexture::render_sub_texture(tex_id, internal_left, internal_right, bottom, internal_bottom, { { internal_left_uv, bottom_uv }, { internal_right_uv, bottom_uv }, { internal_right_uv, internal_bottom_uv }, { internal_left_uv, internal_bottom_uv } });
|
||||
|
||||
// bottom-right corner
|
||||
GLTexture::render_sub_texture(tex_id, internal_right, right, bottom, internal_bottom, { { internal_right_uv, bottom_uv }, { right_uv, bottom_uv }, { right_uv, internal_bottom_uv }, { internal_right_uv, internal_bottom_uv } });
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmosManager::do_render_overlay() const
|
||||
{
|
||||
if (m_gizmos.empty())
|
||||
return;
|
||||
|
||||
float cnv_w = (float)canvas.get_canvas_size().get_width();
|
||||
float cnv_h = (float)canvas.get_canvas_size().get_height();
|
||||
float zoom = (float)canvas.get_camera().get_zoom();
|
||||
float cnv_w = (float)m_parent.get_canvas_size().get_width();
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float zoom = (float)m_parent.get_camera().get_zoom();
|
||||
float inv_zoom = (zoom != 0.0f) ? 1.0f / zoom : 0.0f;
|
||||
|
||||
float height = get_total_overlay_height();
|
||||
float width = get_total_overlay_width();
|
||||
#if ENABLE_SVG_ICONS
|
||||
float scaled_border = m_overlay_border * m_overlay_scale * inv_zoom;
|
||||
#else
|
||||
float scaled_border = m_overlay_border * inv_zoom;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
float top_x = (-0.5f * cnv_w) * inv_zoom;
|
||||
float top_y = (0.5f * height) * inv_zoom;
|
||||
|
|
@ -949,73 +955,8 @@ void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selectio
|
|||
float right = left + width * inv_zoom;
|
||||
float bottom = top - height * inv_zoom;
|
||||
|
||||
// renders background
|
||||
unsigned int bg_tex_id = m_background_texture.texture.get_id();
|
||||
float bg_tex_width = (float)m_background_texture.texture.get_width();
|
||||
float bg_tex_height = (float)m_background_texture.texture.get_height();
|
||||
if ((bg_tex_id != 0) && (bg_tex_width > 0) && (bg_tex_height > 0))
|
||||
{
|
||||
float inv_bg_tex_width = (bg_tex_width != 0.0f) ? 1.0f / bg_tex_width : 0.0f;
|
||||
float inv_bg_tex_height = (bg_tex_height != 0.0f) ? 1.0f / bg_tex_height : 0.0f;
|
||||
render_background(left, top, right, bottom, scaled_border);
|
||||
|
||||
float bg_uv_left = 0.0f;
|
||||
float bg_uv_right = 1.0f;
|
||||
float bg_uv_top = 1.0f;
|
||||
float bg_uv_bottom = 0.0f;
|
||||
|
||||
float bg_left = left;
|
||||
float bg_right = right;
|
||||
float bg_top = top;
|
||||
float bg_bottom = bottom;
|
||||
float bg_width = right - left;
|
||||
float bg_height = top - bottom;
|
||||
float bg_min_size = std::min(bg_width, bg_height);
|
||||
|
||||
float bg_uv_i_left = (float)m_background_texture.metadata.left * inv_bg_tex_width;
|
||||
float bg_uv_i_right = 1.0f - (float)m_background_texture.metadata.right * inv_bg_tex_width;
|
||||
float bg_uv_i_top = 1.0f - (float)m_background_texture.metadata.top * inv_bg_tex_height;
|
||||
float bg_uv_i_bottom = (float)m_background_texture.metadata.bottom * inv_bg_tex_height;
|
||||
|
||||
float bg_i_left = bg_left + scaled_border;
|
||||
float bg_i_right = bg_right - scaled_border;
|
||||
float bg_i_top = bg_top - scaled_border;
|
||||
float bg_i_bottom = bg_bottom + scaled_border;
|
||||
|
||||
bg_uv_left = bg_uv_i_left;
|
||||
bg_i_left = bg_left;
|
||||
|
||||
if ((m_overlay_border > 0) && (bg_uv_top != bg_uv_i_top))
|
||||
{
|
||||
if (bg_uv_left != bg_uv_i_left)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_i_top, bg_top, { { bg_uv_left, bg_uv_i_top }, { bg_uv_i_left, bg_uv_i_top }, { bg_uv_i_left, bg_uv_top }, { bg_uv_left, bg_uv_top } });
|
||||
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_left, bg_i_right, bg_i_top, bg_top, { { bg_uv_i_left, bg_uv_i_top }, { bg_uv_i_right, bg_uv_i_top }, { bg_uv_i_right, bg_uv_top }, { bg_uv_i_left, bg_uv_top } });
|
||||
|
||||
if (bg_uv_right != bg_uv_i_right)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_right, bg_right, bg_i_top, bg_top, { { bg_uv_i_right, bg_uv_i_top }, { bg_uv_right, bg_uv_i_top }, { bg_uv_right, bg_uv_top }, { bg_uv_i_right, bg_uv_top } });
|
||||
}
|
||||
|
||||
if ((m_overlay_border > 0) && (bg_uv_left != bg_uv_i_left))
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_i_bottom, bg_i_top, { { bg_uv_left, bg_uv_i_bottom }, { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_i_left, bg_uv_i_top }, { bg_uv_left, bg_uv_i_top } });
|
||||
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_left, bg_i_right, bg_i_bottom, bg_i_top, { { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_i_right, bg_uv_i_bottom }, { bg_uv_i_right, bg_uv_i_top }, { bg_uv_i_left, bg_uv_i_top } });
|
||||
|
||||
if ((m_overlay_border > 0) && (bg_uv_right != bg_uv_i_right))
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_right, bg_right, bg_i_bottom, bg_i_top, { { bg_uv_i_right, bg_uv_i_bottom }, { bg_uv_right, bg_uv_i_bottom }, { bg_uv_right, bg_uv_i_top }, { bg_uv_i_right, bg_uv_i_top } });
|
||||
|
||||
if ((m_overlay_border > 0) && (bg_uv_bottom != bg_uv_i_bottom))
|
||||
{
|
||||
if (bg_uv_left != bg_uv_i_left)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_left, bg_i_left, bg_bottom, bg_i_bottom, { { bg_uv_left, bg_uv_bottom }, { bg_uv_i_left, bg_uv_bottom }, { bg_uv_i_left, bg_uv_i_bottom }, { bg_uv_left, bg_uv_i_bottom } });
|
||||
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_left, bg_i_right, bg_bottom, bg_i_bottom, { { bg_uv_i_left, bg_uv_bottom }, { bg_uv_i_right, bg_uv_bottom }, { bg_uv_i_right, bg_uv_i_bottom }, { bg_uv_i_left, bg_uv_i_bottom } });
|
||||
|
||||
if (bg_uv_right != bg_uv_i_right)
|
||||
GLTexture::render_sub_texture(bg_tex_id, bg_i_right, bg_right, bg_bottom, bg_i_bottom, { { bg_uv_i_right, bg_uv_bottom }, { bg_uv_right, bg_uv_bottom }, { bg_uv_right, bg_uv_i_bottom }, { bg_uv_i_right, bg_uv_i_bottom } });
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
top_x += scaled_border;
|
||||
top_y -= scaled_border;
|
||||
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale * inv_zoom;
|
||||
|
|
@ -1027,21 +968,9 @@ void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selectio
|
|||
unsigned int tex_height = m_icons_texture.get_height();
|
||||
float inv_tex_width = (tex_width != 0) ? 1.0f / (float)tex_width : 0.0f;
|
||||
float inv_tex_height = (tex_height != 0) ? 1.0f / (float)tex_height : 0.0f;
|
||||
#else
|
||||
top_x += m_overlay_border * inv_zoom;
|
||||
top_y -= m_overlay_border * inv_zoom;
|
||||
float scaled_gap_y = m_overlay_gap_y * inv_zoom;
|
||||
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale * inv_zoom;
|
||||
unsigned int icons_texture_id = m_icons_texture.texture.get_id();
|
||||
unsigned int texture_size = m_icons_texture.texture.get_width();
|
||||
float inv_texture_size = (texture_size != 0) ? 1.0f / (float)texture_size : 0.0f;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
if ((icons_texture_id == 0) || (tex_width <= 0) || (tex_height <= 0))
|
||||
return;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
|
|
@ -1051,78 +980,44 @@ void GLGizmosManager::do_render_overlay(const GLCanvas3D& canvas, const Selectio
|
|||
unsigned int sprite_id = it->second->get_sprite_id();
|
||||
GLGizmoBase::EState state = it->second->get_state();
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
float u_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_width;
|
||||
float v_icon_size = m_overlay_icons_size * m_overlay_scale * inv_tex_height;
|
||||
float v_top = sprite_id * v_icon_size;
|
||||
float u_left = state * u_icon_size;
|
||||
float v_bottom = v_top + v_icon_size;
|
||||
float u_right = u_left + u_icon_size;
|
||||
#else
|
||||
float uv_icon_size = (float)m_icons_texture.metadata.icon_size * inv_texture_size;
|
||||
float v_top = sprite_id * uv_icon_size;
|
||||
float u_left = state * uv_icon_size;
|
||||
float v_bottom = v_top + uv_icon_size;
|
||||
float u_right = u_left + uv_icon_size;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
GLTexture::render_sub_texture(icons_texture_id, top_x, top_x + scaled_icons_size, top_y - scaled_icons_size, top_y, { { u_left, v_bottom }, { u_right, v_bottom }, { u_right, v_top }, { u_left, v_top } });
|
||||
if (it->second->get_state() == GLGizmoBase::On) {
|
||||
float toolbar_top = (float)cnv_h - canvas.get_view_toolbar_height();
|
||||
#if ENABLE_SVG_ICONS
|
||||
it->second->render_input_window(width, 0.5f * cnv_h - top_y * zoom, toolbar_top, selection);
|
||||
#else
|
||||
it->second->render_input_window(2.0f * m_overlay_border + icon_size * zoom, 0.5f * cnv_h - top_y * zoom, toolbar_top, selection);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
float toolbar_top = (float)cnv_h - m_parent.get_view_toolbar_height();
|
||||
it->second->render_input_window(width, 0.5f * cnv_h - top_y * zoom, toolbar_top);
|
||||
}
|
||||
#if ENABLE_SVG_ICONS
|
||||
top_y -= scaled_stride_y;
|
||||
#else
|
||||
top_y -= (scaled_icons_size + scaled_gap_y);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
}
|
||||
}
|
||||
|
||||
float GLGizmosManager::get_total_overlay_height() const
|
||||
{
|
||||
#if ENABLE_SVG_ICONS
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
|
||||
float scaled_border = m_overlay_border * m_overlay_scale;
|
||||
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
|
||||
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
|
||||
float height = 2.0f * scaled_border;
|
||||
#else
|
||||
float height = 2.0f * m_overlay_border;
|
||||
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
height += scaled_stride_y;
|
||||
#else
|
||||
height += (scaled_icons_size + m_overlay_gap_y);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
return height - scaled_gap_y;
|
||||
#else
|
||||
return height - m_overlay_gap_y;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
}
|
||||
|
||||
float GLGizmosManager::get_total_overlay_width() const
|
||||
{
|
||||
#if ENABLE_SVG_ICONS
|
||||
return (2.0f * m_overlay_border + m_overlay_icons_size) * m_overlay_scale;
|
||||
#else
|
||||
return (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale + 2.0f * m_overlay_border;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
}
|
||||
|
||||
GLGizmoBase* GLGizmosManager::get_current() const
|
||||
|
|
@ -1131,7 +1026,6 @@ GLGizmoBase* GLGizmosManager::get_current() const
|
|||
return (it != m_gizmos.end()) ? it->second : nullptr;
|
||||
}
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
bool GLGizmosManager::generate_icons_texture() const
|
||||
{
|
||||
std::string path = resources_dir() + "/icons/";
|
||||
|
|
@ -1157,38 +1051,28 @@ bool GLGizmosManager::generate_icons_texture() const
|
|||
|
||||
return res;
|
||||
}
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
void GLGizmosManager::update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection)
|
||||
void GLGizmosManager::update_on_off_state(const Vec2d& mouse_pos)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
float cnv_h = (float)canvas.get_canvas_size().get_height();
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float height = get_total_overlay_height();
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
|
||||
float scaled_border = m_overlay_border * m_overlay_scale;
|
||||
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
|
||||
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
|
||||
float top_y = 0.5f * (cnv_h - height) + scaled_border;
|
||||
#else
|
||||
float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
|
||||
#else
|
||||
bool inside = (m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
if (it->second->is_activable(selection) && inside)
|
||||
if (it->second->is_activable() && inside)
|
||||
{
|
||||
if ((it->second->get_state() == GLGizmoBase::On))
|
||||
{
|
||||
|
|
@ -1204,11 +1088,7 @@ void GLGizmosManager::update_on_off_state(const GLCanvas3D& canvas, const Vec2d&
|
|||
else
|
||||
it->second->set_state(GLGizmoBase::Off);
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
top_y += scaled_stride_y;
|
||||
#else
|
||||
top_y += (scaled_icons_size + m_overlay_gap_y);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
}
|
||||
|
||||
GizmosMap::iterator it = m_gizmos.find(m_current);
|
||||
|
|
@ -1216,90 +1096,62 @@ void GLGizmosManager::update_on_off_state(const GLCanvas3D& canvas, const Vec2d&
|
|||
it->second->set_state(GLGizmoBase::On);
|
||||
}
|
||||
|
||||
std::string GLGizmosManager::update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos)
|
||||
std::string GLGizmosManager::update_hover_state(const Vec2d& mouse_pos)
|
||||
{
|
||||
std::string name = "";
|
||||
|
||||
if (!m_enabled)
|
||||
return name;
|
||||
|
||||
const Selection& selection = canvas.get_selection();
|
||||
|
||||
float cnv_h = (float)canvas.get_canvas_size().get_height();
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float height = get_total_overlay_height();
|
||||
#if ENABLE_SVG_ICONS
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
|
||||
float scaled_border = m_overlay_border * m_overlay_scale;
|
||||
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
|
||||
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
|
||||
float top_y = 0.5f * (cnv_h - height) + scaled_border;
|
||||
#else
|
||||
float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
for (GizmosMap::iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
bool inside = (scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
|
||||
#else
|
||||
bool inside = (m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
if (inside)
|
||||
name = it->second->get_name();
|
||||
|
||||
if (it->second->is_activable(selection) && (it->second->get_state() != GLGizmoBase::On))
|
||||
if (it->second->is_activable() && (it->second->get_state() != GLGizmoBase::On))
|
||||
it->second->set_state(inside ? GLGizmoBase::Hover : GLGizmoBase::Off);
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
top_y += scaled_stride_y;
|
||||
#else
|
||||
top_y += (scaled_icons_size + m_overlay_gap_y);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
bool GLGizmosManager::overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const
|
||||
bool GLGizmosManager::overlay_contains_mouse(const Vec2d& mouse_pos) const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return false;
|
||||
|
||||
float cnv_h = (float)canvas.get_canvas_size().get_height();
|
||||
float cnv_h = (float)m_parent.get_canvas_size().get_height();
|
||||
float height = get_total_overlay_height();
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
float scaled_icons_size = m_overlay_icons_size * m_overlay_scale;
|
||||
float scaled_border = m_overlay_border * m_overlay_scale;
|
||||
float scaled_gap_y = m_overlay_gap_y * m_overlay_scale;
|
||||
float scaled_stride_y = scaled_icons_size + scaled_gap_y;
|
||||
float top_y = 0.5f * (cnv_h - height) + scaled_border;
|
||||
#else
|
||||
float top_y = 0.5f * (cnv_h - height) + m_overlay_border;
|
||||
float scaled_icons_size = (float)m_icons_texture.metadata.icon_size * m_overlay_icons_scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
for (GizmosMap::const_iterator it = m_gizmos.begin(); it != m_gizmos.end(); ++it)
|
||||
{
|
||||
if ((it->second == nullptr) || !it->second->is_selectable())
|
||||
continue;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
if ((scaled_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= scaled_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
|
||||
#else
|
||||
if ((m_overlay_border <= (float)mouse_pos(0)) && ((float)mouse_pos(0) <= m_overlay_border + scaled_icons_size) && (top_y <= (float)mouse_pos(1)) && ((float)mouse_pos(1) <= top_y + scaled_icons_size))
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
return true;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
top_y += scaled_stride_y;
|
||||
#else
|
||||
top_y += (scaled_icons_size + m_overlay_gap_y);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -4,14 +4,13 @@
|
|||
#include "slic3r/GUI/GLTexture.hpp"
|
||||
#include "slic3r/GUI/GLToolbar.hpp"
|
||||
#include "slic3r/GUI/Gizmos/GLGizmos.hpp"
|
||||
#include "libslic3r/ObjectID.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
class Selection;
|
||||
class GLGizmoBase;
|
||||
class GLCanvas3D;
|
||||
class ClippingPlane;
|
||||
|
||||
|
|
@ -43,12 +42,10 @@ public:
|
|||
float get_height() const { return m_top - m_bottom; }
|
||||
};
|
||||
|
||||
class GLGizmosManager
|
||||
class GLGizmosManager : public Slic3r::ObjectBase
|
||||
{
|
||||
public:
|
||||
#if ENABLE_SVG_ICONS
|
||||
static const float Default_Icons_Size;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
enum EType : unsigned char
|
||||
{
|
||||
|
|
@ -63,24 +60,17 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
GLCanvas3D& m_parent;
|
||||
bool m_enabled;
|
||||
typedef std::map<EType, GLGizmoBase*> GizmosMap;
|
||||
GizmosMap m_gizmos;
|
||||
#if ENABLE_SVG_ICONS
|
||||
mutable GLTexture m_icons_texture;
|
||||
mutable bool m_icons_texture_dirty;
|
||||
#else
|
||||
ItemsIconsTexture m_icons_texture;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
BackgroundTexture m_background_texture;
|
||||
EType m_current;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
float m_overlay_icons_size;
|
||||
float m_overlay_scale;
|
||||
#else
|
||||
float m_overlay_icons_scale;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
float m_overlay_border;
|
||||
float m_overlay_gap_y;
|
||||
|
||||
|
|
@ -99,38 +89,67 @@ private:
|
|||
|
||||
MouseCapture m_mouse_capture;
|
||||
std::string m_tooltip;
|
||||
bool m_serializing;
|
||||
|
||||
public:
|
||||
GLGizmosManager();
|
||||
explicit GLGizmosManager(GLCanvas3D& parent);
|
||||
~GLGizmosManager();
|
||||
|
||||
bool init(GLCanvas3D& parent);
|
||||
bool init();
|
||||
|
||||
template<class Archive>
|
||||
void load(Archive& ar)
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
m_serializing = true;
|
||||
|
||||
ar(m_current);
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
{
|
||||
curr->set_state(GLGizmoBase::On);
|
||||
curr->load(ar);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Archive>
|
||||
void save(Archive& ar) const
|
||||
{
|
||||
if (!m_enabled)
|
||||
return;
|
||||
|
||||
ar(m_current);
|
||||
|
||||
GLGizmoBase* curr = get_current();
|
||||
if (curr != nullptr)
|
||||
curr->save(ar);
|
||||
}
|
||||
|
||||
bool is_enabled() const { return m_enabled; }
|
||||
void set_enabled(bool enable) { m_enabled = enable; }
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
void set_overlay_icon_size(float size);
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
void set_overlay_scale(float scale);
|
||||
|
||||
void refresh_on_off_state(const Selection& selection);
|
||||
void refresh_on_off_state();
|
||||
void reset_all_states();
|
||||
|
||||
void set_hover_id(int id);
|
||||
void enable_grabber(EType type, unsigned int id, bool enable);
|
||||
|
||||
void update(const Linef3& mouse_ray, const Selection& selection, const Point* mouse_pos = nullptr);
|
||||
void update_data(GLCanvas3D& canvas);
|
||||
void update(const Linef3& mouse_ray, const Point& mouse_pos);
|
||||
void update_data();
|
||||
|
||||
Rect get_reset_rect_viewport(const GLCanvas3D& canvas) const;
|
||||
EType get_current_type() const { return m_current; }
|
||||
|
||||
bool is_running() const;
|
||||
bool handle_shortcut(int key, const Selection& selection);
|
||||
bool handle_shortcut(int key);
|
||||
|
||||
bool is_dragging() const;
|
||||
void start_dragging(const Selection& selection);
|
||||
void start_dragging();
|
||||
void stop_dragging();
|
||||
|
||||
Vec3d get_displacement() const;
|
||||
|
|
@ -147,43 +166,49 @@ public:
|
|||
|
||||
void set_flattening_data(const ModelObject* model_object);
|
||||
|
||||
void set_sla_support_data(ModelObject* model_object, const Selection& selection);
|
||||
void set_sla_support_data(ModelObject* model_object);
|
||||
bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false, bool alt_down = false, bool control_down = false);
|
||||
ClippingPlane get_sla_clipping_plane() const;
|
||||
|
||||
void render_current_gizmo(const Selection& selection) const;
|
||||
void render_current_gizmo_for_picking_pass(const Selection& selection) const;
|
||||
void render_current_gizmo() const;
|
||||
void render_current_gizmo_for_picking_pass() const;
|
||||
|
||||
void render_overlay(const GLCanvas3D& canvas, const Selection& selection) const;
|
||||
void render_overlay() const;
|
||||
|
||||
const std::string& get_tooltip() const { return m_tooltip; }
|
||||
|
||||
bool on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas);
|
||||
bool on_mouse_wheel(wxMouseEvent& evt, GLCanvas3D& canvas);
|
||||
bool on_char(wxKeyEvent& evt, GLCanvas3D& canvas);
|
||||
bool on_key(wxKeyEvent& evt, GLCanvas3D& canvas);
|
||||
bool on_mouse(wxMouseEvent& evt);
|
||||
bool on_mouse_wheel(wxMouseEvent& evt);
|
||||
bool on_char(wxKeyEvent& evt);
|
||||
bool on_key(wxKeyEvent& evt);
|
||||
|
||||
void update_after_undo_redo();
|
||||
|
||||
private:
|
||||
void reset();
|
||||
|
||||
void do_render_overlay(const GLCanvas3D& canvas, const Selection& selection) const;
|
||||
void render_background(float left, float top, float right, float bottom, float border) const;
|
||||
void do_render_overlay() const;
|
||||
|
||||
float get_total_overlay_height() const;
|
||||
float get_total_overlay_width() const;
|
||||
|
||||
GLGizmoBase* get_current() const;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
bool generate_icons_texture() const;
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
|
||||
void update_on_off_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos, const Selection& selection);
|
||||
std::string update_hover_state(const GLCanvas3D& canvas, const Vec2d& mouse_pos);
|
||||
bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const;
|
||||
void update_on_off_state(const Vec2d& mouse_pos);
|
||||
std::string update_hover_state(const Vec2d& mouse_pos);
|
||||
bool overlay_contains_mouse(const Vec2d& mouse_pos) const;
|
||||
bool grabber_contains_mouse() const;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
namespace cereal
|
||||
{
|
||||
template <class Archive> struct specialize<Archive, Slic3r::GUI::GLGizmosManager, cereal::specialization::member_load_save> {};
|
||||
}
|
||||
|
||||
#endif // slic3r_GUI_GLGizmosManager_hpp_
|
||||
|
|
|
|||
|
|
@ -233,9 +233,9 @@ ImVec2 ImGuiWrapper::calc_text_size(const wxString &text)
|
|||
return size;
|
||||
}
|
||||
|
||||
void ImGuiWrapper::set_next_window_pos(float x, float y, int flag)
|
||||
void ImGuiWrapper::set_next_window_pos(float x, float y, int flag, float pivot_x, float pivot_y)
|
||||
{
|
||||
ImGui::SetNextWindowPos(ImVec2(x, y), (ImGuiCond)flag);
|
||||
ImGui::SetNextWindowPos(ImVec2(x, y), (ImGuiCond)flag, ImVec2(pivot_x, pivot_y));
|
||||
ImGui::SetNextWindowSize(ImVec2(0.0, 0.0));
|
||||
}
|
||||
|
||||
|
|
@ -342,6 +342,32 @@ bool ImGuiWrapper::combo(const wxString& label, const std::vector<std::string>&
|
|||
return res;
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool , int , const char**), int& hovered, int& selected)
|
||||
{
|
||||
bool is_hovered = false;
|
||||
ImGui::ListBoxHeader("", size);
|
||||
|
||||
int i=0;
|
||||
const char* item_text;
|
||||
while (items_getter(is_undo, i, &item_text))
|
||||
{
|
||||
ImGui::Selectable(item_text, i < hovered);
|
||||
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip(item_text);
|
||||
hovered = i;
|
||||
is_hovered = true;
|
||||
}
|
||||
|
||||
if (ImGui::IsItemClicked())
|
||||
selected = i;
|
||||
i++;
|
||||
}
|
||||
|
||||
ImGui::ListBoxFooter();
|
||||
return is_hovered;
|
||||
}
|
||||
|
||||
void ImGuiWrapper::disabled_begin(bool disabled)
|
||||
{
|
||||
wxCHECK_RET(!m_disabled, "ImGUI: Unbalanced disabled_begin() call");
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ public:
|
|||
ImVec2 scaled(float x, float y) const { return ImVec2(x * m_font_size, y * m_font_size); }
|
||||
ImVec2 calc_text_size(const wxString &text);
|
||||
|
||||
void set_next_window_pos(float x, float y, int flag);
|
||||
void set_next_window_pos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f);
|
||||
void set_next_window_bg_alpha(float alpha);
|
||||
|
||||
bool begin(const std::string &name, int flags = 0);
|
||||
|
|
@ -67,6 +67,7 @@ public:
|
|||
void text(const std::string &label);
|
||||
void text(const wxString &label);
|
||||
bool combo(const wxString& label, const std::vector<std::string>& options, int& selection); // Use -1 to not mark any option as selected
|
||||
bool undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool, int, const char**), int& hovered, int& selected);
|
||||
|
||||
void disabled_begin(bool disabled);
|
||||
void disabled_end();
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ namespace GUI {
|
|||
MainFrame::MainFrame() :
|
||||
DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "mainframe"),
|
||||
m_printhost_queue_dlg(new PrintHostQueueDialog(this))
|
||||
, m_recent_projects(9)
|
||||
{
|
||||
// Fonts were created by the DPIFrame constructor for the monitor, on which the window opened.
|
||||
wxGetApp().update_fonts(this);
|
||||
|
|
@ -383,6 +384,40 @@ void MainFrame::init_menubar()
|
|||
append_menu_item(fileMenu, wxID_ANY, _(L("&Open Project")) + dots + "\tCtrl+O", _(L("Open a project file")),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, menu_icon("open"), nullptr,
|
||||
[this](){return m_plater != nullptr; }, this);
|
||||
|
||||
wxMenu* recent_projects_menu = new wxMenu();
|
||||
wxMenuItem* recent_projects_submenu = append_submenu(fileMenu, recent_projects_menu, wxID_ANY, _(L("Recent projects")), "");
|
||||
m_recent_projects.UseMenu(recent_projects_menu);
|
||||
Bind(wxEVT_MENU, [this](wxCommandEvent& evt) {
|
||||
size_t file_id = evt.GetId() - wxID_FILE1;
|
||||
wxString filename = m_recent_projects.GetHistoryFile(file_id);
|
||||
if (wxFileExists(filename))
|
||||
m_plater->load_project(filename);
|
||||
else
|
||||
{
|
||||
wxMessageDialog msg(this, _(L("The selected project is no more available")), _(L("Error")));
|
||||
msg.ShowModal();
|
||||
|
||||
m_recent_projects.RemoveFileFromHistory(file_id);
|
||||
std::vector<std::string> recent_projects;
|
||||
size_t count = m_recent_projects.GetCount();
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i)));
|
||||
}
|
||||
wxGetApp().app_config->set_recent_projects(recent_projects);
|
||||
wxGetApp().app_config->save();
|
||||
}
|
||||
}, wxID_FILE1, wxID_FILE9);
|
||||
|
||||
std::vector<std::string> recent_projects = wxGetApp().app_config->get_recent_projects();
|
||||
for (const std::string& project : recent_projects)
|
||||
{
|
||||
m_recent_projects.AddFileToHistory(from_u8(project));
|
||||
}
|
||||
|
||||
Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_recent_projects.GetCount() > 0); }, recent_projects_submenu->GetId());
|
||||
|
||||
append_menu_item(fileMenu, wxID_ANY, _(L("&Save Project")) + "\tCtrl+S", _(L("Save current project file")),
|
||||
[this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename(".3mf"))); }, menu_icon("save"), nullptr,
|
||||
[this](){return m_plater != nullptr && can_save(); }, this);
|
||||
|
|
@ -502,6 +537,14 @@ void MainFrame::init_menubar()
|
|||
_(L("Deletes all objects")), [this](wxCommandEvent&) { m_plater->reset_with_confirm(); },
|
||||
menu_icon("delete_all_menu"), nullptr, [this](){return can_delete_all(); }, this);
|
||||
|
||||
editMenu->AppendSeparator();
|
||||
append_menu_item(editMenu, wxID_ANY, _(L("&Undo")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "Z",
|
||||
_(L("Undo")), [this](wxCommandEvent&) { m_plater->undo(); },
|
||||
"undo", nullptr, [this](){return m_plater->can_undo(); }, this);
|
||||
append_menu_item(editMenu, wxID_ANY, _(L("&Redo")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "Y",
|
||||
_(L("Redo")), [this](wxCommandEvent&) { m_plater->redo(); },
|
||||
"redo", nullptr, [this](){return m_plater->can_redo(); }, this);
|
||||
|
||||
editMenu->AppendSeparator();
|
||||
append_menu_item(editMenu, wxID_ANY, _(L("&Copy")) + sep + GUI::shortkey_ctrl_prefix() + sep_space + "C",
|
||||
_(L("Copy selection to clipboard")), [this](wxCommandEvent&) { m_plater->copy_selection_to_clipboard(); },
|
||||
|
|
@ -1046,6 +1089,23 @@ void MainFrame::on_config_changed(DynamicPrintConfig* config) const
|
|||
m_plater->on_config_change(*config); // propagate config change events to the plater
|
||||
}
|
||||
|
||||
void MainFrame::add_to_recent_projects(const wxString& filename)
|
||||
{
|
||||
if (wxFileExists(filename))
|
||||
{
|
||||
m_recent_projects.AddFileToHistory(filename);
|
||||
std::vector<std::string> recent_projects;
|
||||
size_t count = m_recent_projects.GetCount();
|
||||
for (size_t i = 0; i < count; ++i)
|
||||
{
|
||||
recent_projects.push_back(into_u8(m_recent_projects.GetHistoryFile(i)));
|
||||
}
|
||||
wxGetApp().app_config->set_recent_projects(recent_projects);
|
||||
wxGetApp().app_config->save();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Called after the Preferences dialog is closed and the program settings are saved.
|
||||
// Update the UI based on the current preferences.
|
||||
void MainFrame::update_ui_from_settings()
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include <wx/frame.h>
|
||||
#include <wx/settings.h>
|
||||
#include <wx/string.h>
|
||||
#include <wx/filehistory.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
|
@ -84,6 +85,8 @@ class MainFrame : public DPIFrame
|
|||
// vector of a MenuBar items changeable in respect to printer technology
|
||||
std::vector<wxMenuItem*> m_changeable_menu_items;
|
||||
|
||||
wxFileHistory m_recent_projects;
|
||||
|
||||
protected:
|
||||
virtual void on_dpi_changed(const wxRect &suggested_rect);
|
||||
|
||||
|
|
@ -121,6 +124,8 @@ public:
|
|||
// Propagate changed configuration from the Tab to the Platter and save changes to the AppConfig
|
||||
void on_config_changed(DynamicPrintConfig* cfg) const ;
|
||||
|
||||
void add_to_recent_projects(const wxString& filename);
|
||||
|
||||
PrintHostQueueDialog* printhost_queue_dlg() { return m_printhost_queue_dlg; }
|
||||
|
||||
Plater* m_plater { nullptr };
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n
|
|||
is_sizer_field(field) ?
|
||||
v_sizer->Add(field->getSizer(), 0, wxEXPAND) :
|
||||
v_sizer->Add(field->getWindow(), 0, wxEXPAND);
|
||||
return;
|
||||
break;//return;
|
||||
}
|
||||
|
||||
is_sizer_field(field) ?
|
||||
|
|
@ -300,7 +300,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n
|
|||
{
|
||||
// extra widget for non-staticbox option group (like for the frequently used parameters on the sidebar) should be wxALIGN_RIGHT
|
||||
const auto v_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(v_sizer, 1, wxEXPAND);
|
||||
sizer->Add(v_sizer, option_set.size() == 1 ? 0 : 1, wxEXPAND);
|
||||
v_sizer->Add(extra_widget(this->ctrl_parent()), 0, wxALIGN_RIGHT);
|
||||
return;
|
||||
}
|
||||
|
|
@ -320,6 +320,17 @@ Line OptionsGroup::create_single_option_line(const Option& option) const {
|
|||
return retval;
|
||||
}
|
||||
|
||||
void OptionsGroup::clear_fields_except_of(const std::vector<std::string> left_fields)
|
||||
{
|
||||
auto it = m_fields.begin();
|
||||
while (it != m_fields.end()) {
|
||||
if (std::find(left_fields.begin(), left_fields.end(), it->first) == left_fields.end())
|
||||
it = m_fields.erase(it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsGroup::on_set_focus(const std::string& opt_key)
|
||||
{
|
||||
if (m_set_focus != nullptr)
|
||||
|
|
|
|||
|
|
@ -160,6 +160,14 @@ public:
|
|||
m_show_modified_btns = show;
|
||||
}
|
||||
|
||||
void clear_fields_except_of(const std::vector<std::string> left_fields);
|
||||
|
||||
void hide_labels() {
|
||||
label_width = 0;
|
||||
m_grid_sizer->SetCols(m_grid_sizer->GetEffectiveColsCount()-1);
|
||||
static_cast<wxFlexGridSizer*>(m_grid_sizer)->AddGrowableCol(!extra_column ? 0 : 1);
|
||||
}
|
||||
|
||||
OptionsGroup( wxWindow* _parent, const wxString& title, bool is_tab_opt = false,
|
||||
column_t extra_clmn = nullptr) :
|
||||
m_parent(_parent), title(title),
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
#include "GUI_App.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "GUI_ObjectLayers.hpp"
|
||||
#include "GUI_Utils.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
|
|
@ -69,6 +70,7 @@
|
|||
#include "../Utils/ASCIIFolding.hpp"
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
#include "../Utils/FixModelByWin10.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
|
||||
#include <wx/glcanvas.h> // Needs to be last because reasons :-/
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
|
@ -244,6 +246,7 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 *
|
|||
last_selected(wxNOT_FOUND),
|
||||
m_em_unit(wxGetApp().em_unit())
|
||||
{
|
||||
SetFont(wxGetApp().normal_font());
|
||||
Bind(wxEVT_COMBOBOX, [this](wxCommandEvent &evt) {
|
||||
auto selected_item = this->GetSelection();
|
||||
|
||||
|
|
@ -371,24 +374,36 @@ class FreqChangedParams : public OG_Settings
|
|||
wxSizer* m_sizer {nullptr};
|
||||
|
||||
std::shared_ptr<ConfigOptionsGroup> m_og_sla;
|
||||
std::vector<ScalableButton*> m_empty_buttons;
|
||||
public:
|
||||
FreqChangedParams(wxWindow* parent, const int label_width);
|
||||
FreqChangedParams(wxWindow* parent);
|
||||
~FreqChangedParams() {}
|
||||
|
||||
wxButton* get_wiping_dialog_button() { return m_wiping_dialog_button; }
|
||||
wxSizer* get_sizer() override;
|
||||
ConfigOptionsGroup* get_og(const bool is_fff);
|
||||
void Show(const bool is_fff);
|
||||
|
||||
void msw_rescale();
|
||||
};
|
||||
|
||||
FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) :
|
||||
void FreqChangedParams::msw_rescale()
|
||||
{
|
||||
m_og->msw_rescale();
|
||||
m_og_sla->msw_rescale();
|
||||
|
||||
for (auto btn: m_empty_buttons)
|
||||
btn->msw_rescale();
|
||||
}
|
||||
|
||||
FreqChangedParams::FreqChangedParams(wxWindow* parent) :
|
||||
OG_Settings(parent, false)
|
||||
{
|
||||
DynamicPrintConfig* config = &wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
|
||||
// Frequently changed parameters for FFF_technology
|
||||
m_og->set_config(config);
|
||||
m_og->label_width = label_width == 0 ? 1 : label_width;
|
||||
m_og->hide_labels();
|
||||
|
||||
m_og->m_on_change = [config, this](t_config_option_key opt_key, boost::any value) {
|
||||
Tab* tab_print = wxGetApp().get_tab(Preset::TYPE_PRINT);
|
||||
|
|
@ -460,6 +475,20 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) :
|
|||
Option option = Option(support_def, "support");
|
||||
option.opt.full_width = true;
|
||||
line.append_option(option);
|
||||
|
||||
/* Not a best solution, but
|
||||
* Temporary workaround for right border alignment
|
||||
*/
|
||||
auto empty_widget = [this] (wxWindow* parent) {
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_transparent.png", wxEmptyString,
|
||||
wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW);
|
||||
sizer->Add(btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, int(0.3 * wxGetApp().em_unit()));
|
||||
m_empty_buttons.push_back(btn);
|
||||
return sizer;
|
||||
};
|
||||
line.append_widget(empty_widget);
|
||||
|
||||
m_og->append_line(line);
|
||||
|
||||
|
||||
|
|
@ -468,7 +497,7 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) :
|
|||
option = m_og->get_option("fill_density");
|
||||
option.opt.label = L("Infill");
|
||||
option.opt.width = 7/*6*/;
|
||||
option.opt.sidetext = " ";
|
||||
option.opt.sidetext = " ";
|
||||
line.append_option(option);
|
||||
|
||||
m_brim_width = config->opt_float("brim_width");
|
||||
|
|
@ -479,13 +508,14 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) :
|
|||
def.gui_type = "";
|
||||
def.set_default_value(new ConfigOptionBool{ m_brim_width > 0.0 ? true : false });
|
||||
option = Option(def, "brim");
|
||||
option.opt.sidetext = " ";
|
||||
option.opt.sidetext = "";
|
||||
line.append_option(option);
|
||||
|
||||
auto wiping_dialog_btn = [config, this](wxWindow* parent) {
|
||||
m_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
m_wiping_dialog_button->SetFont(wxGetApp().normal_font());
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(m_wiping_dialog_button);
|
||||
sizer->Add(m_wiping_dialog_button, 0, wxALIGN_CENTER_VERTICAL);
|
||||
m_wiping_dialog_button->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent& e)
|
||||
{
|
||||
auto &config = wxGetApp().preset_bundle->project_config;
|
||||
|
|
@ -502,6 +532,13 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) :
|
|||
wxPostEvent(parent, SimpleEvent(EVT_SCHEDULE_BACKGROUND_PROCESS, parent));
|
||||
}
|
||||
}));
|
||||
|
||||
auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_transparent.png", wxEmptyString,
|
||||
wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW);
|
||||
sizer->Add(btn , 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT,
|
||||
int(0.3 * wxGetApp().em_unit()));
|
||||
m_empty_buttons.push_back(btn);
|
||||
|
||||
return sizer;
|
||||
};
|
||||
line.append_widget(wiping_dialog_btn);
|
||||
|
|
@ -511,9 +548,9 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) :
|
|||
|
||||
// Frequently changed parameters for SLA_technology
|
||||
m_og_sla = std::make_shared<ConfigOptionsGroup>(parent, "");
|
||||
m_og_sla->hide_labels();
|
||||
DynamicPrintConfig* config_sla = &wxGetApp().preset_bundle->sla_prints.get_edited_preset().config;
|
||||
m_og_sla->set_config(config_sla);
|
||||
m_og_sla->label_width = label_width == 0 ? 1 : label_width;
|
||||
|
||||
m_og_sla->m_on_change = [config_sla, this](t_config_option_key opt_key, boost::any value) {
|
||||
Tab* tab = wxGetApp().get_tab(Preset::TYPE_SLA_PRINT);
|
||||
|
|
@ -551,7 +588,8 @@ FreqChangedParams::FreqChangedParams(wxWindow* parent, const int label_width) :
|
|||
support_def_sla.enum_labels.erase(support_def_sla.enum_labels.begin() + 2);
|
||||
option = Option(support_def_sla, "support");
|
||||
option.opt.full_width = true;
|
||||
line.append_option(option);
|
||||
line.append_option(option);
|
||||
line.append_widget(empty_widget);
|
||||
m_og_sla->append_line(line);
|
||||
|
||||
line = Line{ "", "" };
|
||||
|
|
@ -618,6 +656,7 @@ struct Sidebar::priv
|
|||
ObjectList *object_list{ nullptr };
|
||||
ObjectManipulation *object_manipulation{ nullptr };
|
||||
ObjectSettings *object_settings{ nullptr };
|
||||
ObjectLayers *object_layers{ nullptr };
|
||||
ObjectInfo *object_info;
|
||||
SlicedInfo *sliced_info;
|
||||
|
||||
|
|
@ -641,6 +680,9 @@ Sidebar::priv::~priv()
|
|||
|
||||
if (frequently_changed_parameters != nullptr)
|
||||
delete frequently_changed_parameters;
|
||||
|
||||
if (object_layers != nullptr)
|
||||
delete object_layers;
|
||||
}
|
||||
|
||||
void Sidebar::priv::show_preset_comboboxes()
|
||||
|
|
@ -728,13 +770,12 @@ Sidebar::Sidebar(Plater *parent)
|
|||
init_combo(&p->combo_printer, _(L("Printer")), Preset::TYPE_PRINTER, false);
|
||||
|
||||
const int margin_5 = int(0.5*wxGetApp().em_unit());// 5;
|
||||
const int margin_10 = 10;//int(1.5*wxGetApp().em_unit());// 15;
|
||||
|
||||
p->sizer_params = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// Frequently changed parameters
|
||||
p->frequently_changed_parameters = new FreqChangedParams(p->scrolled, 0/*label_width*/);
|
||||
p->sizer_params->Add(p->frequently_changed_parameters->get_sizer(), 0, wxEXPAND | wxTOP | wxBOTTOM, margin_10);
|
||||
p->frequently_changed_parameters = new FreqChangedParams(p->scrolled);
|
||||
p->sizer_params->Add(p->frequently_changed_parameters->get_sizer(), 0, wxEXPAND | wxTOP | wxBOTTOM, wxOSX ? 1 : margin_5);
|
||||
|
||||
// Object List
|
||||
p->object_list = new ObjectList(p->scrolled);
|
||||
|
|
@ -749,6 +790,11 @@ Sidebar::Sidebar(Plater *parent)
|
|||
p->object_settings = new ObjectSettings(p->scrolled);
|
||||
p->object_settings->Hide();
|
||||
p->sizer_params->Add(p->object_settings->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
|
||||
|
||||
// Object Layers
|
||||
p->object_layers = new ObjectLayers(p->scrolled);
|
||||
p->object_layers->Hide();
|
||||
p->sizer_params->Add(p->object_layers->get_sizer(), 0, wxEXPAND | wxTOP, margin_5);
|
||||
|
||||
// Info boxes
|
||||
p->object_info = new ObjectInfo(p->scrolled);
|
||||
|
|
@ -936,12 +982,11 @@ void Sidebar::msw_rescale()
|
|||
// ... then refill them and set min size to correct layout of the sidebar
|
||||
update_all_preset_comboboxes();
|
||||
|
||||
p->frequently_changed_parameters->get_og(true)->msw_rescale();
|
||||
p->frequently_changed_parameters->get_og(false)->msw_rescale();
|
||||
|
||||
p->frequently_changed_parameters->msw_rescale();
|
||||
p->object_list->msw_rescale();
|
||||
p->object_manipulation->msw_rescale();
|
||||
p->object_settings->msw_rescale();
|
||||
p->object_layers->msw_rescale();
|
||||
|
||||
p->object_info->msw_rescale();
|
||||
|
||||
|
|
@ -963,6 +1008,11 @@ ObjectSettings* Sidebar::obj_settings()
|
|||
return p->object_settings;
|
||||
}
|
||||
|
||||
ObjectLayers* Sidebar::obj_layers()
|
||||
{
|
||||
return p->object_layers;
|
||||
}
|
||||
|
||||
wxScrolledWindow* Sidebar::scrolled_panel()
|
||||
{
|
||||
return p->scrolled;
|
||||
|
|
@ -1116,10 +1166,20 @@ void Sidebar::show_sliced_info_sizer(const bool show)
|
|||
if (ps.estimated_normal_print_time != "N/A") {
|
||||
new_label += wxString::Format("\n - %s", _(L("normal mode")));
|
||||
info_text += wxString::Format("\n%s", ps.estimated_normal_print_time);
|
||||
for (int i = (int)ps.estimated_normal_color_print_times.size() - 1; i >= 0; --i)
|
||||
{
|
||||
new_label += wxString::Format("\n - %s%d", _(L("Color ")), i + 1);
|
||||
info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]);
|
||||
}
|
||||
}
|
||||
if (ps.estimated_silent_print_time != "N/A") {
|
||||
new_label += wxString::Format("\n - %s", _(L("stealth mode")));
|
||||
info_text += wxString::Format("\n%s", ps.estimated_silent_print_time);
|
||||
for (int i = (int)ps.estimated_normal_color_print_times.size() - 1; i >= 0; --i)
|
||||
{
|
||||
new_label += wxString::Format("\n - %s%d", _(L("Color ")), i + 1);
|
||||
info_text += wxString::Format("\n%s", ps.estimated_normal_color_print_times[i]);
|
||||
}
|
||||
}
|
||||
p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label);
|
||||
}
|
||||
|
|
@ -1196,10 +1256,8 @@ const std::regex PlaterDropTarget::pattern_drop(".*[.](stl|obj|amf|3mf|prusa)",
|
|||
bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames)
|
||||
{
|
||||
std::vector<fs::path> paths;
|
||||
|
||||
for (const auto &filename : filenames) {
|
||||
fs::path path(into_path(filename));
|
||||
|
||||
if (std::regex_match(path.string(), pattern_drop)) {
|
||||
paths.push_back(std::move(path));
|
||||
} else {
|
||||
|
|
@ -1207,6 +1265,23 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi
|
|||
}
|
||||
}
|
||||
|
||||
wxString snapshot_label;
|
||||
assert(! paths.empty());
|
||||
if (paths.size() == 1) {
|
||||
snapshot_label = _(L("Load File"));
|
||||
snapshot_label += ": ";
|
||||
snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str());
|
||||
} else {
|
||||
snapshot_label = _(L("Load Files"));
|
||||
snapshot_label += ": ";
|
||||
snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str());
|
||||
for (size_t i = 1; i < paths.size(); ++ i) {
|
||||
snapshot_label += ", ";
|
||||
snapshot_label += wxString::FromUTF8(paths[i].filename().string().c_str());
|
||||
}
|
||||
}
|
||||
Plater::TakeSnapshot snapshot(plater, snapshot_label);
|
||||
|
||||
// FIXME: when drag and drop is done on a .3mf or a .amf file we should clear the plater for consistence with the open project command
|
||||
// (the following call to plater->load_files() will load the config data, if present)
|
||||
|
||||
|
|
@ -1260,7 +1335,12 @@ struct Plater::priv
|
|||
Slic3r::Model model;
|
||||
PrinterTechnology printer_technology = ptFFF;
|
||||
Slic3r::GCodePreviewData gcode_preview_data;
|
||||
|
||||
Slic3r::UndoRedo::Stack undo_redo_stack;
|
||||
int m_prevent_snapshots = 0; /* Used for avoid of excess "snapshoting".
|
||||
* Like for "delete selected" or "set numbers of copies"
|
||||
* we should call tack_snapshot just ones
|
||||
* instead of calls for each action separately
|
||||
* */
|
||||
// GUI elements
|
||||
wxSizer* panel_sizer{ nullptr };
|
||||
wxPanel* current_panel{ nullptr };
|
||||
|
|
@ -1528,7 +1608,7 @@ struct Plater::priv
|
|||
priv(Plater *q, MainFrame *main_frame);
|
||||
~priv();
|
||||
|
||||
void update(bool force_full_scene_refresh = false);
|
||||
void update(bool force_full_scene_refresh = false, bool force_background_processing_update = false);
|
||||
void select_view(const std::string& direction);
|
||||
void select_view_3D(const std::string& name);
|
||||
void select_next_view_3D();
|
||||
|
|
@ -1560,6 +1640,17 @@ struct Plater::priv
|
|||
void split_object();
|
||||
void split_volume();
|
||||
void scale_selection_to_fit_print_volume();
|
||||
|
||||
void take_snapshot(const std::string& snapshot_name);
|
||||
void take_snapshot(const wxString& snapshot_name) { this->take_snapshot(std::string(snapshot_name.ToUTF8().data())); }
|
||||
int get_active_snapshot_index();
|
||||
void undo();
|
||||
void redo();
|
||||
void undo_redo_to(size_t time_to_load);
|
||||
|
||||
void suppress_snapshots() { this->m_prevent_snapshots++; }
|
||||
void allow_snapshots() { this->m_prevent_snapshots--; }
|
||||
|
||||
bool background_processing_enabled() const { return this->get_config("background_processing") == "1"; }
|
||||
void update_print_volume_state();
|
||||
void schedule_background_process();
|
||||
|
|
@ -1650,9 +1741,13 @@ private:
|
|||
|
||||
void update_fff_scene();
|
||||
void update_sla_scene();
|
||||
void undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator it_snapshot);
|
||||
void update_after_undo_redo(bool temp_snapshot_was_taken = false);
|
||||
|
||||
// path to project file stored with no extension
|
||||
wxString m_project_filename;
|
||||
std::string m_last_fff_printer_profile_name;
|
||||
std::string m_last_sla_printer_profile_name;
|
||||
};
|
||||
|
||||
const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase);
|
||||
|
|
@ -1677,11 +1772,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
}))
|
||||
, sidebar(new Sidebar(q))
|
||||
, delayed_scene_refresh(false)
|
||||
#if ENABLE_SVG_ICONS
|
||||
, view_toolbar(GLToolbar::Radio, "View")
|
||||
#else
|
||||
, view_toolbar(GLToolbar::Radio)
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
, m_project_filename(wxEmptyString)
|
||||
{
|
||||
this->q->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||
|
|
@ -1756,6 +1847,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
view3D_canvas->Bind(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, &priv::on_3dcanvas_mouse_dragging_finished, this);
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_TAB, [this](SimpleEvent&) { select_next_view_3D(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_RESETGIZMOS, [this](SimpleEvent&) { reset_all_gizmos(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_UNDO, [this](SimpleEvent&) { this->undo(); });
|
||||
view3D_canvas->Bind(EVT_GLCANVAS_REDO, [this](SimpleEvent&) { this->redo(); });
|
||||
|
||||
// 3DScene/Toolbar:
|
||||
view3D_canvas->Bind(EVT_GLTOOLBAR_ADD, &priv::on_action_add, this);
|
||||
|
|
@ -1794,6 +1887,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
|
||||
// updates camera type from .ini file
|
||||
camera.set_type(get_config("use_perspective_camera"));
|
||||
|
||||
// Initialize the Undo / Redo stack with a first snapshot.
|
||||
this->take_snapshot(_(L("New Project")));
|
||||
}
|
||||
|
||||
Plater::priv::~priv()
|
||||
|
|
@ -1802,7 +1898,7 @@ Plater::priv::~priv()
|
|||
delete config;
|
||||
}
|
||||
|
||||
void Plater::priv::update(bool force_full_scene_refresh)
|
||||
void Plater::priv::update(bool force_full_scene_refresh, bool force_background_processing_update)
|
||||
{
|
||||
// the following line, when enabled, causes flickering on NVIDIA graphics cards
|
||||
// wxWindowUpdateLocker freeze_guard(q);
|
||||
|
|
@ -1815,7 +1911,7 @@ void Plater::priv::update(bool force_full_scene_refresh)
|
|||
}
|
||||
|
||||
unsigned int update_status = 0;
|
||||
if (this->printer_technology == ptSLA)
|
||||
if (this->printer_technology == ptSLA || force_background_processing_update)
|
||||
// Update the SLAPrint from the current Model, so that the reload_scene()
|
||||
// pulls the correct data.
|
||||
update_status = this->update_background_process(false);
|
||||
|
|
@ -2001,66 +2097,22 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
}
|
||||
}
|
||||
}
|
||||
else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf))
|
||||
{
|
||||
bool advanced = false;
|
||||
for (const ModelObject* model_object : model.objects)
|
||||
else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf) && model_has_advanced_features(model)) {
|
||||
wxMessageDialog dlg(q, _(L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?\n")),
|
||||
_(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO);
|
||||
if (dlg.ShowModal() == wxID_YES)
|
||||
{
|
||||
// is there more than one instance ?
|
||||
if (model_object->instances.size() > 1)
|
||||
{
|
||||
advanced = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// is there any advanced config data ?
|
||||
auto opt_keys = model_object->config.keys();
|
||||
if (!opt_keys.empty() && !((opt_keys.size() == 1) && (opt_keys[0] == "extruder")))
|
||||
{
|
||||
advanced = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// is there any modifier ?
|
||||
for (const ModelVolume* model_volume : model_object->volumes)
|
||||
{
|
||||
if (!model_volume->is_model_part())
|
||||
{
|
||||
advanced = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// is there any advanced config data ?
|
||||
opt_keys = model_volume->config.keys();
|
||||
if (!opt_keys.empty() && !((opt_keys.size() == 1) && (opt_keys[0] == "extruder")))
|
||||
{
|
||||
advanced = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (advanced)
|
||||
break;
|
||||
}
|
||||
|
||||
if (advanced)
|
||||
{
|
||||
wxMessageDialog dlg(q, _(L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?\n")),
|
||||
_(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO);
|
||||
if (dlg.ShowModal() == wxID_YES)
|
||||
{
|
||||
Slic3r::GUI::wxGetApp().save_mode(comAdvanced);
|
||||
view3D->set_as_dirty();
|
||||
}
|
||||
else
|
||||
return obj_idxs;
|
||||
Slic3r::GUI::wxGetApp().save_mode(comAdvanced);
|
||||
view3D->set_as_dirty();
|
||||
}
|
||||
else
|
||||
return obj_idxs;
|
||||
}
|
||||
|
||||
for (ModelObject* model_object : model.objects) {
|
||||
model_object->center_around_origin(false);
|
||||
model_object->ensure_on_bed();
|
||||
}
|
||||
for (ModelObject* model_object : model.objects) {
|
||||
model_object->center_around_origin(false);
|
||||
model_object->ensure_on_bed();
|
||||
}
|
||||
|
||||
// check multi-part object adding for the SLA-printing
|
||||
if (printer_technology == ptSLA)
|
||||
|
|
@ -2164,7 +2216,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
|||
// the size of the object is too big -> this could lead to overflow when moving to clipper coordinates,
|
||||
// so scale down the mesh
|
||||
double inv = 1. / max_ratio;
|
||||
object->scale_mesh(Vec3d(inv, inv, inv));
|
||||
object->scale_mesh_after_creation(Vec3d(inv, inv, inv));
|
||||
object->origin_translation = Vec3d::Zero();
|
||||
object->center_around_origin();
|
||||
scaled_down = true;
|
||||
|
|
@ -2177,9 +2229,6 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
|||
}
|
||||
|
||||
object->ensure_on_bed();
|
||||
|
||||
// print.auto_assign_extruders(object);
|
||||
// print.add_model_object(object);
|
||||
}
|
||||
|
||||
#ifdef AUTOPLACEMENT_ON_LOAD
|
||||
|
|
@ -2346,12 +2395,15 @@ void Plater::priv::object_list_changed()
|
|||
|
||||
void Plater::priv::select_all()
|
||||
{
|
||||
// this->take_snapshot(_(L("Select All")));
|
||||
|
||||
view3D->select_all();
|
||||
this->sidebar->obj_list()->update_selections();
|
||||
}
|
||||
|
||||
void Plater::priv::deselect_all()
|
||||
{
|
||||
// this->take_snapshot(_(L("Deselect All")));
|
||||
view3D->deselect_all();
|
||||
}
|
||||
|
||||
|
|
@ -2373,6 +2425,10 @@ void Plater::priv::remove(size_t obj_idx)
|
|||
|
||||
void Plater::priv::delete_object_from_model(size_t obj_idx)
|
||||
{
|
||||
wxString snapshot_label = _(L("Delete Object"));
|
||||
if (! model.objects[obj_idx]->name.empty())
|
||||
snapshot_label += ": " + wxString::FromUTF8(model.objects[obj_idx]->name.c_str());
|
||||
Plater::TakeSnapshot snapshot(q, snapshot_label);
|
||||
model.delete_object(obj_idx);
|
||||
update();
|
||||
object_list_changed();
|
||||
|
|
@ -2380,6 +2436,8 @@ void Plater::priv::delete_object_from_model(size_t obj_idx)
|
|||
|
||||
void Plater::priv::reset()
|
||||
{
|
||||
Plater::TakeSnapshot snapshot(q, _(L("Reset Project")));
|
||||
|
||||
set_project_filename(wxEmptyString);
|
||||
|
||||
// Prevent toolpaths preview from rendering while we modify the Print object
|
||||
|
|
@ -2405,17 +2463,20 @@ void Plater::priv::reset()
|
|||
|
||||
void Plater::priv::mirror(Axis axis)
|
||||
{
|
||||
this->take_snapshot(_(L("Mirror")));
|
||||
view3D->mirror_selection(axis);
|
||||
}
|
||||
|
||||
void Plater::priv::arrange()
|
||||
{
|
||||
this->take_snapshot(_(L("Arrange")));
|
||||
m_ui_jobs.start(Jobs::Arrange);
|
||||
}
|
||||
|
||||
// This method will find an optimal orientation for the currently selected item
|
||||
// Very similar in nature to the arrange method above...
|
||||
void Plater::priv::sla_optimize_rotation() {
|
||||
this->take_snapshot(_(L("Optimize Rotation")));
|
||||
m_ui_jobs.start(Jobs::Rotoptimize);
|
||||
}
|
||||
|
||||
|
|
@ -2571,6 +2632,8 @@ void Plater::priv::split_object()
|
|||
Slic3r::GUI::warning_catcher(q, _(L("The selected object couldn't be split because it contains only one part.")));
|
||||
else
|
||||
{
|
||||
Plater::TakeSnapshot snapshot(q, _(L("Split to Objects")));
|
||||
|
||||
unsigned int counter = 1;
|
||||
for (ModelObject* m : new_objects)
|
||||
m->name = current_model_object->name + "_" + std::to_string(counter++);
|
||||
|
|
@ -2809,6 +2872,8 @@ void Plater::priv::update_sla_scene()
|
|||
|
||||
void Plater::priv::reload_from_disk()
|
||||
{
|
||||
Plater::TakeSnapshot snapshot(q, _(L("Reload from Disk")));
|
||||
|
||||
const auto &selection = get_selection();
|
||||
const auto obj_orig_idx = selection.get_object_idx();
|
||||
if (selection.is_wipe_tower() || obj_orig_idx == -1) { return; }
|
||||
|
|
@ -2842,6 +2907,9 @@ void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* =
|
|||
{
|
||||
if (obj_idx < 0)
|
||||
return;
|
||||
|
||||
Plater::TakeSnapshot snapshot(q, _(L("Fix Throught NetFabb")));
|
||||
|
||||
fix_model_by_win10_sdk_gui(*model.objects[obj_idx], vol_idx);
|
||||
this->update();
|
||||
this->object_list_changed();
|
||||
|
|
@ -2949,8 +3017,14 @@ void Plater::priv::on_select_preset(wxCommandEvent &evt)
|
|||
|
||||
// update plater with new config
|
||||
wxGetApp().plater()->on_config_change(wxGetApp().preset_bundle->full_config());
|
||||
/* Settings list can be changed after printer preset changing, so
|
||||
* update all settings items for all item had it.
|
||||
* Furthermore, Layers editing is implemented only for FFF printers
|
||||
* and for SLA presets they should be deleted
|
||||
*/
|
||||
if (preset_type == Preset::TYPE_PRINTER)
|
||||
wxGetApp().obj_list()->update_settings_items();
|
||||
// wxGetApp().obj_list()->update_settings_items();
|
||||
wxGetApp().obj_list()->update_object_list_by_printer_technology();
|
||||
}
|
||||
|
||||
void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
|
||||
|
|
@ -3081,6 +3155,8 @@ void Plater::priv::on_action_layersediting(SimpleEvent&)
|
|||
|
||||
void Plater::priv::on_object_select(SimpleEvent& evt)
|
||||
{
|
||||
// this->take_snapshot(_(L("Object Selection")));
|
||||
|
||||
wxGetApp().obj_list()->update_selections();
|
||||
selection_changed();
|
||||
}
|
||||
|
|
@ -3219,6 +3295,9 @@ void Plater::priv::set_project_filename(const wxString& filename)
|
|||
|
||||
m_project_filename = from_path(full_path);
|
||||
wxGetApp().mainframe->update_title();
|
||||
|
||||
if (!filename.empty())
|
||||
wxGetApp().mainframe->add_to_recent_projects(filename);
|
||||
}
|
||||
|
||||
bool Plater::priv::init_common_menu(wxMenu* menu, const bool is_part/* = false*/)
|
||||
|
|
@ -3295,6 +3374,10 @@ bool Plater::priv::complit_init_object_menu()
|
|||
[this]() { return can_split() && wxGetApp().get_mode() > comSimple; }, q);
|
||||
object_menu.AppendSeparator();
|
||||
|
||||
// Layers Editing for object
|
||||
sidebar->obj_list()->append_menu_item_layers_editing(&object_menu);
|
||||
object_menu.AppendSeparator();
|
||||
|
||||
// "Add (volumes)" popupmenu will be added later in append_menu_items_add_volume()
|
||||
|
||||
return true;
|
||||
|
|
@ -3329,12 +3412,6 @@ bool Plater::priv::complit_init_part_menu()
|
|||
|
||||
void Plater::priv::init_view_toolbar()
|
||||
{
|
||||
#if !ENABLE_SVG_ICONS
|
||||
ItemsIconsTexture::Metadata icons_data;
|
||||
icons_data.filename = "view_toolbar.png";
|
||||
icons_data.icon_size = 64;
|
||||
#endif // !ENABLE_SVG_ICONS
|
||||
|
||||
BackgroundTexture::Metadata background_data;
|
||||
background_data.filename = "toolbar_background.png";
|
||||
background_data.left = 16;
|
||||
|
|
@ -3342,38 +3419,29 @@ void Plater::priv::init_view_toolbar()
|
|||
background_data.right = 16;
|
||||
background_data.bottom = 16;
|
||||
|
||||
#if ENABLE_SVG_ICONS
|
||||
if (!view_toolbar.init(background_data))
|
||||
#else
|
||||
if (!view_toolbar.init(icons_data, background_data))
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
return;
|
||||
|
||||
view_toolbar.set_layout_orientation(GLToolbar::Layout::Bottom);
|
||||
view_toolbar.set_horizontal_orientation(GLToolbar::Layout::HO_Left);
|
||||
view_toolbar.set_vertical_orientation(GLToolbar::Layout::VO_Bottom);
|
||||
view_toolbar.set_border(5.0f);
|
||||
view_toolbar.set_gap_size(1.0f);
|
||||
|
||||
GLToolbarItem::Data item;
|
||||
|
||||
item.name = "3D";
|
||||
#if ENABLE_SVG_ICONS
|
||||
item.icon_filename = "editor.svg";
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
item.tooltip = _utf8(L("3D editor view")) + " [" + GUI::shortkey_ctrl_prefix() + "5]";
|
||||
item.sprite_id = 0;
|
||||
item.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); };
|
||||
item.is_toggable = false;
|
||||
item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_3D)); };
|
||||
if (!view_toolbar.add_item(item))
|
||||
return;
|
||||
|
||||
item.name = "Preview";
|
||||
#if ENABLE_SVG_ICONS
|
||||
item.icon_filename = "preview.svg";
|
||||
#endif // ENABLE_SVG_ICONS
|
||||
item.tooltip = _utf8(L("Preview")) + " [" + GUI::shortkey_ctrl_prefix() + "6]";
|
||||
item.sprite_id = 1;
|
||||
item.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); };
|
||||
item.is_toggable = false;
|
||||
item.left.action_callback = [this]() { if (this->q != nullptr) wxPostEvent(this->q, SimpleEvent(EVT_GLVIEWTOOLBAR_PREVIEW)); };
|
||||
if (!view_toolbar.add_item(item))
|
||||
return;
|
||||
|
||||
|
|
@ -3503,6 +3571,156 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
|||
}
|
||||
}
|
||||
|
||||
int Plater::priv::get_active_snapshot_index()
|
||||
{
|
||||
const size_t active_snapshot_time = this->undo_redo_stack.active_snapshot_time();
|
||||
const std::vector<UndoRedo::Snapshot>& ss_stack = this->undo_redo_stack.snapshots();
|
||||
const auto it = std::lower_bound(ss_stack.begin(), ss_stack.end(), UndoRedo::Snapshot(active_snapshot_time));
|
||||
return it - ss_stack.begin();
|
||||
}
|
||||
|
||||
void Plater::priv::take_snapshot(const std::string& snapshot_name)
|
||||
{
|
||||
if (this->m_prevent_snapshots > 0)
|
||||
return;
|
||||
assert(this->m_prevent_snapshots >= 0);
|
||||
unsigned int flags = 0;
|
||||
if (this->view3D->is_layers_editing_enabled())
|
||||
flags |= UndoRedo::Snapshot::VARIABLE_LAYER_EDITING_ACTIVE;
|
||||
//FIXME updating the Wipe tower config values at the ModelWipeTower from the Print config.
|
||||
// This is a workaround until we refactor the Wipe Tower position / orientation to live solely inside the Model, not in the Print config.
|
||||
if (this->printer_technology == ptFFF) {
|
||||
const DynamicPrintConfig &config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
model.wipe_tower.position = Vec2d(config.opt_float("wipe_tower_x"), config.opt_float("wipe_tower_y"));
|
||||
model.wipe_tower.rotation = config.opt_float("wipe_tower_rotation_angle");
|
||||
}
|
||||
this->undo_redo_stack.take_snapshot(snapshot_name, model, view3D->get_canvas3d()->get_selection(), view3D->get_canvas3d()->get_gizmos_manager(), this->printer_technology, flags);
|
||||
this->undo_redo_stack.release_least_recently_used();
|
||||
// Save the last active preset name of a particular printer technology.
|
||||
((this->printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name) = wxGetApp().preset_bundle->printers.get_selected_preset_name();
|
||||
BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot taken: " << snapshot_name << ", Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack.memsize()) << log_memory_info();
|
||||
}
|
||||
|
||||
void Plater::priv::undo()
|
||||
{
|
||||
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack.snapshots();
|
||||
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack.active_snapshot_time()));
|
||||
if (-- it_current != snapshots.begin())
|
||||
this->undo_redo_to(it_current);
|
||||
}
|
||||
|
||||
void Plater::priv::redo()
|
||||
{
|
||||
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack.snapshots();
|
||||
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack.active_snapshot_time()));
|
||||
if (++ it_current != snapshots.end())
|
||||
this->undo_redo_to(it_current);
|
||||
}
|
||||
|
||||
void Plater::priv::undo_redo_to(size_t time_to_load)
|
||||
{
|
||||
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack.snapshots();
|
||||
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(time_to_load));
|
||||
assert(it_current != snapshots.end());
|
||||
this->undo_redo_to(it_current);
|
||||
}
|
||||
|
||||
void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator it_snapshot)
|
||||
{
|
||||
bool temp_snapshot_was_taken = this->undo_redo_stack.temp_snapshot_active();
|
||||
PrinterTechnology new_printer_technology = it_snapshot->printer_technology;
|
||||
bool printer_technology_changed = this->printer_technology != new_printer_technology;
|
||||
if (printer_technology_changed) {
|
||||
// Switching the printer technology when jumping forwards / backwards in time. Switch to the last active printer profile of the other type.
|
||||
std::string s_pt = (it_snapshot->printer_technology == ptFFF) ? "FFF" : "SLA";
|
||||
if (! wxGetApp().check_unsaved_changes(from_u8((boost::format(_utf8(
|
||||
L("%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."))) % s_pt).str())))
|
||||
// Don't switch the profiles.
|
||||
return;
|
||||
}
|
||||
// Save the last active preset name of a particular printer technology.
|
||||
((this->printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name) = wxGetApp().preset_bundle->printers.get_selected_preset_name();
|
||||
//FIXME updating the Wipe tower config values at the ModelWipeTower from the Print config.
|
||||
// This is a workaround until we refactor the Wipe Tower position / orientation to live solely inside the Model, not in the Print config.
|
||||
if (this->printer_technology == ptFFF) {
|
||||
const DynamicPrintConfig &config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
model.wipe_tower.position = Vec2d(config.opt_float("wipe_tower_x"), config.opt_float("wipe_tower_y"));
|
||||
model.wipe_tower.rotation = config.opt_float("wipe_tower_rotation_angle");
|
||||
}
|
||||
// Flags made of Snapshot::Flags enum values.
|
||||
unsigned int new_flags = it_snapshot->flags;
|
||||
unsigned int top_snapshot_flags = 0;
|
||||
if (this->view3D->is_layers_editing_enabled())
|
||||
top_snapshot_flags |= UndoRedo::Snapshot::VARIABLE_LAYER_EDITING_ACTIVE;
|
||||
bool new_variable_layer_editing_active = (new_flags & UndoRedo::Snapshot::VARIABLE_LAYER_EDITING_ACTIVE) != 0;
|
||||
// Disable layer editing before the Undo / Redo jump.
|
||||
if (!new_variable_layer_editing_active && view3D->is_layers_editing_enabled())
|
||||
view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting"));
|
||||
// Do the jump in time.
|
||||
if (it_snapshot->timestamp < this->undo_redo_stack.active_snapshot_time() ?
|
||||
this->undo_redo_stack.undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager(), this->printer_technology, top_snapshot_flags, it_snapshot->timestamp) :
|
||||
this->undo_redo_stack.redo(model, this->view3D->get_canvas3d()->get_gizmos_manager(), it_snapshot->timestamp)) {
|
||||
if (printer_technology_changed) {
|
||||
// Switch to the other printer technology. Switch to the last printer active for that particular technology.
|
||||
AppConfig *app_config = wxGetApp().app_config;
|
||||
app_config->set("presets", "printer", (new_printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name);
|
||||
wxGetApp().preset_bundle->load_presets(*app_config);
|
||||
// Load the currently selected preset into the GUI, update the preset selection box.
|
||||
// This also switches the printer technology based on the printer technology of the active printer profile.
|
||||
wxGetApp().load_current_presets();
|
||||
}
|
||||
//FIXME updating the Print config from the Wipe tower config values at the ModelWipeTower.
|
||||
// This is a workaround until we refactor the Wipe Tower position / orientation to live solely inside the Model, not in the Print config.
|
||||
if (this->printer_technology == ptFFF) {
|
||||
const DynamicPrintConfig ¤t_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||
Vec2d current_position(current_config.opt_float("wipe_tower_x"), current_config.opt_float("wipe_tower_y"));
|
||||
double current_rotation = current_config.opt_float("wipe_tower_rotation_angle");
|
||||
if (current_position != model.wipe_tower.position || current_rotation != model.wipe_tower.rotation) {
|
||||
DynamicPrintConfig new_config;
|
||||
new_config.set_key_value("wipe_tower_x", new ConfigOptionFloat(model.wipe_tower.position.x()));
|
||||
new_config.set_key_value("wipe_tower_y", new ConfigOptionFloat(model.wipe_tower.position.y()));
|
||||
new_config.set_key_value("wipe_tower_rotation_angle", new ConfigOptionFloat(model.wipe_tower.rotation));
|
||||
Tab *tab_print = wxGetApp().get_tab(Preset::TYPE_PRINT);
|
||||
tab_print->load_config(new_config);
|
||||
tab_print->update_dirty();
|
||||
}
|
||||
}
|
||||
this->update_after_undo_redo(temp_snapshot_was_taken);
|
||||
// Enable layer editing after the Undo / Redo jump.
|
||||
if (! view3D->is_layers_editing_enabled() && this->layers_height_allowed() && new_variable_layer_editing_active)
|
||||
view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting"));
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::priv::update_after_undo_redo(bool /* temp_snapshot_was_taken */)
|
||||
{
|
||||
this->view3D->get_canvas3d()->get_selection().clear();
|
||||
// Update volumes from the deserializd model, always stop / update the background processing (for both the SLA and FFF technologies).
|
||||
this->update(false, true);
|
||||
// Release old snapshots if the memory allocated is excessive. This may remove the top most snapshot if jumping to the very first snapshot.
|
||||
//if (temp_snapshot_was_taken)
|
||||
// Release the old snapshots always, as it may have happened, that some of the triangle meshes got deserialized from the snapshot, while some
|
||||
// triangle meshes may have gotten released from the scene or the background processing, therefore now being calculated into the Undo / Redo stack size.
|
||||
this->undo_redo_stack.release_least_recently_used();
|
||||
//YS_FIXME update obj_list from the deserialized model (maybe store ObjectIDs into the tree?) (no selections at this point of time)
|
||||
this->view3D->get_canvas3d()->get_selection().set_deserialized(GUI::Selection::EMode(this->undo_redo_stack.selection_deserialized().mode), this->undo_redo_stack.selection_deserialized().volumes_and_instances);
|
||||
this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo();
|
||||
|
||||
wxGetApp().obj_list()->update_after_undo_redo();
|
||||
|
||||
if (wxGetApp().get_mode() == comSimple && model_has_advanced_features(this->model)) {
|
||||
// If the user jumped to a snapshot that require user interface with advanced features, switch to the advanced mode without asking.
|
||||
// There is a little risk of surprising the user, as he already must have had the advanced or expert mode active for such a snapshot to be taken.
|
||||
Slic3r::GUI::wxGetApp().save_mode(comAdvanced);
|
||||
view3D->set_as_dirty();
|
||||
}
|
||||
|
||||
//FIXME what about the state of the manipulators?
|
||||
//FIXME what about the focus? Cursor in the side panel?
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot reloaded. Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack.memsize()) << log_memory_info();
|
||||
}
|
||||
|
||||
void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& label) const
|
||||
{
|
||||
switch (btn_type)
|
||||
|
|
@ -3540,17 +3758,25 @@ void Plater::new_project()
|
|||
|
||||
void Plater::load_project()
|
||||
{
|
||||
// Ask user for a project file name.
|
||||
wxString input_file;
|
||||
wxGetApp().load_project(this, input_file);
|
||||
// Take the Undo / Redo snapshot.
|
||||
Plater::TakeSnapshot snapshot(this, _(L("Load Project")) + ": " + wxString::FromUTF8(into_path(input_file).stem().string().c_str()));
|
||||
// And finally load the new project.
|
||||
load_project(input_file);
|
||||
}
|
||||
|
||||
if (input_file.empty())
|
||||
void Plater::load_project(const wxString& filename)
|
||||
{
|
||||
if (filename.empty())
|
||||
return;
|
||||
|
||||
p->reset();
|
||||
p->set_project_filename(input_file);
|
||||
p->set_project_filename(filename);
|
||||
|
||||
std::vector<fs::path> input_paths;
|
||||
input_paths.push_back(into_path(input_file));
|
||||
input_paths.push_back(into_path(filename));
|
||||
load_files(input_paths);
|
||||
}
|
||||
|
||||
|
|
@ -3561,11 +3787,28 @@ void Plater::add_model()
|
|||
if (input_files.empty())
|
||||
return;
|
||||
|
||||
std::vector<fs::path> input_paths;
|
||||
for (const auto &file : input_files) {
|
||||
input_paths.push_back(into_path(file));
|
||||
}
|
||||
load_files(input_paths, true, false);
|
||||
std::vector<fs::path> paths;
|
||||
for (const auto &file : input_files)
|
||||
paths.push_back(into_path(file));
|
||||
|
||||
wxString snapshot_label;
|
||||
assert(! paths.empty());
|
||||
if (paths.size() == 1) {
|
||||
snapshot_label = _(L("Import Object"));
|
||||
snapshot_label += ": ";
|
||||
snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str());
|
||||
} else {
|
||||
snapshot_label = _(L("Import Objects"));
|
||||
snapshot_label += ": ";
|
||||
snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str());
|
||||
for (size_t i = 1; i < paths.size(); ++ i) {
|
||||
snapshot_label += ", ";
|
||||
snapshot_label += wxString::FromUTF8(paths[i].filename().string().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Plater::TakeSnapshot snapshot(this, snapshot_label);
|
||||
load_files(paths, true, false);
|
||||
}
|
||||
|
||||
void Plater::extract_config_from_project()
|
||||
|
|
@ -3618,6 +3861,7 @@ void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_mo
|
|||
|
||||
void Plater::remove_selected()
|
||||
{
|
||||
Plater::TakeSnapshot snapshot(this, _(L("Delete Selected Objects")));
|
||||
this->p->view3D->delete_selected();
|
||||
}
|
||||
|
||||
|
|
@ -3625,6 +3869,8 @@ void Plater::increase_instances(size_t num)
|
|||
{
|
||||
if (! can_increase_instances()) { return; }
|
||||
|
||||
Plater::TakeSnapshot snapshot(this, _(L("Increase Instances")));
|
||||
|
||||
int obj_idx = p->get_selected_object_idx();
|
||||
|
||||
ModelObject* model_object = p->model.objects[obj_idx];
|
||||
|
|
@ -3659,6 +3905,8 @@ void Plater::decrease_instances(size_t num)
|
|||
{
|
||||
if (! can_decrease_instances()) { return; }
|
||||
|
||||
Plater::TakeSnapshot snapshot(this, _(L("Decrease Instances")));
|
||||
|
||||
int obj_idx = p->get_selected_object_idx();
|
||||
|
||||
ModelObject* model_object = p->model.objects[obj_idx];
|
||||
|
|
@ -3693,6 +3941,8 @@ void Plater::set_number_of_copies(/*size_t num*/)
|
|||
if (num < 0)
|
||||
return;
|
||||
|
||||
Plater::TakeSnapshot snapshot(this, wxString::Format(_(L("Set numbers of copies to %d")), num));
|
||||
|
||||
int diff = (int)num - (int)model_object->instances.size();
|
||||
if (diff > 0)
|
||||
increase_instances(diff);
|
||||
|
|
@ -3721,6 +3971,8 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe
|
|||
return;
|
||||
}
|
||||
|
||||
Plater::TakeSnapshot snapshot(this, _(L("Cut by Plane")));
|
||||
|
||||
wxBusyCursor wait;
|
||||
const auto new_objects = object->cut(instance_idx, z, keep_upper, keep_lower, rotate_lower);
|
||||
|
||||
|
|
@ -4010,6 +4262,58 @@ void Plater::send_gcode()
|
|||
}
|
||||
}
|
||||
|
||||
void Plater::take_snapshot(const std::string &snapshot_name) { p->take_snapshot(snapshot_name); }
|
||||
void Plater::take_snapshot(const wxString &snapshot_name) { p->take_snapshot(snapshot_name); }
|
||||
void Plater::suppress_snapshots() { p->suppress_snapshots(); }
|
||||
void Plater::allow_snapshots() { p->allow_snapshots(); }
|
||||
void Plater::undo() { p->undo(); }
|
||||
void Plater::redo() { p->redo(); }
|
||||
void Plater::undo_to(int selection)
|
||||
{
|
||||
if (selection == 0) {
|
||||
p->undo();
|
||||
return;
|
||||
}
|
||||
|
||||
const int idx = p->get_active_snapshot_index() - selection - 1;
|
||||
p->undo_redo_to(p->undo_redo_stack.snapshots()[idx].timestamp);
|
||||
}
|
||||
void Plater::redo_to(int selection)
|
||||
{
|
||||
if (selection == 0) {
|
||||
p->redo();
|
||||
return;
|
||||
}
|
||||
|
||||
const int idx = p->get_active_snapshot_index() + selection + 1;
|
||||
p->undo_redo_to(p->undo_redo_stack.snapshots()[idx].timestamp);
|
||||
}
|
||||
bool Plater::undo_redo_string_getter(const bool is_undo, int idx, const char** out_text)
|
||||
{
|
||||
const std::vector<UndoRedo::Snapshot>& ss_stack = p->undo_redo_stack.snapshots();
|
||||
const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -(++idx) : idx);
|
||||
|
||||
if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) {
|
||||
*out_text = ss_stack[idx_in_ss_stack].name.c_str();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Plater::undo_redo_topmost_string_getter(const bool is_undo, std::string& out_text)
|
||||
{
|
||||
const std::vector<UndoRedo::Snapshot>& ss_stack = p->undo_redo_stack.snapshots();
|
||||
const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -1 : 0);
|
||||
|
||||
if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) {
|
||||
out_text = ss_stack[idx_in_ss_stack].name;
|
||||
return;
|
||||
}
|
||||
|
||||
out_text = L("");
|
||||
}
|
||||
|
||||
void Plater::on_extruders_change(int num_extruders)
|
||||
{
|
||||
auto& choices = sidebar().combos_filament();
|
||||
|
|
@ -4235,8 +4539,11 @@ void Plater::copy_selection_to_clipboard()
|
|||
|
||||
void Plater::paste_from_clipboard()
|
||||
{
|
||||
if (can_paste_from_clipboard())
|
||||
p->view3D->get_canvas3d()->get_selection().paste_from_clipboard();
|
||||
if (!can_paste_from_clipboard())
|
||||
return;
|
||||
|
||||
this->take_snapshot(_(L("Paste From Clipboard")));
|
||||
p->view3D->get_canvas3d()->get_selection().paste_from_clipboard();
|
||||
}
|
||||
|
||||
void Plater::msw_rescale()
|
||||
|
|
@ -4253,6 +4560,11 @@ void Plater::msw_rescale()
|
|||
GetParent()->Layout();
|
||||
}
|
||||
|
||||
const Camera& Plater::get_camera() const
|
||||
{
|
||||
return p->camera;
|
||||
}
|
||||
|
||||
bool Plater::can_delete() const { return p->can_delete(); }
|
||||
bool Plater::can_delete_all() const { return p->can_delete_all(); }
|
||||
bool Plater::can_increase_instances() const { return p->can_increase_instances(); }
|
||||
|
|
@ -4296,6 +4608,10 @@ bool Plater::can_copy_to_clipboard() const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Plater::can_undo() const { return p->undo_redo_stack.has_undo_snapshot(); }
|
||||
bool Plater::can_redo() const { return p->undo_redo_stack.has_redo_snapshot(); }
|
||||
const UndoRedo::Stack& Plater::undo_redo_stack() const { return p->undo_redo_stack; }
|
||||
|
||||
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
|
||||
m_was_running(wxGetApp().plater()->is_background_process_running())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,12 +27,18 @@ class ModelObject;
|
|||
class Print;
|
||||
class SLAPrint;
|
||||
|
||||
namespace UndoRedo {
|
||||
class Stack;
|
||||
struct Snapshot;
|
||||
};
|
||||
|
||||
namespace GUI {
|
||||
|
||||
class MainFrame;
|
||||
class ConfigOptionsGroup;
|
||||
class ObjectManipulation;
|
||||
class ObjectSettings;
|
||||
class ObjectLayers;
|
||||
class ObjectList;
|
||||
class GLCanvas3D;
|
||||
|
||||
|
|
@ -93,6 +99,7 @@ public:
|
|||
ObjectManipulation* obj_manipul();
|
||||
ObjectList* obj_list();
|
||||
ObjectSettings* obj_settings();
|
||||
ObjectLayers* obj_layers();
|
||||
wxScrolledWindow* scrolled_panel();
|
||||
wxPanel* presets_panel();
|
||||
|
||||
|
|
@ -136,6 +143,7 @@ public:
|
|||
|
||||
void new_project();
|
||||
void load_project();
|
||||
void load_project(const wxString& filename);
|
||||
void add_model();
|
||||
void extract_config_from_project();
|
||||
|
||||
|
|
@ -181,6 +189,16 @@ public:
|
|||
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
|
||||
void send_gcode();
|
||||
|
||||
void take_snapshot(const std::string &snapshot_name);
|
||||
void take_snapshot(const wxString &snapshot_name);
|
||||
void undo();
|
||||
void redo();
|
||||
void undo_to(int selection);
|
||||
void redo_to(int selection);
|
||||
bool undo_redo_string_getter(const bool is_undo, int idx, const char** out_text);
|
||||
void undo_redo_topmost_string_getter(const bool is_undo, std::string& out_text);
|
||||
const Slic3r::UndoRedo::Stack& undo_redo_stack() const;
|
||||
|
||||
void on_extruders_change(int extruders_count);
|
||||
void on_config_change(const DynamicPrintConfig &config);
|
||||
// On activating the parent window.
|
||||
|
|
@ -215,13 +233,53 @@ public:
|
|||
bool can_layers_editing() const;
|
||||
bool can_paste_from_clipboard() const;
|
||||
bool can_copy_to_clipboard() const;
|
||||
bool can_undo() const;
|
||||
bool can_redo() const;
|
||||
|
||||
void msw_rescale();
|
||||
|
||||
const Camera& get_camera() const;
|
||||
|
||||
// ROII wrapper for suppressing the Undo / Redo snapshot to be taken.
|
||||
class SuppressSnapshots
|
||||
{
|
||||
public:
|
||||
SuppressSnapshots(Plater *plater) : m_plater(plater)
|
||||
{
|
||||
m_plater->suppress_snapshots();
|
||||
}
|
||||
~SuppressSnapshots()
|
||||
{
|
||||
m_plater->allow_snapshots();
|
||||
}
|
||||
private:
|
||||
Plater *m_plater;
|
||||
};
|
||||
|
||||
// ROII wrapper for taking an Undo / Redo snapshot while disabling the snapshot taking by the methods called from inside this snapshot.
|
||||
class TakeSnapshot
|
||||
{
|
||||
public:
|
||||
TakeSnapshot(Plater *plater, const wxString &snapshot_name) : m_plater(plater)
|
||||
{
|
||||
m_plater->take_snapshot(snapshot_name);
|
||||
m_plater->suppress_snapshots();
|
||||
}
|
||||
~TakeSnapshot()
|
||||
{
|
||||
m_plater->allow_snapshots();
|
||||
}
|
||||
private:
|
||||
Plater *m_plater;
|
||||
};
|
||||
|
||||
private:
|
||||
struct priv;
|
||||
std::unique_ptr<priv> p;
|
||||
|
||||
void suppress_snapshots();
|
||||
void allow_snapshots();
|
||||
|
||||
friend class SuppressBackgroundProcessingUpdate;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -461,6 +461,7 @@ const std::vector<std::string>& Preset::sla_print_options()
|
|||
"support_pillar_widening_factor",
|
||||
"support_base_diameter",
|
||||
"support_base_height",
|
||||
"support_base_safety_distance",
|
||||
"support_critical_angle",
|
||||
"support_max_bridge_length",
|
||||
"support_max_pillar_link_distance",
|
||||
|
|
@ -474,6 +475,10 @@ const std::vector<std::string>& Preset::sla_print_options()
|
|||
"pad_max_merge_distance",
|
||||
"pad_edge_radius",
|
||||
"pad_wall_slope",
|
||||
"pad_object_gap",
|
||||
"pad_object_connector_stride",
|
||||
"pad_object_connector_width",
|
||||
"pad_object_connector_penetration",
|
||||
"output_filename_format",
|
||||
"default_sla_print_profile",
|
||||
"compatible_printers",
|
||||
|
|
@ -824,11 +829,25 @@ const Preset* PresetCollection::get_selected_preset_parent() const
|
|||
if (this->get_selected_idx() == -1)
|
||||
// This preset collection has no preset activated yet. Only the get_edited_preset() is valid.
|
||||
return nullptr;
|
||||
const std::string &inherits = this->get_edited_preset().inherits();
|
||||
// const std::string &inherits = this->get_edited_preset().inherits();
|
||||
// if (inherits.empty())
|
||||
// return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
|
||||
|
||||
std::string inherits = this->get_edited_preset().inherits();
|
||||
if (inherits.empty())
|
||||
return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
|
||||
{
|
||||
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 ?
|
||||
"- default FFF -" : "- default SLA -" ;
|
||||
}
|
||||
|
||||
const Preset* preset = this->find_preset(inherits, false);
|
||||
return (preset == nullptr || preset->is_default || preset->is_external) ? nullptr : preset;
|
||||
return (preset == nullptr/* || preset->is_default*/ || preset->is_external) ? nullptr : preset;
|
||||
}
|
||||
|
||||
const Preset* PresetCollection::get_preset_parent(const Preset& child) const
|
||||
|
|
|
|||
|
|
@ -1366,7 +1366,7 @@ void PresetBundle::export_configbundle(const std::string &path, bool export_syst
|
|||
continue;
|
||||
c << std::endl << "[" << presets->section_name() << ":" << preset.name << "]" << std::endl;
|
||||
for (const std::string &opt_key : preset.config.keys())
|
||||
c << opt_key << " = " << preset.config.serialize(opt_key) << std::endl;
|
||||
c << opt_key << " = " << preset.config.opt_serialize(opt_key) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "Gizmos/GLGizmoBase.hpp"
|
||||
#include "slic3r/GUI/3DScene.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#include "Camera.hpp"
|
||||
|
||||
#include <GL/glew.h>
|
||||
|
||||
|
|
@ -99,14 +100,14 @@ void Selection::set_volumes(GLVolumePtrs* volumes)
|
|||
update_valid();
|
||||
}
|
||||
|
||||
bool Selection::init(bool useVBOs)
|
||||
bool Selection::init()
|
||||
{
|
||||
if (!m_arrow.init(useVBOs))
|
||||
if (!m_arrow.init())
|
||||
return false;
|
||||
|
||||
m_arrow.set_scale(5.0 * Vec3d::Ones());
|
||||
|
||||
if (!m_curved_arrow.init(useVBOs))
|
||||
if (!m_curved_arrow.init())
|
||||
return false;
|
||||
|
||||
m_curved_arrow.set_scale(5.0 * Vec3d::Ones());
|
||||
|
|
@ -311,6 +312,22 @@ void Selection::add_all()
|
|||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
void Selection::set_deserialized(EMode mode, const std::vector<std::pair<size_t, size_t>> &volumes_and_instances)
|
||||
{
|
||||
if (! m_valid)
|
||||
return;
|
||||
|
||||
m_mode = mode;
|
||||
for (unsigned int i : m_list)
|
||||
(*m_volumes)[i]->selected = false;
|
||||
m_list.clear();
|
||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++ i)
|
||||
if (std::binary_search(volumes_and_instances.begin(), volumes_and_instances.end(), (*m_volumes)[i]->geometry_id))
|
||||
this->do_add_volume(i);
|
||||
update_type();
|
||||
this->set_bounding_boxes_dirty();
|
||||
}
|
||||
|
||||
void Selection::clear()
|
||||
{
|
||||
if (!m_valid)
|
||||
|
|
@ -331,6 +348,9 @@ void Selection::clear()
|
|||
|
||||
// resets the cache in the sidebar
|
||||
wxGetApp().obj_manipul()->reset_cache();
|
||||
|
||||
// #et_FIXME fake KillFocus from sidebar
|
||||
wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event("", false);
|
||||
}
|
||||
|
||||
// Update the selection based on the new instance IDs.
|
||||
|
|
@ -786,6 +806,8 @@ void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
|
|||
double s = std::min(sx, std::min(sy, sz));
|
||||
if (s != 1.0)
|
||||
{
|
||||
wxGetApp().plater()->take_snapshot(_(L("Scale To Fit")));
|
||||
|
||||
TransformationType type;
|
||||
type.set_world();
|
||||
type.set_relative();
|
||||
|
|
@ -794,12 +816,12 @@ void Selection::scale_to_fit_print_volume(const DynamicPrintConfig& config)
|
|||
// apply scale
|
||||
start_dragging();
|
||||
scale(s * Vec3d::Ones(), type);
|
||||
wxGetApp().plater()->canvas3D()->do_scale();
|
||||
wxGetApp().plater()->canvas3D()->do_scale(L("")); // avoid storing another snapshot
|
||||
|
||||
// center selection on print bed
|
||||
start_dragging();
|
||||
translate(print_volume.center() - get_bounding_box().center());
|
||||
wxGetApp().plater()->canvas3D()->do_move();
|
||||
wxGetApp().plater()->canvas3D()->do_move(L("")); // avoid storing another snapshot
|
||||
|
||||
wxGetApp().obj_manipul()->set_dirty();
|
||||
}
|
||||
|
|
@ -1070,61 +1092,68 @@ void Selection::render_center(bool gizmo_is_dragging) const
|
|||
}
|
||||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
|
||||
void Selection::render_sidebar_hints(const std::string& sidebar_field) const
|
||||
void Selection::render_sidebar_hints(const std::string& sidebar_field, const Shader& shader) const
|
||||
{
|
||||
if (sidebar_field.empty())
|
||||
return;
|
||||
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
if (!boost::starts_with(sidebar_field, "layer"))
|
||||
{
|
||||
shader.start_using();
|
||||
glsafe(::glClear(GL_DEPTH_BUFFER_BIT));
|
||||
glsafe(::glEnable(GL_LIGHTING));
|
||||
}
|
||||
|
||||
glsafe(::glEnable(GL_LIGHTING));
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
|
||||
glsafe(::glPushMatrix());
|
||||
|
||||
const Vec3d& center = get_bounding_box().center();
|
||||
|
||||
if (is_single_full_instance() && ! wxGetApp().obj_manipul()->get_world_coordinates())
|
||||
if (!boost::starts_with(sidebar_field, "layer"))
|
||||
{
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
if (!boost::starts_with(sidebar_field, "position"))
|
||||
const Vec3d& center = get_bounding_box().center();
|
||||
|
||||
if (is_single_full_instance() && !wxGetApp().obj_manipul()->get_world_coordinates())
|
||||
{
|
||||
Transform3d orient_matrix = Transform3d::Identity();
|
||||
if (boost::starts_with(sidebar_field, "scale"))
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else if (boost::starts_with(sidebar_field, "rotation"))
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
if (!boost::starts_with(sidebar_field, "position"))
|
||||
{
|
||||
if (boost::ends_with(sidebar_field, "x"))
|
||||
Transform3d orient_matrix = Transform3d::Identity();
|
||||
if (boost::starts_with(sidebar_field, "scale"))
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else if (boost::ends_with(sidebar_field, "y"))
|
||||
else if (boost::starts_with(sidebar_field, "rotation"))
|
||||
{
|
||||
const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation();
|
||||
if (rotation(0) == 0.0)
|
||||
if (boost::ends_with(sidebar_field, "x"))
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else
|
||||
orient_matrix.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ()));
|
||||
else if (boost::ends_with(sidebar_field, "y"))
|
||||
{
|
||||
const Vec3d& rotation = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_rotation();
|
||||
if (rotation(0) == 0.0)
|
||||
orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
else
|
||||
orient_matrix.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ()));
|
||||
}
|
||||
}
|
||||
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
}
|
||||
else if (is_single_volume() || is_single_modifier())
|
||||
{
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
if (!boost::starts_with(sidebar_field, "position"))
|
||||
orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_matrix(true, false, true, true);
|
||||
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
}
|
||||
else if (is_single_volume() || is_single_modifier())
|
||||
{
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
if (!boost::starts_with(sidebar_field, "position"))
|
||||
orient_matrix = orient_matrix * (*m_volumes)[*m_list.begin()]->get_volume_transformation().get_matrix(true, false, true, true);
|
||||
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
else
|
||||
{
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
if (requires_local_axes())
|
||||
else
|
||||
{
|
||||
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
glsafe(::glTranslated(center(0), center(1), center(2)));
|
||||
if (requires_local_axes())
|
||||
{
|
||||
Transform3d orient_matrix = (*m_volumes)[*m_list.begin()]->get_instance_transformation().get_matrix(true, false, true, true);
|
||||
glsafe(::glMultMatrixd(orient_matrix.data()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1136,10 +1165,16 @@ void Selection::render_sidebar_hints(const std::string& sidebar_field) const
|
|||
render_sidebar_scale_hints(sidebar_field);
|
||||
else if (boost::starts_with(sidebar_field, "size"))
|
||||
render_sidebar_size_hints(sidebar_field);
|
||||
else if (boost::starts_with(sidebar_field, "layer"))
|
||||
render_sidebar_layers_hints(sidebar_field);
|
||||
|
||||
glsafe(::glPopMatrix());
|
||||
|
||||
glsafe(::glDisable(GL_LIGHTING));
|
||||
if (!boost::starts_with(sidebar_field, "layer"))
|
||||
{
|
||||
glsafe(::glDisable(GL_LIGHTING));
|
||||
shader.stop_using();
|
||||
}
|
||||
}
|
||||
|
||||
bool Selection::requires_local_axes() const
|
||||
|
|
@ -1160,10 +1195,10 @@ void Selection::copy_to_clipboard()
|
|||
ModelObject* dst_object = m_clipboard.add_object();
|
||||
dst_object->name = src_object->name;
|
||||
dst_object->input_file = src_object->input_file;
|
||||
dst_object->config = src_object->config;
|
||||
static_cast<DynamicPrintConfig&>(dst_object->config) = static_cast<const DynamicPrintConfig&>(src_object->config);
|
||||
dst_object->sla_support_points = src_object->sla_support_points;
|
||||
dst_object->sla_points_status = src_object->sla_points_status;
|
||||
dst_object->layer_height_ranges = src_object->layer_height_ranges;
|
||||
dst_object->layer_config_ranges = src_object->layer_config_ranges; // #ys_FIXME_experiment
|
||||
dst_object->layer_height_profile = src_object->layer_height_profile;
|
||||
dst_object->origin_translation = src_object->origin_translation;
|
||||
|
||||
|
|
@ -1709,6 +1744,78 @@ void Selection::render_sidebar_size_hints(const std::string& sidebar_field) cons
|
|||
render_sidebar_scale_hints(sidebar_field);
|
||||
}
|
||||
|
||||
void Selection::render_sidebar_layers_hints(const std::string& sidebar_field) const
|
||||
{
|
||||
static const double Margin = 10.0;
|
||||
|
||||
std::string field = sidebar_field;
|
||||
|
||||
// extract max_z
|
||||
std::string::size_type pos = field.rfind("_");
|
||||
if (pos == std::string::npos)
|
||||
return;
|
||||
|
||||
double max_z = std::stod(field.substr(pos + 1));
|
||||
|
||||
// extract min_z
|
||||
field = field.substr(0, pos);
|
||||
pos = field.rfind("_");
|
||||
if (pos == std::string::npos)
|
||||
return;
|
||||
|
||||
double min_z = std::stod(field.substr(pos + 1));
|
||||
|
||||
// extract type
|
||||
field = field.substr(0, pos);
|
||||
pos = field.rfind("_");
|
||||
if (pos == std::string::npos)
|
||||
return;
|
||||
|
||||
int type = std::stoi(field.substr(pos + 1));
|
||||
|
||||
const BoundingBoxf3& box = get_bounding_box();
|
||||
|
||||
const float min_x = box.min(0) - Margin;
|
||||
const float max_x = box.max(0) + Margin;
|
||||
const float min_y = box.min(1) - Margin;
|
||||
const float max_y = box.max(1) + Margin;
|
||||
|
||||
// view dependend order of rendering to keep correct transparency
|
||||
bool camera_on_top = wxGetApp().plater()->get_camera().get_theta() <= 90.0f;
|
||||
float z1 = camera_on_top ? min_z : max_z;
|
||||
float z2 = camera_on_top ? max_z : min_z;
|
||||
|
||||
glsafe(::glEnable(GL_DEPTH_TEST));
|
||||
glsafe(::glDisable(GL_CULL_FACE));
|
||||
glsafe(::glEnable(GL_BLEND));
|
||||
glsafe(::glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
|
||||
::glBegin(GL_QUADS);
|
||||
if ((camera_on_top && (type == 1)) || (!camera_on_top && (type == 2)))
|
||||
::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
|
||||
else
|
||||
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
|
||||
::glVertex3f(min_x, min_y, z1);
|
||||
::glVertex3f(max_x, min_y, z1);
|
||||
::glVertex3f(max_x, max_y, z1);
|
||||
::glVertex3f(min_x, max_y, z1);
|
||||
glsafe(::glEnd());
|
||||
|
||||
::glBegin(GL_QUADS);
|
||||
if ((camera_on_top && (type == 2)) || (!camera_on_top && (type == 1)))
|
||||
::glColor4f(1.0f, 0.38f, 0.0f, 1.0f);
|
||||
else
|
||||
::glColor4f(0.8f, 0.8f, 0.8f, 0.5f);
|
||||
::glVertex3f(min_x, min_y, z2);
|
||||
::glVertex3f(max_x, min_y, z2);
|
||||
::glVertex3f(max_x, max_y, z2);
|
||||
::glVertex3f(min_x, max_y, z2);
|
||||
glsafe(::glEnd());
|
||||
|
||||
glsafe(::glEnable(GL_CULL_FACE));
|
||||
glsafe(::glDisable(GL_BLEND));
|
||||
}
|
||||
|
||||
void Selection::render_sidebar_position_hint(Axis axis) const
|
||||
{
|
||||
m_arrow.set_color(AXES_COLOR[axis], 3);
|
||||
|
|
@ -1927,6 +2034,10 @@ bool Selection::is_from_fully_selected_instance(unsigned int volume_idx) const
|
|||
|
||||
void Selection::paste_volumes_from_clipboard()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
|
||||
int dst_obj_idx = get_object_idx();
|
||||
if ((dst_obj_idx < 0) || ((int)m_model->objects.size() <= dst_obj_idx))
|
||||
return;
|
||||
|
|
@ -1968,6 +2079,9 @@ void Selection::paste_volumes_from_clipboard()
|
|||
}
|
||||
|
||||
volumes.push_back(dst_volume);
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
// keeps relative position of multivolume selections
|
||||
|
|
@ -1981,10 +2095,18 @@ void Selection::paste_volumes_from_clipboard()
|
|||
|
||||
wxGetApp().obj_list()->paste_volumes_into_list(dst_obj_idx, volumes);
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
void Selection::paste_objects_from_clipboard()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
|
||||
std::vector<size_t> object_idxs;
|
||||
const ModelObjectPtrs& src_objects = m_clipboard.get_objects();
|
||||
for (const ModelObject* src_object : src_objects)
|
||||
|
|
@ -1998,9 +2120,16 @@ void Selection::paste_objects_from_clipboard()
|
|||
}
|
||||
|
||||
object_idxs.push_back(m_model->objects.size() - 1);
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
wxGetApp().obj_list()->paste_objects_into_list(object_idxs);
|
||||
|
||||
#ifdef _DEBUG
|
||||
check_model_ids_validity(*m_model);
|
||||
#endif /* _DEBUG */
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ typedef class GLUquadric GLUquadricObj;
|
|||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
|
||||
namespace Slic3r {
|
||||
class Shader;
|
||||
namespace GUI {
|
||||
|
||||
class TransformationType
|
||||
{
|
||||
public:
|
||||
|
|
@ -171,7 +171,7 @@ private:
|
|||
Vec3d dragging_center;
|
||||
// Map from indices of ModelObject instances in Model::objects
|
||||
// to a set of indices of ModelVolume instances in ModelObject::instances
|
||||
// Here the index means a position inside the respective std::vector, not ModelID.
|
||||
// Here the index means a position inside the respective std::vector, not ObjectID.
|
||||
ObjectIdxsToInstanceIdxsMap content;
|
||||
};
|
||||
|
||||
|
|
@ -212,7 +212,7 @@ public:
|
|||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
|
||||
void set_volumes(GLVolumePtrs* volumes);
|
||||
bool init(bool useVBOs);
|
||||
bool init();
|
||||
|
||||
bool is_enabled() const { return m_enabled; }
|
||||
void set_enabled(bool enable) { m_enabled = enable; }
|
||||
|
|
@ -237,6 +237,9 @@ public:
|
|||
|
||||
void add_all();
|
||||
|
||||
// To be called after Undo or Redo once the volumes are updated.
|
||||
void set_deserialized(EMode mode, const std::vector<std::pair<size_t, size_t>> &volumes_and_instances);
|
||||
|
||||
// Update the selection based on the new instance IDs.
|
||||
void instances_changed(const std::vector<size_t> &instance_ids_selected);
|
||||
// Update the selection based on the map from old indices to new indices after m_volumes changed.
|
||||
|
|
@ -302,7 +305,7 @@ public:
|
|||
#if ENABLE_RENDER_SELECTION_CENTER
|
||||
void render_center(bool gizmo_is_dragging) const;
|
||||
#endif // ENABLE_RENDER_SELECTION_CENTER
|
||||
void render_sidebar_hints(const std::string& sidebar_field) const;
|
||||
void render_sidebar_hints(const std::string& sidebar_field, const Shader& shader) const;
|
||||
|
||||
bool requires_local_axes() const;
|
||||
|
||||
|
|
@ -332,6 +335,7 @@ private:
|
|||
void render_sidebar_rotation_hints(const std::string& sidebar_field) const;
|
||||
void render_sidebar_scale_hints(const std::string& sidebar_field) const;
|
||||
void render_sidebar_size_hints(const std::string& sidebar_field) const;
|
||||
void render_sidebar_layers_hints(const std::string& sidebar_field) const;
|
||||
void render_sidebar_position_hint(Axis axis) const;
|
||||
void render_sidebar_rotation_hint(Axis axis) const;
|
||||
void render_sidebar_scale_hint(Axis axis) const;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include "I18N.hpp"
|
||||
#include "3DScene.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -10,6 +11,14 @@
|
|||
#include "GUI_App.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
#ifdef _WIN32
|
||||
// The standard Windows includes.
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#include <psapi.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
|
@ -36,10 +45,37 @@ std::string get_main_info(bool format_as_html)
|
|||
"System Version: "
|
||||
#endif
|
||||
<< b_end << wxPlatformInfo::Get().GetOperatingSystemDescription() << line_end;
|
||||
out << b_start << "Total RAM size [MB]: " << b_end << Slic3r::format_memsize_MB(Slic3r::total_physical_memory());
|
||||
|
||||
return out.str();
|
||||
}
|
||||
|
||||
std::string get_mem_info(bool format_as_html)
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
std::string b_start = format_as_html ? "<b>" : "";
|
||||
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();
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
return out.str();
|
||||
}
|
||||
|
||||
SysInfoDialog::SysInfoDialog()
|
||||
: DPIDialog(NULL, wxID_ANY, wxString(SLIC3R_APP_NAME) + " - " + _(L("System Information")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
|
||||
{
|
||||
|
|
@ -111,7 +147,7 @@ SysInfoDialog::SysInfoDialog()
|
|||
"</font>"
|
||||
"</body>"
|
||||
"</html>", bgr_clr_str, text_clr_str, text_clr_str,
|
||||
_3DScene::get_gl_info(true, true));
|
||||
get_mem_info(true) + "<br>" + _3DScene::get_gl_info(true, true));
|
||||
m_opengl_info_html->SetPage(text);
|
||||
main_sizer->Add(m_opengl_info_html, 1, wxEXPAND | wxBOTTOM, 15);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ void Tab::update_changed_ui()
|
|||
const ScalableBitmap *sys_icon = &m_bmp_value_lock;
|
||||
const ScalableBitmap *icon = &m_bmp_value_revert;
|
||||
|
||||
const wxColour *color = &m_sys_label_clr;
|
||||
const wxColour *color = m_is_default_preset ? &m_default_text_clr : &m_sys_label_clr;
|
||||
|
||||
const wxString *sys_tt = &m_tt_value_lock;
|
||||
const wxString *tt = &m_tt_value_revert;
|
||||
|
|
@ -590,7 +590,7 @@ void Tab::update_changed_tree_ui()
|
|||
}
|
||||
}
|
||||
|
||||
const wxColor *clr = sys_page ? &m_sys_label_clr :
|
||||
const wxColor *clr = sys_page ? (m_is_default_preset ? &m_default_text_clr : &m_sys_label_clr) :
|
||||
modified_page ? &m_modified_label_clr :
|
||||
&m_default_text_clr;
|
||||
|
||||
|
|
@ -874,11 +874,10 @@ void Tab::update_wiping_button_visibility() {
|
|||
return; // ys_FIXME
|
||||
bool wipe_tower_enabled = dynamic_cast<ConfigOptionBool*>( (m_preset_bundle->prints.get_edited_preset().config ).option("wipe_tower"))->value;
|
||||
bool multiple_extruders = dynamic_cast<ConfigOptionFloats*>((m_preset_bundle->printers.get_edited_preset().config).option("nozzle_diameter"))->values.size() > 1;
|
||||
bool single_extruder_mm = dynamic_cast<ConfigOptionBool*>( (m_preset_bundle->printers.get_edited_preset().config).option("single_extruder_multi_material"))->value;
|
||||
|
||||
auto wiping_dialog_button = wxGetApp().sidebar().get_wiping_dialog_button();
|
||||
if (wiping_dialog_button) {
|
||||
wiping_dialog_button->Show(wipe_tower_enabled && multiple_extruders && single_extruder_mm);
|
||||
wiping_dialog_button->Show(wipe_tower_enabled && multiple_extruders);
|
||||
wiping_dialog_button->GetParent()->Layout();
|
||||
}
|
||||
}
|
||||
|
|
@ -1642,6 +1641,9 @@ void TabFilament::build()
|
|||
};
|
||||
optgroup->append_line(line);
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Wipe tower parameters")));
|
||||
optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower");
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Toolchange parameters with single extruder MM printers")));
|
||||
optgroup->append_single_option_line("filament_loading_speed_start");
|
||||
optgroup->append_single_option_line("filament_loading_speed");
|
||||
|
|
@ -1653,7 +1655,6 @@ void TabFilament::build()
|
|||
optgroup->append_single_option_line("filament_cooling_moves");
|
||||
optgroup->append_single_option_line("filament_cooling_initial_speed");
|
||||
optgroup->append_single_option_line("filament_cooling_final_speed");
|
||||
optgroup->append_single_option_line("filament_minimal_purge_on_wipe_tower");
|
||||
|
||||
line = optgroup->create_single_option_line("filament_ramming_parameters");// { _(L("Ramming")), "" };
|
||||
line.widget = [this](wxWindow* parent) {
|
||||
|
|
@ -2673,11 +2674,14 @@ void Tab::load_current_preset()
|
|||
// Reload preset pages with the new configuration values.
|
||||
reload_config();
|
||||
|
||||
m_bmp_non_system = m_presets->get_selected_preset_parent() ? &m_bmp_value_unlock : &m_bmp_white_bullet;
|
||||
m_ttg_non_system = m_presets->get_selected_preset_parent() ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns;
|
||||
m_tt_non_system = m_presets->get_selected_preset_parent() ? &m_tt_value_unlock : &m_ttg_white_bullet_ns;
|
||||
const Preset* selected_preset_parent = m_presets->get_selected_preset_parent();
|
||||
m_is_default_preset = selected_preset_parent != nullptr && selected_preset_parent->is_default;
|
||||
|
||||
m_undo_to_sys_btn->Enable(!preset.is_default);
|
||||
m_bmp_non_system = selected_preset_parent ? &m_bmp_value_unlock : &m_bmp_white_bullet;
|
||||
m_ttg_non_system = selected_preset_parent ? &m_ttg_value_unlock : &m_ttg_white_bullet_ns;
|
||||
m_tt_non_system = selected_preset_parent ? &m_tt_value_unlock : &m_ttg_white_bullet_ns;
|
||||
|
||||
// m_undo_to_sys_btn->Enable(!preset.is_default);
|
||||
|
||||
#if 0
|
||||
// use CallAfter because some field triggers schedule on_change calls using CallAfter,
|
||||
|
|
@ -2989,7 +2993,7 @@ bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr
|
|||
// Because of we can't to print the multi-part objects with SLA technology.
|
||||
bool Tab::may_switch_to_SLA_preset()
|
||||
{
|
||||
if (wxGetApp().obj_list()->has_multi_part_objects())
|
||||
if (model_has_multi_part_objects(wxGetApp().model()))
|
||||
{
|
||||
show_info( parent(),
|
||||
_(L("It's impossible to print multi-part object(s) with SLA technology.")) + "\n\n" +
|
||||
|
|
@ -3263,18 +3267,18 @@ void Tab::fill_icon_descriptions()
|
|||
{
|
||||
m_icon_descriptions.emplace_back(&m_bmp_value_lock, L("LOCKED LOCK"),
|
||||
// TRN Description for "LOCKED LOCK"
|
||||
L("indicates that the settings are the same as the system values for the current option group"));
|
||||
L("indicates that the settings are the same as the system (or default) values for the current option group"));
|
||||
|
||||
m_icon_descriptions.emplace_back(&m_bmp_value_unlock, L("UNLOCKED LOCK"),
|
||||
// TRN Description for "UNLOCKED LOCK"
|
||||
L("indicates that some settings were changed and are not equal to the system values for "
|
||||
L("indicates that some settings were changed and are not equal to the system (or default) values for "
|
||||
"the current option group.\n"
|
||||
"Click the UNLOCKED LOCK icon to reset all settings for current option group to "
|
||||
"the system values."));
|
||||
"the system (or default) values."));
|
||||
|
||||
m_icon_descriptions.emplace_back(&m_bmp_white_bullet, L("WHITE BULLET"),
|
||||
// TRN Description for "WHITE BULLET"
|
||||
L("for the left button: \tindicates a non-system preset,\n"
|
||||
L("for the left button: \tindicates a non-system (or non-default) preset,\n"
|
||||
"for the right button: \tindicates that the settings hasn't been modified."));
|
||||
|
||||
m_icon_descriptions.emplace_back(&m_bmp_value_revert, L("BACK ARROW"),
|
||||
|
|
@ -3287,29 +3291,14 @@ void Tab::fill_icon_descriptions()
|
|||
|
||||
void Tab::set_tooltips_text()
|
||||
{
|
||||
// m_undo_to_sys_btn->SetToolTip(_(L( "LOCKED LOCK icon indicates that the settings are the same as the system values "
|
||||
// "for the current option group.\n"
|
||||
// "UNLOCKED LOCK icon indicates that some settings were changed and are not equal "
|
||||
// "to the system values for the current option group.\n"
|
||||
// "WHITE BULLET icon indicates a non system preset.\n\n"
|
||||
// "Click the UNLOCKED LOCK icon to reset all settings for current option group to "
|
||||
// "the system values.")));
|
||||
//
|
||||
// m_undo_btn->SetToolTip(_(L( "WHITE BULLET icon indicates that the settings are the same as in the last saved"
|
||||
// "preset for the current option group.\n"
|
||||
// "BACK ARROW icon indicates that the settings were changed and are not equal to "
|
||||
// "the last saved preset for the current option group.\n\n"
|
||||
// "Click the BACK ARROW icon to reset all settings for the current option group to "
|
||||
// "the last saved preset.")));
|
||||
|
||||
// --- Tooltip text for reset buttons (for whole options group)
|
||||
// Text to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
|
||||
m_ttg_value_lock = _(L("LOCKED LOCK icon indicates that the settings are the same as the system values "
|
||||
m_ttg_value_lock = _(L("LOCKED LOCK icon indicates that the settings are the same as the system (or default) values "
|
||||
"for the current option group"));
|
||||
m_ttg_value_unlock = _(L("UNLOCKED LOCK icon indicates that some settings were changed and are not equal "
|
||||
"to the system values for the current option group.\n"
|
||||
"Click to reset all settings for current option group to the system values."));
|
||||
m_ttg_white_bullet_ns = _(L("WHITE BULLET icon indicates a non system preset."));
|
||||
"to the system (or default) values for the current option group.\n"
|
||||
"Click to reset all settings for current option group to the system (or default) values."));
|
||||
m_ttg_white_bullet_ns = _(L("WHITE BULLET icon indicates a non system (or non default) preset."));
|
||||
m_ttg_non_system = &m_ttg_white_bullet_ns;
|
||||
// Text to be shown on the "Undo user changes" button next to each input field.
|
||||
m_ttg_white_bullet = _(L("WHITE BULLET icon indicates that the settings are the same as in the last saved "
|
||||
|
|
@ -3320,10 +3309,10 @@ void Tab::set_tooltips_text()
|
|||
|
||||
// --- Tooltip text for reset buttons (for each option in group)
|
||||
// Text to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
|
||||
m_tt_value_lock = _(L("LOCKED LOCK icon indicates that the value is the same as the system value."));
|
||||
m_tt_value_lock = _(L("LOCKED LOCK icon indicates that the value is the same as the system (or default) value."));
|
||||
m_tt_value_unlock = _(L("UNLOCKED LOCK icon indicates that the value was changed and is not equal "
|
||||
"to the system value.\n"
|
||||
"Click to reset current value to the system value."));
|
||||
"to the system (or default) value.\n"
|
||||
"Click to reset current value to the system (or default) value."));
|
||||
// m_tt_white_bullet_ns= _(L("WHITE BULLET icon indicates a non system preset."));
|
||||
m_tt_non_system = &m_ttg_white_bullet_ns;
|
||||
// Text to be shown on the "Undo user changes" button next to each input field.
|
||||
|
|
@ -3577,9 +3566,9 @@ void TabSLAMaterial::reload_config()
|
|||
void TabSLAMaterial::update()
|
||||
{
|
||||
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
|
||||
return; // #ys_FIXME
|
||||
return;
|
||||
|
||||
// #ys_FIXME
|
||||
// #ys_FIXME. Just a template for this function
|
||||
// m_update_cnt++;
|
||||
// ! something to update
|
||||
// m_update_cnt--;
|
||||
|
|
@ -3616,6 +3605,7 @@ void TabSLAPrint::build()
|
|||
// optgroup->append_single_option_line("support_pillar_widening_factor");
|
||||
optgroup->append_single_option_line("support_base_diameter");
|
||||
optgroup->append_single_option_line("support_base_height");
|
||||
optgroup->append_single_option_line("support_base_safety_distance");
|
||||
optgroup->append_single_option_line("support_object_elevation");
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Connection of the support sticks and junctions")));
|
||||
|
|
@ -3636,7 +3626,12 @@ void TabSLAPrint::build()
|
|||
// TODO: Disabling this parameter for the beta release
|
||||
// optgroup->append_single_option_line("pad_edge_radius");
|
||||
optgroup->append_single_option_line("pad_wall_slope");
|
||||
|
||||
|
||||
optgroup->append_single_option_line("pad_object_gap");
|
||||
optgroup->append_single_option_line("pad_object_connector_stride");
|
||||
optgroup->append_single_option_line("pad_object_connector_width");
|
||||
optgroup->append_single_option_line("pad_object_connector_penetration");
|
||||
|
||||
page = add_options_page(_(L("Advanced")), "wrench");
|
||||
optgroup = page->new_optgroup(_(L("Slicing")));
|
||||
optgroup->append_single_option_line("slice_closing_radius");
|
||||
|
|
@ -3677,41 +3672,61 @@ void TabSLAPrint::reload_config()
|
|||
void TabSLAPrint::update()
|
||||
{
|
||||
if (m_preset_bundle->printers.get_selected_preset().printer_technology() == ptFFF)
|
||||
return; // #ys_FIXME
|
||||
return;
|
||||
|
||||
// #ys_FIXME
|
||||
m_update_cnt++;
|
||||
|
||||
double head_penetration = m_config->opt_float("support_head_penetration");
|
||||
double head_width = m_config->opt_float("support_head_width");
|
||||
if(head_penetration > head_width) {
|
||||
wxString msg_text = _(L("Head penetration should not be greater than the head width."));
|
||||
auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Invalid Head penetration")), wxICON_WARNING | wxOK);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog->ShowModal() == wxID_OK) {
|
||||
new_conf.set_key_value("support_head_penetration", new ConfigOptionFloat(head_width));
|
||||
}
|
||||
double head_penetration = m_config->opt_float("support_head_penetration");
|
||||
double head_width = m_config->opt_float("support_head_width");
|
||||
if (head_penetration > head_width) {
|
||||
wxString msg_text = _(
|
||||
L("Head penetration should not be greater than the head width."));
|
||||
|
||||
load_config(new_conf);
|
||||
}
|
||||
auto dialog = new wxMessageDialog(parent(),
|
||||
msg_text,
|
||||
_(L("Invalid Head penetration")),
|
||||
wxICON_WARNING | wxOK);
|
||||
|
||||
double pinhead_d = m_config->opt_float("support_head_front_diameter");
|
||||
double pillar_d = m_config->opt_float("support_pillar_diameter");
|
||||
if(pinhead_d > pillar_d) {
|
||||
wxString msg_text = _(L("Pinhead diameter should be smaller than the pillar diameter."));
|
||||
auto dialog = new wxMessageDialog(parent(), msg_text, _(L("Invalid pinhead diameter")), wxICON_WARNING | wxOK);
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog->ShowModal() == wxID_OK) {
|
||||
new_conf.set_key_value("support_head_front_diameter", new ConfigOptionFloat(pillar_d / 2.0));
|
||||
}
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog->ShowModal() == wxID_OK) {
|
||||
new_conf.set_key_value("support_head_penetration",
|
||||
new ConfigOptionFloat(head_width));
|
||||
}
|
||||
|
||||
load_config(new_conf);
|
||||
}
|
||||
load_config(new_conf);
|
||||
}
|
||||
|
||||
m_update_cnt--;
|
||||
double pinhead_d = m_config->opt_float("support_head_front_diameter");
|
||||
double pillar_d = m_config->opt_float("support_pillar_diameter");
|
||||
if (pinhead_d > pillar_d) {
|
||||
wxString msg_text = _(L(
|
||||
"Pinhead diameter should be smaller than the pillar diameter."));
|
||||
|
||||
if (m_update_cnt == 0)
|
||||
wxGetApp().mainframe->on_config_changed(m_config);
|
||||
auto dialog = new wxMessageDialog(parent(),
|
||||
msg_text,
|
||||
_(L("Invalid pinhead diameter")),
|
||||
wxICON_WARNING | wxOK);
|
||||
|
||||
DynamicPrintConfig new_conf = *m_config;
|
||||
if (dialog->ShowModal() == wxID_OK) {
|
||||
new_conf.set_key_value("support_head_front_diameter",
|
||||
new ConfigOptionFloat(pillar_d / 2.0));
|
||||
}
|
||||
|
||||
load_config(new_conf);
|
||||
}
|
||||
|
||||
// if(m_config->opt_float("support_object_elevation") < EPSILON &&
|
||||
// m_config->opt_bool("pad_enable")) {
|
||||
// // TODO: disable editding of:
|
||||
// // pad_object_connector_stride
|
||||
// // pad_object_connector_width
|
||||
// // pad_object_connector_penetration
|
||||
// }
|
||||
|
||||
m_update_cnt--;
|
||||
|
||||
if (m_update_cnt == 0) wxGetApp().mainframe->on_config_changed(m_config);
|
||||
}
|
||||
|
||||
} // GUI
|
||||
|
|
|
|||
|
|
@ -142,6 +142,12 @@ protected:
|
|||
PresetDependencies m_compatible_printers;
|
||||
PresetDependencies m_compatible_prints;
|
||||
|
||||
/* Indicates, that default preset or preset inherited from default is selected
|
||||
* This value is used for a options color updating
|
||||
* (use green color only for options, which values are equal to system values)
|
||||
*/
|
||||
bool m_is_default_preset {false};
|
||||
|
||||
ScalableButton* m_undo_btn;
|
||||
ScalableButton* m_undo_to_sys_btn;
|
||||
ScalableButton* m_question_btn;
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ void WipingPanel::format_sizer(wxSizer* sizer, wxPanel* page, wxGridSizer* grid_
|
|||
wxSize text_size = GetTextExtent(info);
|
||||
auto info_str = new wxStaticText(page, wxID_ANY, info ,wxDefaultPosition, wxDefaultSize, wxALIGN_CENTER);
|
||||
info_str->Wrap(int(0.6*text_size.x));
|
||||
sizer->Add( info_str, 0, wxALIGN_CENTER_HORIZONTAL | wxEXPAND);
|
||||
sizer->Add( info_str, 0, wxEXPAND);
|
||||
auto table_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(table_sizer, 0, wxALIGN_CENTER | wxCENTER, table_lshift);
|
||||
table_sizer->Add(new wxStaticText(page, wxID_ANY, table_title), 0, wxALIGN_CENTER | wxTOP, 50);
|
||||
|
|
|
|||
|
|
@ -437,27 +437,69 @@ ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent
|
|||
m_type(type),
|
||||
m_extruder(wxEmptyString)
|
||||
{
|
||||
if (type == itSettings) {
|
||||
if (type == itSettings)
|
||||
m_name = "Settings to modified";
|
||||
}
|
||||
else if (type == itInstanceRoot) {
|
||||
else if (type == itInstanceRoot)
|
||||
m_name = _(L("Instances"));
|
||||
#ifdef __WXGTK__
|
||||
m_container = true;
|
||||
#endif //__WXGTK__
|
||||
}
|
||||
else if (type == itInstance) {
|
||||
else if (type == itInstance)
|
||||
{
|
||||
m_idx = parent->GetChildCount();
|
||||
m_name = wxString::Format(_(L("Instance %d")), m_idx + 1);
|
||||
|
||||
set_action_icon();
|
||||
}
|
||||
else if (type == itLayerRoot)
|
||||
{
|
||||
m_bmp = create_scaled_bitmap(nullptr, "layers"); // FIXME: pass window ptr
|
||||
m_name = _(L("Layers"));
|
||||
}
|
||||
|
||||
#ifdef __WXGTK__
|
||||
// it's necessary on GTK because of control have to know if this item will be container
|
||||
// in another case you couldn't to add subitem for this item
|
||||
// it will be produce "segmentation fault"
|
||||
if (type & (itInstanceRoot | itLayerRoot))
|
||||
m_container = true;
|
||||
#endif //__WXGTK__
|
||||
}
|
||||
|
||||
ObjectDataViewModelNode::ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
||||
const t_layer_height_range& layer_range,
|
||||
const int idx /*= -1 */,
|
||||
const wxString& extruder) :
|
||||
m_parent(parent),
|
||||
m_type(itLayer),
|
||||
m_idx(idx),
|
||||
m_layer_range(layer_range),
|
||||
m_extruder(extruder)
|
||||
{
|
||||
const int children_cnt = parent->GetChildCount();
|
||||
if (idx < 0)
|
||||
m_idx = children_cnt;
|
||||
else
|
||||
{
|
||||
// update indexes for another Laeyr Nodes
|
||||
for (int i = m_idx; i < children_cnt; i++)
|
||||
parent->GetNthChild(i)->SetIdx(i + 1);
|
||||
}
|
||||
const std::string label_range = (boost::format(" %.2f-%.2f ") % layer_range.first % layer_range.second).str();
|
||||
m_name = _(L("Range")) + label_range + "(" + _(L("mm")) + ")";
|
||||
m_bmp = create_scaled_bitmap(nullptr, "layers_white"); // FIXME: pass window ptr
|
||||
|
||||
#ifdef __WXGTK__
|
||||
// it's necessary on GTK because of control have to know if this item will be container
|
||||
// in another case you couldn't to add subitem for this item
|
||||
// it will be produce "segmentation fault"
|
||||
m_container = true;
|
||||
#endif //__WXGTK__
|
||||
|
||||
set_action_icon();
|
||||
}
|
||||
|
||||
void ObjectDataViewModelNode::set_action_icon()
|
||||
{
|
||||
m_action_icon_name = m_type == itObject ? "advanced_plus" :
|
||||
m_type == itVolume ? "cog" : "set_separate_obj";
|
||||
m_action_icon_name = m_type & itObject ? "advanced_plus" :
|
||||
m_type & (itVolume | itLayer) ? "cog" : /*m_type & itInstance*/ "set_separate_obj";
|
||||
m_action_icon = create_scaled_bitmap(nullptr, m_action_icon_name); // FIXME: pass window ptr
|
||||
}
|
||||
|
||||
|
|
@ -523,6 +565,22 @@ void ObjectDataViewModelNode::SetIdx(const int& idx)
|
|||
// ObjectDataViewModel
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static int get_root_idx(ObjectDataViewModelNode *parent_node, const ItemType root_type)
|
||||
{
|
||||
// because of istance_root and layers_root are at the end of the list, so
|
||||
// start locking from the end
|
||||
for (int root_idx = parent_node->GetChildCount() - 1; root_idx >= 0; root_idx--)
|
||||
{
|
||||
// if there is SettingsItem or VolumeItem, then RootItems don't exist in current ObjectItem
|
||||
if (parent_node->GetNthChild(root_idx)->GetType() & (itSettings | itVolume))
|
||||
break;
|
||||
if (parent_node->GetNthChild(root_idx)->GetType() & root_type)
|
||||
return root_idx;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ObjectDataViewModel::ObjectDataViewModel()
|
||||
{
|
||||
m_bitmap_cache = new Slic3r::GUI::BitmapCache;
|
||||
|
|
@ -567,10 +625,10 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
|
|||
|
||||
wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
|
||||
|
||||
// because of istance_root is a last item of the object
|
||||
int insert_position = root->GetChildCount() - 1;
|
||||
if (insert_position < 0 || root->GetNthChild(insert_position)->m_type != itInstanceRoot)
|
||||
insert_position = -1;
|
||||
// get insertion position according to the existed Layers and/or Instances Items
|
||||
int insert_position = get_root_idx(root, itLayerRoot);
|
||||
if (insert_position < 0)
|
||||
insert_position = get_root_idx(root, itInstanceRoot);
|
||||
|
||||
const bool obj_errors = root->m_bmp.IsOk();
|
||||
|
||||
|
|
@ -619,15 +677,30 @@ wxDataViewItem ObjectDataViewModel::AddSettingsChild(const wxDataViewItem &paren
|
|||
return child;
|
||||
}
|
||||
|
||||
int get_istances_root_idx(ObjectDataViewModelNode *parent_node)
|
||||
/* return values:
|
||||
* true => root_node is created and added to the parent_root
|
||||
* false => root node alredy exists
|
||||
*/
|
||||
static bool append_root_node(ObjectDataViewModelNode *parent_node,
|
||||
ObjectDataViewModelNode **root_node,
|
||||
const ItemType root_type)
|
||||
{
|
||||
// because of istance_root is a last item of the object
|
||||
const int inst_root_idx = parent_node->GetChildCount()-1;
|
||||
const int inst_root_id = get_root_idx(parent_node, root_type);
|
||||
|
||||
if (inst_root_idx < 0 || parent_node->GetNthChild(inst_root_idx)->GetType() == itInstanceRoot)
|
||||
return inst_root_idx;
|
||||
*root_node = inst_root_id < 0 ?
|
||||
new ObjectDataViewModelNode(parent_node, root_type) :
|
||||
parent_node->GetNthChild(inst_root_id);
|
||||
|
||||
return -1;
|
||||
if (inst_root_id < 0) {
|
||||
if ((root_type&itInstanceRoot) ||
|
||||
(root_type&itLayerRoot) && get_root_idx(parent_node, itInstanceRoot)<0)
|
||||
parent_node->Append(*root_node);
|
||||
else if (root_type&itLayerRoot)
|
||||
parent_node->Insert(*root_node, static_cast<unsigned int>(get_root_idx(parent_node, itInstanceRoot)));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
|
||||
|
|
@ -635,20 +708,15 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
|
|||
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
if (!parent_node) return wxDataViewItem(0);
|
||||
|
||||
// Check and create/get instances root node
|
||||
const int inst_root_id = get_istances_root_idx(parent_node);
|
||||
// get InstanceRoot node
|
||||
ObjectDataViewModelNode *inst_root_node { nullptr };
|
||||
|
||||
ObjectDataViewModelNode *inst_root_node = inst_root_id < 0 ?
|
||||
new ObjectDataViewModelNode(parent_node, itInstanceRoot) :
|
||||
parent_node->GetNthChild(inst_root_id);
|
||||
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);
|
||||
|
||||
if (inst_root_id < 0) {
|
||||
parent_node->Append(inst_root_node);
|
||||
// notify control
|
||||
ItemAdded(parent_item, inst_root_item);
|
||||
// if (num == 1) num++;
|
||||
}
|
||||
if (appended)
|
||||
ItemAdded(parent_item, inst_root_item);// notify control
|
||||
|
||||
// Add instance nodes
|
||||
ObjectDataViewModelNode *instance_node = nullptr;
|
||||
|
|
@ -665,6 +733,63 @@ wxDataViewItem ObjectDataViewModel::AddInstanceChild(const wxDataViewItem &paren
|
|||
return wxDataViewItem((void*)instance_node);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddLayersRoot(const wxDataViewItem &parent_item)
|
||||
{
|
||||
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
if (!parent_node) return wxDataViewItem(0);
|
||||
|
||||
// get LayerRoot node
|
||||
ObjectDataViewModelNode *layer_root_node{ nullptr };
|
||||
const bool appended = append_root_node(parent_node, &layer_root_node, itLayerRoot);
|
||||
if (!layer_root_node) return wxDataViewItem(0);
|
||||
|
||||
const wxDataViewItem layer_root_item((void*)layer_root_node);
|
||||
|
||||
if (appended)
|
||||
ItemAdded(parent_item, layer_root_item);// notify control
|
||||
|
||||
return layer_root_item;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::AddLayersChild(const wxDataViewItem &parent_item,
|
||||
const t_layer_height_range& layer_range,
|
||||
const int extruder/* = 0*/,
|
||||
const int index /* = -1*/)
|
||||
{
|
||||
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
if (!parent_node) return wxDataViewItem(0);
|
||||
|
||||
wxString extruder_str = extruder == 0 ? _(L("default")) : wxString::Format("%d", extruder);
|
||||
|
||||
// get LayerRoot node
|
||||
ObjectDataViewModelNode *layer_root_node;
|
||||
wxDataViewItem layer_root_item;
|
||||
|
||||
if (parent_node->GetType() & itLayerRoot) {
|
||||
layer_root_node = parent_node;
|
||||
layer_root_item = parent_item;
|
||||
}
|
||||
else {
|
||||
const int root_idx = get_root_idx(parent_node, itLayerRoot);
|
||||
if (root_idx < 0) return wxDataViewItem(0);
|
||||
layer_root_node = parent_node->GetNthChild(root_idx);
|
||||
layer_root_item = wxDataViewItem((void*)layer_root_node);
|
||||
}
|
||||
|
||||
// Add layer node
|
||||
ObjectDataViewModelNode *layer_node = new ObjectDataViewModelNode(layer_root_node, layer_range, index, extruder_str);
|
||||
if (index < 0)
|
||||
layer_root_node->Append(layer_node);
|
||||
else
|
||||
layer_root_node->Insert(layer_node, index);
|
||||
|
||||
// notify control
|
||||
const wxDataViewItem layer_item((void*)layer_node);
|
||||
ItemAdded(layer_root_item, layer_item);
|
||||
|
||||
return layer_item;
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
||||
{
|
||||
auto ret_item = wxDataViewItem(0);
|
||||
|
|
@ -679,10 +804,14 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
|||
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
|
||||
// thus removing the node from it doesn't result in freeing it
|
||||
if (node_parent) {
|
||||
if (node->m_type == itInstanceRoot)
|
||||
if (node->m_type & (itInstanceRoot|itLayerRoot))
|
||||
{
|
||||
for (int i = node->GetChildCount() - 1; i > 0; i--)
|
||||
// node can be deleted by the Delete, let's check its type while we safely can
|
||||
bool is_instance_root = (node->m_type & itInstanceRoot);
|
||||
|
||||
for (int i = node->GetChildCount() - 1; i >= (is_instance_root ? 1 : 0); i--)
|
||||
Delete(wxDataViewItem(node->GetNthChild(i)));
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
|
|
@ -690,7 +819,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
|||
auto idx = node->GetIdx();
|
||||
|
||||
|
||||
if (node->m_type == itVolume) {
|
||||
if (node->m_type & (itVolume|itLayer)) {
|
||||
node_parent->m_volumes_cnt--;
|
||||
DeleteSettings(item);
|
||||
}
|
||||
|
|
@ -726,6 +855,22 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
|||
delete node_parent;
|
||||
ret_item = wxDataViewItem(obj_node);
|
||||
|
||||
#ifndef __WXGTK__
|
||||
if (obj_node->GetChildCount() == 0)
|
||||
obj_node->m_container = false;
|
||||
#endif //__WXGTK__
|
||||
ItemDeleted(ret_item, wxDataViewItem(node_parent));
|
||||
return ret_item;
|
||||
}
|
||||
|
||||
// if there was last layer item, delete this one and layers root item
|
||||
if (node_parent->GetChildCount() == 0 && node_parent->m_type == itLayerRoot)
|
||||
{
|
||||
ObjectDataViewModelNode *obj_node = node_parent->GetParent();
|
||||
obj_node->GetChildren().Remove(node_parent);
|
||||
delete node_parent;
|
||||
ret_item = wxDataViewItem(obj_node);
|
||||
|
||||
#ifndef __WXGTK__
|
||||
if (obj_node->GetChildCount() == 0)
|
||||
obj_node->m_container = false;
|
||||
|
|
@ -735,7 +880,7 @@ wxDataViewItem ObjectDataViewModel::Delete(const wxDataViewItem &item)
|
|||
}
|
||||
|
||||
// if there is last volume item after deleting, delete this last volume too
|
||||
if (node_parent->GetChildCount() <= 3)
|
||||
if (node_parent->GetChildCount() <= 3) // 3??? #ys_FIXME
|
||||
{
|
||||
int vol_cnt = 0;
|
||||
int vol_idx = 0;
|
||||
|
|
@ -817,7 +962,7 @@ wxDataViewItem ObjectDataViewModel::DeleteLastInstance(const wxDataViewItem &par
|
|||
ObjectDataViewModelNode *parent_node = (ObjectDataViewModelNode*)parent_item.GetID();
|
||||
if (!parent_node) return ret_item;
|
||||
|
||||
const int inst_root_id = get_istances_root_idx(parent_node);
|
||||
const int inst_root_id = get_root_idx(parent_node, itInstanceRoot);
|
||||
if (inst_root_id < 0) return ret_item;
|
||||
|
||||
wxDataViewItemArray items;
|
||||
|
|
@ -974,28 +1119,67 @@ wxDataViewItem ObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_id
|
|||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
|
||||
wxDataViewItem ObjectDataViewModel::GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type)
|
||||
{
|
||||
if (obj_idx >= m_objects.size() || obj_idx < 0) {
|
||||
printf("Error! Out of objects range.\n");
|
||||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
auto instances_item = GetInstanceRootItem(wxDataViewItem(m_objects[obj_idx]));
|
||||
if (!instances_item)
|
||||
auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), parent_type);
|
||||
if (!item)
|
||||
return wxDataViewItem(0);
|
||||
|
||||
auto parent = (ObjectDataViewModelNode*)instances_item.GetID();;
|
||||
auto parent = (ObjectDataViewModelNode*)item.GetID();
|
||||
for (size_t i = 0; i < parent->GetChildCount(); i++)
|
||||
if (parent->GetNthChild(i)->m_idx == inst_idx)
|
||||
if (parent->GetNthChild(i)->m_idx == sub_obj_idx)
|
||||
return wxDataViewItem(parent->GetNthChild(i));
|
||||
|
||||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
|
||||
{
|
||||
return GetItemById(obj_idx, inst_idx, itInstanceRoot);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetItemByLayerId(int obj_idx, int layer_idx)
|
||||
{
|
||||
return GetItemById(obj_idx, layer_idx, itLayerRoot);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
|
||||
{
|
||||
if (obj_idx >= m_objects.size() || obj_idx < 0) {
|
||||
printf("Error! Out of objects range.\n");
|
||||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
auto item = GetItemByType(wxDataViewItem(m_objects[obj_idx]), itLayerRoot);
|
||||
if (!item)
|
||||
return wxDataViewItem(0);
|
||||
|
||||
auto parent = (ObjectDataViewModelNode*)item.GetID();
|
||||
for (size_t i = 0; i < parent->GetChildCount(); i++)
|
||||
if (parent->GetNthChild(i)->m_layer_range == layer_range)
|
||||
return wxDataViewItem(parent->GetNthChild(i));
|
||||
|
||||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
int ObjectDataViewModel::GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range)
|
||||
{
|
||||
wxDataViewItem item = GetItemByLayerRange(obj_idx, layer_range);
|
||||
if (!item)
|
||||
return -1;
|
||||
|
||||
return GetLayerIdByItem(item);
|
||||
}
|
||||
|
||||
int ObjectDataViewModel::GetIdByItem(const wxDataViewItem& item) const
|
||||
{
|
||||
wxASSERT(item.IsOk());
|
||||
if(!item.IsOk())
|
||||
return -1;
|
||||
|
||||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||
auto it = find(m_objects.begin(), m_objects.end(), node);
|
||||
|
|
@ -1030,13 +1214,28 @@ int ObjectDataViewModel::GetInstanceIdByItem(const wxDataViewItem& item) const
|
|||
return GetIdByItemAndType(item, itInstance);
|
||||
}
|
||||
|
||||
int ObjectDataViewModel::GetLayerIdByItem(const wxDataViewItem& item) const
|
||||
{
|
||||
return GetIdByItemAndType(item, itLayer);
|
||||
}
|
||||
|
||||
t_layer_height_range ObjectDataViewModel::GetLayerRangeByItem(const wxDataViewItem& item) const
|
||||
{
|
||||
wxASSERT(item.IsOk());
|
||||
|
||||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||
if (!node || node->m_type != itLayer)
|
||||
return { 0.0f, 0.0f };
|
||||
return node->GetLayerRange();
|
||||
}
|
||||
|
||||
void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx)
|
||||
{
|
||||
wxASSERT(item.IsOk());
|
||||
type = itUndef;
|
||||
|
||||
ObjectDataViewModelNode *node = (ObjectDataViewModelNode*)item.GetID();
|
||||
if (!node || node->GetIdx() <-1 || node->GetIdx() ==-1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot)))
|
||||
if (!node || node->GetIdx() <-1 || node->GetIdx() == -1 && !(node->GetType() & (itObject | itSettings | itInstanceRoot | itLayerRoot/* | itLayer*/)))
|
||||
return;
|
||||
|
||||
idx = node->GetIdx();
|
||||
|
|
@ -1044,9 +1243,10 @@ void ObjectDataViewModel::GetItemInfo(const wxDataViewItem& item, ItemType& type
|
|||
|
||||
ObjectDataViewModelNode *parent_node = node->GetParent();
|
||||
if (!parent_node) return;
|
||||
if (type == itInstance)
|
||||
parent_node = node->GetParent()->GetParent();
|
||||
if (!parent_node || parent_node->m_type != itObject) { type = itUndef; return; }
|
||||
|
||||
// get top parent (Object) node
|
||||
while (parent_node->m_type != itObject)
|
||||
parent_node = parent_node->GetParent();
|
||||
|
||||
auto it = find(m_objects.begin(), m_objects.end(), parent_node);
|
||||
if (it != m_objects.end())
|
||||
|
|
@ -1214,10 +1414,7 @@ wxDataViewItem ObjectDataViewModel::GetTopParent(const wxDataViewItem &item) con
|
|||
|
||||
ObjectDataViewModelNode *parent_node = node->GetParent();
|
||||
while (parent_node->m_type != itObject)
|
||||
{
|
||||
node = parent_node;
|
||||
parent_node = node->GetParent();
|
||||
}
|
||||
parent_node = parent_node->GetParent();
|
||||
|
||||
return wxDataViewItem((void*)parent_node);
|
||||
}
|
||||
|
|
@ -1318,6 +1515,11 @@ wxDataViewItem ObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &it
|
|||
return GetItemByType(item, itInstanceRoot);
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectDataViewModel::GetLayerRootItem(const wxDataViewItem &item) const
|
||||
{
|
||||
return GetItemByType(item, itLayerRoot);
|
||||
}
|
||||
|
||||
bool ObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
|
||||
{
|
||||
if (!item.IsOk())
|
||||
|
|
@ -2653,7 +2855,7 @@ ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 10*/) :
|
|||
m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first));;
|
||||
#endif // __WXOSX__
|
||||
|
||||
m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, m_mode_btns.size() - 1));
|
||||
m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, int(m_mode_btns.size() - 1)));
|
||||
Add(m_mode_btns.back());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ namespace Slic3r {
|
|||
enum class ModelVolumeType : int;
|
||||
};
|
||||
|
||||
typedef double coordf_t;
|
||||
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||
|
||||
#ifdef __WXMSW__
|
||||
void msw_rescale_menu(wxMenu* menu);
|
||||
#else /* __WXMSW__ */
|
||||
|
|
@ -159,12 +162,14 @@ DECLARE_VARIANT_OBJECT(DataViewBitmapText)
|
|||
// ----------------------------------------------------------------------------
|
||||
|
||||
enum ItemType {
|
||||
itUndef = 0,
|
||||
itObject = 1,
|
||||
itVolume = 2,
|
||||
itInstanceRoot = 4,
|
||||
itInstance = 8,
|
||||
itSettings = 16
|
||||
itUndef = 0,
|
||||
itObject = 1,
|
||||
itVolume = 2,
|
||||
itInstanceRoot = 4,
|
||||
itInstance = 8,
|
||||
itSettings = 16,
|
||||
itLayerRoot = 32,
|
||||
itLayer = 64,
|
||||
};
|
||||
|
||||
class ObjectDataViewModelNode;
|
||||
|
|
@ -177,6 +182,7 @@ class ObjectDataViewModelNode
|
|||
wxBitmap m_empty_bmp;
|
||||
size_t m_volumes_cnt = 0;
|
||||
std::vector< std::string > m_opt_categories;
|
||||
t_layer_height_range m_layer_range = { 0.0f, 0.0f };
|
||||
|
||||
wxString m_name;
|
||||
wxBitmap& m_bmp = m_empty_bmp;
|
||||
|
|
@ -229,6 +235,11 @@ public:
|
|||
set_action_icon();
|
||||
}
|
||||
|
||||
ObjectDataViewModelNode(ObjectDataViewModelNode* parent,
|
||||
const t_layer_height_range& layer_range,
|
||||
const int idx = -1,
|
||||
const wxString& extruder = wxEmptyString );
|
||||
|
||||
ObjectDataViewModelNode(ObjectDataViewModelNode* parent, const ItemType type);
|
||||
|
||||
~ObjectDataViewModelNode()
|
||||
|
|
@ -318,6 +329,7 @@ public:
|
|||
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; }
|
||||
|
||||
// use this function only for childrens
|
||||
void AssignAllVal(ObjectDataViewModelNode& from_node)
|
||||
|
|
@ -348,7 +360,7 @@ public:
|
|||
}
|
||||
|
||||
// Set action icons for node
|
||||
void set_action_icon();
|
||||
void set_action_icon();
|
||||
|
||||
void update_settings_digest_bitmaps();
|
||||
bool update_settings_digest(const std::vector<std::string>& categories);
|
||||
|
|
@ -388,6 +400,11 @@ public:
|
|||
const bool create_frst_child = true);
|
||||
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
|
||||
wxDataViewItem AddInstanceChild(const wxDataViewItem &parent_item, size_t num);
|
||||
wxDataViewItem AddLayersRoot(const wxDataViewItem &parent_item);
|
||||
wxDataViewItem AddLayersChild( const wxDataViewItem &parent_item,
|
||||
const t_layer_height_range& layer_range,
|
||||
const int extruder = 0,
|
||||
const int index = -1);
|
||||
wxDataViewItem Delete(const wxDataViewItem &item);
|
||||
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
|
||||
void DeleteAll();
|
||||
|
|
@ -395,13 +412,18 @@ public:
|
|||
void DeleteVolumeChildren(wxDataViewItem& parent);
|
||||
void DeleteSettings(const wxDataViewItem& parent);
|
||||
wxDataViewItem GetItemById(int obj_idx);
|
||||
wxDataViewItem GetItemById(const int obj_idx, const int sub_obj_idx, const ItemType parent_type);
|
||||
wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
|
||||
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
|
||||
wxDataViewItem GetItemByLayerId(int obj_idx, int layer_idx);
|
||||
wxDataViewItem GetItemByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
|
||||
int GetItemIdByLayerRange(const int obj_idx, const t_layer_height_range& layer_range);
|
||||
int GetIdByItem(const wxDataViewItem& item) const;
|
||||
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
|
||||
int GetObjectIdByItem(const wxDataViewItem& item) const;
|
||||
int GetVolumeIdByItem(const wxDataViewItem& item) const;
|
||||
int GetInstanceIdByItem(const wxDataViewItem& item) const;
|
||||
int GetLayerIdByItem(const wxDataViewItem& item) const;
|
||||
void GetItemInfo(const wxDataViewItem& item, ItemType& type, int& obj_idx, int& idx);
|
||||
int GetRowByItem(const wxDataViewItem& item) const;
|
||||
bool IsEmpty() { return m_objects.empty(); }
|
||||
|
|
@ -450,6 +472,7 @@ public:
|
|||
ItemType type) const;
|
||||
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
|
||||
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
|
||||
wxDataViewItem GetLayerRootItem(const wxDataViewItem &item) const;
|
||||
bool IsSettingsItem(const wxDataViewItem &item) const;
|
||||
void UpdateSettingsDigest( const wxDataViewItem &item,
|
||||
const std::vector<std::string>& categories);
|
||||
|
|
@ -465,6 +488,7 @@ public:
|
|||
wxBitmap GetVolumeIcon(const Slic3r::ModelVolumeType vol_type,
|
||||
const bool is_marked = false);
|
||||
void DeleteWarningIcon(const wxDataViewItem& item, const bool unmark_object = false);
|
||||
t_layer_height_range GetLayerRangeByItem(const wxDataViewItem& item) const;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
|
|||
1076
src/slic3r/Utils/UndoRedo.cpp
Normal file
1076
src/slic3r/Utils/UndoRedo.cpp
Normal file
File diff suppressed because it is too large
Load diff
118
src/slic3r/Utils/UndoRedo.hpp
Normal file
118
src/slic3r/Utils/UndoRedo.hpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#ifndef slic3r_Utils_UndoRedo_hpp_
|
||||
#define slic3r_Utils_UndoRedo_hpp_
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
#include <libslic3r/ObjectID.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Model;
|
||||
enum PrinterTechnology : unsigned char;
|
||||
|
||||
namespace GUI {
|
||||
class Selection;
|
||||
class GLGizmosManager;
|
||||
} // namespace GUI
|
||||
|
||||
namespace UndoRedo {
|
||||
|
||||
struct Snapshot
|
||||
{
|
||||
Snapshot(size_t timestamp) : timestamp(timestamp) {}
|
||||
Snapshot(const std::string &name, size_t timestamp, size_t model_id, Slic3r::PrinterTechnology printer_technology, unsigned int flags) :
|
||||
name(name), timestamp(timestamp), model_id(model_id), printer_technology(printer_technology), flags(flags) {}
|
||||
|
||||
// Bitmask of various binary flags to be stored with the snapshot.
|
||||
enum Flags {
|
||||
VARIABLE_LAYER_EDITING_ACTIVE = 1,
|
||||
};
|
||||
|
||||
std::string name;
|
||||
size_t timestamp;
|
||||
size_t model_id;
|
||||
PrinterTechnology printer_technology;
|
||||
// Bitmap of Flags (see the Flags enum).
|
||||
unsigned int flags;
|
||||
|
||||
bool operator< (const Snapshot &rhs) const { return this->timestamp < rhs.timestamp; }
|
||||
bool operator==(const Snapshot &rhs) const { return this->timestamp == rhs.timestamp; }
|
||||
|
||||
// The topmost snapshot represents the current state when going forward.
|
||||
bool is_topmost() const;
|
||||
// The topmost snapshot is not being serialized to the Undo / Redo stack until going back in time,
|
||||
// when the top most state is being serialized, so we can redo back to the top most state.
|
||||
bool is_topmost_captured() const { assert(this->is_topmost()); return model_id > 0; }
|
||||
};
|
||||
|
||||
// Excerpt of Slic3r::GUI::Selection for serialization onto the Undo / Redo stack.
|
||||
struct Selection : public Slic3r::ObjectBase {
|
||||
unsigned char mode;
|
||||
std::vector<std::pair<size_t, size_t>> volumes_and_instances;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(mode, volumes_and_instances); }
|
||||
};
|
||||
|
||||
class StackImpl;
|
||||
|
||||
class Stack
|
||||
{
|
||||
public:
|
||||
// Stack needs to be initialized. An empty stack is not valid, there must be a "New Project" status stored at the beginning.
|
||||
// The first "New Project" snapshot shall not be removed.
|
||||
Stack();
|
||||
~Stack();
|
||||
|
||||
// Set maximum memory threshold. If the threshold is exceeded, least recently used snapshots are released.
|
||||
void set_memory_limit(size_t memsize);
|
||||
size_t get_memory_limit() const;
|
||||
|
||||
// Estimate size of the RAM consumed by the Undo / Redo stack.
|
||||
size_t memsize() const;
|
||||
|
||||
// Release least recently used snapshots up to the memory limit set above.
|
||||
void release_least_recently_used();
|
||||
|
||||
// Store the current application state onto the Undo / Redo stack, remove all snapshots after m_active_snapshot_time.
|
||||
void take_snapshot(const std::string& snapshot_name, const Slic3r::Model& model, const Slic3r::GUI::Selection& selection, const Slic3r::GUI::GLGizmosManager& gizmos, Slic3r::PrinterTechnology printer_technology, unsigned int flags);
|
||||
|
||||
// To be queried to enable / disable the Undo / Redo buttons at the UI.
|
||||
bool has_undo_snapshot() const;
|
||||
bool has_redo_snapshot() const;
|
||||
|
||||
// Roll back the time. If time_to_load is SIZE_MAX, the previous snapshot is activated.
|
||||
// Undoing an action may need to take a snapshot of the current application state, so that redo to the current state is possible.
|
||||
bool undo(Slic3r::Model& model, const Slic3r::GUI::Selection& selection, Slic3r::GUI::GLGizmosManager& gizmos, PrinterTechnology printer_technology, unsigned int flags, size_t time_to_load = SIZE_MAX);
|
||||
|
||||
// Jump forward in time. If time_to_load is SIZE_MAX, the next snapshot is activated.
|
||||
bool redo(Slic3r::Model& model, Slic3r::GUI::GLGizmosManager& gizmos, size_t time_to_load = SIZE_MAX);
|
||||
|
||||
// Snapshot history (names with timestamps).
|
||||
// Each snapshot indicates start of an interval in which this operation is performed.
|
||||
// There is one additional snapshot taken at the very end, which indicates the current unnamed state.
|
||||
|
||||
const std::vector<Snapshot>& snapshots() const;
|
||||
// Timestamp of the active snapshot. One of the snapshots of this->snapshots() shall have Snapshot::timestamp equal to this->active_snapshot_time().
|
||||
// The snapshot time indicates start of an operation, which is finished at the time of the following snapshot, therefore
|
||||
// the active snapshot is the successive snapshot. The same logic applies to the time_to_load parameter of undo() and redo() operations.
|
||||
size_t active_snapshot_time() const;
|
||||
// Temporary snapshot is active if the topmost snapshot is active and it has not been captured yet.
|
||||
// In that case the Undo action will capture the last snapshot.
|
||||
bool temp_snapshot_active() const;
|
||||
|
||||
// After load_snapshot() / undo() / redo() the selection is deserialized into a list of ObjectIDs, which needs to be converted
|
||||
// into the list of GLVolume pointers once the 3D scene is updated.
|
||||
const Selection& selection_deserialized() const;
|
||||
|
||||
private:
|
||||
friend class StackImpl;
|
||||
std::unique_ptr<StackImpl> pimpl;
|
||||
};
|
||||
|
||||
}; // namespace UndoRedo
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Utils_UndoRedo_hpp_ */
|
||||
Loading…
Add table
Add a link
Reference in a new issue