diff --git a/CMakeLists.txt b/CMakeLists.txt index ba291e450..cbb0e2ec4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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_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_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") @@ -147,19 +146,6 @@ endif() 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. 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 " -fsyntax-only -c && touch ") - set(CMAKE_CXX_COMPILE_OBJECT " -fsyntax-only -c && touch ") - endif () endif() if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 38c0315ab..6c9e79dbd 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1219,7 +1219,6 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas, Bed3D& bed, Camera& camera, GLToolbar , m_moving_enabled(false) , m_dynamic_background_enabled(false) , m_multisample_allowed(false) - , m_regenerate_volumes(true) , m_moving(false) , m_tab_down(false) , m_cursor_type(Standard) @@ -1723,8 +1722,7 @@ void GLCanvas3D::select_all() void GLCanvas3D::deselect_all() { - m_selection.clear(); - m_selection.set_mode(Selection::Instance); + m_selection.remove_all(); wxGetApp().obj_manipul()->set_dirty(); m_gizmos.reset_all_states(); 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(); int volume_idx_wipe_tower_old = -1; - if (printer_technology == ptSLA) - // Always do the full refresh in SLA mode to show / hide SLA support structures when an object is moved outside / inside the build volume. - m_regenerate_volumes = true; - - if (m_regenerate_volumes) - { - // Release invalidated volumes to conserve GPU memory in case of delayed refresh (see m_reload_delayed). - // First initialize model_volumes_new_sorted & model_instances_new_sorted. - for (int object_idx = 0; object_idx < (int)m_model->objects.size(); ++ object_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)); - } + // Release invalidated volumes to conserve GPU memory in case of delayed refresh (see m_reload_delayed). + // First initialize model_volumes_new_sorted & model_instances_new_sorted. + for (int object_idx = 0; object_idx < (int)m_model->objects.size(); ++ object_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) return; bool update_object_list = false; - if (m_regenerate_volumes) - { - if (m_volumes.volumes != glvolumes_new) - update_object_list = true; - m_volumes.volumes = std::move(glvolumes_new); - for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++ obj_idx) { - const ModelObject &model_object = *m_model->objects[obj_idx]; - for (int volume_idx = 0; volume_idx < (int)model_object.volumes.size(); ++ volume_idx) { - const ModelVolume &model_volume = *model_object.volumes[volume_idx]; - for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { - const ModelInstance &model_instance = *model_object.instances[instance_idx]; - ModelVolumeState key(model_volume.id(), model_instance.id()); - auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); - assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); - if (it->new_geometry()) { - // New volume. - m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by); - m_volumes.volumes.back()->geometry_id = key.geometry_id; + if (m_volumes.volumes != glvolumes_new) + update_object_list = true; + m_volumes.volumes = std::move(glvolumes_new); + for (unsigned int obj_idx = 0; obj_idx < (unsigned int)m_model->objects.size(); ++ obj_idx) { + const ModelObject &model_object = *m_model->objects[obj_idx]; + for (int volume_idx = 0; volume_idx < (int)model_object.volumes.size(); ++ volume_idx) { + const ModelVolume &model_volume = *model_object.volumes[volume_idx]; + for (int instance_idx = 0; instance_idx < (int)model_object.instances.size(); ++ instance_idx) { + const ModelInstance &model_instance = *model_object.instances[instance_idx]; + ModelVolumeState key(model_volume.id(), model_instance.id()); + auto it = std::lower_bound(model_volume_state.begin(), model_volume_state.end(), key, model_volume_state_lower); + assert(it != model_volume_state.end() && it->geometry_id == key.geometry_id); + if (it->new_geometry()) { + // New volume. + m_volumes.load_object_volume(&model_object, obj_idx, volume_idx, instance_idx, m_color_by); + m_volumes.volumes.back()->geometry_id = key.geometry_id; + 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) { + existing_volume.composite_id = it->composite_id; 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) { - existing_volume.composite_id = it->composite_id; - update_object_list = true; + } + } + } + } + } + if (printer_technology == ptSLA) { + size_t idx = 0; + const SLAPrint *sla_print = this->sla_print(); + std::vector 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 + std::vector> instances[std::tuple_size::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(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 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 - std::vector> instances[std::tuple_size::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(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 - 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()]); + // 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); } - 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(m_config->option("nozzle_diameter"))->values.size(); + + bool wt = dynamic_cast(m_config->option("wipe_tower"))->value; + bool co = dynamic_cast(m_config->option("complete_objects"))->value; + + if ((extruders_count > 1) && wt && !co) { - // Should the wipe tower be visualized ? - unsigned int extruders_count = (unsigned int)dynamic_cast(m_config->option("nozzle_diameter"))->values.size(); + // Height of a print (Show at least a slab) + double height = std::max(m_model->bounding_box().max(2), 10.0); - bool wt = dynamic_cast(m_config->option("wipe_tower"))->value; - bool co = dynamic_cast(m_config->option("complete_objects"))->value; + float x = dynamic_cast(m_config->option("wipe_tower_x"))->value; + float y = dynamic_cast(m_config->option("wipe_tower_y"))->value; + float w = dynamic_cast(m_config->option("wipe_tower_width"))->value; + float a = dynamic_cast(m_config->option("wipe_tower_rotation_angle"))->value; - if ((extruders_count > 1) && wt && !co) - { - // Height of a print (Show at least a slab) - double height = std::max(m_model->bounding_box().max(2), 10.0); + const Print *print = m_process->fff_print(); + float depth = print->get_wipe_tower_depth(); - float x = dynamic_cast(m_config->option("wipe_tower_x"))->value; - float y = dynamic_cast(m_config->option("wipe_tower_y"))->value; - float w = dynamic_cast(m_config->option("wipe_tower_width"))->value; - float a = dynamic_cast(m_config->option("wipe_tower_rotation_angle"))->value; + // Calculate wipe tower brim spacing. + const DynamicPrintConfig &print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; + double layer_height = print_config.opt_float("layer_height"); + 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(); - float depth = print->get_wipe_tower_depth(); - - // Calculate wipe tower brim spacing. - const DynamicPrintConfig &print_config = wxGetApp().preset_bundle->prints.get_edited_preset().config; - double layer_height = print_config.opt_float("layer_height"); - 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); - - 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; - } + 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 selection indices based on the old/new GLVolumeCollection. - if (m_selection.get_mode() == Selection::Instance) - m_selection.instances_changed(instance_ids_selected); - else - m_selection.volumes_changed(map_glvolume_old_to_new); - } + update_volumes_colors_by_extruder(); + // Update selection indices based on the old/new GLVolumeCollection. + if (m_selection.get_mode() == Selection::Instance) + m_selection.instances_changed(instance_ids_selected); + else + m_selection.volumes_changed(map_glvolume_old_to_new); m_gizmos.update_data(); 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(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, false)); } - // restore to default value - m_regenerate_volumes = true; - m_camera.set_scene_box(scene_bounding_box()); 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); wxGetApp().obj_manipul()->set_dirty(); 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) { - m_regenerate_volumes = false; do_move(L("Move Object")); wxGetApp().obj_manipul()->set_dirty(); // 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 (!ctrl_pressed && (m_rectangle_selection.get_state() == GLSelectionRectangle::Select)) - m_selection.clear(); + m_selection.remove_all(); 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) m_selection.clear(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 2ce35660a..941eeaaf6 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -463,7 +463,6 @@ private: bool m_moving_enabled; bool m_dynamic_background_enabled; bool m_multisample_allowed; - bool m_regenerate_volumes; bool m_moving; bool m_tab_down; ECursorType m_cursor_type; @@ -652,7 +651,6 @@ public: Linef3 mouse_ray(const Point& mouse_pos); 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()); } bool is_mouse_dragging() const { return m_mouse.dragging; } diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 8d5c3fda9..32ade56c9 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1566,9 +1566,9 @@ void ObjectList::create_freq_settings_popupmenu(wxMenu *menu) #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) if (find(full_current_opts.begin(), full_current_opts.end(), opt_keys[i]) == full_current_opts.end()) opt_keys.erase(opt_keys.begin() + i); @@ -2161,16 +2161,15 @@ void ObjectList::part_selection_changed() 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(); if (opt_keys.empty()) 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" || - is_layers_range_settings && opt_keys.size() == 2) + if (opt_keys.empty()) return SettingsBundle(); 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) return ret; - const bool is_layers_range_settings = m_objects_model->GetItemType(parent_item) == itLayer; - SettingsBundle cat_options = get_item_settings_bundle(config, is_layers_range_settings); + const bool is_object_settings = m_objects_model->GetItemType(parent_item) == itObject; + SettingsBundle cat_options = get_item_settings_bundle(config, is_object_settings); if (cat_options.empty()) return ret; std::vector categories; categories.reserve(cat_options.size()); 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); - } - - if (categories.empty()) - return ret; if (m_objects_model->GetItemType(parent_item) & itInstance) parent_item = m_objects_model->GetTopParent(parent_item); @@ -2803,26 +2793,35 @@ void ObjectList::update_selections_on_canvas() const int sel_cnt = GetSelectedItemsCount(); if (sel_cnt == 0) { - selection.clear(); + selection.remove_all(); wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); return; } - auto add_to_selection = [this](const wxDataViewItem& item, Selection& selection, int instance_idx, bool as_single_selection) + std::vector 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 int obj_idx = m_objects_model->GetObjectIdByItem(item); if (type == itVolume) { 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 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) { const int inst_idx = m_objects_model->GetInstanceIdByItem(item); - selection.add_instance(obj_idx, inst_idx, as_single_selection); + mode = Selection::Instance; + std::vector idxs = selection.get_volume_idxs_from_instance(obj_idx, inst_idx); + volume_idxs.insert(volume_idxs.end(), idxs.begin(), idxs.end()); } else - selection.add_object(obj_idx, as_single_selection); + { + mode = Selection::Instance; + std::vector 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 @@ -2831,21 +2830,38 @@ void ObjectList::update_selections_on_canvas() if (sel_cnt == 1) { wxDataViewItem item = GetSelection(); 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 - add_to_selection(item, selection, instance_idx, true); - - wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); - wxGetApp().plater()->canvas3D()->render(); - return; + add_to_selection(item, selection, instance_idx, mode); } - - wxDataViewItemArray sels; - GetSelections(sels); + else + { + wxDataViewItemArray sels; + GetSelections(sels); - selection.clear(); - for (auto item: sels) - add_to_selection(item, selection, instance_idx, false); + for (auto item : sels) + { + 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()->render(); diff --git a/src/slic3r/GUI/GUI_ObjectList.hpp b/src/slic3r/GUI/GUI_ObjectList.hpp index 5c971c40f..39558d1c5 100644 --- a/src/slic3r/GUI/GUI_ObjectList.hpp +++ b/src/slic3r/GUI/GUI_ObjectList.hpp @@ -238,7 +238,7 @@ public: wxMenu* create_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_part(ModelObject* model_object, std::vector> &volumes_info, ModelVolumeType type); @@ -266,7 +266,7 @@ public: wxBoxSizer* get_sizer() {return m_sizer;} int get_selected_obj_idx() const; DynamicPrintConfig& get_item_config(const wxDataViewItem& item) const; - SettingsBundle get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_layers_range_settings); + SettingsBundle get_item_settings_bundle(const DynamicPrintConfig* config, const bool is_object_settings); void changed_object(const int obj_idx = -1) const; void part_selection_changed(); diff --git a/src/slic3r/GUI/GUI_ObjectSettings.cpp b/src/slic3r/GUI/GUI_ObjectSettings.cpp index 8728156ac..78c64e03e 100644 --- a/src/slic3r/GUI/GUI_ObjectSettings.cpp +++ b/src/slic3r/GUI/GUI_ObjectSettings.cpp @@ -77,8 +77,8 @@ bool ObjectSettings::update_settings_list() if (!item || !objects_model->IsSettingsItem(item) || !config || objects_ctrl->multiple_selection()) return false; - const bool is_layers_range_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itLayer; - SettingsBundle cat_options = objects_ctrl->get_item_settings_bundle(config, is_layers_range_settings); + const bool is_object_settings = objects_model->GetItemType(objects_model->GetParent(item)) == itObject; + SettingsBundle cat_options = objects_ctrl->get_item_settings_bundle(config, is_object_settings); if (!cat_options.empty()) { @@ -107,10 +107,6 @@ bool ObjectSettings::update_settings_list() 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); auto optgroup = std::make_shared(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"; for (auto& opt : cat.second) { - if (opt == "extruder" || is_layers_range_settings && opt == "layer_height") - continue; Option option = optgroup->get_option(opt); option.opt.width = 12; if (is_extruders_cat) diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index d96b806e5..d5a3a93c4 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -623,7 +623,6 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt) { case Move: { - m_parent.disable_regenerate_volumes(); m_parent.do_move(L("Gizmo-Move")); break; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 067d13b8a..387fd34d2 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -718,7 +718,7 @@ Sidebar::Sidebar(Plater *parent) p->scrolled->SetSizer(scrolled_sizer); // 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 p->sizer_presets = new wxFlexGridSizer(10, 1, 1, 2); @@ -1335,12 +1335,7 @@ struct Plater::priv Slic3r::Model model; PrinterTechnology printer_technology = ptFFF; Slic3r::GCodePreviewData gcode_preview_data; - Slic3r::UndoRedo::Stack undo_redo_stack; - int m_prevent_snapshots = 0; /* Used for avoid of excess "snapshoting". - * Like for "delete selected" or "set numbers of copies" - * we should call tack_snapshot just ones - * instead of calls for each action separately - * */ + // GUI elements wxSizer* panel_sizer{ nullptr }; wxPanel* current_panel{ nullptr }; @@ -1785,9 +1780,16 @@ struct Plater::priv void split_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 wxString& snapshot_name) { this->take_snapshot(std::string(snapshot_name.ToUTF8().data())); } int get_active_snapshot_index(); + void undo(); void redo(); void undo_redo_to(size_t time_to_load); @@ -1889,7 +1891,15 @@ private: void update_after_undo_redo(bool temp_snapshot_was_taken = false); // 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_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() { - const size_t active_snapshot_time = this->undo_redo_stack.active_snapshot_time(); - const std::vector& ss_stack = this->undo_redo_stack.snapshots(); + const size_t active_snapshot_time = this->undo_redo_stack().active_snapshot_time(); + const std::vector& ss_stack = this->undo_redo_stack().snapshots(); const auto it = std::lower_bound(ss_stack.begin(), ss_stack.end(), UndoRedo::Snapshot(active_snapshot_time)); return it - ss_stack.begin(); } @@ -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.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.release_least_recently_used(); + 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(); // Save the last active preset name of a particular printer technology. ((this->printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name) = wxGetApp().preset_bundle->printers.get_selected_preset_name(); - BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot taken: " << snapshot_name << ", Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack.memsize()) << log_memory_info(); + BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot taken: " << snapshot_name << ", Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack().memsize()) << log_memory_info(); } void Plater::priv::undo() { - const std::vector &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())); + const std::vector &snapshots = this->undo_redo_stack().snapshots(); + auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack().active_snapshot_time())); if (-- it_current != snapshots.begin()) this->undo_redo_to(it_current); } void Plater::priv::redo() { - const std::vector &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())); + const std::vector &snapshots = this->undo_redo_stack().snapshots(); + auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack().active_snapshot_time())); if (++ it_current != snapshots.end()) this->undo_redo_to(it_current); } void Plater::priv::undo_redo_to(size_t time_to_load) { - const std::vector &snapshots = this->undo_redo_stack.snapshots(); + const std::vector &snapshots = this->undo_redo_stack().snapshots(); auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(time_to_load)); assert(it_current != snapshots.end()); this->undo_redo_to(it_current); @@ -3779,7 +3811,7 @@ void Plater::priv::undo_redo_to(size_t time_to_load) void Plater::priv::undo_redo_to(std::vector::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; bool printer_technology_changed = this->printer_technology != new_printer_technology; if (printer_technology_changed) { @@ -3799,6 +3831,7 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator 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"); } + const int layer_range_idx = it_snapshot->snapshot_data.layer_range_idx; // Flags made of Snapshot::Flags enum values. unsigned int new_flags = it_snapshot->snapshot_data.flags; UndoRedo::SnapshotData top_snapshot_data; @@ -3824,9 +3857,9 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator if (!new_variable_layer_editing_active && view3D->is_layers_editing_enabled()) view3D->get_canvas3d()->force_main_toolbar_left_action(view3D->get_canvas3d()->get_main_toolbar_item_id("layersediting")); // Do the jump in time. - if (it_snapshot->timestamp < this->undo_redo_stack.active_snapshot_time() ? - this->undo_redo_stack.undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager(), top_snapshot_data, it_snapshot->timestamp) : - this->undo_redo_stack.redo(model, this->view3D->get_canvas3d()->get_gizmos_manager(), it_snapshot->timestamp)) { + 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().redo(model, this->view3D->get_canvas3d()->get_gizmos_manager(), it_snapshot->timestamp)) { if (printer_technology_changed) { // Switch to the other printer technology. Switch to the last printer active for that particular technology. AppConfig *app_config = wxGetApp().app_config; @@ -3858,7 +3891,7 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator new_selected_layerroot_on_sidebar ? ObjectList::SELECTION_MODE::smLayerRoot : ObjectList::SELECTION_MODE::smUndef); 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); // 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) // Release the old snapshots always, as it may have happened, that some of the triangle meshes got deserialized from the snapshot, while some // triangle meshes may have gotten released from the scene or the background processing, therefore now being calculated into the Undo / Redo stack size. - this->undo_redo_stack.release_least_recently_used(); + this->undo_redo_stack().release_least_recently_used(); //YS_FIXME update obj_list from the deserialized model (maybe store ObjectIDs into the tree?) (no selections at this point of time) - this->view3D->get_canvas3d()->get_selection().set_deserialized(GUI::Selection::EMode(this->undo_redo_stack.selection_deserialized().mode), this->undo_redo_stack.selection_deserialized().volumes_and_instances); + this->view3D->get_canvas3d()->get_selection().set_deserialized(GUI::Selection::EMode(this->undo_redo_stack().selection_deserialized().mode), this->undo_redo_stack().selection_deserialized().volumes_and_instances); this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo(); wxGetApp().obj_list()->update_after_undo_redo(); @@ -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 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 @@ -4452,7 +4485,7 @@ void Plater::undo_to(int selection) } 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) { @@ -4462,11 +4495,11 @@ void Plater::redo_to(int selection) } 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) { - const std::vector& ss_stack = p->undo_redo_stack.snapshots(); + const std::vector& ss_stack = p->undo_redo_stack().snapshots(); const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -(++idx) : idx); if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) { @@ -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) { - const std::vector& ss_stack = p->undo_redo_stack.snapshots(); + const std::vector& ss_stack = p->undo_redo_stack().snapshots(); const int idx_in_ss_stack = p->get_active_snapshot_index() + (is_undo ? -1 : 0); if (0 < idx_in_ss_stack && idx_in_ss_stack < ss_stack.size() - 1) { @@ -4718,7 +4751,7 @@ void Plater::paste_from_clipboard() if (!can_paste_from_clipboard()) 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(); } @@ -4784,9 +4817,11 @@ bool Plater::can_copy_to_clipboard() const return true; } -bool Plater::can_undo() const { return p->undo_redo_stack.has_undo_snapshot(); } -bool Plater::can_redo() const { return p->undo_redo_stack.has_redo_snapshot(); } -const UndoRedo::Stack& Plater::undo_redo_stack() const { return p->undo_redo_stack; } +bool Plater::can_undo() const { return p->undo_redo_stack().has_undo_snapshot(); } +bool Plater::can_redo() const { return p->undo_redo_stack().has_redo_snapshot(); } +const UndoRedo::Stack& Plater::undo_redo_stack_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() : m_was_running(wxGetApp().plater()->is_background_process_running()) diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index e0737c6b9..d7f7f3791 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -197,7 +197,11 @@ public: void redo_to(int selection); bool undo_redo_string_getter(const bool is_undo, int idx, const char** out_text); void undo_redo_topmost_string_getter(const bool is_undo, std::string& out_text); - const Slic3r::UndoRedo::Stack& undo_redo_stack() const; + // 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_config_change(const DynamicPrintConfig &config); diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index b990f28b8..211863627 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -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 |= is_any_modifier() && !volume->is_modifier; - if (needs_reset) - clear(); - if (!already_contained || needs_reset) { + wxGetApp().plater()->take_snapshot(_(L("Selection-Add"))); + + if (needs_reset) + clear(); + if (!keep_instance_mode) 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: { - 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; } } @@ -177,6 +180,11 @@ void Selection::remove(unsigned int volume_idx) if (!m_valid || ((unsigned int)m_volumes->size() <= volume_idx)) return; + if (!contains_volume(volume_idx)) + return; + + wxGetApp().plater()->take_snapshot(_(L("Selection-Remove"))); + GLVolume* volume = (*m_volumes)[volume_idx]; switch (m_mode) @@ -202,13 +210,20 @@ void Selection::add_object(unsigned int object_idx, bool as_single_selection) if (!m_valid) return; + std::vector 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 if (as_single_selection) clear(); m_mode = Instance; - do_add_object(object_idx); + do_add_volumes(volume_idxs); update_type(); this->set_bounding_boxes_dirty(); @@ -219,6 +234,8 @@ void Selection::remove_object(unsigned int object_idx) if (!m_valid) return; + wxGetApp().plater()->take_snapshot(_(L("Selection-Remove Object"))); + do_remove_object(object_idx); update_type(); @@ -230,13 +247,20 @@ void Selection::add_instance(unsigned int object_idx, unsigned int instance_idx, if (!m_valid) return; + std::vector 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 if (as_single_selection) clear(); m_mode = Instance; - do_add_instance(object_idx, instance_idx); + do_add_volumes(volume_idxs); update_type(); this->set_bounding_boxes_dirty(); @@ -247,6 +271,8 @@ void Selection::remove_instance(unsigned int object_idx, unsigned int instance_i if (!m_valid) return; + wxGetApp().plater()->take_snapshot(_(L("Selection-Remove Instance"))); + do_remove_instance(object_idx, instance_idx); update_type(); @@ -258,21 +284,20 @@ void Selection::add_volume(unsigned int object_idx, unsigned int volume_idx, int if (!m_valid) return; + std::vector 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 if (as_single_selection) clear(); m_mode = Volume; - for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) - { - 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); - } - } + do_add_volumes(volume_idxs); update_type(); this->set_bounding_boxes_dirty(); @@ -283,6 +308,8 @@ void Selection::remove_volume(unsigned int object_idx, unsigned int volume_idx) if (!m_valid) return; + wxGetApp().plater()->take_snapshot(_(L("Selection-Remove Volume"))); + for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++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(); } +void Selection::add_volumes(EMode mode, const std::vector& 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& 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() { if (!m_valid) 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; clear(); @@ -312,6 +395,21 @@ void Selection::add_all() 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> &volumes_and_instances) { if (! m_valid) @@ -439,6 +537,43 @@ bool Selection::is_sla_compliant() const return true; } +bool Selection::contains_all_volumes(const std::vector& 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& 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& 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 { if (is_single_full_instance() || is_single_modifier() || is_single_volume()) @@ -1253,6 +1388,77 @@ void Selection::paste_from_clipboard() } } +std::vector Selection::get_volume_idxs_from_object(unsigned int object_idx) const +{ + std::vector 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 Selection::get_volume_idxs_from_instance(unsigned int object_idx, unsigned int instance_idx) const +{ + std::vector 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 Selection::get_volume_idxs_from_volume(unsigned int object_idx, unsigned int instance_idx, unsigned int volume_idx) const +{ + std::vector 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 Selection::get_missing_volume_idxs_from(const std::vector& volume_idxs) const +{ + std::vector idxs; + + for (unsigned int i : m_list) + { + std::vector::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 Selection::get_unselected_volume_idxs_from(const std::vector& volume_idxs) const +{ + std::vector 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() { 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; } -void Selection::do_add_instance(unsigned int object_idx, unsigned int instance_idx) +void Selection::do_add_volumes(const std::vector& 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 ((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) + if (i < (unsigned int)m_volumes->size()) do_add_volume(i); } } diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 915a8c855..0f71cefc4 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -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 remove_volume(unsigned int object_idx, unsigned int volume_idx); + void add_volumes(EMode mode, const std::vector& volume_idxs, bool as_single_selection = true); + void remove_volumes(EMode mode, const std::vector& volume_idxs); + void add_all(); + void remove_all(); // To be called after Undo or Redo once the volumes are updated. void set_deserialized(EMode mode, const std::vector> &volumes_and_instances); @@ -265,6 +269,13 @@ public: bool is_sla_compliant() const; 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& volume_idxs) const; + // returns true if the selection contains at least one of the given indices + bool contains_any_volume(const std::vector& volume_idxs) const; + // returns true if the selection contains all and only the given indices + bool matches(const std::vector& volume_idxs) const; + bool requires_uniform_scale() const; // 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; } + // returns the list of idxs of the volumes contained into the object with the given idx + std::vector 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 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 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 get_missing_volume_idxs_from(const std::vector& volume_idxs) const; + // returns the list of idxs of the volumes contained in the given list but not in the selection + std::vector get_unselected_volume_idxs_from(const std::vector& volume_idxs) const; + private: void update_valid(); void update_type(); void set_caches(); void do_add_volume(unsigned int volume_idx); - void do_add_instance(unsigned int object_idx, unsigned int instance_idx); - void do_add_object(unsigned int object_idx); + void do_add_volumes(const std::vector& volume_idxs); void do_remove_volume(unsigned int volume_idx); void do_remove_instance(unsigned int object_idx, unsigned int instance_idx); void do_remove_object(unsigned int object_idx); diff --git a/src/slic3r/GUI/SysInfoDialog.cpp b/src/slic3r/GUI/SysInfoDialog.cpp index 96a3e9a81..e9487ee15 100644 --- a/src/slic3r/GUI/SysInfoDialog.cpp +++ b/src/slic3r/GUI/SysInfoDialog.cpp @@ -58,7 +58,7 @@ std::string get_mem_info(bool format_as_html) std::string b_end = format_as_html ? "" : ""; std::string line_end = format_as_html ? "
" : "\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 occupied by the Undo / Redo stack [MB]: " << b_end << Slic3r::format_memsize_MB(stack.memsize()) << line_end << line_end; diff --git a/src/slic3r/GUI/Tab.cpp b/src/slic3r/GUI/Tab.cpp index 780489670..4ff64de36 100644 --- a/src/slic3r/GUI/Tab.cpp +++ b/src/slic3r/GUI/Tab.cpp @@ -198,7 +198,7 @@ void Tab::create_preset_tab() // There is used just additional sizer for m_mode_sizer with right alignment auto mode_sizer = new wxBoxSizer(wxVERTICAL); 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. 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& preset = m_presets->get_edited_preset(); - - wxString description_line = preset.is_default ? - _(L("It's a default preset.")) : preset.is_system ? - _(L("It's a system preset.")) : - wxString::Format(_(L("Current preset is inherited from %s")), (parent == nullptr ? - _(L("default preset"))+"." : - ":\n\t" + parent->name)); - + + wxString description_line; + + if (preset.is_default) { + description_line = _(L("This is a default preset.")); + } else if (preset.is_system) { + 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) 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.")) + diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 3fc404864..e5e429a02 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2808,11 +2808,13 @@ ModeButton::ModeButton( wxWindow * parent, const wxString& mode /* = wxEmptyString*/, const wxSize& size /* = wxDefaultSize*/, 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_selected = wxString::Format(_(L("Current mode is %s")), mode); + SetBitmapMargins(3, 0); + //button events Bind(wxEVT_BUTTON, &ModeButton::OnButton, this); Bind(wxEVT_ENTER_WINDOW, &ModeButton::OnEnterBtn, this); @@ -2841,6 +2843,7 @@ void ModeButton::focus_button(const bool focus) Slic3r::GUI::wxGetApp().normal_font(); SetFont(new_font); + SetForegroundColour(wxSystemSettings::GetColour(focus ? wxSYS_COLOUR_BTNTEXT : wxSYS_COLOUR_BTNSHADOW)); Refresh(); Update(); @@ -2851,7 +2854,7 @@ void ModeButton::focus_button(const bool focus) // ModeSizer // ---------------------------------------------------------------------------- -ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 10*/) : +ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 0*/) : wxFlexGridSizer(3, 0, hgap) { SetFlexibleDirection(wxHORIZONTAL); @@ -2869,15 +2872,8 @@ ModeSizer::ModeSizer(wxWindow *parent, int hgap/* = 10*/) : m_mode_btns.reserve(3); for (const auto& button : buttons) { -#ifdef __WXOSX__ - 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.push_back(new ModeButton(parent, wxID_ANY, button.second, button.first)); + m_mode_btns.back()->Bind(wxEVT_BUTTON, std::bind(modebtnfn, std::placeholders::_1, int(m_mode_btns.size() - 1))); Add(m_mode_btns.back()); } diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index a704f79d7..d7d5fcac2 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -946,7 +946,7 @@ private: class ModeSizer : public wxFlexGridSizer { public: - ModeSizer( wxWindow *parent, int hgap = 10); + ModeSizer( wxWindow *parent, int hgap = 0); ~ModeSizer() {} void SetMode(const /*ConfigOptionMode*/int mode); diff --git a/src/slic3r/Utils/UndoRedo.cpp b/src/slic3r/Utils/UndoRedo.cpp index daf6752b7..1d74123dd 100644 --- a/src/slic3r/Utils/UndoRedo.cpp +++ b/src/slic3r/Utils/UndoRedo.cpp @@ -490,6 +490,21 @@ public: // 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) {} + 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; } 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. Stack::Stack() : pimpl(new StackImpl()) {} 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); } size_t Stack::get_memory_limit() const { return pimpl->get_memory_limit(); } size_t Stack::memsize() const { return pimpl->memsize(); } diff --git a/src/slic3r/Utils/UndoRedo.hpp b/src/slic3r/Utils/UndoRedo.hpp index 37cc5a049..558449003 100644 --- a/src/slic3r/Utils/UndoRedo.hpp +++ b/src/slic3r/Utils/UndoRedo.hpp @@ -71,7 +71,8 @@ struct Snapshot // Excerpt of Slic3r::GUI::Selection for serialization onto the Undo / Redo stack. struct Selection : public Slic3r::ObjectBase { - unsigned char mode; + void clear() { mode = 0; volumes_and_instances.clear(); } + unsigned char mode = 0; std::vector> volumes_and_instances; template void serialize(Archive &ar) { ar(mode, volumes_and_instances); } }; @@ -86,6 +87,9 @@ public: Stack(); ~Stack(); + void clear(); + bool empty() const; + // Set maximum memory threshold. If the threshold is exceeded, least recently used snapshots are released. void set_memory_limit(size_t memsize); size_t get_memory_limit() const;