mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-26 10:11:10 -06:00
Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer into et_custom_bed
This commit is contained in:
commit
3344650255
24 changed files with 730 additions and 212 deletions
|
|
@ -135,8 +135,7 @@ void config_wizard(int reason)
|
|||
|
||||
wxGetApp().load_current_presets();
|
||||
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA &&
|
||||
wxGetApp().obj_list()->has_multi_part_objects())
|
||||
if (wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology() == ptSLA && model_has_multi_part_objects(wxGetApp().model()))
|
||||
{
|
||||
show_info(nullptr,
|
||||
_(L("It's impossible to print multi-part object(s) with SLA technology.")) + "\n\n" +
|
||||
|
|
|
|||
|
|
@ -537,7 +537,7 @@ void GUI_App::persist_window_geometry(wxTopLevelWindow *window, bool default_max
|
|||
});
|
||||
}
|
||||
|
||||
void GUI_App::load_project(wxWindow *parent, wxString& input_file)
|
||||
void GUI_App::load_project(wxWindow *parent, wxString& input_file) const
|
||||
{
|
||||
input_file.Clear();
|
||||
wxFileDialog dialog(parent ? parent : GetTopWindow(),
|
||||
|
|
@ -549,7 +549,7 @@ void GUI_App::load_project(wxWindow *parent, wxString& input_file)
|
|||
input_file = dialog.GetPath();
|
||||
}
|
||||
|
||||
void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files)
|
||||
void GUI_App::import_model(wxWindow *parent, wxArrayString& input_files) const
|
||||
{
|
||||
input_files.Clear();
|
||||
wxFileDialog dialog(parent ? parent : GetTopWindow(),
|
||||
|
|
@ -857,7 +857,7 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
|||
|
||||
// This is called when closing the application, when loading a config file or when starting the config wizard
|
||||
// to notify the user whether he is aware that some preset changes will be lost.
|
||||
bool GUI_App::check_unsaved_changes()
|
||||
bool GUI_App::check_unsaved_changes(const wxString &header)
|
||||
{
|
||||
wxString dirty;
|
||||
PrinterTechnology printer_technology = preset_bundle->printers.get_edited_preset().printer_technology();
|
||||
|
|
@ -871,8 +871,12 @@ bool GUI_App::check_unsaved_changes()
|
|||
// No changes, the application may close or reload presets.
|
||||
return true;
|
||||
// Ask the user.
|
||||
wxString message;
|
||||
if (! header.empty())
|
||||
message = header + "\n\n";
|
||||
message += _(L("The presets on the following tabs were modified")) + ": " + dirty + "\n\n" + _(L("Discard changes and continue anyway?"));
|
||||
wxMessageDialog dialog(mainframe,
|
||||
_(L("The presets on the following tabs were modified")) + ": " + dirty + "\n\n" + _(L("Discard changes and continue anyway?")),
|
||||
message,
|
||||
wxString(SLIC3R_APP_NAME) + " - " + _(L("Unsaved Presets")),
|
||||
wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT);
|
||||
return dialog.ShowModal() == wxID_YES;
|
||||
|
|
@ -947,9 +951,9 @@ Plater* GUI_App::plater()
|
|||
return plater_;
|
||||
}
|
||||
|
||||
ModelObjectPtrs* GUI_App::model_objects()
|
||||
Model& GUI_App::model()
|
||||
{
|
||||
return &plater_->model().objects;
|
||||
return plater_->model();
|
||||
}
|
||||
|
||||
wxNotebook* GUI_App::tab_panel() const
|
||||
|
|
|
|||
|
|
@ -124,8 +124,8 @@ public:
|
|||
void recreate_GUI();
|
||||
void system_info();
|
||||
void keyboard_shortcuts();
|
||||
void load_project(wxWindow *parent, wxString& input_file);
|
||||
void import_model(wxWindow *parent, wxArrayString& input_files);
|
||||
void load_project(wxWindow *parent, wxString& input_file) const;
|
||||
void import_model(wxWindow *parent, wxArrayString& input_files) const;
|
||||
static bool catch_error(std::function<void()> cb, const std::string& err);
|
||||
|
||||
void persist_window_geometry(wxTopLevelWindow *window, bool default_maximized = false);
|
||||
|
|
@ -142,7 +142,7 @@ public:
|
|||
void update_mode();
|
||||
|
||||
void add_config_menu(wxMenuBar *menu);
|
||||
bool check_unsaved_changes();
|
||||
bool check_unsaved_changes(const wxString &header = wxString());
|
||||
bool checked_tab(Tab* tab);
|
||||
void load_current_presets();
|
||||
|
||||
|
|
@ -161,7 +161,7 @@ public:
|
|||
ObjectList* obj_list();
|
||||
ObjectLayers* obj_layers();
|
||||
Plater* plater();
|
||||
std::vector<ModelObject*> *model_objects();
|
||||
Model& model();
|
||||
|
||||
AppConfig* app_config{ nullptr };
|
||||
PresetBundle* preset_bundle{ nullptr };
|
||||
|
|
|
|||
|
|
@ -71,9 +71,6 @@ static void take_snapshot(const wxString& snapshot_name)
|
|||
wxGetApp().plater()->take_snapshot(snapshot_name);
|
||||
}
|
||||
|
||||
static void suppress_snapshots(){ wxGetApp().plater()->suppress_snapshots(); }
|
||||
static void allow_snapshots() { wxGetApp().plater()->allow_snapshots(); }
|
||||
|
||||
ObjectList::ObjectList(wxWindow* parent) :
|
||||
wxDataViewCtrl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_MULTIPLE),
|
||||
m_parent(parent)
|
||||
|
|
@ -2406,8 +2403,7 @@ void ObjectList::remove()
|
|||
|
||||
wxDataViewItem parent = wxDataViewItem(0);
|
||||
|
||||
take_snapshot(_(L("Delete Selected")));
|
||||
suppress_snapshots();
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Delete Selected")));
|
||||
|
||||
for (auto& item : sels)
|
||||
{
|
||||
|
|
@ -2429,8 +2425,6 @@ void ObjectList::remove()
|
|||
|
||||
if (parent)
|
||||
select_item(parent);
|
||||
|
||||
allow_snapshots();
|
||||
}
|
||||
|
||||
void ObjectList::del_layer_range(const t_layer_height_range& range)
|
||||
|
|
@ -2505,8 +2499,7 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range& curre
|
|||
|
||||
t_layer_height_range new_range = { midl_layer, next_range.second };
|
||||
|
||||
take_snapshot(_(L("Add New Layers Range")));
|
||||
suppress_snapshots();
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _(L("Add New Layers Range")));
|
||||
|
||||
// create new 2 layers instead of deleted one
|
||||
|
||||
|
|
@ -2521,7 +2514,6 @@ void ObjectList::add_layer_range_after_current(const t_layer_height_range& curre
|
|||
new_range = { current_range.second, midl_layer };
|
||||
ranges[new_range] = get_default_layer_config(obj_idx);
|
||||
add_layer_item(new_range, layers_item, layer_idx);
|
||||
allow_snapshots();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -2611,7 +2603,7 @@ bool ObjectList::edit_layer_range(const t_layer_height_range& range, const t_lay
|
|||
|
||||
void ObjectList::init_objects()
|
||||
{
|
||||
m_objects = wxGetApp().model_objects();
|
||||
m_objects = &wxGetApp().model().objects;
|
||||
}
|
||||
|
||||
bool ObjectList::multiple_selection() const
|
||||
|
|
@ -3088,19 +3080,6 @@ void ObjectList::last_volume_is_deleted(const int obj_idx)
|
|||
volume->config.set_key_value("extruder", new ConfigOptionInt(0));
|
||||
}
|
||||
|
||||
bool ObjectList::has_multi_part_objects()
|
||||
{
|
||||
if (!m_objects_model->IsEmpty()) {
|
||||
wxDataViewItemArray items;
|
||||
m_objects_model->GetChildren(wxDataViewItem(0), items);
|
||||
|
||||
for (auto& item : items)
|
||||
if (m_objects_model->GetItemByType(item, itVolume))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* #lm_FIXME_delete_after_testing
|
||||
void ObjectList::update_settings_items()
|
||||
{
|
||||
|
|
@ -3531,7 +3510,7 @@ void ObjectList::update_after_undo_redo()
|
|||
m_prevent_list_events = true;
|
||||
m_prevent_canvas_selection_update = true;
|
||||
|
||||
suppress_snapshots();
|
||||
Plater::SuppressSnapshots suppress(wxGetApp().plater());
|
||||
|
||||
// Unselect all objects before deleting them, so that no change of selection is emitted during deletion.
|
||||
this->UnselectAll();
|
||||
|
|
@ -3543,8 +3522,6 @@ void ObjectList::update_after_undo_redo()
|
|||
++obj_idx;
|
||||
}
|
||||
|
||||
allow_snapshots();
|
||||
|
||||
#ifndef __WXOSX__
|
||||
selection_changed();
|
||||
#endif /* __WXOSX__ */
|
||||
|
|
|
|||
|
|
@ -317,7 +317,6 @@ public:
|
|||
void change_part_type();
|
||||
|
||||
void last_volume_is_deleted(const int obj_idx);
|
||||
bool has_multi_part_objects();
|
||||
void update_settings_items();
|
||||
void update_and_show_object_settings_item();
|
||||
void update_settings_item_and_selection(wxDataViewItem item, wxDataViewItemArray& selections);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ static double get_volume_min_z(const GLVolume* volume)
|
|||
const Transform3f& world_matrix = volume->world_matrix().cast<float>();
|
||||
|
||||
// need to get the ModelVolume pointer
|
||||
const ModelObject* mo = wxGetApp().model_objects()->at(volume->composite_id.object_id);
|
||||
const ModelObject* mo = wxGetApp().model().objects[volume->composite_id.object_id];
|
||||
const ModelVolume* mv = mo->volumes[volume->composite_id.volume_id];
|
||||
const TriangleMesh& hull = mv->get_convex_hull();
|
||||
|
||||
|
|
@ -466,7 +466,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection)
|
|||
m_new_scale = m_new_size.cwiseProduct(selection.get_unscaled_instance_bounding_box().size().cwiseInverse()) * 100.;
|
||||
} else {
|
||||
m_new_rotation = volume->get_instance_rotation() * (180. / M_PI);
|
||||
m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct((*wxGetApp().model_objects())[volume->object_idx()]->raw_mesh_bounding_box().size());
|
||||
m_new_size = volume->get_instance_transformation().get_scaling_factor().cwiseProduct(wxGetApp().model().objects[volume->object_idx()]->raw_mesh_bounding_box().size());
|
||||
m_new_scale = volume->get_instance_scaling_factor() * 100.;
|
||||
}
|
||||
|
||||
|
|
@ -779,7 +779,7 @@ void ObjectManipulation::change_size_value(int axis, double value)
|
|||
else if (selection.is_single_full_instance())
|
||||
ref_size = m_world_coordinates ?
|
||||
selection.get_unscaled_instance_bounding_box().size() :
|
||||
(*wxGetApp().model_objects())[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size();
|
||||
wxGetApp().model().objects[selection.get_volume(*selection.get_volume_idxs().begin())->object_idx()]->raw_mesh_bounding_box().size();
|
||||
|
||||
this->do_scale(axis, 100. * Vec3d(size(0) / ref_size(0), size(1) / ref_size(1), size(2) / ref_size(2)));
|
||||
|
||||
|
|
@ -902,7 +902,7 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value)
|
|||
return;
|
||||
}
|
||||
// Bake the rotation into the meshes of the object.
|
||||
(*wxGetApp().model_objects())[volume->composite_id.object_id]->bake_xy_rotation_into_meshes(volume->composite_id.instance_id);
|
||||
wxGetApp().model().objects[volume->composite_id.object_id]->bake_xy_rotation_into_meshes(volume->composite_id.instance_id);
|
||||
// Update the 3D scene, selections etc.
|
||||
wxGetApp().plater()->update();
|
||||
// Recalculate cached values at this panel, refresh the screen.
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ void GLGizmoFlatten::on_set_state()
|
|||
// m_model_object pointer can be invalid (for instance because of undo/redo action),
|
||||
// we should recover it from the object id
|
||||
m_model_object = nullptr;
|
||||
for (const auto mo : *wxGetApp().model_objects()) {
|
||||
for (const auto mo : wxGetApp().model().objects) {
|
||||
if (mo->id() == m_model_object_id) {
|
||||
m_model_object = mo;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1049,7 +1049,7 @@ void GLGizmoSlaSupports::on_set_state()
|
|||
// we should recover it from the object id
|
||||
const ModelObject* old_model_object = m_model_object;
|
||||
m_model_object = nullptr;
|
||||
for (const auto mo : *wxGetApp().model_objects()) {
|
||||
for (const auto mo : wxGetApp().model().objects) {
|
||||
if (mo->id() == m_current_mesh_object_id) {
|
||||
m_model_object = mo;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1255,13 +1255,9 @@ const std::regex PlaterDropTarget::pattern_drop(".*[.](stl|obj|amf|3mf|prusa)",
|
|||
|
||||
bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &filenames)
|
||||
{
|
||||
plater->take_snapshot(_(L("Load Files")));
|
||||
|
||||
std::vector<fs::path> paths;
|
||||
|
||||
for (const auto &filename : filenames) {
|
||||
fs::path path(into_path(filename));
|
||||
|
||||
if (std::regex_match(path.string(), pattern_drop)) {
|
||||
paths.push_back(std::move(path));
|
||||
} else {
|
||||
|
|
@ -1269,6 +1265,23 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi
|
|||
}
|
||||
}
|
||||
|
||||
wxString snapshot_label;
|
||||
assert(! paths.empty());
|
||||
if (paths.size() == 1) {
|
||||
snapshot_label = _(L("Load File"));
|
||||
snapshot_label += ": ";
|
||||
snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str());
|
||||
} else {
|
||||
snapshot_label = _(L("Load Files"));
|
||||
snapshot_label += ": ";
|
||||
snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str());
|
||||
for (size_t i = 1; i < paths.size(); ++ i) {
|
||||
snapshot_label += ", ";
|
||||
snapshot_label += wxString::FromUTF8(paths[i].filename().string().c_str());
|
||||
}
|
||||
}
|
||||
Plater::TakeSnapshot snapshot(plater, snapshot_label);
|
||||
|
||||
// FIXME: when drag and drop is done on a .3mf or a .amf file we should clear the plater for consistence with the open project command
|
||||
// (the following call to plater->load_files() will load the config data, if present)
|
||||
|
||||
|
|
@ -1595,7 +1608,7 @@ struct Plater::priv
|
|||
priv(Plater *q, MainFrame *main_frame);
|
||||
~priv();
|
||||
|
||||
void update(bool force_full_scene_refresh = false);
|
||||
void update(bool force_full_scene_refresh = false, bool force_background_processing_update = false);
|
||||
void select_view(const std::string& direction);
|
||||
void select_view_3D(const std::string& name);
|
||||
void select_next_view_3D();
|
||||
|
|
@ -1633,14 +1646,18 @@ struct Plater::priv
|
|||
if (this->m_prevent_snapshots > 0)
|
||||
return;
|
||||
assert(this->m_prevent_snapshots >= 0);
|
||||
this->undo_redo_stack.take_snapshot(snapshot_name, model, view3D->get_canvas3d()->get_selection(), view3D->get_canvas3d()->get_gizmos_manager());
|
||||
}
|
||||
this->undo_redo_stack.take_snapshot(snapshot_name, model, view3D->get_canvas3d()->get_selection(), view3D->get_canvas3d()->get_gizmos_manager(), this->printer_technology);
|
||||
this->undo_redo_stack.release_least_recently_used();
|
||||
// Save the last active preset name of a particular printer technology.
|
||||
((this->printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name) = wxGetApp().preset_bundle->printers.get_selected_preset_name();
|
||||
BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot taken: " << snapshot_name << ", Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack.memsize()) << log_memory_info();
|
||||
}
|
||||
void 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_to(size_t time_to_load);
|
||||
void redo_to(size_t time_to_load);
|
||||
void undo_redo_to(size_t time_to_load);
|
||||
|
||||
void suppress_snapshots() { this->m_prevent_snapshots++; }
|
||||
void allow_snapshots() { this->m_prevent_snapshots--; }
|
||||
|
||||
|
|
@ -1734,10 +1751,13 @@ private:
|
|||
|
||||
void update_fff_scene();
|
||||
void update_sla_scene();
|
||||
void update_after_undo_redo();
|
||||
void undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator it_snapshot);
|
||||
void update_after_undo_redo(bool temp_snapshot_was_taken = false);
|
||||
|
||||
// path to project file stored with no extension
|
||||
wxString m_project_filename;
|
||||
std::string m_last_fff_printer_profile_name;
|
||||
std::string m_last_sla_printer_profile_name;
|
||||
};
|
||||
|
||||
const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase);
|
||||
|
|
@ -1896,7 +1916,7 @@ Plater::priv::~priv()
|
|||
delete config;
|
||||
}
|
||||
|
||||
void Plater::priv::update(bool force_full_scene_refresh)
|
||||
void Plater::priv::update(bool force_full_scene_refresh, bool force_background_processing_update)
|
||||
{
|
||||
// the following line, when enabled, causes flickering on NVIDIA graphics cards
|
||||
// wxWindowUpdateLocker freeze_guard(q);
|
||||
|
|
@ -1909,7 +1929,7 @@ void Plater::priv::update(bool force_full_scene_refresh)
|
|||
}
|
||||
|
||||
unsigned int update_status = 0;
|
||||
if (this->printer_technology == ptSLA)
|
||||
if (this->printer_technology == ptSLA || force_background_processing_update)
|
||||
// Update the SLAPrint from the current Model, so that the reload_scene()
|
||||
// pulls the correct data.
|
||||
update_status = this->update_background_process(false);
|
||||
|
|
@ -2095,66 +2115,22 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||
}
|
||||
}
|
||||
}
|
||||
else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf))
|
||||
{
|
||||
bool advanced = false;
|
||||
for (const ModelObject* model_object : model.objects)
|
||||
else if ((wxGetApp().get_mode() == comSimple) && (type_3mf || type_any_amf) && model_has_advanced_features(model)) {
|
||||
wxMessageDialog dlg(q, _(L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?\n")),
|
||||
_(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO);
|
||||
if (dlg.ShowModal() == wxID_YES)
|
||||
{
|
||||
// is there more than one instance ?
|
||||
if (model_object->instances.size() > 1)
|
||||
{
|
||||
advanced = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// is there any advanced config data ?
|
||||
auto opt_keys = model_object->config.keys();
|
||||
if (!opt_keys.empty() && !((opt_keys.size() == 1) && (opt_keys[0] == "extruder")))
|
||||
{
|
||||
advanced = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// is there any modifier ?
|
||||
for (const ModelVolume* model_volume : model_object->volumes)
|
||||
{
|
||||
if (!model_volume->is_model_part())
|
||||
{
|
||||
advanced = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// is there any advanced config data ?
|
||||
opt_keys = model_volume->config.keys();
|
||||
if (!opt_keys.empty() && !((opt_keys.size() == 1) && (opt_keys[0] == "extruder")))
|
||||
{
|
||||
advanced = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (advanced)
|
||||
break;
|
||||
}
|
||||
|
||||
if (advanced)
|
||||
{
|
||||
wxMessageDialog dlg(q, _(L("This file cannot be loaded in a simple mode. Do you want to switch to an advanced mode?\n")),
|
||||
_(L("Detected advanced data")), wxICON_WARNING | wxYES | wxNO);
|
||||
if (dlg.ShowModal() == wxID_YES)
|
||||
{
|
||||
Slic3r::GUI::wxGetApp().save_mode(comAdvanced);
|
||||
view3D->set_as_dirty();
|
||||
}
|
||||
else
|
||||
return obj_idxs;
|
||||
Slic3r::GUI::wxGetApp().save_mode(comAdvanced);
|
||||
view3D->set_as_dirty();
|
||||
}
|
||||
else
|
||||
return obj_idxs;
|
||||
}
|
||||
|
||||
for (ModelObject* model_object : model.objects) {
|
||||
model_object->center_around_origin(false);
|
||||
model_object->ensure_on_bed();
|
||||
}
|
||||
for (ModelObject* model_object : model.objects) {
|
||||
model_object->center_around_origin(false);
|
||||
model_object->ensure_on_bed();
|
||||
}
|
||||
|
||||
// check multi-part object adding for the SLA-printing
|
||||
if (printer_technology == ptSLA)
|
||||
|
|
@ -2467,7 +2443,10 @@ void Plater::priv::remove(size_t obj_idx)
|
|||
|
||||
void Plater::priv::delete_object_from_model(size_t obj_idx)
|
||||
{
|
||||
this->take_snapshot(_(L("Delete Object")));
|
||||
wxString snapshot_label = _(L("Delete Object"));
|
||||
if (! model.objects[obj_idx]->name.empty())
|
||||
snapshot_label += ": " + wxString::FromUTF8(model.objects[obj_idx]->name.c_str());
|
||||
Plater::TakeSnapshot snapshot(q, snapshot_label);
|
||||
model.delete_object(obj_idx);
|
||||
update();
|
||||
object_list_changed();
|
||||
|
|
@ -2475,7 +2454,7 @@ void Plater::priv::delete_object_from_model(size_t obj_idx)
|
|||
|
||||
void Plater::priv::reset()
|
||||
{
|
||||
this->take_snapshot(_(L("Reset Project")));
|
||||
Plater::TakeSnapshot snapshot(q, _(L("Reset Project")));
|
||||
|
||||
set_project_filename(wxEmptyString);
|
||||
|
||||
|
|
@ -2671,7 +2650,7 @@ void Plater::priv::split_object()
|
|||
Slic3r::GUI::warning_catcher(q, _(L("The selected object couldn't be split because it contains only one part.")));
|
||||
else
|
||||
{
|
||||
this->take_snapshot(_(L("Split to Objects")));
|
||||
Plater::TakeSnapshot snapshot(q, _(L("Split to Objects")));
|
||||
|
||||
unsigned int counter = 1;
|
||||
for (ModelObject* m : new_objects)
|
||||
|
|
@ -2911,7 +2890,7 @@ void Plater::priv::update_sla_scene()
|
|||
|
||||
void Plater::priv::reload_from_disk()
|
||||
{
|
||||
this->take_snapshot(_(L("Reload from Disk")));
|
||||
Plater::TakeSnapshot snapshot(q, _(L("Reload from Disk")));
|
||||
|
||||
const auto &selection = get_selection();
|
||||
const auto obj_orig_idx = selection.get_object_idx();
|
||||
|
|
@ -2947,7 +2926,7 @@ void Plater::priv::fix_through_netfabb(const int obj_idx, const int vol_idx/* =
|
|||
if (obj_idx < 0)
|
||||
return;
|
||||
|
||||
this->take_snapshot(_(L("Fix Throught NetFabb")));
|
||||
Plater::TakeSnapshot snapshot(q, _(L("Fix Throught NetFabb")));
|
||||
|
||||
fix_model_by_win10_sdk_gui(*model.objects[obj_idx], vol_idx);
|
||||
this->update();
|
||||
|
|
@ -3611,7 +3590,7 @@ void Plater::priv::show_action_buttons(const bool is_ready_to_slice) const
|
|||
|
||||
int Plater::priv::get_active_snapshot_index()
|
||||
{
|
||||
const size_t& active_snapshot_time = this->undo_redo_stack.active_snapshot_time();
|
||||
const size_t active_snapshot_time = this->undo_redo_stack.active_snapshot_time();
|
||||
const std::vector<UndoRedo::Snapshot>& ss_stack = this->undo_redo_stack.snapshots();
|
||||
const auto it = std::lower_bound(ss_stack.begin(), ss_stack.end(), UndoRedo::Snapshot(active_snapshot_time));
|
||||
return it - ss_stack.begin();
|
||||
|
|
@ -3619,40 +3598,87 @@ int Plater::priv::get_active_snapshot_index()
|
|||
|
||||
void Plater::priv::undo()
|
||||
{
|
||||
if (this->undo_redo_stack.undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager()))
|
||||
this->update_after_undo_redo();
|
||||
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack.snapshots();
|
||||
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack.active_snapshot_time()));
|
||||
if (-- it_current != snapshots.begin())
|
||||
this->undo_redo_to(it_current);
|
||||
}
|
||||
|
||||
void Plater::priv::redo()
|
||||
{
|
||||
if (this->undo_redo_stack.redo(model, this->view3D->get_canvas3d()->get_gizmos_manager()))
|
||||
this->update_after_undo_redo();
|
||||
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack.snapshots();
|
||||
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(this->undo_redo_stack.active_snapshot_time()));
|
||||
if (++ it_current != snapshots.end())
|
||||
this->undo_redo_to(it_current);
|
||||
}
|
||||
|
||||
void Plater::priv::undo_to(size_t time_to_load)
|
||||
void Plater::priv::undo_redo_to(size_t time_to_load)
|
||||
{
|
||||
if (this->undo_redo_stack.undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager(), time_to_load))
|
||||
this->update_after_undo_redo();
|
||||
const std::vector<UndoRedo::Snapshot> &snapshots = this->undo_redo_stack.snapshots();
|
||||
auto it_current = std::lower_bound(snapshots.begin(), snapshots.end(), UndoRedo::Snapshot(time_to_load));
|
||||
assert(it_current != snapshots.end());
|
||||
this->undo_redo_to(it_current);
|
||||
}
|
||||
|
||||
void Plater::priv::redo_to(size_t time_to_load)
|
||||
{
|
||||
if (this->undo_redo_stack.redo(model, this->view3D->get_canvas3d()->get_gizmos_manager(), time_to_load))
|
||||
this->update_after_undo_redo();
|
||||
}
|
||||
|
||||
void Plater::priv::update_after_undo_redo()
|
||||
void Plater::priv::undo_redo_to(std::vector<UndoRedo::Snapshot>::const_iterator it_snapshot)
|
||||
{
|
||||
this->view3D->get_canvas3d()->get_selection().clear();
|
||||
this->update(false); // update volumes from the deserializd model
|
||||
bool temp_snapshot_was_taken = this->undo_redo_stack.temp_snapshot_active();
|
||||
PrinterTechnology new_printer_technology = it_snapshot->printer_technology;
|
||||
bool printer_technology_changed = this->printer_technology != new_printer_technology;
|
||||
if (printer_technology_changed) {
|
||||
// Switching the printer technology when jumping forwards / backwards in time. Switch to the last active printer profile of the other type.
|
||||
std::string s_pt = (it_snapshot->printer_technology == ptFFF) ? "FFF" : "SLA";
|
||||
if (! wxGetApp().check_unsaved_changes(from_u8((boost::format(_utf8(
|
||||
L("%1% printer was active at the time the target Undo / Redo snapshot was taken. Switching to %1% printer requires reloading of %1% presets."))) % s_pt).str())))
|
||||
// Don't switch the profiles.
|
||||
return;
|
||||
}
|
||||
// Save the last active preset name of a particular printer technology.
|
||||
((this->printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name) = wxGetApp().preset_bundle->printers.get_selected_preset_name();
|
||||
// Do the jump in time.
|
||||
if (it_snapshot->timestamp < this->undo_redo_stack.active_snapshot_time() ?
|
||||
this->undo_redo_stack.undo(model, this->view3D->get_canvas3d()->get_selection(), this->view3D->get_canvas3d()->get_gizmos_manager(), this->printer_technology, it_snapshot->timestamp) :
|
||||
this->undo_redo_stack.redo(model, this->view3D->get_canvas3d()->get_gizmos_manager(), it_snapshot->timestamp)) {
|
||||
if (printer_technology_changed) {
|
||||
// Switch to the other printer technology. Switch to the last printer active for that particular technology.
|
||||
AppConfig *app_config = wxGetApp().app_config;
|
||||
app_config->set("presets", "printer", (new_printer_technology == ptFFF) ? m_last_fff_printer_profile_name : m_last_sla_printer_profile_name);
|
||||
wxGetApp().preset_bundle->load_presets(*app_config);
|
||||
// Load the currently selected preset into the GUI, update the preset selection box.
|
||||
// This also switches the printer technology based on the printer technology of the active printer profile.
|
||||
wxGetApp().load_current_presets();
|
||||
}
|
||||
this->update_after_undo_redo(temp_snapshot_was_taken);
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::priv::update_after_undo_redo(bool /* temp_snapshot_was_taken */)
|
||||
{
|
||||
this->view3D->get_canvas3d()->get_selection().clear();
|
||||
// Update volumes from the deserializd model, always stop / update the background processing (for both the SLA and FFF technologies).
|
||||
this->update(false, true);
|
||||
// Release old snapshots if the memory allocated is excessive. This may remove the top most snapshot if jumping to the very first snapshot.
|
||||
//if (temp_snapshot_was_taken)
|
||||
// Release the old snapshots always, as it may have happened, that some of the triangle meshes got deserialized from the snapshot, while some
|
||||
// triangle meshes may have gotten released from the scene or the background processing, therefore now being calculated into the Undo / Redo stack size.
|
||||
this->undo_redo_stack.release_least_recently_used();
|
||||
//YS_FIXME update obj_list from the deserialized model (maybe store ObjectIDs into the tree?) (no selections at this point of time)
|
||||
this->view3D->get_canvas3d()->get_selection().set_deserialized(GUI::Selection::EMode(this->undo_redo_stack.selection_deserialized().mode), this->undo_redo_stack.selection_deserialized().volumes_and_instances);
|
||||
this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo();
|
||||
|
||||
wxGetApp().obj_list()->update_after_undo_redo();
|
||||
|
||||
if (wxGetApp().get_mode() == comSimple && model_has_advanced_features(this->model)) {
|
||||
// If the user jumped to a snapshot that require user interface with advanced features, switch to the advanced mode without asking.
|
||||
// There is a little risk of surprising the user, as he already must have had the advanced or expert mode active for such a snapshot to be taken.
|
||||
Slic3r::GUI::wxGetApp().save_mode(comAdvanced);
|
||||
view3D->set_as_dirty();
|
||||
}
|
||||
|
||||
//FIXME what about the state of the manipulators?
|
||||
//FIXME what about the focus? Cursor in the side panel?
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Undo / Redo snapshot reloaded. Undo / Redo stack memory: " << Slic3r::format_memsize_MB(this->undo_redo_stack.memsize()) << log_memory_info();
|
||||
}
|
||||
|
||||
void Sidebar::set_btn_label(const ActionButtonType btn_type, const wxString& label) const
|
||||
|
|
@ -3692,10 +3718,12 @@ void Plater::new_project()
|
|||
|
||||
void Plater::load_project()
|
||||
{
|
||||
this->take_snapshot(_(L("Load Project")));
|
||||
|
||||
// Ask user for a project file name.
|
||||
wxString input_file;
|
||||
wxGetApp().load_project(this, input_file);
|
||||
// Take the Undo / Redo snapshot.
|
||||
Plater::TakeSnapshot snapshot(this, _(L("Load Project")) + ": " + wxString::FromUTF8(into_path(input_file).stem().string().c_str()));
|
||||
// And finally load the new project.
|
||||
load_project(input_file);
|
||||
}
|
||||
|
||||
|
|
@ -3719,13 +3747,28 @@ void Plater::add_model()
|
|||
if (input_files.empty())
|
||||
return;
|
||||
|
||||
this->take_snapshot(_(L("Add object(s)")));
|
||||
std::vector<fs::path> paths;
|
||||
for (const auto &file : input_files)
|
||||
paths.push_back(into_path(file));
|
||||
|
||||
std::vector<fs::path> input_paths;
|
||||
for (const auto &file : input_files) {
|
||||
input_paths.push_back(into_path(file));
|
||||
}
|
||||
load_files(input_paths, true, false);
|
||||
wxString snapshot_label;
|
||||
assert(! paths.empty());
|
||||
if (paths.size() == 1) {
|
||||
snapshot_label = _(L("Import Object"));
|
||||
snapshot_label += ": ";
|
||||
snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str());
|
||||
} else {
|
||||
snapshot_label = _(L("Import Objects"));
|
||||
snapshot_label += ": ";
|
||||
snapshot_label += wxString::FromUTF8(paths.front().filename().string().c_str());
|
||||
for (size_t i = 1; i < paths.size(); ++ i) {
|
||||
snapshot_label += ", ";
|
||||
snapshot_label += wxString::FromUTF8(paths[i].filename().string().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
Plater::TakeSnapshot snapshot(this, snapshot_label);
|
||||
load_files(paths, true, false);
|
||||
}
|
||||
|
||||
void Plater::extract_config_from_project()
|
||||
|
|
@ -3778,17 +3821,15 @@ void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_mo
|
|||
|
||||
void Plater::remove_selected()
|
||||
{
|
||||
this->take_snapshot(_(L("Delete Selected Objects")));
|
||||
this->suppress_snapshots();
|
||||
Plater::TakeSnapshot snapshot(this, _(L("Delete Selected Objects")));
|
||||
this->p->view3D->delete_selected();
|
||||
this->allow_snapshots();
|
||||
}
|
||||
|
||||
void Plater::increase_instances(size_t num)
|
||||
{
|
||||
if (! can_increase_instances()) { return; }
|
||||
|
||||
this->take_snapshot(_(L("Increase Instances")));
|
||||
Plater::TakeSnapshot snapshot(this, _(L("Increase Instances")));
|
||||
|
||||
int obj_idx = p->get_selected_object_idx();
|
||||
|
||||
|
|
@ -3824,7 +3865,7 @@ void Plater::decrease_instances(size_t num)
|
|||
{
|
||||
if (! can_decrease_instances()) { return; }
|
||||
|
||||
this->take_snapshot(_(L("Decrease Instances")));
|
||||
Plater::TakeSnapshot snapshot(this, _(L("Decrease Instances")));
|
||||
|
||||
int obj_idx = p->get_selected_object_idx();
|
||||
|
||||
|
|
@ -3860,16 +3901,13 @@ void Plater::set_number_of_copies(/*size_t num*/)
|
|||
if (num < 0)
|
||||
return;
|
||||
|
||||
this->take_snapshot(wxString::Format(_(L("Set numbers of copies to %d")), num));
|
||||
this->suppress_snapshots();
|
||||
Plater::TakeSnapshot snapshot(this, wxString::Format(_(L("Set numbers of copies to %d")), num));
|
||||
|
||||
int diff = (int)num - (int)model_object->instances.size();
|
||||
if (diff > 0)
|
||||
increase_instances(diff);
|
||||
else if (diff < 0)
|
||||
decrease_instances(-diff);
|
||||
|
||||
this->allow_snapshots();
|
||||
}
|
||||
|
||||
bool Plater::is_selection_empty() const
|
||||
|
|
@ -3893,7 +3931,7 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, coordf_t z, bool keep_uppe
|
|||
return;
|
||||
}
|
||||
|
||||
this->take_snapshot(_(L("Gizmo-Cut")));
|
||||
Plater::TakeSnapshot snapshot(this, _(L("Cut by Plane")));
|
||||
|
||||
wxBusyCursor wait;
|
||||
const auto new_objects = object->cut(instance_idx, z, keep_upper, keep_lower, rotate_lower);
|
||||
|
|
@ -4198,7 +4236,7 @@ void Plater::undo_to(int selection)
|
|||
}
|
||||
|
||||
const int idx = p->get_active_snapshot_index() - selection - 1;
|
||||
p->undo_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)
|
||||
{
|
||||
|
|
@ -4208,7 +4246,7 @@ void Plater::redo_to(int selection)
|
|||
}
|
||||
|
||||
const int idx = p->get_active_snapshot_index() + selection + 1;
|
||||
p->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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -186,8 +186,6 @@ public:
|
|||
|
||||
void take_snapshot(const std::string &snapshot_name);
|
||||
void take_snapshot(const wxString &snapshot_name);
|
||||
void suppress_snapshots();
|
||||
void allow_snapshots();
|
||||
void undo();
|
||||
void redo();
|
||||
void undo_to(int selection);
|
||||
|
|
@ -235,10 +233,46 @@ public:
|
|||
|
||||
const Camera& get_camera() const;
|
||||
|
||||
// ROII wrapper for suppressing the Undo / Redo snapshot to be taken.
|
||||
class SuppressSnapshots
|
||||
{
|
||||
public:
|
||||
SuppressSnapshots(Plater *plater) : m_plater(plater)
|
||||
{
|
||||
m_plater->suppress_snapshots();
|
||||
}
|
||||
~SuppressSnapshots()
|
||||
{
|
||||
m_plater->allow_snapshots();
|
||||
}
|
||||
private:
|
||||
Plater *m_plater;
|
||||
};
|
||||
|
||||
// ROII wrapper for taking an Undo / Redo snapshot while disabling the snapshot taking by the methods called from inside this snapshot.
|
||||
class TakeSnapshot
|
||||
{
|
||||
public:
|
||||
TakeSnapshot(Plater *plater, const wxString &snapshot_name) : m_plater(plater)
|
||||
{
|
||||
m_plater->take_snapshot(snapshot_name);
|
||||
m_plater->suppress_snapshots();
|
||||
}
|
||||
~TakeSnapshot()
|
||||
{
|
||||
m_plater->allow_snapshots();
|
||||
}
|
||||
private:
|
||||
Plater *m_plater;
|
||||
};
|
||||
|
||||
private:
|
||||
struct priv;
|
||||
std::unique_ptr<priv> p;
|
||||
|
||||
void suppress_snapshots();
|
||||
void allow_snapshots();
|
||||
|
||||
friend class SuppressBackgroundProcessingUpdate;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2916,7 +2916,7 @@ bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr
|
|||
// Because of we can't to print the multi-part objects with SLA technology.
|
||||
bool Tab::may_switch_to_SLA_preset()
|
||||
{
|
||||
if (wxGetApp().obj_list()->has_multi_part_objects())
|
||||
if (model_has_multi_part_objects(wxGetApp().model()))
|
||||
{
|
||||
show_info( parent(),
|
||||
_(L("It's impossible to print multi-part object(s) with SLA technology.")) + "\n\n" +
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue