When synchronizing the front end with the back end after Undo / Redo

jump, postpone error messages, so they are displayed after
the Undo / Redo jump has been fully performed.
Otherwise there would be a message box opening, taking over the message
queue, and possibly performing actions as rendering on an inconsistent
application state.
This commit is contained in:
bubnikv 2019-08-23 15:53:45 +02:00
parent bb6cde789d
commit 6adebb9c78
5 changed files with 42 additions and 26 deletions

View file

@ -1320,9 +1320,9 @@ bool GLGizmoSlaSupports::has_backend_supports() const
return false;
}
void GLGizmoSlaSupports::reslice_SLA_supports() const
void GLGizmoSlaSupports::reslice_SLA_supports(bool postpone_error_messages) const
{
wxGetApp().CallAfter([this]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object); });
wxGetApp().CallAfter([this, postpone_error_messages]() { wxGetApp().plater()->reslice_SLA_supports(*m_model_object, postpone_error_messages); });
}
void GLGizmoSlaSupports::get_data_from_backend()

View file

@ -87,7 +87,7 @@ public:
bool is_in_editing_mode() const { return m_editing_mode; }
bool is_selection_rectangle_dragging() const { return m_selection_rectangle.is_dragging(); }
bool has_backend_supports() const;
void reslice_SLA_supports() const;
void reslice_SLA_supports(bool postpone_error_messages = false) const;
private:
bool on_init();

View file

@ -882,7 +882,7 @@ void GLGizmosManager::update_after_undo_redo(const UndoRedo::Snapshot& snapshot)
m_serializing = false;
if (m_current == SlaSupports
&& snapshot.snapshot_data.flags & UndoRedo::SnapshotData::RECALCULATE_SLA_SUPPORTS)
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports])->reslice_SLA_supports();
dynamic_cast<GLGizmoSlaSupports*>(m_gizmos[SlaSupports])->reslice_SLA_supports(true);
}
void GLGizmosManager::reset()

View file

@ -1457,7 +1457,7 @@ struct Plater::priv
// Do a full refresh of scene tree, including regenerating
// all the GLVolumes. FIXME The update function shall just
// reload the modified matrices.
if (!was_canceled()) plater().update(true);
if (!was_canceled()) plater().update((unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH);
}
public:
@ -1676,7 +1676,7 @@ struct Plater::priv
// Apply the arrange result to all selected objects
for (ArrangePolygon &ap : m_selected) ap.apply();
plater().update(false /*dont force_full_scene_refresh*/);
plater().update();
}
};
@ -1759,7 +1759,12 @@ struct Plater::priv
priv(Plater *q, MainFrame *main_frame);
~priv();
void update(bool force_full_scene_refresh = false, bool force_background_processing_update = false);
enum class UpdateParams {
FORCE_FULL_SCREEN_REFRESH = 1,
FORCE_BACKGROUND_PROCESSING_UPDATE = 2,
POSTPONE_VALIDATION_ERROR_MESSAGE = 4,
};
void update(unsigned int flags = 0);
void select_view(const std::string& direction);
void select_view_3D(const std::string& name);
void select_next_view_3D();
@ -1837,11 +1842,18 @@ struct Plater::priv
UPDATE_BACKGROUND_PROCESS_FORCE_EXPORT = 16,
};
// returns bit mask of UpdateBackgroundProcessReturnState
unsigned int update_background_process(bool force_validation = false);
unsigned int update_background_process(bool force_validation = false, bool postpone_error_messages = false);
// Restart background processing thread based on a bitmask of UpdateBackgroundProcessReturnState.
bool restart_background_process(unsigned int state);
// returns bit mask of UpdateBackgroundProcessReturnState
unsigned int update_restart_background_process(bool force_scene_update, bool force_preview_update);
void show_delayed_error_message() {
if (!this->delayed_error_message.empty()) {
std::string msg = std::move(this->delayed_error_message);
this->delayed_error_message.clear();
GUI::show_error(this->q, msg);
}
}
void export_gcode(fs::path output_path, PrintHostJob upload_job);
void reload_from_disk();
void fix_through_netfabb(const int obj_idx, const int vol_idx = -1);
@ -2082,7 +2094,7 @@ Plater::priv::~priv()
delete config;
}
void Plater::priv::update(bool force_full_scene_refresh, bool force_background_processing_update)
void Plater::priv::update(unsigned int flags)
{
// the following line, when enabled, causes flickering on NVIDIA graphics cards
// wxWindowUpdateLocker freeze_guard(q);
@ -2095,11 +2107,11 @@ void Plater::priv::update(bool force_full_scene_refresh, bool force_background_p
}
unsigned int update_status = 0;
if (this->printer_technology == ptSLA || force_background_processing_update)
if (this->printer_technology == ptSLA || (flags & (unsigned int)UpdateParams::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);
this->view3D->reload_scene(false, force_full_scene_refresh);
update_status = this->update_background_process(false, flags & (unsigned int)UpdateParams::POSTPONE_VALIDATION_ERROR_MESSAGE);
this->view3D->reload_scene(false, flags & (unsigned int)UpdateParams::FORCE_FULL_SCREEN_REFRESH);
this->preview->reload_print();
if (this->printer_technology == ptSLA)
this->restart_background_process(update_status);
@ -2871,7 +2883,7 @@ void Plater::priv::update_print_volume_state()
// Update background processing thread from the current config and Model.
// Returns a bitmask of UpdateBackgroundProcessReturnState.
unsigned int Plater::priv::update_background_process(bool force_validation)
unsigned int Plater::priv::update_background_process(bool force_validation, bool postpone_error_messages)
{
// bitmap of enum UpdateBackgroundProcessReturnState
unsigned int return_state = 0;
@ -2881,8 +2893,6 @@ unsigned int Plater::priv::update_background_process(bool force_validation)
this->background_process_timer.Stop();
// Update the "out of print bed" state of ModelInstances.
this->update_print_volume_state();
// The delayed error message is no more valid.
this->delayed_error_message.clear();
// Apply new config to the possibly running background task.
bool was_running = this->background_process.running();
Print::ApplyStatus invalidated = this->background_process.apply(this->q->model(), wxGetApp().preset_bundle->full_config());
@ -2908,7 +2918,9 @@ unsigned int Plater::priv::update_background_process(bool force_validation)
}
if ((invalidated != Print::APPLY_STATUS_UNCHANGED || force_validation) && ! this->background_process.empty()) {
// The state of the Print changed, and it is non-zero. Let's validate it and give the user feedback on errors.
// The delayed error message is no more valid.
this->delayed_error_message.clear();
// The state of the Print changed, and it is non-zero. Let's validate it and give the user feedback on errors.
std::string err = this->background_process.validate();
if (err.empty()) {
if (invalidated != Print::APPLY_STATUS_UNCHANGED && this->background_processing_enabled())
@ -2920,7 +2932,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation)
while (p->GetParent())
p = p->GetParent();
auto *top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
if (top_level_wnd && top_level_wnd->IsActive()) {
if (! postpone_error_messages && top_level_wnd && top_level_wnd->IsActive()) {
// The error returned from the Print needs to be translated into the local language.
GUI::show_error(this->q, _(err));
} else {
@ -2929,6 +2941,9 @@ unsigned int Plater::priv::update_background_process(bool force_validation)
}
return_state |= UPDATE_BACKGROUND_PROCESS_INVALID;
}
} else if (! this->delayed_error_message.empty()) {
// Reusing the old state.
return_state |= UPDATE_BACKGROUND_PROCESS_INVALID;
}
if (invalidated != Print::APPLY_STATUS_UNCHANGED && was_running && ! this->background_process.running() &&
@ -3970,7 +3985,7 @@ void Plater::priv::update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bo
{
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);
this->update((unsigned int)UpdateParams::FORCE_BACKGROUND_PROCESSING_UPDATE | (unsigned int)UpdateParams::POSTPONE_VALIDATION_ERROR_MESSAGE);
// 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
@ -3989,6 +4004,11 @@ void Plater::priv::update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bo
view3D->set_as_dirty();
}
// this->update() above was called with POSTPONE_VALIDATION_ERROR_MESSAGE, so that if an error message was generated when updating the back end, it would not open immediately,
// but it would be saved to be show later. Let's do it now. We do not want to display the message box earlier, because on Windows & OSX the message box takes over the message
// queue pump, which in turn executes the rendering function before a full update after the Undo / Redo jump.
this->show_delayed_error_message();
//FIXME what about the state of the manipulators?
//FIXME what about the focus? Cursor in the side panel?
@ -4507,11 +4527,11 @@ void Plater::reslice()
p->preview->update_view_type();
}
void Plater::reslice_SLA_supports(const ModelObject &object)
void Plater::reslice_SLA_supports(const ModelObject &object, bool postpone_error_messages)
{
//FIXME Don't reslice if export of G-code or sending to OctoPrint is running.
// bitmask of UpdateBackgroundProcessReturnState
unsigned int state = this->p->update_background_process(true);
unsigned int state = this->p->update_background_process(true, postpone_error_messages);
if (state & priv::UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE)
this->p->view3D->reload_scene(false);
@ -4735,11 +4755,7 @@ void Plater::on_activate()
this->p->preview->get_wxglcanvas()->SetFocus();
#endif
if (! this->p->delayed_error_message.empty()) {
std::string msg = std::move(this->p->delayed_error_message);
this->p->delayed_error_message.clear();
GUI::show_error(this, msg);
}
this->p->show_delayed_error_message();
}
wxString Plater::get_project_filename(const wxString& extension) const

View file

@ -186,7 +186,7 @@ public:
bool has_toolpaths_to_export() const;
void export_toolpaths_to_obj() const;
void reslice();
void reslice_SLA_supports(const ModelObject &object);
void reslice_SLA_supports(const ModelObject &object, bool postpone_error_messages = false);
void changed_object(int obj_idx);
void changed_objects(const std::vector<size_t>& object_idxs);
void schedule_background_process(bool schedule = true);