mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-29 11:41:20 -06:00
Merge remote-tracking branch 'origin/dev_native' into tm_sla_supports
This commit is contained in:
commit
97b3d94760
55 changed files with 1903 additions and 808 deletions
|
|
@ -193,6 +193,7 @@ const float GLVolume::SELECTED_COLOR[4] = { 0.0f, 1.0f, 0.0f, 1.0f };
|
|||
const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f };
|
||||
const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f };
|
||||
const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f };
|
||||
const float GLVolume::DISABLED_COLOR[4] = { 0.25f, 0.25f, 0.25f, 1.0f };
|
||||
|
||||
GLVolume::GLVolume(float r, float g, float b, float a)
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
|
@ -211,6 +212,7 @@ GLVolume::GLVolume(float r, float g, float b, float a)
|
|||
, composite_id(-1)
|
||||
, extruder_id(0)
|
||||
, selected(false)
|
||||
, disabled(false)
|
||||
, is_active(true)
|
||||
, zoom_to_volumes(true)
|
||||
, shader_outside_printer_detection_enabled(false)
|
||||
|
|
@ -252,6 +254,8 @@ void GLVolume::set_render_color()
|
|||
set_render_color(is_outside ? SELECTED_OUTSIDE_COLOR : SELECTED_COLOR, 4);
|
||||
else if (hover)
|
||||
set_render_color(HOVER_COLOR, 4);
|
||||
else if (disabled)
|
||||
set_render_color(DISABLED_COLOR, 4);
|
||||
else if (is_outside && shader_outside_printer_detection_enabled)
|
||||
set_render_color(OUTSIDE_COLOR, 4);
|
||||
else
|
||||
|
|
@ -723,7 +727,11 @@ std::vector<int> GLVolumeCollection::load_object(
|
|||
|
||||
for (int instance_idx : instance_idxs) {
|
||||
const ModelInstance *instance = model_object->instances[instance_idx];
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
const TriangleMesh& mesh = model_volume->mesh;
|
||||
#else
|
||||
TriangleMesh mesh = model_volume->mesh;
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
volumes_idx.push_back(int(this->volumes.size()));
|
||||
float color[4];
|
||||
memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3);
|
||||
|
|
@ -758,7 +766,8 @@ std::vector<int> GLVolumeCollection::load_object(
|
|||
v.is_modifier = ! model_volume->is_model_part();
|
||||
v.shader_outside_printer_detection_enabled = model_volume->is_model_part();
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
v.set_transformation(instance->get_transformation());
|
||||
v.set_instance_transformation(instance->get_transformation());
|
||||
v.set_volume_transformation(model_volume->get_transformation());
|
||||
#else
|
||||
v.set_offset(instance->get_offset());
|
||||
v.set_rotation(instance->get_rotation());
|
||||
|
|
@ -833,7 +842,11 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||
else
|
||||
v.indexed_vertex_array.load_mesh_flat_shading(mesh);
|
||||
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0));
|
||||
#else
|
||||
v.set_offset(Vec3d(pos_x, pos_y, 0.0));
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
||||
// finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
|
||||
v.bounding_box = v.indexed_vertex_array.bounding_box();
|
||||
|
|
|
|||
|
|
@ -249,13 +249,15 @@ public:
|
|||
static const float HOVER_COLOR[4];
|
||||
static const float OUTSIDE_COLOR[4];
|
||||
static const float SELECTED_OUTSIDE_COLOR[4];
|
||||
static const float DISABLED_COLOR[4];
|
||||
|
||||
GLVolume(float r = 1.f, float g = 1.f, float b = 1.f, float a = 1.f);
|
||||
GLVolume(const float *rgba) : GLVolume(rgba[0], rgba[1], rgba[2], rgba[3]) {}
|
||||
|
||||
private:
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
Geometry::Transformation m_transformation;
|
||||
Geometry::Transformation m_instance_transformation;
|
||||
Geometry::Transformation m_volume_transformation;
|
||||
#else
|
||||
// Offset of the volume to be rendered.
|
||||
Vec3d m_offset;
|
||||
|
|
@ -294,6 +296,8 @@ public:
|
|||
int extruder_id;
|
||||
// Is this object selected?
|
||||
bool selected;
|
||||
// Is this object disabled from selection?
|
||||
bool disabled;
|
||||
// Whether or not this volume is active for rendering
|
||||
bool is_active;
|
||||
// Whether or not to use this volume when applying zoom_to_volumes()
|
||||
|
|
@ -329,32 +333,59 @@ public:
|
|||
void set_render_color();
|
||||
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
const Geometry::Transformation& get_transformation() const { return m_transformation; }
|
||||
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; set_bounding_boxes_as_dirty(); }
|
||||
const Geometry::Transformation& get_instance_transformation() const { return m_instance_transformation; }
|
||||
void set_instance_transformation(const Geometry::Transformation& transformation) { m_instance_transformation = transformation; set_bounding_boxes_as_dirty(); }
|
||||
|
||||
const Vec3d& get_offset() const { return m_transformation.get_offset(); }
|
||||
double get_offset(Axis axis) const { return m_transformation.get_offset(axis); }
|
||||
const Vec3d& get_instance_offset() const { return m_instance_transformation.get_offset(); }
|
||||
double get_instance_offset(Axis axis) const { return m_instance_transformation.get_offset(axis); }
|
||||
|
||||
void set_offset(const Vec3d& offset) { m_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
|
||||
void set_offset(Axis axis, double offset) { m_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_offset(const Vec3d& offset) { m_instance_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_offset(Axis axis, double offset) { m_instance_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
const Vec3d& get_rotation() const { return m_transformation.get_rotation(); }
|
||||
double get_rotation(Axis axis) const { return m_transformation.get_rotation(axis); }
|
||||
const Vec3d& get_instance_rotation() const { return m_instance_transformation.get_rotation(); }
|
||||
double get_instance_rotation(Axis axis) const { return m_instance_transformation.get_rotation(axis); }
|
||||
|
||||
void set_rotation(const Vec3d& rotation) { m_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
|
||||
void set_rotation(Axis axis, double rotation) { m_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_rotation(const Vec3d& rotation) { m_instance_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_rotation(Axis axis, double rotation) { m_instance_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
Vec3d get_scaling_factor() const { return m_transformation.get_scaling_factor(); }
|
||||
double get_scaling_factor(Axis axis) const { return m_transformation.get_scaling_factor(axis); }
|
||||
Vec3d get_instance_scaling_factor() const { return m_instance_transformation.get_scaling_factor(); }
|
||||
double get_instance_scaling_factor(Axis axis) const { return m_instance_transformation.get_scaling_factor(axis); }
|
||||
|
||||
void set_scaling_factor(const Vec3d& scaling_factor) { m_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
void set_scaling_factor(Axis axis, double scaling_factor) { m_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_scaling_factor(const Vec3d& scaling_factor) { m_instance_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_scaling_factor(Axis axis, double scaling_factor) { m_instance_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
const Vec3d& get_mirror() const { return m_transformation.get_mirror(); }
|
||||
double get_mirror(Axis axis) const { return m_transformation.get_mirror(axis); }
|
||||
const Vec3d& get_instance_mirror() const { return m_instance_transformation.get_mirror(); }
|
||||
double get_instance_mirror(Axis axis) const { return m_instance_transformation.get_mirror(axis); }
|
||||
|
||||
void set_mirror(const Vec3d& mirror) { m_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
|
||||
void set_mirror(Axis axis, double mirror) { m_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_mirror(const Vec3d& mirror) { m_instance_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
|
||||
void set_instance_mirror(Axis axis, double mirror) { m_instance_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
const Geometry::Transformation& get_volume_transformation() const { return m_volume_transformation; }
|
||||
void set_volume_transformation(const Geometry::Transformation& transformation) { m_volume_transformation = transformation; set_bounding_boxes_as_dirty(); }
|
||||
|
||||
const Vec3d& get_volume_offset() const { return m_volume_transformation.get_offset(); }
|
||||
double get_volume_offset(Axis axis) const { return m_volume_transformation.get_offset(axis); }
|
||||
|
||||
void set_volume_offset(const Vec3d& offset) { m_volume_transformation.set_offset(offset); set_bounding_boxes_as_dirty(); }
|
||||
void set_volume_offset(Axis axis, double offset) { m_volume_transformation.set_offset(axis, offset); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
const Vec3d& get_volume_rotation() const { return m_volume_transformation.get_rotation(); }
|
||||
double get_volume_rotation(Axis axis) const { return m_volume_transformation.get_rotation(axis); }
|
||||
|
||||
void set_volume_rotation(const Vec3d& rotation) { m_volume_transformation.set_rotation(rotation); set_bounding_boxes_as_dirty(); }
|
||||
void set_volume_rotation(Axis axis, double rotation) { m_volume_transformation.set_rotation(axis, rotation); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
Vec3d get_volume_scaling_factor() const { return m_volume_transformation.get_scaling_factor(); }
|
||||
double get_volume_scaling_factor(Axis axis) const { return m_volume_transformation.get_scaling_factor(axis); }
|
||||
|
||||
void set_volume_scaling_factor(const Vec3d& scaling_factor) { m_volume_transformation.set_scaling_factor(scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
void set_volume_scaling_factor(Axis axis, double scaling_factor) { m_volume_transformation.set_scaling_factor(axis, scaling_factor); set_bounding_boxes_as_dirty(); }
|
||||
|
||||
const Vec3d& get_volume_mirror() const { return m_volume_transformation.get_mirror(); }
|
||||
double get_volume_mirror(Axis axis) const { return m_volume_transformation.get_mirror(axis); }
|
||||
|
||||
void set_volume_mirror(const Vec3d& mirror) { m_volume_transformation.set_mirror(mirror); set_bounding_boxes_as_dirty(); }
|
||||
void set_volume_mirror(Axis axis, double mirror) { m_volume_transformation.set_mirror(axis, mirror); set_bounding_boxes_as_dirty(); }
|
||||
#else
|
||||
const Vec3d& get_rotation() const;
|
||||
void set_rotation(const Vec3d& rotation);
|
||||
|
|
@ -378,7 +409,7 @@ public:
|
|||
int instance_idx() const { return this->composite_id % 1000; }
|
||||
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
const Transform3d& world_matrix() const { return m_transformation.get_matrix(); }
|
||||
Transform3d world_matrix() const { return m_instance_transformation.get_matrix() * m_volume_transformation.get_matrix(); }
|
||||
#else
|
||||
const Transform3f& world_matrix() const;
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "BackgroundSlicingProcess.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
|
||||
#include <wx/app.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/stdpaths.h>
|
||||
|
|
@ -103,6 +104,15 @@ void BackgroundSlicingProcess::thread_proc()
|
|||
// End of the background processing thread. The UI thread should join m_thread now.
|
||||
}
|
||||
|
||||
void BackgroundSlicingProcess::thread_proc_safe()
|
||||
{
|
||||
try {
|
||||
this->thread_proc();
|
||||
} catch (...) {
|
||||
wxTheApp->OnUnhandledException();
|
||||
}
|
||||
}
|
||||
|
||||
void BackgroundSlicingProcess::join_background_thread()
|
||||
{
|
||||
std::unique_lock<std::mutex> lck(m_mutex);
|
||||
|
|
@ -127,7 +137,7 @@ bool BackgroundSlicingProcess::start()
|
|||
if (m_state == STATE_INITIAL) {
|
||||
// The worker thread is not running yet. Start it.
|
||||
assert(! m_thread.joinable());
|
||||
m_thread = std::thread([this]{this->thread_proc();});
|
||||
m_thread = std::thread([this]{this->thread_proc_safe();});
|
||||
// Wait until the worker thread is ready to execute the background processing task.
|
||||
m_condition.wait(lck, [this](){ return m_state == STATE_IDLE; });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ public:
|
|||
|
||||
private:
|
||||
void thread_proc();
|
||||
void thread_proc_safe();
|
||||
void join_background_thread();
|
||||
// To be called by Print::apply() through the Print::m_cancel_callback to stop the background
|
||||
// processing before changing any data of running or finalized milestones.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -358,9 +358,14 @@ public:
|
|||
|
||||
enum EMode : unsigned char
|
||||
{
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
Volume,
|
||||
Instance
|
||||
#else
|
||||
Volume,
|
||||
Instance,
|
||||
Object
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
};
|
||||
|
||||
enum EType : unsigned char
|
||||
|
|
@ -368,9 +373,13 @@ public:
|
|||
Invalid,
|
||||
Empty,
|
||||
WipeTower,
|
||||
Modifier,
|
||||
SingleModifier,
|
||||
MultipleModifier,
|
||||
SingleVolume,
|
||||
MultipleVolume,
|
||||
SingleFullObject,
|
||||
SingleFullInstance,
|
||||
MultipleFullInstance,
|
||||
Mixed
|
||||
};
|
||||
|
||||
|
|
@ -378,21 +387,57 @@ public:
|
|||
struct VolumeCache
|
||||
{
|
||||
private:
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
struct TransformCache
|
||||
{
|
||||
Vec3d position;
|
||||
Vec3d rotation;
|
||||
Vec3d scaling_factor;
|
||||
Transform3d rotation_matrix;
|
||||
Transform3d scale_matrix;
|
||||
|
||||
TransformCache();
|
||||
explicit TransformCache(const Geometry::Transformation& transform);
|
||||
};
|
||||
|
||||
TransformCache m_volume;
|
||||
TransformCache m_instance;
|
||||
#else
|
||||
Vec3d m_position;
|
||||
Vec3d m_rotation;
|
||||
Vec3d m_scaling_factor;
|
||||
Transform3d m_rotation_matrix;
|
||||
Transform3d m_scale_matrix;
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
||||
public:
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
VolumeCache() {}
|
||||
VolumeCache(const Geometry::Transformation& volume_transform, const Geometry::Transformation& instance_transform);
|
||||
#else
|
||||
VolumeCache();
|
||||
VolumeCache(const Vec3d& position, const Vec3d& rotation, const Vec3d& scaling_factor);
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
const Vec3d& get_volume_position() const { return m_volume.position; }
|
||||
const Vec3d& get_volume_rotation() const { return m_volume.rotation; }
|
||||
const Vec3d& get_volume_scaling_factor() const { return m_volume.scaling_factor; }
|
||||
const Transform3d& get_volume_rotation_matrix() const { return m_volume.rotation_matrix; }
|
||||
const Transform3d& get_volume_scale_matrix() const { return m_volume.scale_matrix; }
|
||||
|
||||
const Vec3d& get_instance_position() const { return m_instance.position; }
|
||||
const Vec3d& get_instance_rotation() const { return m_instance.rotation; }
|
||||
const Vec3d& get_instance_scaling_factor() const { return m_instance.scaling_factor; }
|
||||
const Transform3d& get_instance_rotation_matrix() const { return m_instance.rotation_matrix; }
|
||||
const Transform3d& get_instance_scale_matrix() const { return m_instance.scale_matrix; }
|
||||
#else
|
||||
const Vec3d& get_position() const { return m_position; }
|
||||
const Vec3d& get_rotation() const { return m_rotation; }
|
||||
const Vec3d& get_scaling_factor() const { return m_scaling_factor; }
|
||||
const Transform3d& get_rotation_matrix() const { return m_rotation_matrix; }
|
||||
const Transform3d& get_scale_matrix() const { return m_scale_matrix; }
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
};
|
||||
|
||||
typedef std::map<unsigned int, VolumeCache> VolumesCache;
|
||||
|
|
@ -435,14 +480,14 @@ public:
|
|||
void add_instance(unsigned int object_idx, unsigned int instance_idx, bool as_single_selection = true);
|
||||
void remove_instance(unsigned int object_idx, unsigned int instance_idx);
|
||||
|
||||
void add_volume(unsigned int object_idx, unsigned int volume_idx, bool as_single_selection = true);
|
||||
void add_volume(unsigned int object_idx, unsigned int volume_idx, int instance_idx, bool as_single_selection = true);
|
||||
void remove_volume(unsigned int object_idx, unsigned int volume_idx);
|
||||
|
||||
void clear();
|
||||
|
||||
bool is_empty() const { return m_type == Empty; }
|
||||
bool is_wipe_tower() const { return m_type == WipeTower; }
|
||||
bool is_modifier() const { return m_type == Modifier; }
|
||||
bool is_modifier() const { return (m_type == SingleModifier) || (m_type == MultipleModifier); }
|
||||
bool is_single_full_instance() const;
|
||||
bool is_single_full_object() const { return m_type == SingleFullObject; }
|
||||
bool is_mixed() const { return m_type == Mixed; }
|
||||
|
|
@ -455,6 +500,9 @@ public:
|
|||
int get_object_idx() const;
|
||||
// Returns the instance id if the selection is from a single object and from a single instance, otherwise is -1
|
||||
int get_instance_idx() const;
|
||||
// Returns the indices of selected instances.
|
||||
// Can only be called if selection is from a single object.
|
||||
const InstanceIdxsList& get_instance_idxs() const;
|
||||
|
||||
const IndicesList& get_volume_idxs() const { return m_list; }
|
||||
const GLVolume* get_volume(unsigned int volume_idx) const;
|
||||
|
|
@ -466,13 +514,14 @@ public:
|
|||
|
||||
void translate(const Vec3d& displacement);
|
||||
void rotate(const Vec3d& rotation);
|
||||
void flattening_rotate(const Vec3d& normal);
|
||||
void scale(const Vec3d& scale);
|
||||
void mirror(Axis axis);
|
||||
|
||||
void translate(unsigned int object_idx, const Vec3d& displacement);
|
||||
void translate(unsigned int object_idx, unsigned int instance_idx, const Vec3d& displacement);
|
||||
|
||||
void render(bool show_indirect_selection) const;
|
||||
void render() const;
|
||||
|
||||
private:
|
||||
void _update_valid();
|
||||
|
|
@ -486,9 +535,10 @@ public:
|
|||
void _remove_object(unsigned int object_idx);
|
||||
void _calc_bounding_box() const;
|
||||
void _render_selected_volumes() const;
|
||||
void _render_unselected_instances() const;
|
||||
void _render_synchronized_volumes() const;
|
||||
void _render_bounding_box(const BoundingBoxf3& box, float* color) const;
|
||||
void _synchronize_unselected_instances();
|
||||
void _synchronize_unselected_volumes();
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
@ -556,7 +606,7 @@ private:
|
|||
Vec3d get_rotation() const;
|
||||
void set_rotation(const Vec3d& rotation);
|
||||
|
||||
Vec3d get_flattening_rotation() const;
|
||||
Vec3d get_flattening_normal() const;
|
||||
|
||||
void set_flattening_data(const ModelObject* model_object);
|
||||
|
||||
|
|
|
|||
|
|
@ -720,7 +720,11 @@ void GLGizmoScale3D::on_process_double_click()
|
|||
void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
|
||||
{
|
||||
bool single_instance = selection.is_single_full_instance();
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
Vec3f scale = single_instance ? 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_instance_scaling_factor().cast<float>() : 100.0f * m_scale.cast<float>();
|
||||
#else
|
||||
Vec3f scale = single_instance ? 100.0f * selection.get_volume(*selection.get_volume_idxs().begin())->get_scaling_factor().cast<float>() : 100.0f * m_scale.cast<float>();
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
||||
if ((single_instance && ((m_hover_id == 0) || (m_hover_id == 1))) || m_grabbers[0].dragging || m_grabbers[1].dragging)
|
||||
set_tooltip("X: " + format(scale(0), 4) + "%");
|
||||
|
|
@ -762,10 +766,18 @@ void GLGizmoScale3D::on_render(const GLCanvas3D::Selection& selection) const
|
|||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
||||
// gets angles from first selected volume
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
angles = v->get_instance_rotation();
|
||||
#else
|
||||
angles = v->get_rotation();
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
||||
// consider rotation+mirror only components of the transform for offsets
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_instance_mirror());
|
||||
#else
|
||||
offsets_transform = Geometry::assemble_transform(Vec3d::Zero(), angles, Vec3d::Ones(), v->get_mirror());
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
}
|
||||
else
|
||||
box = selection.get_bounding_box();
|
||||
|
|
@ -1165,38 +1177,41 @@ void GLGizmoFlatten::on_start_dragging(const GLCanvas3D::Selection& selection)
|
|||
|
||||
void GLGizmoFlatten::on_render(const GLCanvas3D::Selection& selection) const
|
||||
{
|
||||
// the dragged_offset is a vector measuring where was the object moved
|
||||
// with the gizmo being on. This is reset in set_flattening_data and
|
||||
// does not work correctly when there are multiple copies.
|
||||
// The planes are rendered incorrectly when the object is being moved. We better won't render anything in that case.
|
||||
// This indeed has a better solution (to be implemented when there is more time)
|
||||
Vec3d dragged_offset(Vec3d::Zero());
|
||||
if (m_starting_center == Vec3d::Zero())
|
||||
m_starting_center = selection.get_bounding_box().center();
|
||||
dragged_offset = selection.get_bounding_box().center() - m_starting_center;
|
||||
if (dragged_offset.norm() > 0.001)
|
||||
return;
|
||||
|
||||
::glEnable(GL_BLEND);
|
||||
::glEnable(GL_DEPTH_TEST);
|
||||
::glDisable(GL_CULL_FACE);
|
||||
|
||||
for (int i=0; i<(int)m_planes.size(); ++i) {
|
||||
if (i == m_hover_id)
|
||||
::glColor4f(0.9f, 0.9f, 0.9f, 0.75f);
|
||||
else
|
||||
::glColor4f(0.9f, 0.9f, 0.9f, 0.5f);
|
||||
if (selection.is_from_single_object()) {
|
||||
const std::set<int>& instances_list = selection.get_instance_idxs();
|
||||
|
||||
int instance_idx = selection.get_instance_idx();
|
||||
if ((instance_idx != -1) && (m_model_object != nullptr))
|
||||
{
|
||||
if (!instances_list.empty() && m_model_object) {
|
||||
for (const int instance_idx : instances_list) {
|
||||
Transform3d m = m_model_object->instances[instance_idx]->get_matrix();
|
||||
m.pretranslate(dragged_offset);
|
||||
::glPushMatrix();
|
||||
::glMultMatrixd(m.data());
|
||||
::glBegin(GL_POLYGON);
|
||||
for (const Vec3d& vertex : m_planes[i].vertices)
|
||||
{
|
||||
::glVertex3dv(vertex.data());
|
||||
for (int i=0; i<(int)m_planes.size(); ++i) {
|
||||
if (i == m_hover_id)
|
||||
::glColor4f(0.9f, 0.9f, 0.9f, 0.75f);
|
||||
else
|
||||
::glColor4f(0.9f, 0.9f, 0.9f, 0.5f);
|
||||
|
||||
m.pretranslate(dragged_offset);
|
||||
::glPushMatrix();
|
||||
::glMultMatrixd(m.data());
|
||||
::glBegin(GL_POLYGON);
|
||||
for (const Vec3d& vertex : m_planes[i].vertices)
|
||||
::glVertex3dv(vertex.data());
|
||||
::glEnd();
|
||||
::glPopMatrix();
|
||||
}
|
||||
}
|
||||
::glEnd();
|
||||
::glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1208,22 +1223,21 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio
|
|||
{
|
||||
::glEnable(GL_DEPTH_TEST);
|
||||
::glDisable(GL_CULL_FACE);
|
||||
|
||||
for (unsigned int i = 0; i < m_planes.size(); ++i)
|
||||
{
|
||||
::glColor3f(1.0f, 1.0f, picking_color_component(i));
|
||||
int instance_idx = selection.get_instance_idx();
|
||||
if ((instance_idx != -1) && (m_model_object != nullptr))
|
||||
{
|
||||
::glPushMatrix();
|
||||
::glMultMatrixd(m_model_object->instances[instance_idx]->get_matrix().data());
|
||||
::glBegin(GL_POLYGON);
|
||||
for (const Vec3d& vertex : m_planes[i].vertices)
|
||||
{
|
||||
::glVertex3dv(vertex.data());
|
||||
if (selection.is_from_single_object()) {
|
||||
const std::set<int>& instances_list = selection.get_instance_idxs();
|
||||
if (!instances_list.empty() && m_model_object) {
|
||||
for (const int instance_idx : instances_list) {
|
||||
for (int i=0; i<(int)m_planes.size(); ++i) {
|
||||
::glColor3f(1.0f, 1.0f, picking_color_component(i));
|
||||
::glPushMatrix();
|
||||
::glMultMatrixd(m_model_object->instances[instance_idx]->get_matrix().data());
|
||||
::glBegin(GL_POLYGON);
|
||||
for (const Vec3d& vertex : m_planes[i].vertices)
|
||||
::glVertex3dv(vertex.data());
|
||||
::glEnd();
|
||||
::glPopMatrix();
|
||||
}
|
||||
}
|
||||
::glEnd();
|
||||
::glPopMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1233,9 +1247,10 @@ void GLGizmoFlatten::on_render_for_picking(const GLCanvas3D::Selection& selectio
|
|||
void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object)
|
||||
{
|
||||
m_starting_center = Vec3d::Zero();
|
||||
bool object_changed = m_model_object != model_object;
|
||||
m_model_object = model_object;
|
||||
|
||||
if (is_plane_update_necessary())
|
||||
if (object_changed && is_plane_update_necessary())
|
||||
update_planes();
|
||||
}
|
||||
|
||||
|
|
@ -1243,7 +1258,15 @@ void GLGizmoFlatten::update_planes()
|
|||
{
|
||||
TriangleMesh ch;
|
||||
for (const ModelVolume* vol : m_model_object->volumes)
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
{
|
||||
TriangleMesh vol_ch = vol->get_convex_hull();
|
||||
vol_ch.transform(vol->get_matrix());
|
||||
ch.merge(vol_ch);
|
||||
}
|
||||
#else
|
||||
ch.merge(vol->get_convex_hull());
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
||||
ch = ch.convex_hull_3d();
|
||||
|
||||
|
|
@ -1438,20 +1461,14 @@ bool GLGizmoFlatten::is_plane_update_necessary() const
|
|||
return false;
|
||||
}
|
||||
|
||||
Vec3d GLGizmoFlatten::get_flattening_rotation() const
|
||||
Vec3d GLGizmoFlatten::get_flattening_normal() const
|
||||
{
|
||||
// calculates the rotations in model space, taking in account the scaling factors
|
||||
Eigen::Matrix<double, 3, 3, Eigen::DontAlign> m = m_model_object->instances.front()->get_matrix(true, true).matrix().block(0, 0, 3, 3).inverse().transpose();
|
||||
Eigen::Quaterniond q;
|
||||
Vec3d angles = Geometry::extract_euler_angles(q.setFromTwoVectors(m * m_normal, -Vec3d::UnitZ()).toRotationMatrix());
|
||||
Vec3d out = m_normal;
|
||||
m_normal = Vec3d::Zero();
|
||||
m_starting_center = Vec3d::Zero();
|
||||
return angles;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
GLGizmoSlaSupports::GLGizmoSlaSupports(GLCanvas3D& parent)
|
||||
: GLGizmoBase(parent), m_starting_center(Vec3d::Zero())
|
||||
{
|
||||
|
|
@ -1478,11 +1495,14 @@ bool GLGizmoSlaSupports::on_init()
|
|||
|
||||
void GLGizmoSlaSupports::set_model_object_ptr(ModelObject* model_object)
|
||||
{
|
||||
m_starting_center = Vec3d::Zero();
|
||||
m_model_object = model_object;
|
||||
m_model_object_matrix = model_object->instances.front()->get_matrix();
|
||||
if (is_mesh_update_necessary())
|
||||
update_mesh();
|
||||
if (model_object != nullptr)
|
||||
{
|
||||
m_starting_center = Vec3d::Zero();
|
||||
m_model_object = model_object;
|
||||
m_model_object_matrix = model_object->instances.front()->get_matrix();
|
||||
if (is_mesh_update_necessary())
|
||||
update_mesh();
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoSlaSupports::on_render(const GLCanvas3D::Selection& selection) const
|
||||
|
|
|
|||
|
|
@ -359,6 +359,7 @@ private:
|
|||
std::vector<PlaneData> m_planes;
|
||||
mutable Vec3d m_starting_center;
|
||||
const ModelObject* m_model_object = nullptr;
|
||||
std::vector<const Transform3d*> instances_matrices;
|
||||
|
||||
void update_planes();
|
||||
bool is_plane_update_necessary() const;
|
||||
|
|
@ -367,12 +368,12 @@ public:
|
|||
explicit GLGizmoFlatten(GLCanvas3D& parent);
|
||||
|
||||
void set_flattening_data(const ModelObject* model_object);
|
||||
Vec3d get_flattening_rotation() const;
|
||||
Vec3d get_flattening_normal() const;
|
||||
|
||||
protected:
|
||||
virtual bool on_init();
|
||||
virtual std::string on_get_name() const;
|
||||
virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return selection.is_single_full_instance(); }
|
||||
virtual bool on_is_activable(const GLCanvas3D::Selection& selection) const { return (selection.is_from_single_object() && !selection.is_wipe_tower() && !selection.is_modifier()); }
|
||||
virtual void on_start_dragging(const GLCanvas3D::Selection& selection);
|
||||
virtual void on_update(const Linef3& mouse_ray, const Point* mouse_pos) {}
|
||||
virtual void on_render(const GLCanvas3D::Selection& selection) const;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ enum ConfigMenuIDs {
|
|||
|
||||
class Tab;
|
||||
|
||||
static wxString dots("…", wxConvUTF8);
|
||||
static wxString dots("…", wxConvUTF8);
|
||||
|
||||
class GUI_App : public wxApp
|
||||
{
|
||||
|
|
|
|||
|
|
@ -36,11 +36,11 @@ ObjectList::ObjectList(wxWindow* parent) :
|
|||
CATEGORY_ICON[L("Advanced")] = wxBitmap(from_u8(var("wand.png")), wxBITMAP_TYPE_PNG);
|
||||
}
|
||||
|
||||
init_icons();
|
||||
|
||||
// create control
|
||||
create_objects_ctrl();
|
||||
|
||||
init_icons();
|
||||
|
||||
// describe control behavior
|
||||
Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxEvent& event) {
|
||||
selection_changed();
|
||||
|
|
@ -213,17 +213,27 @@ void ObjectList::update_extruder_in_config(const wxString& selection)
|
|||
|
||||
void ObjectList::init_icons()
|
||||
{
|
||||
m_bmp_modifiermesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
|
||||
m_bmp_solidmesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
|
||||
m_bmp_modifiermesh = wxBitmap(from_u8(var("lambda.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("plugin.png")), wxBITMAP_TYPE_PNG);
|
||||
m_bmp_solidmesh = wxBitmap(from_u8(var("object.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("package.png")), wxBITMAP_TYPE_PNG);
|
||||
|
||||
m_bmp_support_enforcer = wxBitmap(from_u8(var("support_enforcer_.png")), wxBITMAP_TYPE_PNG);
|
||||
m_bmp_support_blocker = wxBitmap(from_u8(var("support_blocker_.png")), wxBITMAP_TYPE_PNG);
|
||||
|
||||
m_bmp_vector.reserve(4); // bitmaps for different types of parts
|
||||
m_bmp_vector.push_back(&m_bmp_solidmesh); // Add part
|
||||
m_bmp_vector.push_back(&m_bmp_modifiermesh); // Add modifier
|
||||
m_bmp_vector.push_back(&m_bmp_support_enforcer); // Add support enforcer
|
||||
m_bmp_vector.push_back(&m_bmp_support_blocker); // Add support blocker
|
||||
m_objects_model->SetVolumeBitmaps(m_bmp_vector);
|
||||
|
||||
// init icon for manifold warning
|
||||
m_bmp_manifold_warning = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
|
||||
m_bmp_manifold_warning = wxBitmap(from_u8(var("exclamation_mark_.png")), wxBITMAP_TYPE_PNG);//(Slic3r::var("error.png")), wxBITMAP_TYPE_PNG);
|
||||
|
||||
// init bitmap for "Split to sub-objects" context menu
|
||||
m_bmp_split = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("split.png")), wxBITMAP_TYPE_PNG);
|
||||
m_bmp_split = wxBitmap(from_u8(var("split.png")), wxBITMAP_TYPE_PNG);
|
||||
|
||||
// init bitmap for "Add Settings" context menu
|
||||
m_bmp_cog = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("cog.png")), wxBITMAP_TYPE_PNG);
|
||||
m_bmp_cog = wxBitmap(from_u8(var("cog.png")), wxBITMAP_TYPE_PNG);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -377,7 +387,8 @@ void ObjectList::on_drop(wxDataViewEvent &event)
|
|||
wxDataViewItem item(event.GetItem());
|
||||
|
||||
// only allow drops for item, not containers
|
||||
if (item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) ||
|
||||
if (m_selected_object_id < 0 ||
|
||||
item.IsOk() && m_objects_model->GetParent(item) == wxDataViewItem(0) ||
|
||||
event.GetDataFormat() != wxDF_UNICODETEXT || m_objects_model->GetItemType(item) != itVolume) {
|
||||
event.Veto();
|
||||
return;
|
||||
|
|
@ -518,16 +529,24 @@ void ObjectList::get_settings_choice(wxMenu *menu, int id, bool is_part)
|
|||
wxGetApp().obj_manipul()->update_settings_list();
|
||||
}
|
||||
|
||||
void ObjectList::menu_item_add_generic(wxMenuItem* &menu, int id) {
|
||||
void ObjectList::menu_item_add_generic(wxMenuItem* &menu, int id, const int type) {
|
||||
auto sub_menu = new wxMenu;
|
||||
|
||||
const wxString menu_load = _(L("Load")) +" "+ dots;
|
||||
sub_menu->Append(new wxMenuItem(sub_menu, id++, menu_load));
|
||||
sub_menu->AppendSeparator();
|
||||
|
||||
std::vector<std::string> menu_items = { L("Box"), L("Cylinder"), L("Sphere"), L("Slab") };
|
||||
for (auto& item : menu_items)
|
||||
sub_menu->Append(new wxMenuItem(sub_menu, ++id, _(item)));
|
||||
sub_menu->Append(new wxMenuItem(sub_menu, id++, _(item)));
|
||||
|
||||
#ifndef __WXMSW__
|
||||
sub_menu->Bind(wxEVT_MENU, [this, sub_menu](wxEvent &event) {
|
||||
load_lambda(sub_menu->GetLabel(event.GetId()).ToStdString());
|
||||
sub_menu->Bind(wxEVT_MENU, [sub_menu, type, menu_load, this](wxEvent &event) {
|
||||
auto selection = sub_menu->GetLabel(event.GetId());
|
||||
if (selection == menu_load)
|
||||
load_subobject(type);
|
||||
else
|
||||
load_generic_subobject(selection.ToStdString(), type);
|
||||
});
|
||||
#endif //no __WXMSW__
|
||||
|
||||
|
|
@ -552,55 +571,53 @@ wxMenuItem* ObjectList::menu_item_settings(wxMenu* menu, int id, const bool is_p
|
|||
wxMenu* ObjectList::create_add_part_popupmenu()
|
||||
{
|
||||
wxMenu *menu = new wxMenu;
|
||||
std::vector<std::string> menu_items = { L("Add part"), L("Add modifier"), L("Add generic") };
|
||||
// Note: id accords to type of the sub-object, so sequence of the menu items is important
|
||||
std::vector<std::string> menu_object_types_items = {L("Add part"), // ~ModelVolume::MODEL_PART
|
||||
L("Add modifier"), // ~ModelVolume::PARAMETER_MODIFIER
|
||||
L("Add support enforcer"), // ~ModelVolume::SUPPORT_ENFORCER
|
||||
L("Add support bloker") }; // ~ModelVolume::SUPPORT_BLOCKER
|
||||
|
||||
const int obj_types_count = menu_object_types_items.size();
|
||||
const int generics_count = 5; // "Load ...", "Box", "Cylinder", "Sphere", "Slab"
|
||||
|
||||
wxWindowID config_id_base = wxWindow::NewControlId(menu_items.size() + 4 + 2);
|
||||
wxWindowID config_id_base = NewControlId(generics_count*obj_types_count + 2);
|
||||
|
||||
int i = 0;
|
||||
for (auto& item : menu_items) {
|
||||
auto menu_item = new wxMenuItem(menu, config_id_base + i, _(item));
|
||||
menu_item->SetBitmap(i == 0 ? m_bmp_solidmesh : m_bmp_modifiermesh);
|
||||
if (item == "Add generic")
|
||||
menu_item_add_generic(menu_item, config_id_base + i);
|
||||
// Add first 4 menu items
|
||||
for (int type = 0; type < obj_types_count; type++) {
|
||||
auto& item = menu_object_types_items[type];
|
||||
auto menu_item = new wxMenuItem(menu, config_id_base + type, _(item));
|
||||
menu_item->SetBitmap(*m_bmp_vector[type]);
|
||||
menu_item_add_generic(menu_item, config_id_base + type*generics_count, type);
|
||||
menu->Append(menu_item);
|
||||
i++;
|
||||
}
|
||||
|
||||
// Split object to parts
|
||||
menu->AppendSeparator();
|
||||
auto menu_item = menu_item_split(menu, config_id_base + i + 4);
|
||||
auto menu_item = menu_item_split(menu, config_id_base + obj_types_count * generics_count);
|
||||
menu->Append(menu_item);
|
||||
menu_item->Enable(is_splittable_object(false));
|
||||
|
||||
// Settings
|
||||
menu->AppendSeparator();
|
||||
// Append settings popupmenu
|
||||
menu->Append(menu_item_settings(menu, config_id_base + i + 5, false));
|
||||
menu->Append(menu_item_settings(menu, config_id_base + obj_types_count * generics_count+1, false));
|
||||
|
||||
menu->Bind(wxEVT_MENU, [config_id_base, menu, this](wxEvent &event) {
|
||||
switch (event.GetId() - config_id_base) {
|
||||
case 0:
|
||||
load_subobject();
|
||||
break;
|
||||
case 1:
|
||||
load_subobject(true);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
#ifdef __WXMSW__
|
||||
load_lambda(menu->GetLabel(event.GetId()).ToStdString());
|
||||
#endif // __WXMSW__
|
||||
break;
|
||||
case 7: //3:
|
||||
menu->Bind(wxEVT_MENU, [config_id_base, menu, obj_types_count, generics_count, this](wxEvent &event) {
|
||||
auto selection = event.GetId() - config_id_base;
|
||||
|
||||
if ( selection == 0 * generics_count || // ~ModelVolume::MODEL_PART
|
||||
selection == 1 * generics_count || // ~ModelVolume::PARAMETER_MODIFIER
|
||||
selection == 2 * generics_count || // ~ModelVolume::SUPPORT_ENFORCER
|
||||
selection == 3 * generics_count ) // ~ModelVolume::SUPPORT_BLOCKER
|
||||
load_subobject(int(selection / generics_count));
|
||||
else if ( selection == obj_types_count * generics_count)
|
||||
split(false);
|
||||
break;
|
||||
default:
|
||||
#ifdef __WXMSW__
|
||||
else if ( selection > obj_types_count * generics_count) // "Add Settings" is selected
|
||||
get_settings_choice(menu, event.GetId(), false);
|
||||
else // Some generic model is selected
|
||||
load_generic_subobject(menu->GetLabel(event.GetId()).ToStdString(), int(selection / generics_count));
|
||||
#endif // __WXMSW__
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return menu;
|
||||
|
|
@ -609,24 +626,33 @@ wxMenu* ObjectList::create_add_part_popupmenu()
|
|||
wxMenu* ObjectList::create_part_settings_popupmenu()
|
||||
{
|
||||
wxMenu *menu = new wxMenu;
|
||||
wxWindowID config_id_base = wxWindow::NewControlId(2);
|
||||
wxWindowID config_id_base = NewControlId(3);
|
||||
|
||||
auto menu_item = menu_item_split(menu, config_id_base);
|
||||
menu->Append(menu_item);
|
||||
menu_item->Enable(is_splittable_object(true));
|
||||
|
||||
// Append change part type
|
||||
menu->AppendSeparator();
|
||||
menu->Append(new wxMenuItem(menu, config_id_base + 1, _(L("Change type"))));
|
||||
|
||||
// Append settings popupmenu
|
||||
menu->Append(menu_item_settings(menu, config_id_base + 1, true));
|
||||
menu->AppendSeparator();
|
||||
menu_item = menu_item_settings(menu, config_id_base + 2, true);
|
||||
menu->Append(menu_item);
|
||||
menu_item->Enable(get_selected_model_volume()->type() <= ModelVolume::PARAMETER_MODIFIER);
|
||||
|
||||
menu->Bind(wxEVT_MENU, [config_id_base, menu, this](wxEvent &event) {
|
||||
switch (event.GetId() - config_id_base) {
|
||||
case 0:
|
||||
split(true);
|
||||
break;
|
||||
default:{
|
||||
case 1:
|
||||
change_part_type();
|
||||
break;
|
||||
default:
|
||||
get_settings_choice(menu, event.GetId(), true);
|
||||
break; }
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -655,31 +681,21 @@ wxMenu* ObjectList::create_add_settings_popupmenu(bool is_part)
|
|||
return menu;
|
||||
}
|
||||
|
||||
|
||||
// Load SubObjects (parts and modifiers)
|
||||
void ObjectList::load_subobject(bool is_modifier /*= false*/, bool is_lambda/* = false*/)
|
||||
void ObjectList::load_subobject(int type)
|
||||
{
|
||||
auto item = GetSelection();
|
||||
if (!item)
|
||||
return;
|
||||
int obj_idx = -1;
|
||||
if (m_objects_model->GetParent(item) == wxDataViewItem(0))
|
||||
obj_idx = m_objects_model->GetIdByItem(item);
|
||||
else
|
||||
if (!item || m_objects_model->GetParent(item) != wxDataViewItem(0))
|
||||
return;
|
||||
int obj_idx = m_objects_model->GetIdByItem(item);
|
||||
|
||||
if (obj_idx < 0) return;
|
||||
wxArrayString part_names;
|
||||
if (is_lambda)
|
||||
load_lambda((*m_objects)[obj_idx], part_names, is_modifier);
|
||||
else
|
||||
load_part((*m_objects)[obj_idx], part_names, is_modifier);
|
||||
load_part((*m_objects)[obj_idx], part_names, type);
|
||||
|
||||
parts_changed(obj_idx);
|
||||
|
||||
for (int i = 0; i < part_names.size(); ++i) {
|
||||
const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i),
|
||||
is_modifier ? m_bmp_modifiermesh : m_bmp_solidmesh);
|
||||
const wxDataViewItem sel_item = m_objects_model->AddVolumeChild(item, part_names.Item(i), /**m_bmp_vector[*/type/*]*/);
|
||||
|
||||
if (i == part_names.size() - 1)
|
||||
select_item(sel_item);
|
||||
|
|
@ -688,11 +704,12 @@ void ObjectList::load_subobject(bool is_modifier /*= false*/, bool is_lambda/* =
|
|||
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
|
||||
// selection_changed();
|
||||
#endif //no __WXOSX__//__WXMSW__
|
||||
|
||||
}
|
||||
|
||||
void ObjectList::load_part( ModelObject* model_object,
|
||||
wxArrayString& part_names,
|
||||
const bool is_modifier)
|
||||
int type)
|
||||
{
|
||||
wxWindow* parent = wxGetApp().tab_panel()->GetPage(0);
|
||||
|
||||
|
|
@ -717,19 +734,27 @@ void ObjectList::load_part( ModelObject* model_object,
|
|||
if (model_object->origin_translation != Vec3d::Zero())
|
||||
{
|
||||
object->center_around_origin();
|
||||
#if !ENABLE_MODELVOLUME_TRANSFORM
|
||||
object->ensure_on_bed();
|
||||
#endif // !ENABLE_MODELVOLUME_TRANSFORM
|
||||
delta = model_object->origin_translation - object->origin_translation;
|
||||
}
|
||||
for (auto volume : object->volumes) {
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
Vec3d shift = volume->mesh.bounding_box().center();
|
||||
volume->translate_geometry(-shift);
|
||||
volume->translate(delta + shift);
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
auto new_volume = model_object->add_volume(*volume);
|
||||
new_volume->set_type(is_modifier ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART);
|
||||
boost::filesystem::path(input_file).filename().string();
|
||||
new_volume->set_type(static_cast<ModelVolume::Type>(type));
|
||||
new_volume->name = boost::filesystem::path(input_file).filename().string();
|
||||
|
||||
part_names.Add(new_volume->name);
|
||||
|
||||
#if !ENABLE_MODELVOLUME_TRANSFORM
|
||||
if (delta != Vec3d::Zero())
|
||||
new_volume->translate(delta);
|
||||
#endif // !ENABLE_MODELVOLUME_TRANSFORM
|
||||
|
||||
// set a default extruder value, since user can't add it manually
|
||||
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||
|
|
@ -738,98 +763,46 @@ void ObjectList::load_part( ModelObject* model_object,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ObjectList::load_lambda( ModelObject* model_object,
|
||||
wxArrayString& part_names,
|
||||
const bool is_modifier)
|
||||
void ObjectList::load_generic_subobject(const std::string& type_name, const int type)
|
||||
{
|
||||
auto dlg = new LambdaObjectDialog(GetMainWindow());
|
||||
if (dlg->ShowModal() == wxID_CANCEL) {
|
||||
m_parts_changed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string name = "lambda-";
|
||||
TriangleMesh mesh;
|
||||
|
||||
auto params = dlg->ObjectParameters();
|
||||
switch (params.type)
|
||||
{
|
||||
case LambdaTypeBox:{
|
||||
mesh = make_cube(params.dim[0], params.dim[1], params.dim[2]);
|
||||
name += "Box";
|
||||
break; }
|
||||
case LambdaTypeCylinder:{
|
||||
mesh = make_cylinder(params.cyl_r, params.cyl_h);
|
||||
name += "Cylinder";
|
||||
break; }
|
||||
case LambdaTypeSphere:{
|
||||
mesh = make_sphere(params.sph_rho);
|
||||
name += "Sphere";
|
||||
break; }
|
||||
case LambdaTypeSlab:{
|
||||
const auto& size = model_object->bounding_box().size();
|
||||
mesh = make_cube(size(0)*1.5, size(1)*1.5, params.slab_h);
|
||||
// box sets the base coordinate at 0, 0, move to center of plate and move it up to initial_z
|
||||
mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, params.slab_z);
|
||||
name += "Slab";
|
||||
break; }
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mesh.repair();
|
||||
|
||||
auto new_volume = model_object->add_volume(mesh);
|
||||
new_volume->set_type(is_modifier ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART);
|
||||
|
||||
new_volume->name = name;
|
||||
// set a default extruder value, since user can't add it manually
|
||||
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||
|
||||
part_names.Add(name);
|
||||
|
||||
m_parts_changed = true;
|
||||
}
|
||||
|
||||
void ObjectList::load_lambda(const std::string& type_name)
|
||||
{
|
||||
if (m_selected_object_id < 0) return;
|
||||
|
||||
auto dlg = new LambdaObjectDialog(GetMainWindow(), type_name);
|
||||
if (dlg->ShowModal() == wxID_CANCEL)
|
||||
return;
|
||||
const auto obj_idx = get_selected_obj_idx();
|
||||
if (obj_idx < 0) return;
|
||||
|
||||
const std::string name = "lambda-" + type_name;
|
||||
TriangleMesh mesh;
|
||||
|
||||
const auto params = dlg->ObjectParameters();
|
||||
auto& bed_shape = wxGetApp().preset_bundle->printers.get_edited_preset().config.option<ConfigOptionPoints>("bed_shape")->values;
|
||||
const auto& sz = BoundingBoxf(bed_shape).size();
|
||||
const auto side = 0.1 * std::max(sz(0), sz(1));
|
||||
|
||||
if (type_name == _("Box"))
|
||||
mesh = make_cube(params.dim[0], params.dim[1], params.dim[2]);
|
||||
mesh = make_cube(side, side, side);
|
||||
else if (type_name == _("Cylinder"))
|
||||
mesh = make_cylinder(params.cyl_r, params.cyl_h);
|
||||
mesh = make_cylinder(0.5*side, side);
|
||||
else if (type_name == _("Sphere"))
|
||||
mesh = make_sphere(params.sph_rho);
|
||||
mesh = make_sphere(side, PI/18);
|
||||
else if (type_name == _("Slab")) {
|
||||
const auto& size = (*m_objects)[m_selected_object_id]->bounding_box().size();
|
||||
mesh = make_cube(size(0)*1.5, size(1)*1.5, params.slab_h);
|
||||
const auto& size = (*m_objects)[obj_idx]->bounding_box().size();
|
||||
mesh = make_cube(size(0)*1.5, size(1)*1.5, size(2)*0.5);
|
||||
// box sets the base coordinate at 0, 0, move to center of plate and move it up to initial_z
|
||||
mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, params.slab_z);
|
||||
mesh.translate(-size(0)*1.5 / 2.0, -size(1)*1.5 / 2.0, 0);
|
||||
}
|
||||
mesh.repair();
|
||||
|
||||
auto new_volume = (*m_objects)[m_selected_object_id]->add_volume(mesh);
|
||||
new_volume->set_type(ModelVolume::PARAMETER_MODIFIER);
|
||||
auto new_volume = (*m_objects)[obj_idx]->add_volume(mesh);
|
||||
new_volume->set_type(static_cast<ModelVolume::Type>(type));
|
||||
|
||||
new_volume->name = name;
|
||||
// set a default extruder value, since user can't add it manually
|
||||
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||
|
||||
m_parts_changed = true;
|
||||
parts_changed(m_selected_object_id);
|
||||
parts_changed(obj_idx);
|
||||
|
||||
select_item(m_objects_model->AddVolumeChild(GetSelection(),
|
||||
name, m_bmp_modifiermesh));
|
||||
select_item(m_objects_model->AddVolumeChild(GetSelection(), name, type));
|
||||
#ifndef __WXOSX__ //#ifdef __WXMSW__ // #ys_FIXME
|
||||
selection_changed();
|
||||
#endif //no __WXOSX__ //__WXMSW__
|
||||
|
|
@ -927,8 +900,10 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
|
|||
void ObjectList::split(const bool split_part)
|
||||
{
|
||||
const auto item = GetSelection();
|
||||
if (!item || m_selected_object_id < 0)
|
||||
const int obj_idx = get_selected_obj_idx();
|
||||
if (!item || obj_idx < 0)
|
||||
return;
|
||||
|
||||
ModelVolume* volume;
|
||||
if (!get_volume_by_item(split_part, item, volume)) return;
|
||||
DynamicPrintConfig& config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||
|
|
@ -938,52 +913,54 @@ void ObjectList::split(const bool split_part)
|
|||
return;
|
||||
}
|
||||
|
||||
auto model_object = (*m_objects)[m_selected_object_id];
|
||||
auto model_object = (*m_objects)[obj_idx];
|
||||
|
||||
if (split_part) {
|
||||
auto parent = m_objects_model->GetParent(item);
|
||||
m_objects_model->DeleteChildren(parent);
|
||||
auto parent = m_objects_model->GetTopParent(item);
|
||||
if (parent)
|
||||
m_objects_model->DeleteVolumeChildren(parent);
|
||||
else
|
||||
parent = item;
|
||||
|
||||
for (auto id = 0; id < model_object->volumes.size(); id++)
|
||||
m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name,
|
||||
model_object->volumes[id]->is_modifier() ? m_bmp_modifiermesh : m_bmp_solidmesh,
|
||||
model_object->volumes[id]->config.has("extruder") ?
|
||||
model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0,
|
||||
false);
|
||||
for (auto id = 0; id < model_object->volumes.size(); id++) {
|
||||
const auto vol_item = m_objects_model->AddVolumeChild(parent, model_object->volumes[id]->name,
|
||||
model_object->volumes[id]->is_modifier() ?
|
||||
ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART,
|
||||
model_object->volumes[id]->config.has("extruder") ?
|
||||
model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0,
|
||||
false);
|
||||
// add settings to the part, if it has those
|
||||
auto opt_keys = model_object->volumes[id]->config.keys();
|
||||
if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) {
|
||||
select_item(m_objects_model->AddSettingsChild(vol_item));
|
||||
Collapse(vol_item);
|
||||
}
|
||||
}
|
||||
|
||||
if (parent == item)
|
||||
Expand(parent);
|
||||
}
|
||||
else {
|
||||
for (auto id = 0; id < model_object->volumes.size(); id++)
|
||||
m_objects_model->AddVolumeChild(item, model_object->volumes[id]->name,
|
||||
m_bmp_solidmesh,
|
||||
model_object->volumes[id]->config.has("extruder") ?
|
||||
model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value : 0,
|
||||
false);
|
||||
Expand(item);
|
||||
}
|
||||
|
||||
m_parts_changed = true;
|
||||
parts_changed(m_selected_object_id);
|
||||
|
||||
// restores selection
|
||||
_3DScene::get_canvas(wxGetApp().canvas3D())->get_selection().add_object(m_selected_object_id);
|
||||
parts_changed(obj_idx);
|
||||
}
|
||||
|
||||
bool ObjectList::get_volume_by_item(const bool split_part, const wxDataViewItem& item, ModelVolume*& volume)
|
||||
{
|
||||
if (!item || m_selected_object_id < 0)
|
||||
auto obj_idx = get_selected_obj_idx();
|
||||
if (!item || obj_idx < 0)
|
||||
return false;
|
||||
const auto volume_id = m_objects_model->GetVolumeIdByItem(item);
|
||||
|
||||
// object is selected
|
||||
if (volume_id < 0) {
|
||||
if (split_part) return false;
|
||||
volume = (*m_objects)[m_selected_object_id]->volumes[0];
|
||||
if ( split_part || (*m_objects)[obj_idx]->volumes.size() > 1 )
|
||||
return false;
|
||||
volume = (*m_objects)[obj_idx]->volumes[0];
|
||||
}
|
||||
// volume is selected
|
||||
else
|
||||
volume = (*m_objects)[m_selected_object_id]->volumes[volume_id];
|
||||
if (volume)
|
||||
return true;
|
||||
return false;
|
||||
volume = (*m_objects)[obj_idx]->volumes[volume_id];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ObjectList::is_splittable_object(const bool split_part)
|
||||
|
|
@ -991,20 +968,14 @@ bool ObjectList::is_splittable_object(const bool split_part)
|
|||
const wxDataViewItem item = GetSelection();
|
||||
if (!item) return false;
|
||||
|
||||
wxDataViewItemArray children;
|
||||
if (!split_part && m_objects_model->GetChildren(item, children) > 0)
|
||||
return false;
|
||||
|
||||
ModelVolume* volume;
|
||||
if (!get_volume_by_item(split_part, item, volume) || !volume)
|
||||
return false;
|
||||
|
||||
TriangleMeshPtrs meshptrs = volume->mesh.split();
|
||||
bool splittable = meshptrs.size() > 1;
|
||||
for (TriangleMesh* m : meshptrs)
|
||||
{
|
||||
delete m;
|
||||
}
|
||||
for (TriangleMesh* m : meshptrs) { delete m; }
|
||||
|
||||
return splittable;
|
||||
}
|
||||
|
||||
|
|
@ -1017,7 +988,7 @@ void ObjectList::part_settings_changed()
|
|||
|
||||
void ObjectList::parts_changed(int obj_idx)
|
||||
{
|
||||
wxGetApp().plater()->changed_object(get_selected_obj_idx());
|
||||
wxGetApp().plater()->changed_object(obj_idx);
|
||||
m_parts_changed = false;
|
||||
}
|
||||
|
||||
|
|
@ -1105,19 +1076,28 @@ void ObjectList::add_object_to_list(size_t obj_idx)
|
|||
m_objects_model->SetValue(variant, item, 0);
|
||||
}
|
||||
|
||||
// add volumes to the object
|
||||
if (model_object->volumes.size() > 1) {
|
||||
for (auto id = 0; id < model_object->volumes.size(); id++)
|
||||
m_objects_model->AddVolumeChild(item,
|
||||
model_object->volumes[id]->name,
|
||||
m_bmp_solidmesh,
|
||||
ModelVolume::MODEL_PART,
|
||||
model_object->volumes[id]->config.option<ConfigOptionInt>("extruder")->value,
|
||||
false);
|
||||
Expand(item);
|
||||
}
|
||||
|
||||
// add instances to the object, if it has those
|
||||
if (model_object->instances.size()>1)
|
||||
increase_object_instances(obj_idx, model_object->instances.size());
|
||||
|
||||
// add settings to the object, if it has those
|
||||
auto opt_keys = model_object->config.keys();
|
||||
if ( !(opt_keys.size() == 1 && opt_keys[0] == "extruder") ) {
|
||||
select_item(m_objects_model->AddSettingsChild(item));
|
||||
Collapse(item);
|
||||
}
|
||||
|
||||
#ifndef __WXOSX__
|
||||
selection_changed();
|
||||
#endif //__WXMSW__
|
||||
|
|
@ -1227,11 +1207,18 @@ void ObjectList::update_selections()
|
|||
auto& selection = _3DScene::get_canvas(wxGetApp().canvas3D())->get_selection();
|
||||
wxDataViewItemArray sels;
|
||||
|
||||
for (auto idx: selection.get_volume_idxs())
|
||||
{
|
||||
const auto gl_vol = selection.get_volume(idx);
|
||||
sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx()));
|
||||
if (selection.is_single_full_object()) {
|
||||
for (auto idx : selection.get_volume_idxs()) {
|
||||
const auto gl_vol = selection.get_volume(idx);
|
||||
sels.Add(m_objects_model->GetItemByVolumeId(gl_vol->object_idx(), gl_vol->volume_idx()));
|
||||
}
|
||||
}
|
||||
else if (selection.is_single_full_instance()) {
|
||||
for (auto idx : selection.get_instance_idxs()) {
|
||||
sels.Add(m_objects_model->GetItemByInstanceId(selection.get_object_idx(), idx));
|
||||
}
|
||||
}
|
||||
|
||||
select_items(sels);
|
||||
}
|
||||
|
||||
|
|
@ -1256,7 +1243,7 @@ void ObjectList::update_selections_on_canvas()
|
|||
if (m_objects_model->GetItemType(item) == itVolume) {
|
||||
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetParent(item));
|
||||
const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
|
||||
selection.add_volume(obj_idx, vol_idx, as_single_selection);
|
||||
selection.add_volume(obj_idx, vol_idx, 0, as_single_selection);
|
||||
}
|
||||
else if (m_objects_model->GetItemType(item) == itInstance) {
|
||||
const int obj_idx = m_objects_model->GetIdByItem(m_objects_model->GetTopParent(item));
|
||||
|
|
@ -1334,5 +1321,53 @@ void ObjectList::fix_multiselection_conflicts()
|
|||
m_prevent_list_events = false;
|
||||
}
|
||||
|
||||
ModelVolume* ObjectList::get_selected_model_volume()
|
||||
{
|
||||
auto item = GetSelection();
|
||||
if (!item || m_objects_model->GetItemType(item) != itVolume)
|
||||
return nullptr;
|
||||
|
||||
const auto vol_idx = m_objects_model->GetVolumeIdByItem(item);
|
||||
const auto obj_idx = get_selected_obj_idx();
|
||||
if (vol_idx < 0 || obj_idx < 0)
|
||||
return nullptr;
|
||||
|
||||
return (*m_objects)[obj_idx]->volumes[vol_idx];
|
||||
}
|
||||
|
||||
void ObjectList::change_part_type()
|
||||
{
|
||||
ModelVolume* volume = get_selected_model_volume();
|
||||
if (!volume)
|
||||
return;
|
||||
const auto type = volume->type();
|
||||
|
||||
const wxString names[] = { "Part", "Modifier", "Support Enforcer", "Support Blocker" };
|
||||
|
||||
auto new_type = wxGetSingleChoiceIndex("Type: ", _(L("Select type of part")), wxArrayString(4, names), type);
|
||||
|
||||
if (new_type == type || new_type < 0)
|
||||
return;
|
||||
|
||||
const auto item = GetSelection();
|
||||
volume->set_type(static_cast<ModelVolume::Type>(new_type));
|
||||
m_objects_model->SetVolumeType(item, new_type);
|
||||
|
||||
m_parts_changed = true;
|
||||
parts_changed(get_selected_obj_idx());
|
||||
|
||||
// Update settings showing, if we have it
|
||||
//(we show additional settings for Part and Modifier and hide it for Support Blocker/Enforcer)
|
||||
const auto settings_item = m_objects_model->GetSettingsItem(item);
|
||||
if (settings_item &&
|
||||
new_type == ModelVolume::SUPPORT_ENFORCER || new_type == ModelVolume::SUPPORT_BLOCKER) {
|
||||
m_objects_model->Delete(settings_item);
|
||||
}
|
||||
else if (!settings_item &&
|
||||
new_type == ModelVolume::MODEL_PART || new_type == ModelVolume::PARAMETER_MODIFIER) {
|
||||
select_item(m_objects_model->AddSettingsChild(item));
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace GUI
|
||||
} //namespace Slic3r
|
||||
|
|
@ -28,10 +28,14 @@ class ObjectList : public wxDataViewCtrl
|
|||
|
||||
wxBitmap m_bmp_modifiermesh;
|
||||
wxBitmap m_bmp_solidmesh;
|
||||
wxBitmap m_bmp_support_enforcer;
|
||||
wxBitmap m_bmp_support_blocker;
|
||||
wxBitmap m_bmp_manifold_warning;
|
||||
wxBitmap m_bmp_cog;
|
||||
wxBitmap m_bmp_split;
|
||||
|
||||
std::vector<wxBitmap*> m_bmp_vector;
|
||||
|
||||
int m_selected_object_id = -1;
|
||||
bool m_prevent_list_events = false; // We use this flag to avoid circular event handling Select()
|
||||
// happens to fire a wxEVT_LIST_ITEM_SELECTED on OSX, whose event handler
|
||||
|
|
@ -78,17 +82,16 @@ public:
|
|||
void on_drop(wxDataViewEvent &event);
|
||||
|
||||
void get_settings_choice(wxMenu *menu, int id, bool is_part);
|
||||
void menu_item_add_generic(wxMenuItem* &menu, int id);
|
||||
void menu_item_add_generic(wxMenuItem* &menu, int id, const int type);
|
||||
wxMenuItem* menu_item_split(wxMenu* menu, int id);
|
||||
wxMenuItem* menu_item_settings(wxMenu* menu, int id, const bool is_part);
|
||||
wxMenu* create_add_part_popupmenu();
|
||||
wxMenu* create_part_settings_popupmenu();
|
||||
wxMenu* create_add_settings_popupmenu(bool is_part);
|
||||
|
||||
void load_subobject(bool is_modifier = false, bool is_lambda = false);
|
||||
void load_part(ModelObject* model_object, wxArrayString& part_names, const bool is_modifier);
|
||||
void load_lambda(ModelObject* model_object, wxArrayString& part_names, const bool is_modifier);
|
||||
void load_lambda(const std::string& type_name);
|
||||
void load_subobject(int type);
|
||||
void load_part(ModelObject* model_object, wxArrayString& part_names, int type);
|
||||
void load_generic_subobject(const std::string& type_name, const int type);
|
||||
void del_subobject_item(wxDataViewItem& item);
|
||||
void del_settings_from_config();
|
||||
void del_instances_from_object(const int obj_idx);
|
||||
|
|
@ -142,6 +145,9 @@ public:
|
|||
void select_all();
|
||||
// correct current selections to avoid of the possible conflicts
|
||||
void fix_multiselection_conflicts();
|
||||
|
||||
ModelVolume* get_selected_model_volume();
|
||||
void change_part_type();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -268,6 +268,9 @@ void ObjectManipulation::update_settings_list()
|
|||
|
||||
void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection)
|
||||
{
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
if (selection.is_single_full_instance())
|
||||
#else
|
||||
if (selection.is_single_full_object())
|
||||
{
|
||||
auto obj_idx = selection.get_object_idx();
|
||||
|
|
@ -284,30 +287,49 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele
|
|||
reset_settings_value();
|
||||
}
|
||||
else if (selection.is_single_full_instance())
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
{
|
||||
// all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
update_position_value(volume->get_instance_offset());
|
||||
update_rotation_value(volume->get_instance_rotation());
|
||||
update_scale_value(volume->get_instance_scaling_factor());
|
||||
#else
|
||||
update_position_value(volume->get_offset());
|
||||
update_rotation_value(volume->get_rotation());
|
||||
update_scale_value(volume->get_scaling_factor());
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
m_og->enable();
|
||||
}
|
||||
else if (selection.is_wipe_tower())
|
||||
{
|
||||
// the selection contains a single volume
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
update_position_value(volume->get_volume_offset());
|
||||
update_rotation_value(volume->get_volume_rotation());
|
||||
update_scale_value(volume->get_volume_scaling_factor());
|
||||
#else
|
||||
update_position_value(volume->get_offset());
|
||||
update_rotation_value(volume->get_rotation());
|
||||
update_scale_value(volume->get_scaling_factor());
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
m_og->enable();
|
||||
}
|
||||
else if (selection.is_modifier())
|
||||
{
|
||||
// the selection contains a single volume
|
||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
update_position_value(volume->get_volume_offset());
|
||||
update_rotation_value(volume->get_volume_rotation());
|
||||
update_scale_value(volume->get_volume_scaling_factor());
|
||||
#else
|
||||
update_position_value(volume->get_offset());
|
||||
update_rotation_value(volume->get_rotation());
|
||||
update_scale_value(volume->get_scaling_factor());
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
m_og->enable();
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "../../libslic3r/libslic3r.h"
|
||||
#include "GUI_Preview.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "GUI.hpp"
|
||||
#include "AppConfig.hpp"
|
||||
#include "3DScene.hpp"
|
||||
|
|
@ -22,6 +23,7 @@
|
|||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
|
||||
Preview::Preview(wxNotebook* notebook, DynamicPrintConfig* config, Print* print, GCodePreviewData* gcode_preview_data)
|
||||
: m_canvas(nullptr)
|
||||
, m_double_slider_sizer(nullptr)
|
||||
|
|
@ -482,6 +484,11 @@ void Preview::create_double_slider()
|
|||
if (IsShown())
|
||||
m_canvas->Refresh();
|
||||
});
|
||||
|
||||
Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) {
|
||||
auto& config = wxGetApp().preset_bundle->project_config;
|
||||
((config.option<ConfigOptionFloats>("colorprint_heights"))->values) = (m_slider->GetTicksValues());
|
||||
});
|
||||
}
|
||||
|
||||
void Preview::update_double_slider(bool force_sliders_full_range)
|
||||
|
|
@ -495,6 +502,11 @@ void Preview::update_double_slider(bool force_sliders_full_range)
|
|||
m_slider->SetMaxValue(layers_z.size() - 1);
|
||||
m_slider->SetSliderValues(values);
|
||||
|
||||
const auto& config = wxGetApp().preset_bundle->project_config;
|
||||
const std::vector<double> &ticks_from_config = (config.option<ConfigOptionFloats>("colorprint_heights"))->values;
|
||||
|
||||
m_slider->SetTicksValues(ticks_from_config);
|
||||
|
||||
set_double_slider_thumbs(force_sliders_full_range, layers_z, z_low, z_high);
|
||||
}
|
||||
|
||||
|
|
@ -515,6 +527,15 @@ void Preview::fill_slider_values(std::vector<std::pair<int, double>> &values,
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// All ticks that would end up outside the slider range should be erased.
|
||||
// TODO: this should probably be placed into more appropriate part of code,
|
||||
// this way it relies on the Preview tab being active.
|
||||
auto& config = wxGetApp().preset_bundle->project_config;
|
||||
std::vector<double> &ticks_from_config = (config.option<ConfigOptionFloats>("colorprint_heights"))->values;
|
||||
ticks_from_config.erase(std::remove_if(ticks_from_config.begin(), ticks_from_config.end(),
|
||||
[values](double val) { return values.back().second < val; }),
|
||||
ticks_from_config.end());
|
||||
}
|
||||
|
||||
void Preview::set_double_slider_thumbs(const bool force_sliders_full_range,
|
||||
|
|
|
|||
|
|
@ -49,15 +49,15 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent,
|
|||
|
||||
def.type = coFloat;
|
||||
def.default_value = new ConfigOptionFloat{ 1.0 };
|
||||
def.label = L("L");
|
||||
def.label = L("Length");
|
||||
Option option(def, "l");
|
||||
optgroup->append_single_option_line(option);
|
||||
|
||||
def.label = L("W");
|
||||
def.label = L("Width");
|
||||
option = Option(def, "w");
|
||||
optgroup->append_single_option_line(option);
|
||||
|
||||
def.label = L("H");
|
||||
def.label = L("Height");
|
||||
option = Option(def, "h");
|
||||
optgroup->append_single_option_line(option);
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ LambdaObjectDialog::LambdaObjectDialog(wxWindow* parent,
|
|||
|
||||
def.type = coFloat;
|
||||
def.default_value = new ConfigOptionFloat{ 1.0 };
|
||||
def.label = L("H");
|
||||
def.label = L("Height");
|
||||
auto option = Option(def, "slab_h");
|
||||
optgroup->append_single_option_line(option);
|
||||
|
||||
|
|
|
|||
|
|
@ -596,8 +596,7 @@ void MainFrame::load_config_file(wxString file/* = wxEmptyString*/)
|
|||
// if (Slic3r::GUI::catch_error(this))
|
||||
// return;
|
||||
}
|
||||
for (auto tab : m_options_tabs )
|
||||
tab.second->load_current_preset();
|
||||
wxGetApp().load_current_presets();
|
||||
wxGetApp().app_config->update_config_dir(get_dir_name(file));
|
||||
m_last_config = file;
|
||||
}
|
||||
|
|
@ -659,8 +658,7 @@ void MainFrame::load_configbundle(wxString file/* = wxEmptyString, const bool re
|
|||
}
|
||||
|
||||
// Load the currently selected preset into the GUI, update the preset selection box.
|
||||
for (auto tab : m_options_tabs)
|
||||
tab.second->load_current_preset();
|
||||
wxGetApp().load_current_presets();
|
||||
|
||||
const auto message = wxString::Format(_(L("%d presets successfully imported.")), presets_imported);
|
||||
Slic3r::GUI::show_info(this, message, "Info");
|
||||
|
|
|
|||
|
|
@ -22,18 +22,18 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
|
|||
// is the normal type.
|
||||
if (opt.gui_type.compare("select") == 0) {
|
||||
} else if (opt.gui_type.compare("select_open") == 0) {
|
||||
m_fields.emplace(id, STDMOVE(Choice::Create<Choice>(parent(), opt, id)));
|
||||
m_fields.emplace(id, std::move(Choice::Create<Choice>(parent(), opt, id)));
|
||||
} else if (opt.gui_type.compare("color") == 0) {
|
||||
m_fields.emplace(id, STDMOVE(ColourPicker::Create<ColourPicker>(parent(), opt, id)));
|
||||
m_fields.emplace(id, std::move(ColourPicker::Create<ColourPicker>(parent(), opt, id)));
|
||||
} else if (opt.gui_type.compare("f_enum_open") == 0 ||
|
||||
opt.gui_type.compare("i_enum_open") == 0 ||
|
||||
opt.gui_type.compare("i_enum_closed") == 0) {
|
||||
m_fields.emplace(id, STDMOVE(Choice::Create<Choice>(parent(), opt, id)));
|
||||
m_fields.emplace(id, std::move(Choice::Create<Choice>(parent(), opt, id)));
|
||||
} else if (opt.gui_type.compare("slider") == 0) {
|
||||
m_fields.emplace(id, STDMOVE(SliderCtrl::Create<SliderCtrl>(parent(), opt, id)));
|
||||
m_fields.emplace(id, std::move(SliderCtrl::Create<SliderCtrl>(parent(), opt, id)));
|
||||
} else if (opt.gui_type.compare("i_spin") == 0) { // Spinctrl
|
||||
} else if (opt.gui_type.compare("legend") == 0) { // StaticText
|
||||
m_fields.emplace(id, STDMOVE(StaticText::Create<StaticText>(parent(), opt, id)));
|
||||
m_fields.emplace(id, std::move(StaticText::Create<StaticText>(parent(), opt, id)));
|
||||
} else {
|
||||
switch (opt.type) {
|
||||
case coFloatOrPercent:
|
||||
|
|
@ -43,21 +43,21 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
|
|||
case coPercents:
|
||||
case coString:
|
||||
case coStrings:
|
||||
m_fields.emplace(id, STDMOVE(TextCtrl::Create<TextCtrl>(parent(), opt, id)));
|
||||
m_fields.emplace(id, std::move(TextCtrl::Create<TextCtrl>(parent(), opt, id)));
|
||||
break;
|
||||
case coBool:
|
||||
case coBools:
|
||||
m_fields.emplace(id, STDMOVE(CheckBox::Create<CheckBox>(parent(), opt, id)));
|
||||
m_fields.emplace(id, std::move(CheckBox::Create<CheckBox>(parent(), opt, id)));
|
||||
break;
|
||||
case coInt:
|
||||
case coInts:
|
||||
m_fields.emplace(id, STDMOVE(SpinCtrl::Create<SpinCtrl>(parent(), opt, id)));
|
||||
m_fields.emplace(id, std::move(SpinCtrl::Create<SpinCtrl>(parent(), opt, id)));
|
||||
break;
|
||||
case coEnum:
|
||||
m_fields.emplace(id, STDMOVE(Choice::Create<Choice>(parent(), opt, id)));
|
||||
m_fields.emplace(id, std::move(Choice::Create<Choice>(parent(), opt, id)));
|
||||
break;
|
||||
case coPoints:
|
||||
m_fields.emplace(id, STDMOVE(PointCtrl::Create<PointCtrl>(parent(), opt, id)));
|
||||
m_fields.emplace(id, std::move(PointCtrl::Create<PointCtrl>(parent(), opt, id)));
|
||||
break;
|
||||
case coNone: break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -1154,16 +1154,25 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path> &input_
|
|||
try {
|
||||
if (type_3mf || type_zip_amf) {
|
||||
DynamicPrintConfig config;
|
||||
config.apply(FullPrintConfig::defaults());
|
||||
model = Slic3r::Model::read_from_archive(path.string(), &config, false);
|
||||
Preset::normalize(config);
|
||||
wxGetApp().preset_bundle->load_config_model(filename.string(), std::move(config));
|
||||
for (const auto &kv : main_frame->options_tabs()) { kv.second->load_current_preset(); }
|
||||
{
|
||||
DynamicPrintConfig config_loaded;
|
||||
model = Slic3r::Model::read_from_archive(path.string(), &config_loaded, false);
|
||||
if (! config_loaded.empty()) {
|
||||
// Based on the printer technology field found in the loaded config, select the base for the config,
|
||||
PrinterTechnology printer_technology = Preset::printer_technology(config_loaded);
|
||||
config.apply(printer_technology == ptFFF ?
|
||||
static_cast<const ConfigBase&>(FullPrintConfig::defaults()) :
|
||||
static_cast<const ConfigBase&>(SLAFullPrintConfig::defaults()));
|
||||
// and place the loaded config over the base.
|
||||
config += std::move(config_loaded);
|
||||
}
|
||||
}
|
||||
if (! config.empty()) {
|
||||
Preset::normalize(config);
|
||||
wxGetApp().preset_bundle->load_config_model(filename.string(), std::move(config));
|
||||
wxGetApp().load_current_presets();
|
||||
}
|
||||
wxGetApp().app_config->update_config_dir(path.parent_path().string());
|
||||
// forces the update of the config here, or it will invalidate the imported layer heights profile if done using the timer
|
||||
// and if the config contains a "layer_height" different from the current defined one
|
||||
// TODO:
|
||||
// $self->async_apply_config;
|
||||
} else {
|
||||
model = Slic3r::Model::read_from_file(path.string(), nullptr, false);
|
||||
for (auto obj : model.objects)
|
||||
|
|
@ -1230,7 +1239,9 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path> &input_
|
|||
std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &model_objects)
|
||||
{
|
||||
const BoundingBoxf bed_shape = bed_shape_bb();
|
||||
#if !ENABLE_MODELVOLUME_TRANSFORM
|
||||
const Vec3d bed_center = Slic3r::to_3d(bed_shape.center().cast<double>(), 0.0);
|
||||
#endif // !ENABLE_MODELVOLUME_TRANSFORM
|
||||
const Vec3d bed_size = Slic3r::to_3d(bed_shape.size().cast<double>(), 1.0);
|
||||
|
||||
bool need_arrange = false;
|
||||
|
|
@ -1249,8 +1260,12 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
|
|||
|
||||
// add a default instance and center object around origin
|
||||
object->center_around_origin(); // also aligns object to Z = 0
|
||||
auto *instance = object->add_instance();
|
||||
ModelInstance* instance = object->add_instance();
|
||||
#if ENABLE_MODELVOLUME_TRANSFORM
|
||||
instance->set_offset(Slic3r::to_3d(bed_shape.center().cast<double>(), -object->origin_translation(2)));
|
||||
#else
|
||||
instance->set_offset(bed_center);
|
||||
#endif // ENABLE_MODELVOLUME_TRANSFORM
|
||||
}
|
||||
|
||||
const Vec3d size = object->bounding_box().size();
|
||||
|
|
@ -1438,7 +1453,9 @@ void Plater::priv::mirror(Axis axis)
|
|||
|
||||
void Plater::priv::arrange()
|
||||
{
|
||||
this->background_process.stop();
|
||||
main_frame->app_controller()->arrange_model();
|
||||
this->schedule_background_process();
|
||||
|
||||
// ignore arrange failures on purpose: user has visual feedback and we don't need to warn him
|
||||
// when parts don't fit in print bed
|
||||
|
|
@ -1471,13 +1488,7 @@ void Plater::priv::split_object()
|
|||
{
|
||||
unsigned int counter = 1;
|
||||
for (ModelObject* m : new_objects)
|
||||
{
|
||||
m->name = current_model_object->name + "_" + std::to_string(counter++);
|
||||
for (ModelInstance* i : current_model_object->instances)
|
||||
{
|
||||
m->add_instance(*i);
|
||||
}
|
||||
}
|
||||
|
||||
remove(obj_idx);
|
||||
|
||||
|
|
@ -2108,7 +2119,8 @@ void Plater::export_amf()
|
|||
wxString path = dialog->GetPath();
|
||||
auto path_cstr = path.c_str();
|
||||
|
||||
if (Slic3r::store_amf(path_cstr, &p->model, &p->print, dialog->get_checkbox_value())) {
|
||||
DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config();
|
||||
if (Slic3r::store_amf(path_cstr, &p->model, dialog->get_checkbox_value() ? &cfg : nullptr)) {
|
||||
// Success
|
||||
p->statusbar()->set_status_text(wxString::Format(_(L("AMF file exported to %s")), path));
|
||||
} else {
|
||||
|
|
@ -2127,7 +2139,8 @@ void Plater::export_3mf()
|
|||
wxString path = dialog->GetPath();
|
||||
auto path_cstr = path.c_str();
|
||||
|
||||
if (Slic3r::store_3mf(path_cstr, &p->model, &p->print, dialog->get_checkbox_value())) {
|
||||
DynamicPrintConfig cfg = wxGetApp().preset_bundle->full_config();
|
||||
if (Slic3r::store_3mf(path_cstr, &p->model, dialog->get_checkbox_value() ? &cfg : nullptr)) {
|
||||
// Success
|
||||
p->statusbar()->set_status_text(wxString::Format(_(L("3MF file exported to %s")), path));
|
||||
} else {
|
||||
|
|
@ -2256,7 +2269,9 @@ void Plater::changed_object(int obj_idx)
|
|||
if (list->is_parts_changed()) {
|
||||
// recenter and re - align to Z = 0
|
||||
auto model_object = p->model.objects[obj_idx];
|
||||
#if !ENABLE_MODELVOLUME_TRANSFORM
|
||||
model_object->center_around_origin();
|
||||
#endif // !ENABLE_MODELVOLUME_TRANSFORM
|
||||
model_object->ensure_on_bed();
|
||||
_3DScene::reload_scene(p->canvas3D, false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,10 +170,12 @@ void Preset::set_num_extruders(DynamicPrintConfig &config, unsigned int num_extr
|
|||
{
|
||||
const auto &defaults = FullPrintConfig::defaults();
|
||||
for (const std::string &key : Preset::nozzle_options()) {
|
||||
if (key == "default_filament_profile")
|
||||
continue;
|
||||
auto *opt = config.option(key, false);
|
||||
assert(opt != nullptr);
|
||||
assert(opt->is_vector());
|
||||
if (opt != nullptr && opt->is_vector() && key != "default_filament_profile")
|
||||
if (opt != nullptr && opt->is_vector())
|
||||
static_cast<ConfigOptionVectorBase*>(opt)->resize(num_extruders, defaults.option(key));
|
||||
}
|
||||
}
|
||||
|
|
@ -202,8 +204,7 @@ void Preset::normalize(DynamicPrintConfig &config)
|
|||
// The following keys are mandatory for the UI, but they are not part of FullPrintConfig, therefore they are handled separately.
|
||||
for (const std::string &key : { "filament_settings_id" }) {
|
||||
auto *opt = config.option(key, false);
|
||||
assert(opt != nullptr);
|
||||
assert(opt->type() == coStrings);
|
||||
assert(opt == nullptr || opt->type() == coStrings);
|
||||
if (opt != nullptr && opt->type() == coStrings)
|
||||
static_cast<ConfigOptionStrings*>(opt)->values.resize(n, std::string());
|
||||
}
|
||||
|
|
@ -534,7 +535,8 @@ Preset& PresetCollection::load_external_preset(
|
|||
cfg.apply_only(config, cfg.keys(), true);
|
||||
// Is there a preset already loaded with the name stored inside the config?
|
||||
std::deque<Preset>::iterator it = this->find_preset_internal(original_name);
|
||||
if (it != m_presets.end() && it->name == original_name && profile_print_params_same(it->config, cfg)) {
|
||||
bool found = it != m_presets.end() && it->name == original_name;
|
||||
if (found && profile_print_params_same(it->config, cfg)) {
|
||||
// The preset exists and it matches the values stored inside config.
|
||||
if (select)
|
||||
this->select_preset(it - m_presets.begin());
|
||||
|
|
@ -542,7 +544,7 @@ Preset& PresetCollection::load_external_preset(
|
|||
}
|
||||
// Update the "inherits" field.
|
||||
std::string &inherits = Preset::inherits(cfg);
|
||||
if (it != m_presets.end() && inherits.empty()) {
|
||||
if (found && inherits.empty()) {
|
||||
// There is a profile with the same name already loaded. Should we update the "inherits" field?
|
||||
if (it->vendor == nullptr)
|
||||
inherits = it->inherits();
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
namespace Slic3r {
|
||||
|
||||
static std::vector<std::string> s_project_options {
|
||||
"colorprint_heights",
|
||||
"wiping_volumes_extruders",
|
||||
"wiping_volumes_matrix"
|
||||
};
|
||||
|
|
@ -617,18 +618,6 @@ void PresetBundle::load_config_file(const std::string &path)
|
|||
}
|
||||
}
|
||||
|
||||
void PresetBundle::load_config_string(const char* str, const char* source_filename)
|
||||
{
|
||||
if (str != nullptr)
|
||||
{
|
||||
DynamicPrintConfig config;
|
||||
config.apply(FullPrintConfig::defaults());
|
||||
config.load_from_gcode_string(str);
|
||||
Preset::normalize(config);
|
||||
load_config_file_config((source_filename == nullptr) ? "" : source_filename, true, std::move(config));
|
||||
}
|
||||
}
|
||||
|
||||
// Load a config file from a boost property_tree. This is a private method called from load_config_file.
|
||||
void PresetBundle::load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config)
|
||||
{
|
||||
|
|
@ -676,7 +665,7 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
|||
compatible_printers_condition = compatible_printers_condition_values[idx];
|
||||
if (is_external)
|
||||
presets.load_external_preset(name_or_path, name,
|
||||
config.opt_string((i_group == 0) ? ((printer_technology == ptFFF) ? "print_settings_id" : "sla_material_id") : "printer_settings_id", true),
|
||||
config.opt_string((i_group == 0) ? ((printer_technology == ptFFF) ? "print_settings_id" : "sla_material_settings_id") : "printer_settings_id", true),
|
||||
config);
|
||||
else
|
||||
presets.load_preset(presets.path_from_name(name), name, config).save();
|
||||
|
|
|
|||
|
|
@ -84,11 +84,6 @@ public:
|
|||
// If the file is loaded successfully, its print / filament / printer profiles will be activated.
|
||||
void load_config_file(const std::string &path);
|
||||
|
||||
// Load an external config source containing the print, filament and printer presets.
|
||||
// The given string must contain the full set of parameters (same as those exported to gcode).
|
||||
// If the string is parsed successfully, its print / filament / printer profiles will be activated.
|
||||
void load_config_string(const char* str, const char* source_filename = nullptr);
|
||||
|
||||
// Load a config bundle file, into presets and store the loaded presets into separate files
|
||||
// of the local configuration directory.
|
||||
// Load settings into the provided settings instance.
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters)
|
|||
m_widget_time->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value
|
||||
m_widget_volume->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value
|
||||
Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) {m_widget_volume->SetValue(m_chart->get_volume()); m_widget_time->SetValue(m_chart->get_time());} );
|
||||
Refresh(this);
|
||||
Refresh(true); // erase background
|
||||
}
|
||||
|
||||
void RammingPanel::line_parameters_changed() {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
#include <wx/numformatter.h>
|
||||
#include "GUI_App.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "Model.hpp"
|
||||
|
||||
wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
|
||||
|
||||
wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description,
|
||||
std::function<void(wxCommandEvent& event)> cb, const std::string& icon, wxEvtHandler* event_handler)
|
||||
|
|
@ -400,10 +403,9 @@ bool PrusaObjectDataViewModelNode::update_settings_digest(const std::vector<std:
|
|||
|
||||
m_opt_categories = categories;
|
||||
m_name = wxEmptyString;
|
||||
// m_icon = m_empty_icon;
|
||||
m_bmp = m_empty_bmp;
|
||||
|
||||
std::map<std::string, wxBitmap>& categories_icon = Slic3r::GUI::wxGetApp().obj_list()->CATEGORY_ICON;//Slic3r::GUI::get_category_icon();
|
||||
std::map<std::string, wxBitmap>& categories_icon = Slic3r::GUI::wxGetApp().obj_list()->CATEGORY_ICON;
|
||||
|
||||
for (auto& cat : m_opt_categories)
|
||||
m_name += cat + "; ";
|
||||
|
|
@ -453,29 +455,34 @@ wxDataViewItem PrusaObjectDataViewModel::Add(const wxString &name)
|
|||
|
||||
wxDataViewItem PrusaObjectDataViewModel::AddVolumeChild(const wxDataViewItem &parent_item,
|
||||
const wxString &name,
|
||||
const wxBitmap& icon,
|
||||
const int volume_type,
|
||||
const int extruder/* = 0*/,
|
||||
const bool create_frst_child/* = true*/)
|
||||
{
|
||||
PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent_item.GetID();
|
||||
if (!root) return wxDataViewItem(0);
|
||||
|
||||
const wxString extruder_str = extruder == 0 ? "default" : wxString::Format("%d", extruder);
|
||||
wxString extruder_str = extruder == 0 ? "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;
|
||||
|
||||
if (create_frst_child && root->m_volumes_cnt == 0)
|
||||
{
|
||||
const auto bmp_solid_mesh = wxBitmap(Slic3r::GUI::from_u8(Slic3r::var("object.png")), wxBITMAP_TYPE_PNG);
|
||||
const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, bmp_solid_mesh, extruder_str, 0);
|
||||
root->Append(node);
|
||||
const auto node = new PrusaObjectDataViewModelNode(root, root->m_name, *m_volume_bmps[0], extruder_str, 0);
|
||||
insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position);
|
||||
// notify control
|
||||
const wxDataViewItem child((void*)node);
|
||||
ItemAdded(parent_item, child);
|
||||
|
||||
root->m_volumes_cnt++;
|
||||
if (insert_position > 0) insert_position++;
|
||||
}
|
||||
|
||||
const auto node = new PrusaObjectDataViewModelNode(root, name, icon, extruder_str, root->m_volumes_cnt);
|
||||
root->Append(node);
|
||||
const auto node = new PrusaObjectDataViewModelNode(root, name, *m_volume_bmps[volume_type], extruder_str, root->m_volumes_cnt);
|
||||
insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position);
|
||||
// notify control
|
||||
const wxDataViewItem child((void*)node);
|
||||
ItemAdded(parent_item, child);
|
||||
|
|
@ -499,15 +506,13 @@ wxDataViewItem PrusaObjectDataViewModel::AddSettingsChild(const wxDataViewItem &
|
|||
|
||||
int get_istances_root_idx(PrusaObjectDataViewModelNode *parent_node)
|
||||
{
|
||||
int inst_root_id = -1;
|
||||
int stop_search_i = parent_node->GetChildCount();
|
||||
if (stop_search_i > 2) stop_search_i = 2;
|
||||
for (int i = 0; i < stop_search_i; ++i)
|
||||
if (parent_node->GetNthChild(i)->m_type & itInstanceRoot) {
|
||||
inst_root_id = i;
|
||||
break;
|
||||
}
|
||||
return inst_root_id;
|
||||
// because of istance_root is a last item of the object
|
||||
const int inst_root_idx = parent_node->GetChildCount()-1;
|
||||
|
||||
if (inst_root_idx < 0 || parent_node->GetNthChild(inst_root_idx)->m_type == itInstanceRoot)
|
||||
return inst_root_idx;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
wxDataViewItem PrusaObjectDataViewModel::AddInstanceChild(const wxDataViewItem &parent_item, size_t num)
|
||||
|
|
@ -524,8 +529,7 @@ wxDataViewItem PrusaObjectDataViewModel::AddInstanceChild(const wxDataViewItem &
|
|||
const wxDataViewItem inst_root_item((void*)inst_root_node);
|
||||
|
||||
if (inst_root_id < 0) {
|
||||
const unsigned insert_pos = parent_node->GetChildCount() == 0 || parent_node->GetNthChild(0)->m_type != itSettings ? 0 : 1;
|
||||
parent_node->Insert(inst_root_node, insert_pos);
|
||||
parent_node->Append(inst_root_node);
|
||||
// notify control
|
||||
ItemAdded(parent_item, inst_root_item);
|
||||
if (num == 1) num++;
|
||||
|
|
@ -563,6 +567,10 @@ wxDataViewItem PrusaObjectDataViewModel::Delete(const wxDataViewItem &item)
|
|||
auto id = node_parent->GetChildren().Index(node);
|
||||
auto idx = node->GetIdx();
|
||||
node_parent->GetChildren().Remove(node);
|
||||
|
||||
if (node->m_type == itVolume)
|
||||
node_parent->m_volumes_cnt--;
|
||||
|
||||
if (id > 0) {
|
||||
if(id == node_parent->GetChildCount()) id--;
|
||||
ret_item = wxDataViewItem(node_parent->GetChildren().Item(id));
|
||||
|
|
@ -692,6 +700,9 @@ void PrusaObjectDataViewModel::DeleteChildren(wxDataViewItem& parent)
|
|||
auto item = wxDataViewItem(node);
|
||||
children.RemoveAt(id);
|
||||
|
||||
if (node->m_type == itVolume)
|
||||
root->m_volumes_cnt--;
|
||||
|
||||
// free the node
|
||||
delete node;
|
||||
|
||||
|
|
@ -705,6 +716,39 @@ void PrusaObjectDataViewModel::DeleteChildren(wxDataViewItem& parent)
|
|||
#endif //__WXGTK__
|
||||
}
|
||||
|
||||
void PrusaObjectDataViewModel::DeleteVolumeChildren(wxDataViewItem& parent)
|
||||
{
|
||||
PrusaObjectDataViewModelNode *root = (PrusaObjectDataViewModelNode*)parent.GetID();
|
||||
if (!root) // happens if item.IsOk()==false
|
||||
return;
|
||||
|
||||
// first remove the node from the parent's array of children;
|
||||
// NOTE: MyObjectTreeModelNodePtrArray is only an array of _pointers_
|
||||
// thus removing the node from it doesn't result in freeing it
|
||||
auto& children = root->GetChildren();
|
||||
for (int id = root->GetChildCount() - 1; id >= 0; --id)
|
||||
{
|
||||
auto node = children[id];
|
||||
if (node->m_type != itVolume)
|
||||
continue;
|
||||
|
||||
auto item = wxDataViewItem(node);
|
||||
children.RemoveAt(id);
|
||||
root->m_volumes_cnt--;
|
||||
|
||||
// free the node
|
||||
delete node;
|
||||
|
||||
// notify control
|
||||
ItemDeleted(parent, item);
|
||||
}
|
||||
|
||||
// set m_containet to FALSE if parent has no child
|
||||
#ifndef __WXGTK__
|
||||
root->m_container = false;
|
||||
#endif //__WXGTK__
|
||||
}
|
||||
|
||||
wxDataViewItem PrusaObjectDataViewModel::GetItemById(int obj_idx)
|
||||
{
|
||||
if (obj_idx >= m_objects.size())
|
||||
|
|
@ -718,7 +762,7 @@ wxDataViewItem PrusaObjectDataViewModel::GetItemById(int obj_idx)
|
|||
|
||||
wxDataViewItem PrusaObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volume_idx)
|
||||
{
|
||||
if (obj_idx >= m_objects.size()) {
|
||||
if (obj_idx >= m_objects.size() || obj_idx < 0) {
|
||||
printf("Error! Out of objects range.\n");
|
||||
return wxDataViewItem(0);
|
||||
}
|
||||
|
|
@ -740,6 +784,25 @@ wxDataViewItem PrusaObjectDataViewModel::GetItemByVolumeId(int obj_idx, int volu
|
|||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
wxDataViewItem PrusaObjectDataViewModel::GetItemByInstanceId(int obj_idx, int inst_idx)
|
||||
{
|
||||
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)
|
||||
return wxDataViewItem(0);
|
||||
|
||||
auto parent = (PrusaObjectDataViewModelNode*)instances_item.GetID();;
|
||||
for (size_t i = 0; i < parent->GetChildCount(); i++)
|
||||
if (parent->GetNthChild(i)->m_idx == inst_idx)
|
||||
return wxDataViewItem(parent->GetNthChild(i));
|
||||
|
||||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
int PrusaObjectDataViewModel::GetIdByItem(const wxDataViewItem& item)
|
||||
{
|
||||
wxASSERT(item.IsOk());
|
||||
|
|
@ -1015,21 +1078,33 @@ ItemType PrusaObjectDataViewModel::GetItemType(const wxDataViewItem &item) const
|
|||
return node->m_type;
|
||||
}
|
||||
|
||||
wxDataViewItem PrusaObjectDataViewModel::GetSettingsItem(const wxDataViewItem &item) const
|
||||
wxDataViewItem PrusaObjectDataViewModel::GetItemByType(const wxDataViewItem &parent_item, ItemType type) const
|
||||
{
|
||||
if (!item.IsOk())
|
||||
if (!parent_item.IsOk())
|
||||
return wxDataViewItem(0);
|
||||
|
||||
PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
|
||||
PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)parent_item.GetID();
|
||||
if (node->GetChildCount() == 0)
|
||||
return wxDataViewItem(0);
|
||||
|
||||
if (node->GetNthChild(0)->m_type == itSettings)
|
||||
return wxDataViewItem((void*)node->GetNthChild(0));
|
||||
for (int i = 0; i < node->GetChildCount(); i++) {
|
||||
if (node->GetNthChild(i)->m_type == type)
|
||||
return wxDataViewItem((void*)node->GetNthChild(i));
|
||||
}
|
||||
|
||||
return wxDataViewItem(0);
|
||||
}
|
||||
|
||||
wxDataViewItem PrusaObjectDataViewModel::GetSettingsItem(const wxDataViewItem &item) const
|
||||
{
|
||||
return GetItemByType(item, itSettings);
|
||||
}
|
||||
|
||||
wxDataViewItem PrusaObjectDataViewModel::GetInstanceRootItem(const wxDataViewItem &item) const
|
||||
{
|
||||
return GetItemByType(item, itInstanceRoot);
|
||||
}
|
||||
|
||||
bool PrusaObjectDataViewModel::IsSettingsItem(const wxDataViewItem &item) const
|
||||
{
|
||||
if (!item.IsOk())
|
||||
|
|
@ -1050,6 +1125,16 @@ void PrusaObjectDataViewModel::UpdateSettingsDigest(const wxDataViewItem &item,
|
|||
ItemChanged(item);
|
||||
}
|
||||
|
||||
void PrusaObjectDataViewModel::SetVolumeType(const wxDataViewItem &item, const int type)
|
||||
{
|
||||
if (!item.IsOk() || GetItemType(item) != itVolume)
|
||||
return;
|
||||
|
||||
PrusaObjectDataViewModelNode *node = (PrusaObjectDataViewModelNode*)item.GetID();
|
||||
node->SetBitmap(*m_volume_bmps[type]);
|
||||
ItemChanged(item);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// PrusaDataViewBitmapText
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -1106,7 +1191,6 @@ wxSize PrusaBitmapTextRenderer::GetSize() const
|
|||
// ----------------------------------------------------------------------------
|
||||
// PrusaDoubleSlider
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
PrusaDoubleSlider::PrusaDoubleSlider(wxWindow *parent,
|
||||
wxWindowID id,
|
||||
int lowerValue,
|
||||
|
|
@ -1288,6 +1372,34 @@ double PrusaDoubleSlider::get_double_value(const SelectedSlider& selection) cons
|
|||
return m_values[selection == ssLower ? m_lower_value : m_higher_value].second;
|
||||
}
|
||||
|
||||
std::vector<double> PrusaDoubleSlider::GetTicksValues() const
|
||||
{
|
||||
std::vector<double> values;
|
||||
|
||||
if (!m_values.empty())
|
||||
for (auto tick : m_ticks)
|
||||
values.push_back(m_values[tick].second);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
void PrusaDoubleSlider::SetTicksValues(const std::vector<double>& heights)
|
||||
{
|
||||
if (m_values.empty())
|
||||
return;
|
||||
|
||||
m_ticks.clear();
|
||||
unsigned int i = 0;
|
||||
for (auto h : heights) {
|
||||
while (i < m_values.size() && m_values[i].second - 1e-6 < h)
|
||||
++i;
|
||||
if (i == m_values.size())
|
||||
return;
|
||||
m_ticks.insert(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PrusaDoubleSlider::get_lower_and_higher_position(int& lower_pos, int& higher_pos)
|
||||
{
|
||||
const double step = get_scroll_step();
|
||||
|
|
@ -1712,10 +1824,13 @@ void PrusaDoubleSlider::action_tick(const TicksAction action)
|
|||
m_ticks.insert(tick);
|
||||
else if (it != m_ticks.end() && action == taDel)
|
||||
m_ticks.erase(tick);
|
||||
else
|
||||
else {
|
||||
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
|
||||
Refresh();
|
||||
Update();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -424,7 +424,9 @@ private:
|
|||
|
||||
class PrusaObjectDataViewModel :public wxDataViewModel
|
||||
{
|
||||
std::vector<PrusaObjectDataViewModelNode*> m_objects;
|
||||
std::vector<PrusaObjectDataViewModelNode*> m_objects;
|
||||
std::vector<wxBitmap*> m_volume_bmps;
|
||||
|
||||
public:
|
||||
PrusaObjectDataViewModel();
|
||||
~PrusaObjectDataViewModel();
|
||||
|
|
@ -432,7 +434,7 @@ public:
|
|||
wxDataViewItem Add(const wxString &name);
|
||||
wxDataViewItem AddVolumeChild(const wxDataViewItem &parent_item,
|
||||
const wxString &name,
|
||||
const wxBitmap& icon,
|
||||
const int volume_type,
|
||||
const int extruder = 0,
|
||||
const bool create_frst_child = true);
|
||||
wxDataViewItem AddSettingsChild(const wxDataViewItem &parent_item);
|
||||
|
|
@ -441,8 +443,10 @@ public:
|
|||
wxDataViewItem DeleteLastInstance(const wxDataViewItem &parent_item, size_t num);
|
||||
void DeleteAll();
|
||||
void DeleteChildren(wxDataViewItem& parent);
|
||||
void DeleteVolumeChildren(wxDataViewItem& parent);
|
||||
wxDataViewItem GetItemById(int obj_idx);
|
||||
wxDataViewItem GetItemByVolumeId(int obj_idx, int volume_idx);
|
||||
wxDataViewItem GetItemByInstanceId(int obj_idx, int inst_idx);
|
||||
int GetIdByItem(const wxDataViewItem& item);
|
||||
int GetIdByItemAndType(const wxDataViewItem& item, const ItemType type) const;
|
||||
int GetVolumeIdByItem(const wxDataViewItem& item) const;
|
||||
|
|
@ -488,9 +492,14 @@ public:
|
|||
virtual bool HasContainerColumns(const wxDataViewItem& WXUNUSED(item)) const override { return true; }
|
||||
|
||||
ItemType GetItemType(const wxDataViewItem &item) const ;
|
||||
wxDataViewItem GetItemByType(const wxDataViewItem &parent_item, ItemType type) const;
|
||||
wxDataViewItem GetSettingsItem(const wxDataViewItem &item) const;
|
||||
wxDataViewItem GetInstanceRootItem(const wxDataViewItem &item) const;
|
||||
bool IsSettingsItem(const wxDataViewItem &item) const;
|
||||
void UpdateSettingsDigest(const wxDataViewItem &item, const std::vector<std::string>& categories);
|
||||
|
||||
void SetVolumeBitmaps(const std::vector<wxBitmap*>& volume_bmps) { m_volume_bmps = volume_bmps; }
|
||||
void SetVolumeType(const wxDataViewItem &item, const int type);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
|
@ -613,6 +622,9 @@ private:
|
|||
// PrusaDoubleSlider
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// custom message the slider sends to its parent to notify a tick-change:
|
||||
wxDECLARE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
|
||||
|
||||
enum SelectedSlider {
|
||||
ssUndef,
|
||||
ssLower,
|
||||
|
|
@ -623,6 +635,7 @@ enum TicksAction{
|
|||
taAdd,
|
||||
taDel
|
||||
};
|
||||
|
||||
class PrusaDoubleSlider : public wxControl
|
||||
{
|
||||
public:
|
||||
|
|
@ -660,6 +673,8 @@ public:
|
|||
m_values = values;
|
||||
}
|
||||
void ChangeOneLayerLock();
|
||||
std::vector<double> GetTicksValues() const;
|
||||
void SetTicksValues(const std::vector<double>& heights);
|
||||
|
||||
void OnPaint(wxPaintEvent& ) { render();}
|
||||
void OnLeftDown(wxMouseEvent& event);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue