diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c2e4424313..ff2752cfe4 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1100,6 +1100,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event); wxDEFINE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent); wxDEFINE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent); +wxDEFINE_EVENT(EVT_GLCANVAS_RENDER_TIMER, wxTimerEvent/*RenderTimerEvent*/); const double GLCanvas3D::DefaultCameraZoomToBoxMarginFactor = 1.25; @@ -1184,6 +1185,7 @@ GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) { if (m_canvas != nullptr) { m_timer.SetOwner(m_canvas); + m_render_timer.SetOwner(m_canvas); #if ENABLE_RETINA_GL m_retina_helper.reset(new RetinaHelper(canvas)); #endif // ENABLE_RETINA_GL @@ -1609,6 +1611,9 @@ void GLCanvas3D::render() wxGetApp().plater()->init_environment_texture(); #endif // ENABLE_ENVIRONMENT_MAP + m_render_timer.Stop(); + m_extra_frame_requested_delayed = std::numeric_limits::max(); + const Size& cnv_size = get_canvas_size(); // Probably due to different order of events on Linux/GTK2, when one switched from 3D scene // to preview, this was called before canvas had its final size. It reported zero width @@ -2346,6 +2351,7 @@ void GLCanvas3D::bind_event_handlers() m_canvas->Bind(wxEVT_KEY_UP, &GLCanvas3D::on_key, this); m_canvas->Bind(wxEVT_MOUSEWHEEL, &GLCanvas3D::on_mouse_wheel, this); m_canvas->Bind(wxEVT_TIMER, &GLCanvas3D::on_timer, this); + m_canvas->Bind(EVT_GLCANVAS_RENDER_TIMER, &GLCanvas3D::on_render_timer, this); m_canvas->Bind(wxEVT_LEFT_DOWN, &GLCanvas3D::on_mouse, this); m_canvas->Bind(wxEVT_LEFT_UP, &GLCanvas3D::on_mouse, this); m_canvas->Bind(wxEVT_MIDDLE_DOWN, &GLCanvas3D::on_mouse, this); @@ -2405,11 +2411,11 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt) return; #if ENABLE_NEW_NOTIFICATIONS_FADE_OUT - NotificationManager* notification_mgr = wxGetApp().plater()->get_notification_manager(); + /*NotificationManager* notification_mgr = wxGetApp().plater()->get_notification_manager(); if (notification_mgr->requires_update()) notification_mgr->update_notifications(); - m_dirty |= notification_mgr->requires_render(); + m_dirty |= notification_mgr->requires_render();*/ #endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT // FIXME m_dirty |= m_main_toolbar.update_items_state(); @@ -2420,9 +2426,10 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt) m_dirty |= mouse3d_controller_applied; #if ENABLE_NEW_NOTIFICATIONS_FADE_OUT + /* if (notification_mgr->requires_update()) { evt.RequestMore(); - } + }*/ #endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT if (!m_dirty) @@ -2973,6 +2980,29 @@ void GLCanvas3D::on_timer(wxTimerEvent& evt) _perform_layer_editing_action(); } +void GLCanvas3D::on_render_timer(wxTimerEvent& evt) +{ + render(); +} + +void GLCanvas3D::request_extra_frame_delayed(wxLongLong miliseconds) +{ + + if (!m_render_timer.IsRunning() ) { + m_extra_frame_requested_delayed = miliseconds; + m_render_timer.StartOnce((int)miliseconds.ToLong()); + m_render_timer_start = wxGetLocalTimeMillis(); + } else { + const wxLongLong remaining_time = m_extra_frame_requested_delayed - (wxGetLocalTimeMillis() - m_render_timer_start); + if(miliseconds < remaining_time) { + m_extra_frame_requested_delayed = miliseconds; + m_render_timer.StartOnce((int)miliseconds.ToLong()); + m_render_timer_start = wxGetLocalTimeMillis(); + } + } + +} + #ifndef NDEBUG // #define SLIC3R_DEBUG_MOUSE_EVENTS #endif @@ -6439,5 +6469,10 @@ void GLCanvas3D::WipeTowerInfo::apply_wipe_tower() const wxGetApp().get_tab(Preset::TYPE_PRINT)->load_config(cfg); } + +void GLCanvas3D::RenderTimer::Notify() +{ + wxPostEvent((wxEvtHandler*)GetOwner(), RenderTimerEvent( EVT_GLCANVAS_RENDER_TIMER, *this)); +} } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index e64e65d1b3..38ae484273 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -74,6 +74,25 @@ public: }; +class RenderTimerEvent : public wxEvent +{ +public: + RenderTimerEvent(wxEventType type, wxTimer& timer) + : wxEvent(timer.GetId(), type), + m_timer(&timer) + { + SetEventObject(timer.GetOwner()); + } + int GetInterval() const { return m_timer->GetInterval(); } + wxTimer& GetTimer() const { return *m_timer; } + + virtual wxEvent* Clone() const { return new RenderTimerEvent(*this); } + virtual wxEventCategory GetEventCategory() const { return wxEVT_CATEGORY_TIMER; } +private: + wxTimer* m_timer; +}; + + wxDECLARE_EVENT(EVT_GLCANVAS_OBJECT_SELECT, SimpleEvent); using Vec2dEvent = Event; @@ -119,6 +138,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, Event); wxDECLARE_EVENT(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, HeightProfileSmoothEvent); wxDECLARE_EVENT(EVT_GLCANVAS_RELOAD_FROM_DISK, SimpleEvent); +wxDECLARE_EVENT(EVT_GLCANVAS_RENDER_TIMER, wxTimerEvent/*RenderTimerEvent*/); class GLCanvas3D { @@ -391,6 +411,11 @@ class GLCanvas3D static float get_window_width() { return s_window_width; }; }; + class RenderTimer : public wxTimer { + private: + virtual void Notify() override; + }; + public: enum ECursorType : unsigned char { @@ -428,12 +453,16 @@ private: std::string m_sidebar_field; // when true renders an extra frame by not resetting m_dirty to false // see request_extra_frame() - bool m_extra_frame_requested; + bool m_extra_frame_requested; + wxLongLong m_extra_frame_requested_delayed { std::numeric_limits::max() }; bool m_event_handlers_bound{ false }; mutable GLVolumeCollection m_volumes; GCodeViewer m_gcode_viewer; + RenderTimer m_render_timer; + wxLongLong m_render_timer_start; + Selection m_selection; const DynamicPrintConfig* m_config; Model* m_model; @@ -650,6 +679,7 @@ public: void on_key(wxKeyEvent& evt); void on_mouse_wheel(wxMouseEvent& evt); void on_timer(wxTimerEvent& evt); + void on_render_timer(wxTimerEvent& evt); void on_mouse(wxMouseEvent& evt); void on_paint(wxPaintEvent& evt); void on_set_focus(wxFocusEvent& evt); @@ -712,6 +742,7 @@ public: void msw_rescale(); void request_extra_frame() { m_extra_frame_requested = true; } + void request_extra_frame_delayed(wxLongLong miliseconds); int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); } void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); } @@ -742,6 +773,11 @@ public: return ret; } + + + + + private: bool _is_shown_on_screen() const; diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 7706e7c243..300303bbdd 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -136,6 +136,7 @@ NotificationManager::PopNotification::PopNotification(const NotificationData &n, , m_hypertext (n.hypertext) , m_text2 (n.text2) , m_evt_handler (evt_handler) + , m_notification_start (wxGetLocalTimeMillis()) { //init(); } @@ -147,6 +148,9 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init return; } + if (m_fading_out) + m_last_render_fading = wxGetLocalTimeMillis(); + Size cnv_size = canvas.get_canvas_size(); ImGuiWrapper& imgui = *wxGetApp().imgui(); ImVec2 mouse_pos = ImGui::GetMousePos(); @@ -747,6 +751,8 @@ void NotificationManager::PopNotification::update_state() if (!m_initialized) init(); + m_next_render = std::numeric_limits::max(); + if (m_hidden) { m_state = EState::Hidden; return; @@ -760,21 +766,32 @@ void NotificationManager::PopNotification::update_state() } if (m_counting_down) { + wxMilliClock_t up_time = wxGetLocalTimeMillis() - m_notification_start; + if (m_fading_out && m_current_fade_opacity <= 0.0f) m_finished = true; - else if (!m_fading_out && m_remaining_time == 0) { + else if (!m_fading_out && up_time >= m_remaining_time * 1000) { m_fading_out = true; m_fading_start = wxGetLocalTimeMillis(); + m_last_render_fading = wxGetLocalTimeMillis(); + } else if (!m_fading_out) { + m_next_render = m_remaining_time * 1000 - up_time; + BOOST_LOG_TRIVIAL(error) << (boost::format("next render %1%") % m_next_render); } + } if (m_finished) { m_state = EState::Finished; + m_next_render = 0; + BOOST_LOG_TRIVIAL(error) << "EState::Finished"; return; } if (m_close_pending) { m_finished = true; m_state = EState::ClosePending; + m_next_render = 0; + BOOST_LOG_TRIVIAL(error) << "EState::ClosePending"; return; } if (m_fading_out) { @@ -783,13 +800,17 @@ void NotificationManager::PopNotification::update_state() wxMilliClock_t curr_time = wxGetLocalTimeMillis() - m_fading_start; wxMilliClock_t no_render_time = wxGetLocalTimeMillis() - m_last_render_fading; m_current_fade_opacity = std::clamp(1.0f - 0.001f * static_cast(curr_time.GetValue()) / FADING_OUT_DURATION, 0.0f, 1.0f); - if (no_render_time > FADING_OUT_TIMEOUT) { + auto next_render = FADING_OUT_TIMEOUT - no_render_time; + if (next_render <= 0) { m_last_render_fading = wxGetLocalTimeMillis(); m_state = EState::FadingOutRender; - } + m_next_render = 0; + } else + m_next_render = next_render; + BOOST_LOG_TRIVIAL(error) << (boost::format("fade render %1%") % m_next_render); } - } + } #endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT @@ -1228,6 +1249,7 @@ void NotificationManager::render_notifications(float overlay_width) } } + update_notifications(); } #else void NotificationManager::render_notifications(float overlay_width) @@ -1377,6 +1399,12 @@ void NotificationManager::update_notifications() break; } } + if (m_hovered) { + for (const std::unique_ptr& notification : m_pop_notifications) { + notification->reset_start_time(); + } + } + // Reuire render if some notification was just deleted. size_t curr_size = m_pop_notifications.size(); @@ -1396,6 +1424,18 @@ void NotificationManager::update_notifications() if (m_requires_render) m_requires_update = true; + //request frames + wxLongLong next_render = std::numeric_limits::max(); + const wxLongLong max = std::numeric_limits::max(); + for (const std::unique_ptr& notification : m_pop_notifications) { + next_render = std::min(next_render, notification->next_render()); + } + + if (next_render == 0) + wxGetApp().plater()->get_current_canvas3D()->request_extra_frame(); + else if (next_render < max) + wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(next_render); + // actualizate timers wxWindow* p = dynamic_cast(wxGetApp().plater()); while (p->GetParent() != nullptr) diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 3e278a3908..fef66f1835 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -242,6 +242,8 @@ private: bool requires_render() const { return m_state == EState::FadingOutRender || m_state == EState::ClosePending || m_state == EState::Finished; } bool requires_update() const { return m_state != EState::Hidden; } EState get_state() const { return m_state; } + wxLongLong next_render() const { return m_next_render; } + void reset_start_time() { m_notification_start = wxGetLocalTimeMillis(); } #endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT protected: @@ -297,8 +299,13 @@ private: int m_countdown_frame { 0 }; bool m_fading_out { false }; #if ENABLE_NEW_NOTIFICATIONS_FADE_OUT - wxMilliClock_t m_fading_start { 0LL }; - wxMilliClock_t m_last_render_fading { 0LL }; + wxLongLong m_fading_start { 0LL }; + // time of last done render when fading + wxLongLong m_last_render_fading { 0LL }; + // first appereance of notification or last hover; + wxLongLong m_notification_start; + // time to next must-do render + wxLongLong m_next_render { std::numeric_limits::max() }; #else // total time left when fading beggins float m_fading_time{ 0.0f }; diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 21eea94286..5de3da7432 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -740,6 +740,8 @@ void PresetUpdater::slic3r_update_notify() PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3r_version, bool no_notification) const { if (! p->enabled_config_update) { return R_NOOP; } + + GUI::wxGetApp().plater()->get_notification_manager()->push_notification(GUI::NotificationType::PresetUpdateAvailable); auto updates = p->get_config_updates(old_slic3r_version); if (updates.incompats.size() > 0) {