mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-13 09:47:58 -06:00
Merge remote-tracking branch 'origin/master' into ys_overrides
This commit is contained in:
commit
b8a549259c
17 changed files with 675 additions and 375 deletions
|
@ -32,7 +32,6 @@ option(SLIC3R_MSVC_COMPILE_PARALLEL "Compile on Visual Studio in parallel" 1)
|
||||||
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
option(SLIC3R_MSVC_PDB "Generate PDB files on MSVC in Release mode" 1)
|
||||||
option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0)
|
option(SLIC3R_PERL_XS "Compile XS Perl module and enable Perl unit and integration tests" 0)
|
||||||
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
option(SLIC3R_ASAN "Enable ASan on Clang and GCC" 0)
|
||||||
option(SLIC3R_SYNTAXONLY "Only perform source code correctness checking, no binary output (UNIX only)" 0)
|
|
||||||
|
|
||||||
set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux")
|
set(SLIC3R_GTK "2" CACHE STRING "GTK version to use with wxWidgets on Linux")
|
||||||
|
|
||||||
|
@ -147,19 +146,6 @@ endif()
|
||||||
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
|
if (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUXX)
|
||||||
# Adding -fext-numeric-literals to enable GCC extensions on definitions of quad float literals, which are required by Boost.
|
# Adding -fext-numeric-literals to enable GCC extensions on definitions of quad float literals, which are required by Boost.
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals" )
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals" )
|
||||||
|
|
||||||
if (SLIC3R_SYNTAXONLY)
|
|
||||||
set(CMAKE_CXX_ARCHIVE_CREATE "true")
|
|
||||||
set(CMAKE_C_ARCHIVE_CREATE "true")
|
|
||||||
set(CMAKE_CXX_ARCHIVE_APPEND "true")
|
|
||||||
set(CMAKE_C_ARCHIVE_APPEND "true")
|
|
||||||
set(CMAKE_RANLIB "true")
|
|
||||||
set(CMAKE_C_LINK_EXECUTABLE "true")
|
|
||||||
set(CMAKE_CXX_LINK_EXECUTABLE "true")
|
|
||||||
|
|
||||||
set(CMAKE_C_COMPILE_OBJECT "<CMAKE_C_COMPILER> -fsyntax-only <DEFINES> <INCLUDES> <FLAGS> -c <SOURCE> && touch <OBJECT>")
|
|
||||||
set(CMAKE_CXX_COMPILE_OBJECT "<CMAKE_CXX_COMPILER> -fsyntax-only <DEFINES> <INCLUDES> <FLAGS> -c <SOURCE> && touch <OBJECT>")
|
|
||||||
endif ()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||||
|
|
|
@ -1219,7 +1219,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar
|
||||||
, m_moving_enabled(false)
|
, m_moving_enabled(false)
|
||||||
, m_dynamic_background_enabled(false)
|
, m_dynamic_background_enabled(false)
|
||||||
, m_multisample_allowed(false)
|
, m_multisample_allowed(false)
|
||||||
, m_regenerate_volumes(true)
|
|
||||||
, m_moving(false)
|
, m_moving(false)
|
||||||
, m_tab_down(false)
|
, m_tab_down(false)
|
||||||
, m_cursor_type(Standard)
|
, m_cursor_type(Standard)
|
||||||
|
@ -1723,8 +1722,7 @@ void GLCanvas3D::select_all()
|
||||||
|
|
||||||
void GLCanvas3D::deselect_all()
|
void GLCanvas3D::deselect_all()
|
||||||
{
|
{
|
||||||
m_selection.clear();
|
m_selection.remove_all();
|
||||||
m_selection.set_mode(Selection::Instance);
|
|
||||||
wxGetApp().obj_manipul()->set_dirty();
|
wxGetApp().obj_manipul()->set_dirty();
|
||||||
m_gizmos.reset_all_states();
|
m_gizmos.reset_all_states();
|
||||||
m_gizmos.update_data();
|
m_gizmos.update_data();
|
||||||
|
@ -1858,245 +1856,235 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||||
PrinterTechnology printer_technology = m_process->current_printer_technology();
|
PrinterTechnology printer_technology = m_process->current_printer_technology();
|
||||||
int volume_idx_wipe_tower_old = -1;
|
int volume_idx_wipe_tower_old = -1;
|
||||||
|
|
||||||
if (printer_technology == ptSLA)
|
// Release invalidated volumes to conserve GPU memory in case of delayed refresh (see m_reload_delayed).
|
||||||
// Always do the full refresh in SLA mode to show / hide SLA support structures when an object is moved outside / inside the build volume.
|
// First initialize model_volumes_new_sorted & model_instances_new_sorted.
|
||||||
m_regenerate_volumes = true;
|
for (int object_idx = 0; object_idx < (int)m_model->objects.size(); ++ object_idx) {
|
||||||
|
const ModelObject *model_object = m_model->objects[object_idx];
|
||||||
if (m_regenerate_volumes)
|
for (int instance_idx = 0; instance_idx < (int)model_object->instances.size(); ++ instance_idx) {
|
||||||
{
|
const ModelInstance *model_instance = model_object->instances[instance_idx];
|
||||||
// Release invalidated volumes to conserve GPU memory in case of delayed refresh (see m_reload_delayed).
|
for (int volume_idx = 0; volume_idx < (int)model_object->volumes.size(); ++ volume_idx) {
|
||||||
// First initialize model_volumes_new_sorted & model_instances_new_sorted.
|
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
||||||
for (int object_idx = 0; object_idx < (int)m_model->objects.size(); ++ object_idx) {
|
model_volume_state.emplace_back(model_volume, model_instance->id(), GLVolume::CompositeID(object_idx, volume_idx, instance_idx));
|
||||||
const ModelObject *model_object = m_model->objects[object_idx];
|
|
||||||
for (int instance_idx = 0; instance_idx < (int)model_object->instances.size(); ++ instance_idx) {
|
|
||||||
const ModelInstance *model_instance = model_object->instances[instance_idx];
|
|
||||||
for (int volume_idx = 0; volume_idx < (int)model_object->volumes.size(); ++ volume_idx) {
|
|
||||||
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
|
||||||
model_volume_state.emplace_back(model_volume, model_instance->id(), GLVolume::CompositeID(object_idx, volume_idx, instance_idx));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (printer_technology == ptSLA) {
|
|
||||||
const SLAPrint *sla_print = this->sla_print();
|
|
||||||
#ifndef NDEBUG
|
|
||||||
// Verify that the SLAPrint object is synchronized with m_model.
|
|
||||||
check_model_ids_equal(*m_model, sla_print->model());
|
|
||||||
#endif /* NDEBUG */
|
|
||||||
sla_support_state.reserve(sla_print->objects().size());
|
|
||||||
for (const SLAPrintObject *print_object : sla_print->objects()) {
|
|
||||||
SLASupportState state;
|
|
||||||
for (size_t istep = 0; istep < sla_steps.size(); ++ istep) {
|
|
||||||
state.step[istep] = print_object->step_state_with_timestamp(sla_steps[istep]);
|
|
||||||
if (state.step[istep].state == PrintStateBase::DONE) {
|
|
||||||
if (! print_object->has_mesh(sla_steps[istep]))
|
|
||||||
// Consider the DONE step without a valid mesh as invalid for the purpose
|
|
||||||
// of mesh visualization.
|
|
||||||
state.step[istep].state = PrintStateBase::INVALID;
|
|
||||||
else
|
|
||||||
for (const ModelInstance *model_instance : print_object->model_object()->instances)
|
|
||||||
// Only the instances, which are currently printable, will have the SLA support structures kept.
|
|
||||||
// The instances outside the print bed will have the GLVolumes of their support structures released.
|
|
||||||
if (model_instance->is_printable())
|
|
||||||
aux_volume_state.emplace_back(state.step[istep].timestamp, model_instance->id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sla_support_state.emplace_back(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::sort(model_volume_state.begin(), model_volume_state.end(), model_volume_state_lower);
|
|
||||||
std::sort(aux_volume_state .begin(), aux_volume_state .end(), model_volume_state_lower);
|
|
||||||
// Release all ModelVolume based GLVolumes not found in the current Model.
|
|
||||||
for (size_t volume_id = 0; volume_id < m_volumes.volumes.size(); ++ volume_id) {
|
|
||||||
GLVolume *volume = m_volumes.volumes[volume_id];
|
|
||||||
ModelVolumeState key(volume);
|
|
||||||
ModelVolumeState *mvs = nullptr;
|
|
||||||
if (volume->volume_idx() < 0) {
|
|
||||||
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
|
|
||||||
if (it != aux_volume_state.end() && it->geometry_id == key.geometry_id)
|
|
||||||
mvs = &(*it);
|
|
||||||
} else {
|
|
||||||
auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower);
|
|
||||||
if (it != model_volume_state.end() && it->geometry_id == key.geometry_id)
|
|
||||||
mvs = &(*it);
|
|
||||||
}
|
|
||||||
// Emplace instance ID of the volume. Both the aux volumes and model volumes share the same instance ID.
|
|
||||||
// The wipe tower has its own wipe_tower_instance_id().
|
|
||||||
if (m_selection.contains_volume(volume_id))
|
|
||||||
instance_ids_selected.emplace_back(volume->geometry_id.second);
|
|
||||||
if (mvs == nullptr || force_full_scene_refresh) {
|
|
||||||
// This GLVolume will be released.
|
|
||||||
if (volume->is_wipe_tower) {
|
|
||||||
// There is only one wipe tower.
|
|
||||||
assert(volume_idx_wipe_tower_old == -1);
|
|
||||||
volume_idx_wipe_tower_old = (int)volume_id;
|
|
||||||
}
|
|
||||||
if (! m_reload_delayed)
|
|
||||||
delete volume;
|
|
||||||
} else {
|
|
||||||
// This GLVolume will be reused.
|
|
||||||
volume->set_sla_shift_z(0.0);
|
|
||||||
map_glvolume_old_to_new[volume_id] = glvolumes_new.size();
|
|
||||||
mvs->volume_idx = glvolumes_new.size();
|
|
||||||
glvolumes_new.emplace_back(volume);
|
|
||||||
// Update color of the volume based on the current extruder.
|
|
||||||
if (mvs->model_volume != nullptr) {
|
|
||||||
int extruder_id = mvs->model_volume->extruder_id();
|
|
||||||
if (extruder_id != -1)
|
|
||||||
volume->extruder_id = extruder_id;
|
|
||||||
|
|
||||||
volume->is_modifier = !mvs->model_volume->is_model_part();
|
|
||||||
volume->set_color_from_model_volume(mvs->model_volume);
|
|
||||||
|
|
||||||
// updates volumes transformations
|
|
||||||
volume->set_instance_transformation(mvs->model_volume->get_object()->instances[mvs->composite_id.instance_id]->get_transformation());
|
|
||||||
volume->set_volume_transformation(mvs->model_volume->get_transformation());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort_remove_duplicates(instance_ids_selected);
|
|
||||||
}
|
}
|
||||||
|
if (printer_technology == ptSLA) {
|
||||||
|
const SLAPrint *sla_print = this->sla_print();
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Verify that the SLAPrint object is synchronized with m_model.
|
||||||
|
check_model_ids_equal(*m_model, sla_print->model());
|
||||||
|
#endif /* NDEBUG */
|
||||||
|
sla_support_state.reserve(sla_print->objects().size());
|
||||||
|
for (const SLAPrintObject *print_object : sla_print->objects()) {
|
||||||
|
SLASupportState state;
|
||||||
|
for (size_t istep = 0; istep < sla_steps.size(); ++ istep) {
|
||||||
|
state.step[istep] = print_object->step_state_with_timestamp(sla_steps[istep]);
|
||||||
|
if (state.step[istep].state == PrintStateBase::DONE) {
|
||||||
|
if (! print_object->has_mesh(sla_steps[istep]))
|
||||||
|
// Consider the DONE step without a valid mesh as invalid for the purpose
|
||||||
|
// of mesh visualization.
|
||||||
|
state.step[istep].state = PrintStateBase::INVALID;
|
||||||
|
else
|
||||||
|
for (const ModelInstance *model_instance : print_object->model_object()->instances)
|
||||||
|
// Only the instances, which are currently printable, will have the SLA support structures kept.
|
||||||
|
// The instances outside the print bed will have the GLVolumes of their support structures released.
|
||||||
|
if (model_instance->is_printable())
|
||||||
|
aux_volume_state.emplace_back(state.step[istep].timestamp, model_instance->id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sla_support_state.emplace_back(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::sort(model_volume_state.begin(), model_volume_state.end(), model_volume_state_lower);
|
||||||
|
std::sort(aux_volume_state .begin(), aux_volume_state .end(), model_volume_state_lower);
|
||||||
|
// Release all ModelVolume based GLVolumes not found in the current Model.
|
||||||
|
for (size_t volume_id = 0; volume_id < m_volumes.volumes.size(); ++ volume_id) {
|
||||||
|
GLVolume *volume = m_volumes.volumes[volume_id];
|
||||||
|
ModelVolumeState key(volume);
|
||||||
|
ModelVolumeState *mvs = nullptr;
|
||||||
|
if (volume->volume_idx() < 0) {
|
||||||
|
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
|
||||||
|
if (it != aux_volume_state.end() && it->geometry_id == key.geometry_id)
|
||||||
|
mvs = &(*it);
|
||||||
|
} else {
|
||||||
|
auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower);
|
||||||
|
if (it != model_volume_state.end() && it->geometry_id == key.geometry_id)
|
||||||
|
mvs = &(*it);
|
||||||
|
}
|
||||||
|
// Emplace instance ID of the volume. Both the aux volumes and model volumes share the same instance ID.
|
||||||
|
// The wipe tower has its own wipe_tower_instance_id().
|
||||||
|
if (m_selection.contains_volume(volume_id))
|
||||||
|
instance_ids_selected.emplace_back(volume->geometry_id.second);
|
||||||
|
if (mvs == nullptr || force_full_scene_refresh) {
|
||||||
|
// This GLVolume will be released.
|
||||||
|
if (volume->is_wipe_tower) {
|
||||||
|
// There is only one wipe tower.
|
||||||
|
assert(volume_idx_wipe_tower_old == -1);
|
||||||
|
volume_idx_wipe_tower_old = (int)volume_id;
|
||||||
|
}
|
||||||
|
if (! m_reload_delayed)
|
||||||
|
delete volume;
|
||||||
|
} else {
|
||||||
|
// This GLVolume will be reused.
|
||||||
|
volume->set_sla_shift_z(0.0);
|
||||||
|
map_glvolume_old_to_new[volume_id] = glvolumes_new.size();
|
||||||
|
mvs->volume_idx = glvolumes_new.size();
|
||||||
|
glvolumes_new.emplace_back(volume);
|
||||||
|
// Update color of the volume based on the current extruder.
|
||||||
|
if (mvs->model_volume != nullptr) {
|
||||||
|
int extruder_id = mvs->model_volume->extruder_id();
|
||||||
|
if (extruder_id != -1)
|
||||||
|
volume->extruder_id = extruder_id;
|
||||||
|
|
||||||
|
volume->is_modifier = !mvs->model_volume->is_model_part();
|
||||||
|
volume->set_color_from_model_volume(mvs->model_volume);
|
||||||
|
|
||||||
|
// updates volumes transformations
|
||||||
|
volume->set_instance_transformation(mvs->model_volume->get_object()->instances[mvs->composite_id.instance_id]->get_transformation());
|
||||||
|
volume->set_volume_transformation(mvs->model_volume->get_transformation());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort_remove_duplicates(instance_ids_selected);
|
||||||
|
|
||||||
if (m_reload_delayed)
|
if (m_reload_delayed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool update_object_list = false;
|
bool update_object_list = false;
|
||||||
|
|
||||||
if (m_regenerate_volumes)
|
if (m_volumes.volumes != glvolumes_new)
|
||||||
{
|
update_object_list = true;
|
||||||
if (m_volumes.volumes != glvolumes_new)
|
m_volumes.volumes = std::move(glvolumes_new);
|
||||||
update_object_list = true;
|
for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++ obj_idx) {
|
||||||
m_volumes.volumes = std::move(glvolumes_new);
|
const ModelObject &model_object = *m_model->objects[obj_idx];
|
||||||
for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++ obj_idx) {
|
for (int volume_idx = 0; volume_idx < (int)model_object.volumes.size(); ++ volume_idx) {
|
||||||
const ModelObject &model_object = *m_model->objects[obj_idx];
|
const ModelVolume &model_volume = *model_object.volumes[volume_idx];
|
||||||
for (int volume_idx = 0; volume_idx < (int)model_object.volumes.size(); ++ volume_idx) {
|
for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) {
|
||||||
const ModelVolume &model_volume = *model_object.volumes[volume_idx];
|
const ModelInstance &model_instance = *model_object.instances[instance_idx];
|
||||||
for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) {
|
ModelVolumeState key(model_volume.id(), model_instance.id());
|
||||||
const ModelInstance &model_instance = *model_object.instances[instance_idx];
|
auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower);
|
||||||
ModelVolumeState key(model_volume.id(), model_instance.id());
|
assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id);
|
||||||
auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower);
|
if (it->new_geometry()) {
|
||||||
assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id);
|
// New volume.
|
||||||
if (it->new_geometry()) {
|
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by);
|
||||||
// New volume.
|
m_volumes.volumes.back()->geometry_id = key.geometry_id;
|
||||||
m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by);
|
update_object_list = true;
|
||||||
m_volumes.volumes.back()->geometry_id = key.geometry_id;
|
} else {
|
||||||
|
// Recycling an old GLVolume.
|
||||||
|
GLVolume &existing_volume = *m_volumes.volumes[it->volume_idx];
|
||||||
|
assert(existing_volume.geometry_id == key.geometry_id);
|
||||||
|
// Update the Object/Volume/Instance indices into the current Model.
|
||||||
|
if (existing_volume.composite_id != it->composite_id) {
|
||||||
|
existing_volume.composite_id = it->composite_id;
|
||||||
update_object_list = true;
|
update_object_list = true;
|
||||||
} else {
|
}
|
||||||
// Recycling an old GLVolume.
|
}
|
||||||
GLVolume &existing_volume = *m_volumes.volumes[it->volume_idx];
|
}
|
||||||
assert(existing_volume.geometry_id == key.geometry_id);
|
}
|
||||||
// Update the Object/Volume/Instance indices into the current Model.
|
}
|
||||||
if (existing_volume.composite_id != it->composite_id) {
|
if (printer_technology == ptSLA) {
|
||||||
existing_volume.composite_id = it->composite_id;
|
size_t idx = 0;
|
||||||
update_object_list = true;
|
const SLAPrint *sla_print = this->sla_print();
|
||||||
|
std::vector<double> shift_zs(m_model->objects.size(), 0);
|
||||||
|
double relative_correction_z = sla_print->relative_correction().z();
|
||||||
|
if (relative_correction_z <= EPSILON)
|
||||||
|
relative_correction_z = 1.;
|
||||||
|
for (const SLAPrintObject *print_object : sla_print->objects()) {
|
||||||
|
SLASupportState &state = sla_support_state[idx ++];
|
||||||
|
const ModelObject *model_object = print_object->model_object();
|
||||||
|
// Find an index of the ModelObject
|
||||||
|
int object_idx;
|
||||||
|
if (std::all_of(state.step.begin(), state.step.end(), [](const PrintStateBase::StateWithTimeStamp &state){ return state.state != PrintStateBase::DONE; }))
|
||||||
|
continue;
|
||||||
|
// There may be new SLA volumes added to the scene for this print_object.
|
||||||
|
// Find the object index of this print_object in the Model::objects list.
|
||||||
|
auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object);
|
||||||
|
assert(it != sla_print->model().objects.end());
|
||||||
|
object_idx = it - sla_print->model().objects.begin();
|
||||||
|
// Cache the Z offset to be applied to all volumes with this object_idx.
|
||||||
|
shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z;
|
||||||
|
// Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene.
|
||||||
|
// pairs of <instance_idx, print_instance_idx>
|
||||||
|
std::vector<std::pair<size_t, size_t>> instances[std::tuple_size<SLASteps>::value];
|
||||||
|
for (size_t print_instance_idx = 0; print_instance_idx < print_object->instances().size(); ++ print_instance_idx) {
|
||||||
|
const SLAPrintObject::Instance &instance = print_object->instances()[print_instance_idx];
|
||||||
|
// Find index of ModelInstance corresponding to this SLAPrintObject::Instance.
|
||||||
|
auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(),
|
||||||
|
[&instance](const ModelInstance *mi) { return mi->id() == instance.instance_id; });
|
||||||
|
assert(it != model_object->instances.end());
|
||||||
|
int instance_idx = it - model_object->instances.begin();
|
||||||
|
for (size_t istep = 0; istep < sla_steps.size(); ++ istep)
|
||||||
|
if (state.step[istep].state == PrintStateBase::DONE) {
|
||||||
|
ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id);
|
||||||
|
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
|
||||||
|
assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id);
|
||||||
|
if (it->new_geometry())
|
||||||
|
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
|
||||||
|
else {
|
||||||
|
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
|
||||||
|
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
|
||||||
|
m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (printer_technology == ptSLA) {
|
|
||||||
size_t idx = 0;
|
|
||||||
const SLAPrint *sla_print = this->sla_print();
|
|
||||||
std::vector<double> shift_zs(m_model->objects.size(), 0);
|
|
||||||
double relative_correction_z = sla_print->relative_correction().z();
|
|
||||||
if (relative_correction_z <= EPSILON)
|
|
||||||
relative_correction_z = 1.;
|
|
||||||
for (const SLAPrintObject *print_object : sla_print->objects()) {
|
|
||||||
SLASupportState &state = sla_support_state[idx ++];
|
|
||||||
const ModelObject *model_object = print_object->model_object();
|
|
||||||
// Find an index of the ModelObject
|
|
||||||
int object_idx;
|
|
||||||
if (std::all_of(state.step.begin(), state.step.end(), [](const PrintStateBase::StateWithTimeStamp &state){ return state.state != PrintStateBase::DONE; }))
|
|
||||||
continue;
|
|
||||||
// There may be new SLA volumes added to the scene for this print_object.
|
|
||||||
// Find the object index of this print_object in the Model::objects list.
|
|
||||||
auto it = std::find(sla_print->model().objects.begin(), sla_print->model().objects.end(), model_object);
|
|
||||||
assert(it != sla_print->model().objects.end());
|
|
||||||
object_idx = it - sla_print->model().objects.begin();
|
|
||||||
// Cache the Z offset to be applied to all volumes with this object_idx.
|
|
||||||
shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z;
|
|
||||||
// Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene.
|
|
||||||
// pairs of <instance_idx, print_instance_idx>
|
|
||||||
std::vector<std::pair<size_t, size_t>> instances[std::tuple_size<SLASteps>::value];
|
|
||||||
for (size_t print_instance_idx = 0; print_instance_idx < print_object->instances().size(); ++ print_instance_idx) {
|
|
||||||
const SLAPrintObject::Instance &instance = print_object->instances()[print_instance_idx];
|
|
||||||
// Find index of ModelInstance corresponding to this SLAPrintObject::Instance.
|
|
||||||
auto it = std::find_if(model_object->instances.begin(), model_object->instances.end(),
|
|
||||||
[&instance](const ModelInstance *mi) { return mi->id() == instance.instance_id; });
|
|
||||||
assert(it != model_object->instances.end());
|
|
||||||
int instance_idx = it - model_object->instances.begin();
|
|
||||||
for (size_t istep = 0; istep < sla_steps.size(); ++ istep)
|
|
||||||
if (state.step[istep].state == PrintStateBase::DONE) {
|
|
||||||
ModelVolumeState key(state.step[istep].timestamp, instance.instance_id.id);
|
|
||||||
auto it = std::lower_bound(aux_volume_state.begin(), aux_volume_state.end(), key, model_volume_state_lower);
|
|
||||||
assert(it != aux_volume_state.end() && it->geometry_id == key.geometry_id);
|
|
||||||
if (it->new_geometry())
|
|
||||||
instances[istep].emplace_back(std::pair<size_t, size_t>(instance_idx, print_instance_idx));
|
|
||||||
else {
|
|
||||||
// Recycling an old GLVolume. Update the Object/Instance indices into the current Model.
|
|
||||||
m_volumes.volumes[it->volume_idx]->composite_id = GLVolume::CompositeID(object_idx, m_volumes.volumes[it->volume_idx]->volume_idx(), instance_idx);
|
|
||||||
m_volumes.volumes[it->volume_idx]->set_instance_transformation(model_object->instances[instance_idx]->get_transformation());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// stores the current volumes count
|
|
||||||
size_t volumes_count = m_volumes.volumes.size();
|
|
||||||
|
|
||||||
for (size_t istep = 0; istep < sla_steps.size(); ++istep)
|
|
||||||
if (!instances[istep].empty())
|
|
||||||
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
|
// stores the current volumes count
|
||||||
for (GLVolume* volume : m_volumes.volumes)
|
size_t volumes_count = m_volumes.volumes.size();
|
||||||
if (volume->object_idx() < m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable())
|
|
||||||
volume->set_sla_shift_z(shift_zs[volume->object_idx()]);
|
for (size_t istep = 0; istep < sla_steps.size(); ++istep)
|
||||||
|
if (!instances[istep].empty())
|
||||||
|
m_volumes.load_object_auxiliary(print_object, object_idx, instances[istep], sla_steps[istep], state.step[istep].timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (printer_technology == ptFFF && m_config->has("nozzle_diameter"))
|
// Shift-up all volumes of the object so that it has the right elevation with respect to the print bed
|
||||||
|
for (GLVolume* volume : m_volumes.volumes)
|
||||||
|
if (volume->object_idx() < m_model->objects.size() && m_model->objects[volume->object_idx()]->instances[volume->instance_idx()]->is_printable())
|
||||||
|
volume->set_sla_shift_z(shift_zs[volume->object_idx()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printer_technology == ptFFF && m_config->has("nozzle_diameter"))
|
||||||
|
{
|
||||||
|
// Should the wipe tower be visualized ?
|
||||||
|
unsigned int extruders_count = (unsigned int)dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values.size();
|
||||||
|
|
||||||
|
bool wt = dynamic_cast<const ConfigOptionBool*>(m_config->option("wipe_tower"))->value;
|
||||||
|
bool co = dynamic_cast<const ConfigOptionBool*>(m_config->option("complete_objects"))->value;
|
||||||
|
|
||||||
|
if ((extruders_count > 1) && wt && !co)
|
||||||
{
|
{
|
||||||
// Should the wipe tower be visualized ?
|
// Height of a print (Show at least a slab)
|
||||||
unsigned int extruders_count = (unsigned int)dynamic_cast<const ConfigOptionFloats*>(m_config->option("nozzle_diameter"))->values.size();
|
double height = std::max(m_model->bounding_box().max(2), 10.0);
|
||||||
|
|
||||||
bool wt = dynamic_cast<const ConfigOptionBool*>(m_config->option("wipe_tower"))->value;
|
float x = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_x"))->value;
|
||||||
bool co = dynamic_cast<const ConfigOptionBool*>(m_config->option("complete_objects"))->value;
|
float y = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_y"))->value;
|
||||||
|
float w = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_width"))->value;
|
||||||
|
float a = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_rotation_angle"))->value;
|
||||||
|
|
||||||
if ((extruders_count > 1) && wt && !co)
|
const Print *print = m_process->fff_print();
|
||||||
{
|
float depth = print->get_wipe_tower_depth();
|
||||||
// Height of a print (Show at least a slab)
|
|
||||||
double height = std::max(m_model->bounding_box().max(2), 10.0);
|
|
||||||
|
|
||||||
float x = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_x"))->value;
|
// Calculate wipe tower brim spacing.
|
||||||
float y = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_y"))->value;
|
const DynamicPrintConfig &print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
||||||
float w = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_width"))->value;
|
double layer_height = print_config.opt_float("layer_height");
|
||||||
float a = dynamic_cast<const ConfigOptionFloat*>(m_config->option("wipe_tower_rotation_angle"))->value;
|
double first_layer_height = print_config.get_abs_value("first_layer_height", layer_height);
|
||||||
|
float brim_spacing = print->config().nozzle_diameter.values[0] * 1.25f - first_layer_height * (1. - M_PI_4);
|
||||||
|
|
||||||
const Print *print = m_process->fff_print();
|
if (!print->is_step_done(psWipeTower))
|
||||||
float depth = print->get_wipe_tower_depth();
|
depth = (900.f/w) * (float)(extruders_count - 1);
|
||||||
|
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
|
||||||
// Calculate wipe tower brim spacing.
|
1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
||||||
const DynamicPrintConfig &print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config;
|
brim_spacing * 4.5f);
|
||||||
double layer_height = print_config.opt_float("layer_height");
|
if (volume_idx_wipe_tower_old != -1)
|
||||||
double first_layer_height = print_config.get_abs_value("first_layer_height", layer_height);
|
map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new;
|
||||||
float brim_spacing = print->config().nozzle_diameter.values[0] * 1.25f - first_layer_height * (1. - M_PI_4);
|
|
||||||
|
|
||||||
if (!print->is_step_done(psWipeTower))
|
|
||||||
depth = (900.f/w) * (float)(extruders_count - 1);
|
|
||||||
int volume_idx_wipe_tower_new = m_volumes.load_wipe_tower_preview(
|
|
||||||
1000, x, y, w, depth, (float)height, a, !print->is_step_done(psWipeTower),
|
|
||||||
brim_spacing * 4.5f);
|
|
||||||
if (volume_idx_wipe_tower_old != -1)
|
|
||||||
map_glvolume_old_to_new[volume_idx_wipe_tower_old] = volume_idx_wipe_tower_new;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
update_volumes_colors_by_extruder();
|
update_volumes_colors_by_extruder();
|
||||||
// Update selection indices based on the old/new GLVolumeCollection.
|
// Update selection indices based on the old/new GLVolumeCollection.
|
||||||
if (m_selection.get_mode() == Selection::Instance)
|
if (m_selection.get_mode() == Selection::Instance)
|
||||||
m_selection.instances_changed(instance_ids_selected);
|
m_selection.instances_changed(instance_ids_selected);
|
||||||
else
|
else
|
||||||
m_selection.volumes_changed(map_glvolume_old_to_new);
|
m_selection.volumes_changed(map_glvolume_old_to_new);
|
||||||
}
|
|
||||||
|
|
||||||
m_gizmos.update_data();
|
m_gizmos.update_data();
|
||||||
m_gizmos.refresh_on_off_state();
|
m_gizmos.refresh_on_off_state();
|
||||||
|
@ -2139,9 +2127,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||||
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false));
|
post_event(Event<bool>(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
// restore to default value
|
|
||||||
m_regenerate_volumes = true;
|
|
||||||
|
|
||||||
m_camera.set_scene_box(scene_bounding_box());
|
m_camera.set_scene_box(scene_bounding_box());
|
||||||
|
|
||||||
if (m_selection.is_empty())
|
if (m_selection.is_empty())
|
||||||
|
@ -2913,7 +2898,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_regenerate_volumes = false;
|
|
||||||
m_selection.translate(cur_pos - m_mouse.drag.start_position_3D);
|
m_selection.translate(cur_pos - m_mouse.drag.start_position_3D);
|
||||||
wxGetApp().obj_manipul()->set_dirty();
|
wxGetApp().obj_manipul()->set_dirty();
|
||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
|
@ -2973,7 +2957,6 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
||||||
}
|
}
|
||||||
else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging)
|
else if ((m_mouse.drag.move_volume_idx != -1) && m_mouse.dragging)
|
||||||
{
|
{
|
||||||
m_regenerate_volumes = false;
|
|
||||||
do_move(L("Move Object"));
|
do_move(L("Move Object"));
|
||||||
wxGetApp().obj_manipul()->set_dirty();
|
wxGetApp().obj_manipul()->set_dirty();
|
||||||
// Let the plater know that the dragging finished, so a delayed refresh
|
// Let the plater know that the dragging finished, so a delayed refresh
|
||||||
|
@ -5661,7 +5644,7 @@ void GLCanvas3D::_update_selection_from_hover()
|
||||||
if (m_hover_volume_idxs.empty())
|
if (m_hover_volume_idxs.empty())
|
||||||
{
|
{
|
||||||
if (!ctrl_pressed && (m_rectangle_selection.get_state() == GLSelectionRectangle::Select))
|
if (!ctrl_pressed && (m_rectangle_selection.get_state() == GLSelectionRectangle::Select))
|
||||||
m_selection.clear();
|
m_selection.remove_all();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -5678,6 +5661,51 @@ void GLCanvas3D::_update_selection_from_hover()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool selection_changed = false;
|
||||||
|
if (state == GLSelectionRectangle::Select)
|
||||||
|
{
|
||||||
|
bool contains_all = true;
|
||||||
|
for (int i : m_hover_volume_idxs)
|
||||||
|
{
|
||||||
|
if (!m_selection.contains_volume((unsigned int)i))
|
||||||
|
{
|
||||||
|
contains_all = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the selection is going to be modified (Add)
|
||||||
|
if (!contains_all)
|
||||||
|
{
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Add from rectangle")));
|
||||||
|
selection_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool contains_any = false;
|
||||||
|
for (int i : m_hover_volume_idxs)
|
||||||
|
{
|
||||||
|
if (m_selection.contains_volume((unsigned int)i))
|
||||||
|
{
|
||||||
|
contains_any = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// the selection is going to be modified (Remove)
|
||||||
|
if (contains_any)
|
||||||
|
{
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove from rectangle")));
|
||||||
|
selection_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!selection_changed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Plater::SuppressSnapshots suppress(wxGetApp().plater());
|
||||||
|
|
||||||
if ((state == GLSelectionRectangle::Select) && !ctrl_pressed)
|
if ((state == GLSelectionRectangle::Select) && !ctrl_pressed)
|
||||||
m_selection.clear();
|
m_selection.clear();
|
||||||
|
|
||||||
|
|
|
@ -463,7 +463,6 @@ private:
|
||||||
bool m_moving_enabled;
|
bool m_moving_enabled;
|
||||||
bool m_dynamic_background_enabled;
|
bool m_dynamic_background_enabled;
|
||||||
bool m_multisample_allowed;
|
bool m_multisample_allowed;
|
||||||
bool m_regenerate_volumes;
|
|
||||||
bool m_moving;
|
bool m_moving;
|
||||||
bool m_tab_down;
|
bool m_tab_down;
|
||||||
ECursorType m_cursor_type;
|
ECursorType m_cursor_type;
|
||||||
|
@ -652,7 +651,6 @@ public:
|
||||||
Linef3 mouse_ray(const Point& mouse_pos);
|
Linef3 mouse_ray(const Point& mouse_pos);
|
||||||
|
|
||||||
void set_mouse_as_dragging() { m_mouse.dragging = true; }
|
void set_mouse_as_dragging() { m_mouse.dragging = true; }
|
||||||
void disable_regenerate_volumes() { m_regenerate_volumes = false; }
|
|
||||||
void refresh_camera_scene_box() { m_camera.set_scene_box(scene_bounding_box()); }
|
void refresh_camera_scene_box() { m_camera.set_scene_box(scene_bounding_box()); }
|
||||||
bool is_mouse_dragging() const { return m_mouse.dragging; }
|
bool is_mouse_dragging() const { return m_mouse.dragging; }
|
||||||
|
|
||||||
|
|
|
@ -1566,9 +1566,9 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::update_opt_keys(t_config_option_keys& opt_keys)
|
void ObjectList::update_opt_keys(t_config_option_keys& opt_keys, const bool is_object)
|
||||||
{
|
{
|
||||||
auto full_current_opts = get_options(false);
|
auto full_current_opts = get_options(!is_object);
|
||||||
for (int i = opt_keys.size()-1; i >= 0; --i)
|
for (int i = opt_keys.size()-1; i >= 0; --i)
|
||||||
if (find(full_current_opts.begin(), full_current_opts.end(), opt_keys[i]) == full_current_opts.end())
|
if (find(full_current_opts.begin(), full_current_opts.end(), opt_keys[i]) == full_current_opts.end())
|
||||||
opt_keys.erase(opt_keys.begin() + i);
|
opt_keys.erase(opt_keys.begin() + i);
|
||||||
|
@ -2161,16 +2161,15 @@ void ObjectList::part_selection_changed()
|
||||||
panel.Thaw();
|
panel.Thaw();
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsBundle ObjectList::get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_layers_range_settings)
|
SettingsBundle ObjectList::get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_object_settings)
|
||||||
{
|
{
|
||||||
auto opt_keys = config->keys();
|
auto opt_keys = config->keys();
|
||||||
if (opt_keys.empty())
|
if (opt_keys.empty())
|
||||||
return SettingsBundle();
|
return SettingsBundle();
|
||||||
|
|
||||||
update_opt_keys(opt_keys); // update options list according to print technology
|
update_opt_keys(opt_keys, is_object_settings); // update options list according to print technology
|
||||||
|
|
||||||
if (opt_keys.size() == 1 && opt_keys[0] == "extruder" ||
|
if (opt_keys.empty())
|
||||||
is_layers_range_settings && opt_keys.size() == 2)
|
|
||||||
return SettingsBundle();
|
return SettingsBundle();
|
||||||
|
|
||||||
const int extruders_cnt = wxGetApp().extruders_edited_cnt();
|
const int extruders_cnt = wxGetApp().extruders_edited_cnt();
|
||||||
|
@ -2201,24 +2200,15 @@ wxDataViewItem ObjectList::add_settings_item(wxDataViewItem parent_item, const D
|
||||||
if (!parent_item)
|
if (!parent_item)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
const bool is_layers_range_settings = m_objects_model->GetItemType(parent_item) == itLayer;
|
const bool is_object_settings = m_objects_model->GetItemType(parent_item) == itObject;
|
||||||
SettingsBundle cat_options = get_item_settings_bundle(config, is_layers_range_settings);
|
SettingsBundle cat_options = get_item_settings_bundle(config, is_object_settings);
|
||||||
if (cat_options.empty())
|
if (cat_options.empty())
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
std::vector<std::string> categories;
|
std::vector<std::string> categories;
|
||||||
categories.reserve(cat_options.size());
|
categories.reserve(cat_options.size());
|
||||||
for (auto& cat : cat_options)
|
for (auto& cat : cat_options)
|
||||||
{
|
|
||||||
if (cat.second.size() == 1 &&
|
|
||||||
(cat.second[0] == "extruder" || is_layers_range_settings && cat.second[0] == "layer_height"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
categories.push_back(cat.first);
|
categories.push_back(cat.first);
|
||||||
}
|
|
||||||
|
|
||||||
if (categories.empty())
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (m_objects_model->GetItemType(parent_item) & itInstance)
|
if (m_objects_model->GetItemType(parent_item) & itInstance)
|
||||||
parent_item = m_objects_model->GetTopParent(parent_item);
|
parent_item = m_objects_model->GetTopParent(parent_item);
|
||||||
|
@ -2803,26 +2793,35 @@ void ObjectList::update_selections_on_canvas()
|
||||||
|
|
||||||
const int sel_cnt = GetSelectedItemsCount();
|
const int sel_cnt = GetSelectedItemsCount();
|
||||||
if (sel_cnt == 0) {
|
if (sel_cnt == 0) {
|
||||||
selection.clear();
|
selection.remove_all();
|
||||||
wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state();
|
wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection)
|
std::vector<unsigned int> volume_idxs;
|
||||||
|
Selection::EMode mode = Selection::Volume;
|
||||||
|
auto add_to_selection = [this, &volume_idxs](const wxDataViewItem& item, const Selection& selection, int instance_idx, Selection::EMode& mode)
|
||||||
{
|
{
|
||||||
const ItemType& type = m_objects_model->GetItemType(item);
|
const ItemType& type = m_objects_model->GetItemType(item);
|
||||||
const int obj_idx = m_objects_model->GetObjectIdByItem(item);
|
const int obj_idx = m_objects_model->GetObjectIdByItem(item);
|
||||||
|
|
||||||
if (type == itVolume) {
|
if (type == itVolume) {
|
||||||
const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
|
const int vol_idx = m_objects_model->GetVolumeIdByItem(item);
|
||||||
selection.add_volume(obj_idx, vol_idx, std::max(instance_idx, 0), as_single_selection);
|
std::vector<unsigned int> idxs = selection.get_volume_idxs_from_volume(obj_idx, std::max(instance_idx, 0), vol_idx);
|
||||||
|
volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end());
|
||||||
}
|
}
|
||||||
else if (type == itInstance) {
|
else if (type == itInstance) {
|
||||||
const int inst_idx = m_objects_model->GetInstanceIdByItem(item);
|
const int inst_idx = m_objects_model->GetInstanceIdByItem(item);
|
||||||
selection.add_instance(obj_idx, inst_idx, as_single_selection);
|
mode = Selection::Instance;
|
||||||
|
std::vector<unsigned int> idxs = selection.get_volume_idxs_from_instance(obj_idx, inst_idx);
|
||||||
|
volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
selection.add_object(obj_idx, as_single_selection);
|
{
|
||||||
|
mode = Selection::Instance;
|
||||||
|
std::vector<unsigned int> idxs = selection.get_volume_idxs_from_object(obj_idx);
|
||||||
|
volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// stores current instance idx before to clear the selection
|
// stores current instance idx before to clear the selection
|
||||||
|
@ -2831,21 +2830,38 @@ void ObjectList::update_selections_on_canvas()
|
||||||
if (sel_cnt == 1) {
|
if (sel_cnt == 1) {
|
||||||
wxDataViewItem item = GetSelection();
|
wxDataViewItem item = GetSelection();
|
||||||
if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer))
|
if (m_objects_model->GetItemType(item) & (itSettings | itInstanceRoot | itLayerRoot | itLayer))
|
||||||
add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, true);
|
add_to_selection(m_objects_model->GetParent(item), selection, instance_idx, mode);
|
||||||
else
|
else
|
||||||
add_to_selection(item, selection, instance_idx, true);
|
add_to_selection(item, selection, instance_idx, mode);
|
||||||
|
|
||||||
wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state();
|
|
||||||
wxGetApp().plater()->canvas3D()->render();
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
wxDataViewItemArray sels;
|
{
|
||||||
GetSelections(sels);
|
wxDataViewItemArray sels;
|
||||||
|
GetSelections(sels);
|
||||||
|
|
||||||
selection.clear();
|
for (auto item : sels)
|
||||||
for (auto item: sels)
|
{
|
||||||
add_to_selection(item, selection, instance_idx, false);
|
add_to_selection(item, selection, instance_idx, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selection.contains_all_volumes(volume_idxs))
|
||||||
|
{
|
||||||
|
// remove
|
||||||
|
volume_idxs = selection.get_missing_volume_idxs_from(volume_idxs);
|
||||||
|
if (volume_idxs.size() > 0)
|
||||||
|
{
|
||||||
|
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Selection-Remove from list")));
|
||||||
|
selection.remove_volumes(mode, volume_idxs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// add
|
||||||
|
volume_idxs = selection.get_unselected_volume_idxs_from(volume_idxs);
|
||||||
|
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Selection-Add from list")));
|
||||||
|
selection.add_volumes(mode, volume_idxs, sel_cnt == 1);
|
||||||
|
}
|
||||||
|
|
||||||
wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state();
|
wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state();
|
||||||
wxGetApp().plater()->canvas3D()->render();
|
wxGetApp().plater()->canvas3D()->render();
|
||||||
|
|
|
@ -238,7 +238,7 @@ public:
|
||||||
wxMenu* create_settings_popupmenu(wxMenu *parent_menu);
|
wxMenu* create_settings_popupmenu(wxMenu *parent_menu);
|
||||||
void create_freq_settings_popupmenu(wxMenu *parent_menu);
|
void create_freq_settings_popupmenu(wxMenu *parent_menu);
|
||||||
|
|
||||||
void update_opt_keys(t_config_option_keys& t_optopt_keys);
|
void update_opt_keys(t_config_option_keys& t_optopt_keys, const bool is_object);
|
||||||
|
|
||||||
void load_subobject(ModelVolumeType type);
|
void load_subobject(ModelVolumeType type);
|
||||||
void load_part(ModelObject* model_object, std::vector<std::pair<wxString, bool>> &volumes_info, ModelVolumeType type);
|
void load_part(ModelObject* model_object, std::vector<std::pair<wxString, bool>> &volumes_info, ModelVolumeType type);
|
||||||
|
@ -266,7 +266,7 @@ public:
|
||||||
wxBoxSizer* get_sizer() {return m_sizer;}
|
wxBoxSizer* get_sizer() {return m_sizer;}
|
||||||
int get_selected_obj_idx() const;
|
int get_selected_obj_idx() const;
|
||||||
DynamicPrintConfig& get_item_config(const wxDataViewItem& item) const;
|
DynamicPrintConfig& get_item_config(const wxDataViewItem& item) const;
|
||||||
SettingsBundle get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_layers_range_settings);
|
SettingsBundle get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_object_settings);
|
||||||
|
|
||||||
void changed_object(const int obj_idx = -1) const;
|
void changed_object(const int obj_idx = -1) const;
|
||||||
void part_selection_changed();
|
void part_selection_changed();
|
||||||
|
|
|
@ -77,8 +77,8 @@ bool ObjectSettings::update_settings_list()
|
||||||
if (!item || !objects_model->IsSettingsItem(item) || !config || objects_ctrl->multiple_selection())
|
if (!item || !objects_model->IsSettingsItem(item) || !config || objects_ctrl->multiple_selection())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const bool is_layers_range_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itLayer;
|
const bool is_object_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itObject;
|
||||||
SettingsBundle cat_options = objects_ctrl->get_item_settings_bundle(config, is_layers_range_settings);
|
SettingsBundle cat_options = objects_ctrl->get_item_settings_bundle(config, is_object_settings);
|
||||||
|
|
||||||
if (!cat_options.empty())
|
if (!cat_options.empty())
|
||||||
{
|
{
|
||||||
|
@ -107,10 +107,6 @@ bool ObjectSettings::update_settings_list()
|
||||||
|
|
||||||
for (auto& cat : cat_options)
|
for (auto& cat : cat_options)
|
||||||
{
|
{
|
||||||
if (cat.second.size() == 1 &&
|
|
||||||
(cat.second[0] == "extruder" || is_layers_range_settings && cat.second[0] == "layer_height"))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
categories.push_back(cat.first);
|
categories.push_back(cat.first);
|
||||||
|
|
||||||
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
|
auto optgroup = std::make_shared<ConfigOptionsGroup>(m_og->ctrl_parent(), _(cat.first), config, false, extra_column);
|
||||||
|
@ -131,8 +127,6 @@ bool ObjectSettings::update_settings_list()
|
||||||
const bool is_extruders_cat = cat.first == "Extruders";
|
const bool is_extruders_cat = cat.first == "Extruders";
|
||||||
for (auto& opt : cat.second)
|
for (auto& opt : cat.second)
|
||||||
{
|
{
|
||||||
if (opt == "extruder" || is_layers_range_settings && opt == "layer_height")
|
|
||||||
continue;
|
|
||||||
Option option = optgroup->get_option(opt);
|
Option option = optgroup->get_option(opt);
|
||||||
option.opt.width = 12;
|
option.opt.width = 12;
|
||||||
if (is_extruders_cat)
|
if (is_extruders_cat)
|
||||||
|
|
|
@ -623,7 +623,6 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt)
|
||||||
{
|
{
|
||||||
case Move:
|
case Move:
|
||||||
{
|
{
|
||||||
m_parent.disable_regenerate_volumes();
|
|
||||||
m_parent.do_move(L("Gizmo-Move"));
|
m_parent.do_move(L("Gizmo-Move"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -718,7 +718,7 @@ Sidebar::Sidebar(Plater *parent)
|
||||||
p->scrolled->SetSizer(scrolled_sizer);
|
p->scrolled->SetSizer(scrolled_sizer);
|
||||||
|
|
||||||
// Sizer with buttons for mode changing
|
// Sizer with buttons for mode changing
|
||||||
p->mode_sizer = new ModeSizer(p->scrolled, 2 * wxGetApp().em_unit());
|
p->mode_sizer = new ModeSizer(p->scrolled);
|
||||||
|
|
||||||
// The preset chooser
|
// The preset chooser
|
||||||
p->sizer_presets = new wxFlexGridSizer(10, 1, 1, 2);
|
p->sizer_presets = new wxFlexGridSizer(10, 1, 1, 2);
|
||||||
|
@ -1335,12 +1335,7 @@ struct Plater::priv
|
||||||
Slic3r::Model model;
|
Slic3r::Model model;
|
||||||
PrinterTechnology printer_technology = ptFFF;
|
PrinterTechnology printer_technology = ptFFF;
|
||||||
Slic3r::GCodePreviewData gcode_preview_data;
|
Slic3r::GCodePreviewData gcode_preview_data;
|
||||||
Slic3r::UndoRedo::Stack undo_redo_stack;
|
|
||||||
int m_prevent_snapshots = 0; /* Used for avoid of excess "snapshoting".
|
|
||||||
* Like for "delete selected" or "set numbers of copies"
|
|
||||||
* we should call tack_snapshot just ones
|
|
||||||
* instead of calls for each action separately
|
|
||||||
* */
|
|
||||||
// GUI elements
|
// GUI elements
|
||||||
wxSizer* panel_sizer{ nullptr };
|
wxSizer* panel_sizer{ nullptr };
|
||||||
wxPanel* current_panel{ nullptr };
|
wxPanel* current_panel{ nullptr };
|
||||||
|
@ -1785,9 +1780,16 @@ struct Plater::priv
|
||||||
void split_volume();
|
void split_volume();
|
||||||
void scale_selection_to_fit_print_volume();
|
void scale_selection_to_fit_print_volume();
|
||||||
|
|
||||||
|
// Return the active Undo/Redo stack. It may be either the main stack or the Gimzo stack.
|
||||||
|
Slic3r::UndoRedo::Stack& undo_redo_stack() { assert(m_undo_redo_stack_active != nullptr); return *m_undo_redo_stack_active; }
|
||||||
|
Slic3r::UndoRedo::Stack& undo_redo_stack_main() { return m_undo_redo_stack_main; }
|
||||||
|
void enter_gizmos_stack();
|
||||||
|
void leave_gizmos_stack();
|
||||||
|
|
||||||
void take_snapshot(const std::string& snapshot_name);
|
void take_snapshot(const std::string& snapshot_name);
|
||||||
void take_snapshot(const wxString& snapshot_name) { this->take_snapshot(std::string(snapshot_name.ToUTF8().data())); }
|
void take_snapshot(const wxString& snapshot_name) { this->take_snapshot(std::string(snapshot_name.ToUTF8().data())); }
|
||||||
int get_active_snapshot_index();
|
int get_active_snapshot_index();
|
||||||
|
|
||||||
void undo();
|
void undo();
|
||||||
void redo();
|
void redo();
|
||||||
void undo_redo_to(size_t time_to_load);
|
void undo_redo_to(size_t time_to_load);
|
||||||
|
@ -1889,7 +1891,15 @@ private:
|
||||||
void update_after_undo_redo(bool temp_snapshot_was_taken = false);
|
void update_after_undo_redo(bool temp_snapshot_was_taken = false);
|
||||||
|
|
||||||
// path to project file stored with no extension
|
// path to project file stored with no extension
|
||||||
wxString m_project_filename;
|
wxString m_project_filename;
|
||||||
|
Slic3r::UndoRedo::Stack m_undo_redo_stack_main;
|
||||||
|
Slic3r::UndoRedo::Stack m_undo_redo_stack_gizmos;
|
||||||
|
Slic3r::UndoRedo::Stack *m_undo_redo_stack_active = &m_undo_redo_stack_main;
|
||||||
|
int m_prevent_snapshots = 0; /* Used for avoid of excess "snapshoting".
|
||||||
|
* Like for "delete selected" or "set numbers of copies"
|
||||||
|
* we should call tack_snapshot just ones
|
||||||
|
* instead of calls for each action separately
|
||||||
|
* */
|
||||||
std::string m_last_fff_printer_profile_name;
|
std::string m_last_fff_printer_profile_name;
|
||||||
std::string m_last_sla_printer_profile_name;
|
std::string m_last_sla_printer_profile_name;
|
||||||
};
|
};
|
||||||
|
@ -3712,10 +3722,32 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Plater::priv::enter_gizmos_stack()
|
||||||
|
{
|
||||||
|
assert(m_undo_redo_stack_active == &m_undo_redo_stack_main);
|
||||||
|
if (m_undo_redo_stack_active == &m_undo_redo_stack_main) {
|
||||||
|
m_undo_redo_stack_active = &m_undo_redo_stack_gizmos;
|
||||||
|
assert(m_undo_redo_stack_active->empty());
|
||||||
|
// Take the initial snapshot of the gizmos.
|
||||||
|
// Not localized on purpose, the text will never be shown to the user.
|
||||||
|
this->take_snapshot(std::string("Gizmos-Initial"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Plater::priv::leave_gizmos_stack()
|
||||||
|
{
|
||||||
|
assert(m_undo_redo_stack_active == &m_undo_redo_stack_gizmos);
|
||||||
|
if (m_undo_redo_stack_active == &m_undo_redo_stack_gizmos) {
|
||||||
|
assert(! m_undo_redo_stack_active->empty());
|
||||||
|
m_undo_redo_stack_active->clear();
|
||||||
|
m_undo_redo_stack_active = &m_undo_redo_stack_main;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int Plater::priv::get_active_snapshot_index()
|
int Plater::priv::get_active_snapshot_index()
|
||||||
{
|
{
|
||||||
const size_t active_snapshot_time = this->undo_redo_stack.active_snapshot_time();
|
const size_t active_snapshot_time = this->undo_redo_stack().active_snapshot_time();
|
||||||
const std::vector<UndoRedo::Snapshot>& ss_stack = this->undo_redo_stack.snapshots();
|
const std::vector<UndoRedo::Snapshot>& ss_stack = this->undo_redo_stack().snapshots();
|
||||||
const auto it = std::lower_bound(ss_stack.begin(), ss_stack.end(), UndoRedo::Snapshot(active_snapshot_time));
|
const auto it = std::lower_bound(ss_stack.begin(), ss_stack.end(), UndoRedo::Snapshot(active_snapshot_time));
|
||||||
return it - ss_stack.begin();
|
return it - ss_stack.begin();
|
||||||
}
|
}
|
||||||
|
@ -3746,32 +3778,32 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name)
|
||||||
model.wipe_tower.position = Vec2d(config.opt_float("wipe_tower_x"), config.opt_float("wipe_tower_y"));
|
model.wipe_tower.position = Vec2d(config.opt_float("wipe_tower_x"), config.opt_float("wipe_tower_y"));
|
||||||
model.wipe_tower.rotation = config.opt_float("wipe_tower_rotation_angle");
|
model.wipe_tower.rotation = config.opt_float("wipe_tower_rotation_angle");
|
||||||
}
|
}
|
||||||
this->undo_redo_stack.take_snapshot(snapshot_name, model, view3D->get_canvas3d()->get_selection(), view3D->get_canvas3d()->get_gizmos_manager(), snapshot_data);
|
this->undo_redo_stack().take_snapshot(snapshot_name, model, view3D->get_canvas3d()->get_selection(), view3D->get_canvas3d()->get_gizmos_manager(), snapshot_data);
|
||||||
this->undo_redo_stack.release_least_recently_used();
|
this->undo_redo_stack().release_least_recently_used();
|
||||||
// Save the last active preset name of a particular printer technology.
|
// Save the last active preset name of a particular printer technology.
|
||||||
((this->printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name) = wxGetApp().preset_bundle->printers.get_selected_preset_name();
|
((this->printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name) = wxGetApp().preset_bundle->printers.get_selected_preset_name();
|
||||||
BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot taken: " << snapshot_name << ", Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack.memsize()) << log_memory_info();
|
BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot taken: " << snapshot_name << ", Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack().memsize()) << log_memory_info();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::undo()
|
void Plater::priv::undo()
|
||||||
{
|
{
|
||||||
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack.snapshots();
|
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack().snapshots();
|
||||||
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack.active_snapshot_time()));
|
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack().active_snapshot_time()));
|
||||||
if (-- it_current != snapshots.begin())
|
if (-- it_current != snapshots.begin())
|
||||||
this->undo_redo_to(it_current);
|
this->undo_redo_to(it_current);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::redo()
|
void Plater::priv::redo()
|
||||||
{
|
{
|
||||||
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack.snapshots();
|
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack().snapshots();
|
||||||
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack.active_snapshot_time()));
|
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack().active_snapshot_time()));
|
||||||
if (++ it_current != snapshots.end())
|
if (++ it_current != snapshots.end())
|
||||||
this->undo_redo_to(it_current);
|
this->undo_redo_to(it_current);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::priv::undo_redo_to(size_t time_to_load)
|
void Plater::priv::undo_redo_to(size_t time_to_load)
|
||||||
{
|
{
|
||||||
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack.snapshots();
|
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack().snapshots();
|
||||||
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(time_to_load));
|
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(time_to_load));
|
||||||
assert(it_current != snapshots.end());
|
assert(it_current != snapshots.end());
|
||||||
this->undo_redo_to(it_current);
|
this->undo_redo_to(it_current);
|
||||||
|
@ -3779,7 +3811,7 @@ void Plater::priv::undo_redo_to(size_t time_to_load)
|
||||||
|
|
||||||
void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator it_snapshot)
|
void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator it_snapshot)
|
||||||
{
|
{
|
||||||
bool temp_snapshot_was_taken = this->undo_redo_stack.temp_snapshot_active();
|
bool temp_snapshot_was_taken = this->undo_redo_stack().temp_snapshot_active();
|
||||||
PrinterTechnology new_printer_technology = it_snapshot->snapshot_data.printer_technology;
|
PrinterTechnology new_printer_technology = it_snapshot->snapshot_data.printer_technology;
|
||||||
bool printer_technology_changed = this->printer_technology != new_printer_technology;
|
bool printer_technology_changed = this->printer_technology != new_printer_technology;
|
||||||
if (printer_technology_changed) {
|
if (printer_technology_changed) {
|
||||||
|
@ -3799,6 +3831,7 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
|
||||||
model.wipe_tower.position = Vec2d(config.opt_float("wipe_tower_x"), config.opt_float("wipe_tower_y"));
|
model.wipe_tower.position = Vec2d(config.opt_float("wipe_tower_x"), config.opt_float("wipe_tower_y"));
|
||||||
model.wipe_tower.rotation = config.opt_float("wipe_tower_rotation_angle");
|
model.wipe_tower.rotation = config.opt_float("wipe_tower_rotation_angle");
|
||||||
}
|
}
|
||||||
|
const int layer_range_idx = it_snapshot->snapshot_data.layer_range_idx;
|
||||||
// Flags made of Snapshot::Flags enum values.
|
// Flags made of Snapshot::Flags enum values.
|
||||||
unsigned int new_flags = it_snapshot->snapshot_data.flags;
|
unsigned int new_flags = it_snapshot->snapshot_data.flags;
|
||||||
UndoRedo::SnapshotData top_snapshot_data;
|
UndoRedo::SnapshotData top_snapshot_data;
|
||||||
|
@ -3824,9 +3857,9 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
|
||||||
if (!new_variable_layer_editing_active && view3D->is_layers_editing_enabled())
|
if (!new_variable_layer_editing_active && view3D->is_layers_editing_enabled())
|
||||||
view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting"));
|
view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting"));
|
||||||
// Do the jump in time.
|
// Do the jump in time.
|
||||||
if (it_snapshot->timestamp < this->undo_redo_stack.active_snapshot_time() ?
|
if (it_snapshot->timestamp < this->undo_redo_stack().active_snapshot_time() ?
|
||||||
this->undo_redo_stack.undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager(), top_snapshot_data, it_snapshot->timestamp) :
|
this->undo_redo_stack().undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager(), top_snapshot_data, it_snapshot->timestamp) :
|
||||||
this->undo_redo_stack.redo(model, this->view3D->get_canvas3d()->get_gizmos_manager(), it_snapshot->timestamp)) {
|
this->undo_redo_stack().redo(model, this->view3D->get_canvas3d()->get_gizmos_manager(), it_snapshot->timestamp)) {
|
||||||
if (printer_technology_changed) {
|
if (printer_technology_changed) {
|
||||||
// Switch to the other printer technology. Switch to the last printer active for that particular technology.
|
// Switch to the other printer technology. Switch to the last printer active for that particular technology.
|
||||||
AppConfig *app_config = wxGetApp().app_config;
|
AppConfig *app_config = wxGetApp().app_config;
|
||||||
|
@ -3858,7 +3891,7 @@ void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator
|
||||||
new_selected_layerroot_on_sidebar ? ObjectList::SELECTION_MODE::smLayerRoot :
|
new_selected_layerroot_on_sidebar ? ObjectList::SELECTION_MODE::smLayerRoot :
|
||||||
ObjectList::SELECTION_MODE::smUndef);
|
ObjectList::SELECTION_MODE::smUndef);
|
||||||
if (new_selected_settings_on_sidebar || new_selected_layer_on_sidebar)
|
if (new_selected_settings_on_sidebar || new_selected_layer_on_sidebar)
|
||||||
this->sidebar->obj_list()->set_selected_layers_range_idx(it_snapshot->snapshot_data.layer_range_idx);
|
this->sidebar->obj_list()->set_selected_layers_range_idx(layer_range_idx);
|
||||||
|
|
||||||
this->update_after_undo_redo(temp_snapshot_was_taken);
|
this->update_after_undo_redo(temp_snapshot_was_taken);
|
||||||
// Enable layer editing after the Undo / Redo jump.
|
// Enable layer editing after the Undo / Redo jump.
|
||||||
|
@ -3876,9 +3909,9 @@ void Plater::priv::update_after_undo_redo(bool /* temp_snapshot_was_taken */)
|
||||||
//if (temp_snapshot_was_taken)
|
//if (temp_snapshot_was_taken)
|
||||||
// Release the old snapshots always, as it may have happened, that some of the triangle meshes got deserialized from the snapshot, while some
|
// Release the old snapshots always, as it may have happened, that some of the triangle meshes got deserialized from the snapshot, while some
|
||||||
// triangle meshes may have gotten released from the scene or the background processing, therefore now being calculated into the Undo / Redo stack size.
|
// triangle meshes may have gotten released from the scene or the background processing, therefore now being calculated into the Undo / Redo stack size.
|
||||||
this->undo_redo_stack.release_least_recently_used();
|
this->undo_redo_stack().release_least_recently_used();
|
||||||
//YS_FIXME update obj_list from the deserialized model (maybe store ObjectIDs into the tree?) (no selections at this point of time)
|
//YS_FIXME update obj_list from the deserialized model (maybe store ObjectIDs into the tree?) (no selections at this point of time)
|
||||||
this->view3D->get_canvas3d()->get_selection().set_deserialized(GUI::Selection::EMode(this->undo_redo_stack.selection_deserialized().mode), this->undo_redo_stack.selection_deserialized().volumes_and_instances);
|
this->view3D->get_canvas3d()->get_selection().set_deserialized(GUI::Selection::EMode(this->undo_redo_stack().selection_deserialized().mode), this->undo_redo_stack().selection_deserialized().volumes_and_instances);
|
||||||
this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo();
|
this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo();
|
||||||
|
|
||||||
wxGetApp().obj_list()->update_after_undo_redo();
|
wxGetApp().obj_list()->update_after_undo_redo();
|
||||||
|
@ -3893,7 +3926,7 @@ void Plater::priv::update_after_undo_redo(bool /* temp_snapshot_was_taken */)
|
||||||
//FIXME what about the state of the manipulators?
|
//FIXME what about the state of the manipulators?
|
||||||
//FIXME what about the focus? Cursor in the side panel?
|
//FIXME what about the focus? Cursor in the side panel?
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot reloaded. Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack.memsize()) << log_memory_info();
|
BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot reloaded. Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack().memsize()) << log_memory_info();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& label) const
|
void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& label) const
|
||||||
|
@ -4452,7 +4485,7 @@ void Plater::undo_to(int selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
const int idx = p->get_active_snapshot_index() - selection - 1;
|
const int idx = p->get_active_snapshot_index() - selection - 1;
|
||||||
p->undo_redo_to(p->undo_redo_stack.snapshots()[idx].timestamp);
|
p->undo_redo_to(p->undo_redo_stack().snapshots()[idx].timestamp);
|
||||||
}
|
}
|
||||||
void Plater::redo_to(int selection)
|
void Plater::redo_to(int selection)
|
||||||
{
|
{
|
||||||
|
@ -4462,11 +4495,11 @@ void Plater::redo_to(int selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
const int idx = p->get_active_snapshot_index() + selection + 1;
|
const int idx = p->get_active_snapshot_index() + selection + 1;
|
||||||
p->undo_redo_to(p->undo_redo_stack.snapshots()[idx].timestamp);
|
p->undo_redo_to(p->undo_redo_stack().snapshots()[idx].timestamp);
|
||||||
}
|
}
|
||||||
bool Plater::undo_redo_string_getter(const bool is_undo, int idx, const char** out_text)
|
bool Plater::undo_redo_string_getter(const bool is_undo, int idx, const char** out_text)
|
||||||
{
|
{
|
||||||
const std::vector<UndoRedo::Snapshot>& ss_stack = p->undo_redo_stack.snapshots();
|
const std::vector<UndoRedo::Snapshot>& ss_stack = p->undo_redo_stack().snapshots();
|
||||||
const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -(++idx) : idx);
|
const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -(++idx) : idx);
|
||||||
|
|
||||||
if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) {
|
if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) {
|
||||||
|
@ -4479,7 +4512,7 @@ bool Plater::undo_redo_string_getter(const bool is_undo, int idx, const char** o
|
||||||
|
|
||||||
void Plater::undo_redo_topmost_string_getter(const bool is_undo, std::string& out_text)
|
void Plater::undo_redo_topmost_string_getter(const bool is_undo, std::string& out_text)
|
||||||
{
|
{
|
||||||
const std::vector<UndoRedo::Snapshot>& ss_stack = p->undo_redo_stack.snapshots();
|
const std::vector<UndoRedo::Snapshot>& ss_stack = p->undo_redo_stack().snapshots();
|
||||||
const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -1 : 0);
|
const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -1 : 0);
|
||||||
|
|
||||||
if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) {
|
if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) {
|
||||||
|
@ -4718,7 +4751,7 @@ void Plater::paste_from_clipboard()
|
||||||
if (!can_paste_from_clipboard())
|
if (!can_paste_from_clipboard())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this->take_snapshot(_(L("Paste From Clipboard")));
|
Plater::TakeSnapshot snapshot(this, _(L("Paste From Clipboard")));
|
||||||
p->view3D->get_canvas3d()->get_selection().paste_from_clipboard();
|
p->view3D->get_canvas3d()->get_selection().paste_from_clipboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4784,9 +4817,11 @@ bool Plater::can_copy_to_clipboard() const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Plater::can_undo() const { return p->undo_redo_stack.has_undo_snapshot(); }
|
bool Plater::can_undo() const { return p->undo_redo_stack().has_undo_snapshot(); }
|
||||||
bool Plater::can_redo() const { return p->undo_redo_stack.has_redo_snapshot(); }
|
bool Plater::can_redo() const { return p->undo_redo_stack().has_redo_snapshot(); }
|
||||||
const UndoRedo::Stack& Plater::undo_redo_stack() const { return p->undo_redo_stack; }
|
const UndoRedo::Stack& Plater::undo_redo_stack_main() const { return p->undo_redo_stack_main(); }
|
||||||
|
void Plater::enter_gizmos_stack() { p->enter_gizmos_stack(); }
|
||||||
|
void Plater::leave_gizmos_stack() { p->leave_gizmos_stack(); }
|
||||||
|
|
||||||
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
|
SuppressBackgroundProcessingUpdate::SuppressBackgroundProcessingUpdate() :
|
||||||
m_was_running(wxGetApp().plater()->is_background_process_running())
|
m_was_running(wxGetApp().plater()->is_background_process_running())
|
||||||
|
|
|
@ -197,7 +197,11 @@ public:
|
||||||
void redo_to(int selection);
|
void redo_to(int selection);
|
||||||
bool undo_redo_string_getter(const bool is_undo, int idx, const char** out_text);
|
bool undo_redo_string_getter(const bool is_undo, int idx, const char** out_text);
|
||||||
void undo_redo_topmost_string_getter(const bool is_undo, std::string& out_text);
|
void undo_redo_topmost_string_getter(const bool is_undo, std::string& out_text);
|
||||||
const Slic3r::UndoRedo::Stack& undo_redo_stack() const;
|
// For the memory statistics.
|
||||||
|
const Slic3r::UndoRedo::Stack& undo_redo_stack_main() const;
|
||||||
|
// Enter / leave the Gizmos specific Undo / Redo stack. To be used by the SLA support point editing gizmo.
|
||||||
|
void enter_gizmos_stack();
|
||||||
|
void leave_gizmos_stack();
|
||||||
|
|
||||||
void on_extruders_change(int extruders_count);
|
void on_extruders_change(int extruders_count);
|
||||||
void on_config_change(const DynamicPrintConfig &config);
|
void on_config_change(const DynamicPrintConfig &config);
|
||||||
|
|
|
@ -140,11 +140,13 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec
|
||||||
needs_reset |= as_single_selection && !is_any_modifier() && volume->is_modifier;
|
needs_reset |= as_single_selection && !is_any_modifier() && volume->is_modifier;
|
||||||
needs_reset |= is_any_modifier() && !volume->is_modifier;
|
needs_reset |= is_any_modifier() && !volume->is_modifier;
|
||||||
|
|
||||||
if (needs_reset)
|
|
||||||
clear();
|
|
||||||
|
|
||||||
if (!already_contained || needs_reset)
|
if (!already_contained || needs_reset)
|
||||||
{
|
{
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Add")));
|
||||||
|
|
||||||
|
if (needs_reset)
|
||||||
|
clear();
|
||||||
|
|
||||||
if (!keep_instance_mode)
|
if (!keep_instance_mode)
|
||||||
m_mode = volume->is_modifier ? Volume : Instance;
|
m_mode = volume->is_modifier ? Volume : Instance;
|
||||||
}
|
}
|
||||||
|
@ -163,7 +165,8 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection, bool chec
|
||||||
}
|
}
|
||||||
case Instance:
|
case Instance:
|
||||||
{
|
{
|
||||||
do_add_instance(volume->object_idx(), volume->instance_idx());
|
Plater::SuppressSnapshots suppress(wxGetApp().plater());
|
||||||
|
add_instance(volume->object_idx(), volume->instance_idx(), as_single_selection);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,6 +180,11 @@ void Selection::remove(unsigned int volume_idx)
|
||||||
if (!m_valid || ((unsigned int)m_volumes->size() <= volume_idx))
|
if (!m_valid || ((unsigned int)m_volumes->size() <= volume_idx))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!contains_volume(volume_idx))
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove")));
|
||||||
|
|
||||||
GLVolume* volume = (*m_volumes)[volume_idx];
|
GLVolume* volume = (*m_volumes)[volume_idx];
|
||||||
|
|
||||||
switch (m_mode)
|
switch (m_mode)
|
||||||
|
@ -202,13 +210,20 @@ void Selection::add_object(unsigned int object_idx, bool as_single_selection)
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
std::vector<unsigned int> volume_idxs = get_volume_idxs_from_object(object_idx);
|
||||||
|
if ((!as_single_selection && contains_all_volumes(volume_idxs)) ||
|
||||||
|
(as_single_selection && matches(volume_idxs)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Add Object")));
|
||||||
|
|
||||||
// resets the current list if needed
|
// resets the current list if needed
|
||||||
if (as_single_selection)
|
if (as_single_selection)
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
m_mode = Instance;
|
m_mode = Instance;
|
||||||
|
|
||||||
do_add_object(object_idx);
|
do_add_volumes(volume_idxs);
|
||||||
|
|
||||||
update_type();
|
update_type();
|
||||||
this->set_bounding_boxes_dirty();
|
this->set_bounding_boxes_dirty();
|
||||||
|
@ -219,6 +234,8 @@ void Selection::remove_object(unsigned int object_idx)
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove Object")));
|
||||||
|
|
||||||
do_remove_object(object_idx);
|
do_remove_object(object_idx);
|
||||||
|
|
||||||
update_type();
|
update_type();
|
||||||
|
@ -230,13 +247,20 @@ void Selection::add_instance(unsigned int object_idx, unsigned int instance_idx,
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
std::vector<unsigned int> volume_idxs = get_volume_idxs_from_instance(object_idx, instance_idx);
|
||||||
|
if ((!as_single_selection && contains_all_volumes(volume_idxs)) ||
|
||||||
|
(as_single_selection && matches(volume_idxs)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Add Instance")));
|
||||||
|
|
||||||
// resets the current list if needed
|
// resets the current list if needed
|
||||||
if (as_single_selection)
|
if (as_single_selection)
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
m_mode = Instance;
|
m_mode = Instance;
|
||||||
|
|
||||||
do_add_instance(object_idx, instance_idx);
|
do_add_volumes(volume_idxs);
|
||||||
|
|
||||||
update_type();
|
update_type();
|
||||||
this->set_bounding_boxes_dirty();
|
this->set_bounding_boxes_dirty();
|
||||||
|
@ -247,6 +271,8 @@ void Selection::remove_instance(unsigned int object_idx, unsigned int instance_i
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove Instance")));
|
||||||
|
|
||||||
do_remove_instance(object_idx, instance_idx);
|
do_remove_instance(object_idx, instance_idx);
|
||||||
|
|
||||||
update_type();
|
update_type();
|
||||||
|
@ -258,21 +284,20 @@ void Selection::add_volume(unsigned int object_idx, unsigned int volume_idx, int
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
std::vector<unsigned int> volume_idxs = get_volume_idxs_from_volume(object_idx, instance_idx, volume_idx);
|
||||||
|
if ((!as_single_selection && contains_all_volumes(volume_idxs)) ||
|
||||||
|
(as_single_selection && matches(volume_idxs)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Add Volume")));
|
||||||
|
|
||||||
// resets the current list if needed
|
// resets the current list if needed
|
||||||
if (as_single_selection)
|
if (as_single_selection)
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
m_mode = Volume;
|
m_mode = Volume;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
do_add_volumes(volume_idxs);
|
||||||
{
|
|
||||||
GLVolume* v = (*m_volumes)[i];
|
|
||||||
if ((v->object_idx() == object_idx) && (v->volume_idx() == volume_idx))
|
|
||||||
{
|
|
||||||
if ((instance_idx != -1) && (v->instance_idx() == instance_idx))
|
|
||||||
do_add_volume(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update_type();
|
update_type();
|
||||||
this->set_bounding_boxes_dirty();
|
this->set_bounding_boxes_dirty();
|
||||||
|
@ -283,6 +308,8 @@ void Selection::remove_volume(unsigned int object_idx, unsigned int volume_idx)
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove Volume")));
|
||||||
|
|
||||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||||
{
|
{
|
||||||
GLVolume* v = (*m_volumes)[i];
|
GLVolume* v = (*m_volumes)[i];
|
||||||
|
@ -294,11 +321,67 @@ void Selection::remove_volume(unsigned int object_idx, unsigned int volume_idx)
|
||||||
this->set_bounding_boxes_dirty();
|
this->set_bounding_boxes_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Selection::add_volumes(EMode mode, const std::vector<unsigned int>& volume_idxs, bool as_single_selection)
|
||||||
|
{
|
||||||
|
if (!m_valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((!as_single_selection && contains_all_volumes(volume_idxs)) ||
|
||||||
|
(as_single_selection && matches(volume_idxs)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Add Volumes")));
|
||||||
|
|
||||||
|
// resets the current list if needed
|
||||||
|
if (as_single_selection)
|
||||||
|
clear();
|
||||||
|
|
||||||
|
m_mode = mode;
|
||||||
|
for (unsigned int i : volume_idxs)
|
||||||
|
{
|
||||||
|
if (i < (unsigned int)m_volumes->size())
|
||||||
|
do_add_volume(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_type();
|
||||||
|
this->set_bounding_boxes_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Selection::remove_volumes(EMode mode, const std::vector<unsigned int>& volume_idxs)
|
||||||
|
{
|
||||||
|
if (!m_valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove Volumes")));
|
||||||
|
|
||||||
|
m_mode = mode;
|
||||||
|
for (unsigned int i : volume_idxs)
|
||||||
|
{
|
||||||
|
if (i < (unsigned int)m_volumes->size())
|
||||||
|
do_remove_volume(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_type();
|
||||||
|
this->set_bounding_boxes_dirty();
|
||||||
|
}
|
||||||
|
|
||||||
void Selection::add_all()
|
void Selection::add_all()
|
||||||
{
|
{
|
||||||
if (!m_valid)
|
if (!m_valid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
unsigned int count = 0;
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||||
|
{
|
||||||
|
if (!(*m_volumes)[i]->is_wipe_tower)
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((unsigned int)m_list.size() == count)
|
||||||
|
return;
|
||||||
|
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Add All")));
|
||||||
|
|
||||||
m_mode = Instance;
|
m_mode = Instance;
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
|
@ -312,6 +395,21 @@ void Selection::add_all()
|
||||||
this->set_bounding_boxes_dirty();
|
this->set_bounding_boxes_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Selection::remove_all()
|
||||||
|
{
|
||||||
|
if (!m_valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (is_empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!wxGetApp().plater()->can_redo())
|
||||||
|
wxGetApp().plater()->take_snapshot(_(L("Selection-Remove All")));
|
||||||
|
|
||||||
|
m_mode = Instance;
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
void Selection::set_deserialized(EMode mode, const std::vector<std::pair<size_t, size_t>> &volumes_and_instances)
|
void Selection::set_deserialized(EMode mode, const std::vector<std::pair<size_t, size_t>> &volumes_and_instances)
|
||||||
{
|
{
|
||||||
if (! m_valid)
|
if (! m_valid)
|
||||||
|
@ -439,6 +537,43 @@ bool Selection::is_sla_compliant() const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Selection::contains_all_volumes(const std::vector<unsigned int>& volume_idxs) const
|
||||||
|
{
|
||||||
|
for (unsigned int i : volume_idxs)
|
||||||
|
{
|
||||||
|
if (m_list.find(i) == m_list.end())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Selection::contains_any_volume(const std::vector<unsigned int>& volume_idxs) const
|
||||||
|
{
|
||||||
|
for (unsigned int i : volume_idxs)
|
||||||
|
{
|
||||||
|
if (m_list.find(i) != m_list.end())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Selection::matches(const std::vector<unsigned int>& volume_idxs) const
|
||||||
|
{
|
||||||
|
unsigned int count = 0;
|
||||||
|
|
||||||
|
for (unsigned int i : volume_idxs)
|
||||||
|
{
|
||||||
|
if (m_list.find(i) != m_list.end())
|
||||||
|
++count;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count == (unsigned int)m_list.size();
|
||||||
|
}
|
||||||
|
|
||||||
bool Selection::requires_uniform_scale() const
|
bool Selection::requires_uniform_scale() const
|
||||||
{
|
{
|
||||||
if (is_single_full_instance() || is_single_modifier() || is_single_volume())
|
if (is_single_full_instance() || is_single_modifier() || is_single_volume())
|
||||||
|
@ -1253,6 +1388,77 @@ void Selection::paste_from_clipboard()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned int> Selection::get_volume_idxs_from_object(unsigned int object_idx) const
|
||||||
|
{
|
||||||
|
std::vector<unsigned int> idxs;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||||
|
{
|
||||||
|
if ((*m_volumes)[i]->object_idx() == object_idx)
|
||||||
|
idxs.push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return idxs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned int> Selection::get_volume_idxs_from_instance(unsigned int object_idx, unsigned int instance_idx) const
|
||||||
|
{
|
||||||
|
std::vector<unsigned int> idxs;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||||
|
{
|
||||||
|
const GLVolume* v = (*m_volumes)[i];
|
||||||
|
if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
|
||||||
|
idxs.push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return idxs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned int> Selection::get_volume_idxs_from_volume(unsigned int object_idx, unsigned int instance_idx, unsigned int volume_idx) const
|
||||||
|
{
|
||||||
|
std::vector<unsigned int> idxs;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
||||||
|
{
|
||||||
|
const GLVolume* v = (*m_volumes)[i];
|
||||||
|
if ((v->object_idx() == object_idx) && (v->volume_idx() == volume_idx))
|
||||||
|
{
|
||||||
|
if ((instance_idx != -1) && (v->instance_idx() == instance_idx))
|
||||||
|
idxs.push_back(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return idxs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned int> Selection::get_missing_volume_idxs_from(const std::vector<unsigned int>& volume_idxs) const
|
||||||
|
{
|
||||||
|
std::vector<unsigned int> idxs;
|
||||||
|
|
||||||
|
for (unsigned int i : m_list)
|
||||||
|
{
|
||||||
|
std::vector<unsigned int>::const_iterator it = std::find(volume_idxs.begin(), volume_idxs.end(), i);
|
||||||
|
if (it == volume_idxs.end())
|
||||||
|
idxs.push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return idxs;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned int> Selection::get_unselected_volume_idxs_from(const std::vector<unsigned int>& volume_idxs) const
|
||||||
|
{
|
||||||
|
std::vector<unsigned int> idxs;
|
||||||
|
|
||||||
|
for (unsigned int i : volume_idxs)
|
||||||
|
{
|
||||||
|
if (m_list.find(i) == m_list.end())
|
||||||
|
idxs.push_back(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return idxs;
|
||||||
|
}
|
||||||
|
|
||||||
void Selection::update_valid()
|
void Selection::update_valid()
|
||||||
{
|
{
|
||||||
m_valid = (m_volumes != nullptr) && (m_model != nullptr);
|
m_valid = (m_volumes != nullptr) && (m_model != nullptr);
|
||||||
|
@ -1499,22 +1705,11 @@ void Selection::do_add_volume(unsigned int volume_idx)
|
||||||
(*m_volumes)[volume_idx]->selected = true;
|
(*m_volumes)[volume_idx]->selected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Selection::do_add_instance(unsigned int object_idx, unsigned int instance_idx)
|
void Selection::do_add_volumes(const std::vector<unsigned int>& volume_idxs)
|
||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
for (unsigned int i : volume_idxs)
|
||||||
{
|
{
|
||||||
GLVolume* v = (*m_volumes)[i];
|
if (i < (unsigned int)m_volumes->size())
|
||||||
if ((v->object_idx() == object_idx) && (v->instance_idx() == instance_idx))
|
|
||||||
do_add_volume(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Selection::do_add_object(unsigned int object_idx)
|
|
||||||
{
|
|
||||||
for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i)
|
|
||||||
{
|
|
||||||
GLVolume* v = (*m_volumes)[i];
|
|
||||||
if (v->object_idx() == object_idx)
|
|
||||||
do_add_volume(i);
|
do_add_volume(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,7 +235,11 @@ public:
|
||||||
void add_volume(unsigned int object_idx, unsigned int volume_idx, int instance_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 remove_volume(unsigned int object_idx, unsigned int volume_idx);
|
||||||
|
|
||||||
|
void add_volumes(EMode mode, const std::vector<unsigned int>& volume_idxs, bool as_single_selection = true);
|
||||||
|
void remove_volumes(EMode mode, const std::vector<unsigned int>& volume_idxs);
|
||||||
|
|
||||||
void add_all();
|
void add_all();
|
||||||
|
void remove_all();
|
||||||
|
|
||||||
// To be called after Undo or Redo once the volumes are updated.
|
// To be called after Undo or Redo once the volumes are updated.
|
||||||
void set_deserialized(EMode mode, const std::vector<std::pair<size_t, size_t>> &volumes_and_instances);
|
void set_deserialized(EMode mode, const std::vector<std::pair<size_t, size_t>> &volumes_and_instances);
|
||||||
|
@ -265,6 +269,13 @@ public:
|
||||||
bool is_sla_compliant() const;
|
bool is_sla_compliant() const;
|
||||||
|
|
||||||
bool contains_volume(unsigned int volume_idx) const { return m_list.find(volume_idx) != m_list.end(); }
|
bool contains_volume(unsigned int volume_idx) const { return m_list.find(volume_idx) != m_list.end(); }
|
||||||
|
// returns true if the selection contains all the given indices
|
||||||
|
bool contains_all_volumes(const std::vector<unsigned int>& volume_idxs) const;
|
||||||
|
// returns true if the selection contains at least one of the given indices
|
||||||
|
bool contains_any_volume(const std::vector<unsigned int>& volume_idxs) const;
|
||||||
|
// returns true if the selection contains all and only the given indices
|
||||||
|
bool matches(const std::vector<unsigned int>& volume_idxs) const;
|
||||||
|
|
||||||
bool requires_uniform_scale() const;
|
bool requires_uniform_scale() const;
|
||||||
|
|
||||||
// Returns the the object id if the selection is from a single object, otherwise is -1
|
// Returns the the object id if the selection is from a single object, otherwise is -1
|
||||||
|
@ -314,13 +325,23 @@ public:
|
||||||
|
|
||||||
const Clipboard& get_clipboard() const { return m_clipboard; }
|
const Clipboard& get_clipboard() const { return m_clipboard; }
|
||||||
|
|
||||||
|
// returns the list of idxs of the volumes contained into the object with the given idx
|
||||||
|
std::vector<unsigned int> get_volume_idxs_from_object(unsigned int object_idx) const;
|
||||||
|
// returns the list of idxs of the volumes contained into the instance with the given idxs
|
||||||
|
std::vector<unsigned int> get_volume_idxs_from_instance(unsigned int object_idx, unsigned int instance_idx) const;
|
||||||
|
// returns the idx of the volume corresponding to the volume with the given idxs
|
||||||
|
std::vector<unsigned int> get_volume_idxs_from_volume(unsigned int object_idx, unsigned int instance_idx, unsigned int volume_idx) const;
|
||||||
|
// returns the list of idxs of the volumes contained in the selection but not in the given list
|
||||||
|
std::vector<unsigned int> get_missing_volume_idxs_from(const std::vector<unsigned int>& volume_idxs) const;
|
||||||
|
// returns the list of idxs of the volumes contained in the given list but not in the selection
|
||||||
|
std::vector<unsigned int> get_unselected_volume_idxs_from(const std::vector<unsigned int>& volume_idxs) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void update_valid();
|
void update_valid();
|
||||||
void update_type();
|
void update_type();
|
||||||
void set_caches();
|
void set_caches();
|
||||||
void do_add_volume(unsigned int volume_idx);
|
void do_add_volume(unsigned int volume_idx);
|
||||||
void do_add_instance(unsigned int object_idx, unsigned int instance_idx);
|
void do_add_volumes(const std::vector<unsigned int>& volume_idxs);
|
||||||
void do_add_object(unsigned int object_idx);
|
|
||||||
void do_remove_volume(unsigned int volume_idx);
|
void do_remove_volume(unsigned int volume_idx);
|
||||||
void do_remove_instance(unsigned int object_idx, unsigned int instance_idx);
|
void do_remove_instance(unsigned int object_idx, unsigned int instance_idx);
|
||||||
void do_remove_object(unsigned int object_idx);
|
void do_remove_object(unsigned int object_idx);
|
||||||
|
|
|
@ -58,7 +58,7 @@ std::string get_mem_info(bool format_as_html)
|
||||||
std::string b_end = format_as_html ? "</b>" : "";
|
std::string b_end = format_as_html ? "</b>" : "";
|
||||||
std::string line_end = format_as_html ? "<br>" : "\n";
|
std::string line_end = format_as_html ? "<br>" : "\n";
|
||||||
|
|
||||||
const Slic3r::UndoRedo::Stack &stack = wxGetApp().plater()->undo_redo_stack();
|
const Slic3r::UndoRedo::Stack &stack = wxGetApp().plater()->undo_redo_stack_main();
|
||||||
out << b_start << "RAM size reserved for the Undo / Redo stack [MB]: " << b_end << Slic3r::format_memsize_MB(stack.get_memory_limit()) << line_end;
|
out << b_start << "RAM size reserved for the Undo / Redo stack [MB]: " << b_end << Slic3r::format_memsize_MB(stack.get_memory_limit()) << line_end;
|
||||||
out << b_start << "RAM size occupied by the Undo / Redo stack [MB]: " << b_end << Slic3r::format_memsize_MB(stack.memsize()) << line_end << line_end;
|
out << b_start << "RAM size occupied by the Undo / Redo stack [MB]: " << b_end << Slic3r::format_memsize_MB(stack.memsize()) << line_end << line_end;
|
||||||
|
|
||||||
|
|
|
@ -198,7 +198,7 @@ void Tab::create_preset_tab()
|
||||||
// There is used just additional sizer for m_mode_sizer with right alignment
|
// There is used just additional sizer for m_mode_sizer with right alignment
|
||||||
auto mode_sizer = new wxBoxSizer(wxVERTICAL);
|
auto mode_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
mode_sizer->Add(m_mode_sizer, 1, wxALIGN_RIGHT);
|
mode_sizer->Add(m_mode_sizer, 1, wxALIGN_RIGHT);
|
||||||
m_hsizer->Add(mode_sizer, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, wxOSX ? 15 : 5);
|
m_hsizer->Add(mode_sizer, 1, wxALIGN_CENTER_VERTICAL | wxRIGHT, wxOSX ? 15 : 10);
|
||||||
|
|
||||||
//Horizontal sizer to hold the tree and the selected page.
|
//Horizontal sizer to hold the tree and the selected page.
|
||||||
m_hsizer = new wxBoxSizer(wxHORIZONTAL);
|
m_hsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
@ -914,14 +914,20 @@ void Tab::update_preset_description_line()
|
||||||
{
|
{
|
||||||
const Preset* parent = m_presets->get_selected_preset_parent();
|
const Preset* parent = m_presets->get_selected_preset_parent();
|
||||||
const Preset& preset = m_presets->get_edited_preset();
|
const Preset& preset = m_presets->get_edited_preset();
|
||||||
|
|
||||||
wxString description_line = preset.is_default ?
|
wxString description_line;
|
||||||
_(L("It's a default preset.")) : preset.is_system ?
|
|
||||||
_(L("It's a system preset.")) :
|
if (preset.is_default) {
|
||||||
wxString::Format(_(L("Current preset is inherited from %s")), (parent == nullptr ?
|
description_line = _(L("This is a default preset."));
|
||||||
_(L("default preset"))+"." :
|
} else if (preset.is_system) {
|
||||||
":\n\t" + parent->name));
|
description_line = _(L("This is a system preset."));
|
||||||
|
} else if (parent == nullptr) {
|
||||||
|
description_line = _(L("Current preset is inherited from the default preset."));
|
||||||
|
} else {
|
||||||
|
description_line = wxString::Format(
|
||||||
|
_(L("Current preset is inherited from:\n\t%s")), GUI::from_u8(parent->name));
|
||||||
|
}
|
||||||
|
|
||||||
if (preset.is_default || preset.is_system)
|
if (preset.is_default || preset.is_system)
|
||||||
description_line += "\n\t" + _(L("It can't be deleted or modified.")) +
|
description_line += "\n\t" + _(L("It can't be deleted or modified.")) +
|
||||||
"\n\t" + _(L("Any modifications should be saved as a new preset inherited from this one.")) +
|
"\n\t" + _(L("Any modifications should be saved as a new preset inherited from this one.")) +
|
||||||
|
|
|
@ -2808,11 +2808,13 @@ ModeButton::ModeButton( wxWindow * parent,
|
||||||
const wxString& mode /* = wxEmptyString*/,
|
const wxString& mode /* = wxEmptyString*/,
|
||||||
const wxSize& size /* = wxDefaultSize*/,
|
const wxSize& size /* = wxDefaultSize*/,
|
||||||
const wxPoint& pos /* = wxDefaultPosition*/) :
|
const wxPoint& pos /* = wxDefaultPosition*/) :
|
||||||
ScalableButton(parent, id, icon_name, mode, size, pos)
|
ScalableButton(parent, id, icon_name, mode, size, pos, wxBU_EXACTFIT)
|
||||||
{
|
{
|
||||||
m_tt_focused = wxString::Format(_(L("Switch to the %s mode")), mode);
|
m_tt_focused = wxString::Format(_(L("Switch to the %s mode")), mode);
|
||||||
m_tt_selected = wxString::Format(_(L("Current mode is %s")), mode);
|
m_tt_selected = wxString::Format(_(L("Current mode is %s")), mode);
|
||||||
|
|
||||||
|
SetBitmapMargins(3, 0);
|
||||||
|
|
||||||
//button events
|
//button events
|
||||||
Bind(wxEVT_BUTTON, &ModeButton::OnButton, this);
|
Bind(wxEVT_BUTTON, &ModeButton::OnButton, this);
|
||||||
Bind(wxEVT_ENTER_WINDOW, &ModeButton::OnEnterBtn, this);
|
Bind(wxEVT_ENTER_WINDOW, &ModeButton::OnEnterBtn, this);
|
||||||
|
@ -2841,6 +2843,7 @@ void ModeButton::focus_button(const bool focus)
|
||||||
Slic3r::GUI::wxGetApp().normal_font();
|
Slic3r::GUI::wxGetApp().normal_font();
|
||||||
|
|
||||||
SetFont(new_font);
|
SetFont(new_font);
|
||||||
|
SetForegroundColour(wxSystemSettings::GetColour(focus ? wxSYS_COLOUR_BTNTEXT : wxSYS_COLOUR_BTNSHADOW));
|
||||||
|
|
||||||
Refresh();
|
Refresh();
|
||||||
Update();
|
Update();
|
||||||
|
@ -2851,7 +2854,7 @@ void ModeButton::focus_button(const bool focus)
|
||||||
// ModeSizer
|
// ModeSizer
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 10*/) :
|
ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 0*/) :
|
||||||
wxFlexGridSizer(3, 0, hgap)
|
wxFlexGridSizer(3, 0, hgap)
|
||||||
{
|
{
|
||||||
SetFlexibleDirection(wxHORIZONTAL);
|
SetFlexibleDirection(wxHORIZONTAL);
|
||||||
|
@ -2869,15 +2872,8 @@ ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 10*/) :
|
||||||
|
|
||||||
m_mode_btns.reserve(3);
|
m_mode_btns.reserve(3);
|
||||||
for (const auto& button : buttons) {
|
for (const auto& button : buttons) {
|
||||||
#ifdef __WXOSX__
|
m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first));
|
||||||
wxSize sz = parent->GetTextExtent(button.first);
|
|
||||||
// set default width for ModeButtons to correct rendering on OnFocus under OSX
|
|
||||||
sz.x += 2 * em_unit(parent);
|
|
||||||
m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first, sz));
|
|
||||||
#else
|
|
||||||
m_mode_btns.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first));;
|
|
||||||
#endif // __WXOSX__
|
|
||||||
|
|
||||||
m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, int(m_mode_btns.size() - 1)));
|
m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, int(m_mode_btns.size() - 1)));
|
||||||
Add(m_mode_btns.back());
|
Add(m_mode_btns.back());
|
||||||
}
|
}
|
||||||
|
|
|
@ -946,7 +946,7 @@ private:
|
||||||
class ModeSizer : public wxFlexGridSizer
|
class ModeSizer : public wxFlexGridSizer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ModeSizer( wxWindow *parent, int hgap = 10);
|
ModeSizer( wxWindow *parent, int hgap = 0);
|
||||||
~ModeSizer() {}
|
~ModeSizer() {}
|
||||||
|
|
||||||
void SetMode(const /*ConfigOptionMode*/int mode);
|
void SetMode(const /*ConfigOptionMode*/int mode);
|
||||||
|
|
|
@ -490,6 +490,21 @@ public:
|
||||||
// Initially enable Undo / Redo stack to occupy maximum 10% of the total system physical memory.
|
// Initially enable Undo / Redo stack to occupy maximum 10% of the total system physical memory.
|
||||||
StackImpl() : m_memory_limit(std::min(Slic3r::total_physical_memory() / 10, size_t(1 * 16384 * 65536 / UNDO_REDO_DEBUG_LOW_MEM_FACTOR))), m_active_snapshot_time(0), m_current_time(0) {}
|
StackImpl() : m_memory_limit(std::min(Slic3r::total_physical_memory() / 10, size_t(1 * 16384 * 65536 / UNDO_REDO_DEBUG_LOW_MEM_FACTOR))), m_active_snapshot_time(0), m_current_time(0) {}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
m_objects.clear();
|
||||||
|
m_shared_ptr_to_object_id.clear();
|
||||||
|
m_snapshots.clear();
|
||||||
|
m_active_snapshot_time = 0;
|
||||||
|
m_current_time = 0;
|
||||||
|
m_selection.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
assert(m_objects.empty() == m_snapshots.empty());
|
||||||
|
assert(! m_objects.empty() || (m_current_time == 0 && m_active_snapshot_time == 0));
|
||||||
|
return m_snapshots.empty();
|
||||||
|
}
|
||||||
|
|
||||||
void set_memory_limit(size_t memsize) { m_memory_limit = memsize; }
|
void set_memory_limit(size_t memsize) { m_memory_limit = memsize; }
|
||||||
size_t get_memory_limit() const { return m_memory_limit; }
|
size_t get_memory_limit() const { return m_memory_limit; }
|
||||||
|
|
||||||
|
@ -1020,6 +1035,9 @@ void StackImpl::release_least_recently_used()
|
||||||
// Wrappers of the private implementation.
|
// Wrappers of the private implementation.
|
||||||
Stack::Stack() : pimpl(new StackImpl()) {}
|
Stack::Stack() : pimpl(new StackImpl()) {}
|
||||||
Stack::~Stack() {}
|
Stack::~Stack() {}
|
||||||
|
void Stack::clear() { pimpl->clear(); }
|
||||||
|
bool Stack::empty() const { return pimpl->empty(); }
|
||||||
|
|
||||||
void Stack::set_memory_limit(size_t memsize) { pimpl->set_memory_limit(memsize); }
|
void Stack::set_memory_limit(size_t memsize) { pimpl->set_memory_limit(memsize); }
|
||||||
size_t Stack::get_memory_limit() const { return pimpl->get_memory_limit(); }
|
size_t Stack::get_memory_limit() const { return pimpl->get_memory_limit(); }
|
||||||
size_t Stack::memsize() const { return pimpl->memsize(); }
|
size_t Stack::memsize() const { return pimpl->memsize(); }
|
||||||
|
|
|
@ -71,7 +71,8 @@ struct Snapshot
|
||||||
|
|
||||||
// Excerpt of Slic3r::GUI::Selection for serialization onto the Undo / Redo stack.
|
// Excerpt of Slic3r::GUI::Selection for serialization onto the Undo / Redo stack.
|
||||||
struct Selection : public Slic3r::ObjectBase {
|
struct Selection : public Slic3r::ObjectBase {
|
||||||
unsigned char mode;
|
void clear() { mode = 0; volumes_and_instances.clear(); }
|
||||||
|
unsigned char mode = 0;
|
||||||
std::vector<std::pair<size_t, size_t>> volumes_and_instances;
|
std::vector<std::pair<size_t, size_t>> volumes_and_instances;
|
||||||
template<class Archive> void serialize(Archive &ar) { ar(mode, volumes_and_instances); }
|
template<class Archive> void serialize(Archive &ar) { ar(mode, volumes_and_instances); }
|
||||||
};
|
};
|
||||||
|
@ -86,6 +87,9 @@ public:
|
||||||
Stack();
|
Stack();
|
||||||
~Stack();
|
~Stack();
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
// Set maximum memory threshold. If the threshold is exceeded, least recently used snapshots are released.
|
// Set maximum memory threshold. If the threshold is exceeded, least recently used snapshots are released.
|
||||||
void set_memory_limit(size_t memsize);
|
void set_memory_limit(size_t memsize);
|
||||||
size_t get_memory_limit() const;
|
size_t get_memory_limit() const;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue