diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 47987430c0..2452214ce7 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -5974,7 +5974,9 @@ void GUI_App::open_preferences(size_t open_on_tab, const std::string& highlight_ // so we put it into an inner scope PreferencesDialog dlg(mainframe, open_on_tab, highlight_option); dlg.ShowModal(); - this->plater_->get_current_canvas3D()->force_set_focus(); + GLCanvas3D* canvas = this->plater_->get_current_canvas3D(); + if (canvas) + canvas->force_set_focus(); // BBS //app_layout_changed = dlg.settings_layout_changed(); #if ENABLE_GCODE_LINES_ID_IN_H_SLIDER diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index a6d4c42bb8..e0350ba246 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -501,8 +501,11 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_ //FIXME maybe this is useful for __WXGTK3__ as well? #if __APPLE__ Bind(wxEVT_MOVE, [](wxMoveEvent& event) { - wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); - wxGetApp().plater()->get_current_canvas3D()->request_extra_frame(); + GLCanvas3D* canvas = wxGetApp().plater()->get_current_canvas3D(); + if (canvas) { + canvas->set_as_dirty(); + canvas->request_extra_frame(); + } event.Skip(); }); #endif @@ -2240,7 +2243,9 @@ static wxMenu* generate_help_menu() append_menu_item(helpMenu, wxID_ANY, _L("Show Tip of the Day"), _L("Show Tip of the Day"), [](wxCommandEvent&) { wxGetApp().plater()->get_dailytips()->open(); - wxGetApp().plater()->get_current_canvas3D()->set_as_dirty(); + GLCanvas3D* canvas = wxGetApp().plater()->get_current_canvas3D(); + if (canvas) + canvas->set_as_dirty(); }); // Report a bug @@ -2514,8 +2519,11 @@ void MainFrame::init_menubar_as_editor() auto handle_key_event = [](wxKeyEvent& evt) { if (wxGetApp().imgui()->update_key_data(evt)) { - wxGetApp().plater()->get_current_canvas3D()->render(); - return true; + GLCanvas3D* canvas = wxGetApp().plater()->get_current_canvas3D(); + if (canvas) { + canvas->render(); + return true; + } } return false; }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 129a0dab32..fcdc7a1b1a 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1903,11 +1903,14 @@ void Sidebar::update_presets(Preset::Type preset_type) } Preset& printer_preset = wxGetApp().preset_bundle->printers.get_edited_preset(); - if (auto printer_structure_opt = printer_preset.config.option>("printer_structure")) { - wxGetApp().plater()->get_current_canvas3D()->get_arrange_settings().align_to_y_axis = (printer_structure_opt->value == PrinterStructure::psI3); + GLCanvas3D* canvas = wxGetApp().plater()->get_current_canvas3D(); + if (canvas) { + if (auto printer_structure_opt = printer_preset.config.option>("printer_structure")) { + canvas->get_arrange_settings().align_to_y_axis = (printer_structure_opt->value == PrinterStructure::psI3); + } + else + canvas->get_arrange_settings().align_to_y_axis = false; } - else - wxGetApp().plater()->get_current_canvas3D()->get_arrange_settings().align_to_y_axis = false; break; } @@ -2749,9 +2752,12 @@ void Sidebar::update_ui_from_settings() // BBS //p->object_manipulation->update_ui_from_settings(); // update Cut gizmo, if it's open - p->plater->canvas3D()->update_gizmos_on_off_state(); - p->plater->set_current_canvas_as_dirty(); - p->plater->get_current_canvas3D()->request_extra_frame(); + GLCanvas3D* canvas = p->plater->canvas3D(); + if (canvas) { + canvas->update_gizmos_on_off_state(); + p->plater->set_current_canvas_as_dirty(); + p->plater->get_current_canvas3D()->request_extra_frame(); + } #if 0 p->object_list->apply_volumes_order(); #endif @@ -5671,7 +5677,13 @@ Selection& Plater::priv::get_selection() Selection& Plater::priv::get_curr_selection() { - return get_current_canvas3D()->get_selection(); + GLCanvas3D* canvas = get_current_canvas3D(); + if (!canvas) { + // During destruction, return a reference to a static empty selection + static Selection empty_selection; + return empty_selection; + } + return canvas->get_selection(); } int Plater::priv::get_selected_object_idx() const @@ -5701,10 +5713,15 @@ void Plater::priv::selection_changed() } // forces a frame render to update the view (to avoid a missed update if, for example, the context menu appears) - if (get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView) { - assemble_view->render(); - } else { - view3D->render(); + GLCanvas3D* canvas = get_current_canvas3D(); + if (canvas) { + if (canvas->get_canvas_type() == GLCanvas3D::CanvasAssembleView) { + if (assemble_view) + assemble_view->render(); + } else { + if (view3D) + view3D->render(); + } } } @@ -6473,7 +6490,10 @@ bool Plater::priv::replace_volume_with_stl(int object_idx, int volume_idx, const return false; } - wxBusyInfo info(_L("Replace from:") + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas()); + GLCanvas3D* canvas = q->get_current_canvas3D(); + if (!canvas) + return false; + wxBusyInfo info(_L("Replace from:") + " " + from_u8(path), canvas->get_wxglcanvas()); if (!snapshot.empty()) q->take_snapshot(snapshot); @@ -6770,7 +6790,10 @@ void Plater::priv::reload_from_disk() if (color_dlg.ShowModal() != wxID_OK) { filament_ids.clear(); } }; wxBusyCursor wait; - wxBusyInfo info(_L("Reload from:") + " " + from_u8(path), q->get_current_canvas3D()->get_wxglcanvas()); + GLCanvas3D* canvas = q->get_current_canvas3D(); + if (!canvas) + return false; + wxBusyInfo info(_L("Reload from:") + " " + from_u8(path), canvas->get_wxglcanvas()); Model new_model; try @@ -9396,7 +9419,13 @@ void Plater::priv::take_snapshot(const std::string& snapshot_name, const UndoRed tower.rotation = proj_cfg.opt_float("wipe_tower_rotation_angle"); } } - const GLGizmosManager& gizmos = get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_gizmos_manager() : view3D->get_canvas3d()->get_gizmos_manager(); + GLCanvas3D* canvas = get_current_canvas3D(); + if (!canvas) { + // During destruction, skip snapshot + return; + } + + const GLGizmosManager& gizmos = canvas->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_gizmos_manager() : view3D->get_canvas3d()->get_gizmos_manager(); if (snapshot_type == UndoRedo::SnapshotType::ProjectSeparator) this->undo_redo_stack().clear(); @@ -9430,7 +9459,9 @@ void Plater::priv::undo() // BBS: undo-redo until modify record while (--it_current != snapshots.begin() && !snapshot_modifies_project(*it_current)); if (it_current == snapshots.begin()) return; - if (get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView) { + GLCanvas3D* canvas = get_current_canvas3D(); + if (!canvas) return; + if (canvas->get_canvas_type() == GLCanvas3D::CanvasAssembleView) { if (it_current->snapshot_data.snapshot_type != UndoRedo::SnapshotType::GizmoAction && it_current->snapshot_data.snapshot_type != UndoRedo::SnapshotType::EnteringGizmo && it_current->snapshot_data.snapshot_type != UndoRedo::SnapshotType::LeavingGizmoNoAction && @@ -9538,9 +9569,13 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator // Make a copy of the snapshot, undo/redo could invalidate the iterator const UndoRedo::Snapshot snapshot_copy = *it_snapshot; // Do the jump in time. + GLCanvas3D* canvas = get_current_canvas3D(); + if (!canvas) return; + + bool is_assemble = canvas->get_canvas_type() == GLCanvas3D::CanvasAssembleView; if (it_snapshot->timestamp < this->undo_redo_stack().active_snapshot_time() ? - this->undo_redo_stack().undo(model, get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_selection() : this->view3D->get_canvas3d()->get_selection(), get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_gizmos_manager() : this->view3D->get_canvas3d()->get_gizmos_manager(), this->partplate_list, top_snapshot_data, it_snapshot->timestamp) : - this->undo_redo_stack().redo(model, get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_gizmos_manager() : this->view3D->get_canvas3d()->get_gizmos_manager(), this->partplate_list, it_snapshot->timestamp)) { + this->undo_redo_stack().undo(model, is_assemble ? assemble_view->get_canvas3d()->get_selection() : this->view3D->get_canvas3d()->get_selection(), is_assemble ? assemble_view->get_canvas3d()->get_gizmos_manager() : this->view3D->get_canvas3d()->get_gizmos_manager(), this->partplate_list, top_snapshot_data, it_snapshot->timestamp) : + this->undo_redo_stack().redo(model, is_assemble ? assemble_view->get_canvas3d()->get_gizmos_manager() : this->view3D->get_canvas3d()->get_gizmos_manager(), this->partplate_list, 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; @@ -9618,7 +9653,11 @@ void Plater::priv::undo_redo_to(std::vector::const_iterator void Plater::priv::update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bool /* temp_snapshot_was_taken */) { - get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? assemble_view->get_canvas3d()->get_selection().clear() : this->view3D->get_canvas3d()->get_selection().clear(); + GLCanvas3D* canvas = get_current_canvas3D(); + if (!canvas) return; + + bool is_assemble = canvas->get_canvas_type() == GLCanvas3D::CanvasAssembleView; + is_assemble ? assemble_view->get_canvas3d()->get_selection().clear() : 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((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. @@ -9627,10 +9666,10 @@ void Plater::priv::update_after_undo_redo(const UndoRedo::Snapshot& snapshot, bo // 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) - get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? + is_assemble ? assemble_view->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); - get_current_canvas3D()->get_canvas_type() == GLCanvas3D::CanvasAssembleView ? + is_assemble ? assemble_view->get_canvas3d()->get_gizmos_manager().update_after_undo_redo(snapshot) : this->view3D->get_canvas3d()->get_gizmos_manager().update_after_undo_redo(snapshot); @@ -11309,7 +11348,9 @@ void Plater::load_gcode(const wxString& filename) p->preview->reload_print(false, m_only_gcode); wxGetApp().mainframe->select_tab(MainFrame::tpPreview); p->set_current_panel(p->preview, true); - p->get_current_canvas3D()->render(); + GLCanvas3D* canvas = p->get_current_canvas3D(); + if (canvas) + canvas->render(); //p->notification_manager->bbl_show_plateinfo_notification(into_u8(_L("Preview only mode for gcode file."))); wxBusyCursor wait; @@ -12309,7 +12350,9 @@ void Plater::set_selected_visible(bool visible) Plater::TakeSnapshot snapshot(this, "Set Selected Objects Visible in AssembleView"); get_ui_job_worker().cancel_all(); - p->get_current_canvas3D()->set_selected_visible(visible); + GLCanvas3D* canvas = p->get_current_canvas3D(); + if (canvas) + canvas->set_selected_visible(visible); } @@ -12329,7 +12372,9 @@ void Plater::remove_selected() //BBS delete current selected // p->view3D->delete_selected(); - p->get_current_canvas3D()->delete_selected(); + GLCanvas3D* canvas = p->get_current_canvas3D(); + if (canvas) + canvas->delete_selected(); } void Plater::increase_instances(size_t num) @@ -14644,7 +14689,9 @@ void Plater::changed_object(ModelObject &object){ p->schedule_background_process(); // Check outside bed - get_current_canvas3D()->requires_check_outside_state(); + GLCanvas3D* canvas = get_current_canvas3D(); + if (canvas) + canvas->requires_check_outside_state(); } void Plater::changed_object(int obj_idx)