diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 3d5e56b46..79186a8ea 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -958,6 +958,8 @@ bool GUI_App::on_init_inner() // update_mode(); // !!! do that later SetTopWindow(mainframe); + plater_->init_notification_manager(); + m_printhost_job_queue.reset(new PrintHostJobQueue(mainframe->printhost_queue_dlg())); if (is_gcode_viewer()) { @@ -2278,7 +2280,7 @@ wxBookCtrlBase* GUI_App::tab_panel() const return mainframe->m_tabpanel; } -NotificationManager* GUI_App::notification_manager() +std::shared_ptr GUI_App::notification_manager() { return plater_->get_notification_manager(); } diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index a088e10d4..5acab0c94 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -276,7 +276,7 @@ public: ObjectLayers* obj_layers(); Plater* plater(); Model& model(); - NotificationManager* notification_manager(); + std::shared_ptr notification_manager(); // Parameters extracted from the command line to be passed to GUI after initialization. GUI_InitParams* init_params { nullptr }; diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 45da928f5..eb511177d 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -734,9 +734,9 @@ void Preview::update_layers_slider(const std::vector& layers_z, bool kee double top_area = area(object->get_layer(int(object->layers().size()) - 1)->lslices); if( bottom_area - top_area > delta_area) { - NotificationManager* notif_mngr = wxGetApp().plater()->get_notification_manager(); + std::shared_ptr notif_mngr = wxGetApp().plater()->get_notification_manager(); notif_mngr->push_notification( - NotificationType::SignDetected, NotificationManager::NotificationLevel::RegularNotification, + NotificationType::SignDetected, NotificationManager::NotificationLevel::RegularNotificationLevel, _u8L("NOTE:") + "\n" + _u8L("Sliced object looks like the sign") + "\n", _u8L("Apply auto color change to print"), [this](wxEvtHandler*) { diff --git a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp index 608e7bd1f..4bd98f8c8 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoMmuSegmentation.cpp @@ -22,7 +22,7 @@ static inline void show_notification_extruders_limit_exceeded() wxGetApp() .plater() ->get_notification_manager() - ->push_notification(NotificationType::MmSegmentationExceededExtrudersLimit, NotificationManager::NotificationLevel::RegularNotification, + ->push_notification(NotificationType::MmSegmentationExceededExtrudersLimit, NotificationManager::NotificationLevel::RegularNotificationLevel, GUI::format(_L("Your printer has more extruders than the multi-material painting gizmo supports. For this reason, only the " "first %1% extruders will be able to be used for painting."), GLGizmoMmuSegmentation::EXTRUDERS_LIMIT)); } diff --git a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp index 9f49f9734..a2c4910e3 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoSimplify.cpp @@ -337,7 +337,7 @@ void GLGizmoSimplify::on_set_state() auto notification_manager = wxGetApp().plater()->get_notification_manager(); notification_manager->push_notification( NotificationType::CustomNotification, - NotificationManager::NotificationLevel::RegularNotification, + NotificationManager::NotificationLevel::RegularNotificationLevel, _u8L("ERROR: Wait until Simplification ends or Cancel process.")); return; } diff --git a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp index 93eba3042..7a9373a5f 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmosManager.cpp @@ -194,7 +194,7 @@ bool GLGizmosManager::check_gizmos_closed_except(EType type) const if (get_current_type() != type && get_current_type() != Undefined) { wxGetApp().plater()->get_notification_manager()->push_notification( NotificationType::CustomSupportsAndSeamRemovedAfterRepair, - NotificationManager::NotificationLevel::RegularNotification, + NotificationManager::NotificationLevel::RegularNotificationLevel, _u8L("ERROR: Please close all manipulators available from " "the left toolbar first")); return false; @@ -1256,7 +1256,7 @@ bool GLGizmosManager::is_in_editing_mode(bool error_notification) const if (error_notification) wxGetApp().plater()->get_notification_manager()->push_notification( NotificationType::QuitSLAManualMode, - NotificationManager::NotificationLevel::ErrorNotification, + NotificationManager::NotificationLevel::ErrorNotificationLevel, _u8L("You are currently editing SLA support points. Please, " "apply or discard your changes first.")); diff --git a/src/slic3r/GUI/HintNotification.cpp b/src/slic3r/GUI/HintNotification.cpp index fe5eeb67c..53435e318 100644 --- a/src/slic3r/GUI/HintNotification.cpp +++ b/src/slic3r/GUI/HintNotification.cpp @@ -1012,7 +1012,7 @@ void NotificationManager::HintNotification::retrieve_data(bool new_hint/* = true if(hint_data != nullptr) { NotificationData nd { NotificationType::DidYouKnowHint, - NotificationLevel::RegularNotification, + NotificationLevel::RegularNotificationLevel, 0, hint_data->text, hint_data->hypertext, nullptr, diff --git a/src/slic3r/GUI/Jobs/ArrangeJob.hpp b/src/slic3r/GUI/Jobs/ArrangeJob.hpp index 2744920da..2ccb7a04f 100644 --- a/src/slic3r/GUI/Jobs/ArrangeJob.hpp +++ b/src/slic3r/GUI/Jobs/ArrangeJob.hpp @@ -9,6 +9,7 @@ namespace Slic3r { class ModelInstance; namespace GUI { +class NotificationManager; class ArrangeJob : public PlaterJob { @@ -39,8 +40,8 @@ protected: void process() override; public: - ArrangeJob(std::shared_ptr pri, Plater *plater) - : PlaterJob{std::move(pri), plater} + ArrangeJob(std::shared_ptr nm, Plater *plater) + : PlaterJob{nm, plater} {} int status_range() const override diff --git a/src/slic3r/GUI/Jobs/FillBedJob.hpp b/src/slic3r/GUI/Jobs/FillBedJob.hpp index bf407656d..548974fa6 100644 --- a/src/slic3r/GUI/Jobs/FillBedJob.hpp +++ b/src/slic3r/GUI/Jobs/FillBedJob.hpp @@ -6,6 +6,7 @@ namespace Slic3r { namespace GUI { class Plater; +class NotificationManager; class FillBedJob : public PlaterJob { @@ -27,8 +28,8 @@ protected: void process() override; public: - FillBedJob(std::shared_ptr pri, Plater *plater) - : PlaterJob{std::move(pri), plater} + FillBedJob(std::shared_ptr nm, Plater *plater) + : PlaterJob{nm, plater} {} int status_range() const override diff --git a/src/slic3r/GUI/Jobs/Job.cpp b/src/slic3r/GUI/Jobs/Job.cpp index 6346227aa..c198de40c 100644 --- a/src/slic3r/GUI/Jobs/Job.cpp +++ b/src/slic3r/GUI/Jobs/Job.cpp @@ -2,9 +2,11 @@ #include #include "Job.hpp" +#include "../NotificationManager.hpp" #include #include + namespace Slic3r { void GUI::Job::run(std::exception_ptr &eptr) @@ -30,8 +32,8 @@ void GUI::Job::update_status(int st, const wxString &msg) wxQueueEvent(this, evt); } -GUI::Job::Job(std::shared_ptr pri) - : m_progress(std::move(pri)) +GUI::Job::Job(std::shared_ptr nm) + : m_notifications(nm) { m_thread_evt_id = wxNewId(); @@ -40,21 +42,21 @@ GUI::Job::Job(std::shared_ptr pri) auto msg = evt.GetString(); if (!msg.empty() && !m_worker_error) - m_progress->set_status_text(msg.ToUTF8().data()); + m_notifications->progress_indicator_set_status_text(msg.ToUTF8().data()); if (m_finalized) return; - m_progress->set_progress(evt.GetInt()); + m_notifications->progress_indicator_set_progress(evt.GetInt()); if (evt.GetInt() == status_range() || m_worker_error) { // set back the original range and cancel callback - m_progress->set_range(m_range); - m_progress->set_cancel_callback(); + m_notifications->progress_indicator_set_range(m_range); + m_notifications->progress_indicator_set_cancel_callback(); wxEndBusyCursor(); if (m_worker_error) { m_finalized = true; - m_progress->set_status_text(""); - m_progress->set_progress(m_range); + m_notifications->progress_indicator_set_status_text(""); + m_notifications->progress_indicator_set_progress(m_range); on_exception(m_worker_error); } else { @@ -86,12 +88,12 @@ void GUI::Job::start() prepare(); // Save the current status indicatior range and push the new one - m_range = m_progress->get_range(); - m_progress->set_range(status_range()); + m_range = m_notifications->progress_indicator_get_range(); + m_notifications->progress_indicator_set_range(status_range()); // init cancellation flag and set the cancel callback m_canceled.store(false); - m_progress->set_cancel_callback( + m_notifications->progress_indicator_set_cancel_callback( [this]() { m_canceled.store(true); }); m_finalized = false; diff --git a/src/slic3r/GUI/Jobs/Job.hpp b/src/slic3r/GUI/Jobs/Job.hpp index 8243ce943..ed80d8b5f 100644 --- a/src/slic3r/GUI/Jobs/Job.hpp +++ b/src/slic3r/GUI/Jobs/Job.hpp @@ -8,14 +8,13 @@ #include -#include "ProgressIndicator.hpp" - #include #include namespace Slic3r { namespace GUI { +class NotificationManager; // A class to handle UI jobs like arranging and optimizing rotation. // These are not instant jobs, the user has to be informed about their // state in the status progress indicator. On the other hand they are @@ -33,7 +32,7 @@ class Job : public wxEvtHandler boost::thread m_thread; std::atomic m_running{false}, m_canceled{false}; bool m_finalized = false, m_finalizing = false; - std::shared_ptr m_progress; + std::shared_ptr m_notifications; std::exception_ptr m_worker_error = nullptr; void run(std::exception_ptr &); @@ -65,7 +64,7 @@ protected: } public: - Job(std::shared_ptr pri); + Job(std::shared_ptr nm); bool is_finalized() const { return m_finalized; } diff --git a/src/slic3r/GUI/Jobs/PlaterJob.hpp b/src/slic3r/GUI/Jobs/PlaterJob.hpp index fcf0a54b8..52e5741aa 100644 --- a/src/slic3r/GUI/Jobs/PlaterJob.hpp +++ b/src/slic3r/GUI/Jobs/PlaterJob.hpp @@ -6,6 +6,7 @@ namespace Slic3r { namespace GUI { class Plater; +class NotificationManager; class PlaterJob : public Job { protected: @@ -15,8 +16,8 @@ protected: public: - PlaterJob(std::shared_ptr pri, Plater *plater): - Job{std::move(pri)}, m_plater{plater} {} + PlaterJob(std::shared_ptr nm, Plater *plater): + Job{nm}, m_plater{plater} {} }; }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp index cdb367f23..f967bb7a3 100644 --- a/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp +++ b/src/slic3r/GUI/Jobs/RotoptimizeJob.hpp @@ -10,6 +10,8 @@ namespace Slic3r { namespace GUI { +class NotificationManager; + class RotoptimizeJob : public PlaterJob { using FindFn = std::function pri, Plater *plater) - : PlaterJob{std::move(pri), plater} + RotoptimizeJob(std::shared_ptr nm, Plater *plater) + : PlaterJob{nm, plater} {} void finalize() override; diff --git a/src/slic3r/GUI/Jobs/SLAImportJob.cpp b/src/slic3r/GUI/Jobs/SLAImportJob.cpp index 027bf6849..9b9151f77 100644 --- a/src/slic3r/GUI/Jobs/SLAImportJob.cpp +++ b/src/slic3r/GUI/Jobs/SLAImportJob.cpp @@ -6,6 +6,7 @@ #include "slic3r/GUI/GUI_App.hpp" #include "slic3r/GUI/Plater.hpp" #include "slic3r/GUI/GUI_ObjectList.hpp" +#include "slic3r/GUI/NotificationManager.hpp" #include "libslic3r/Model.hpp" #include "libslic3r/PresetBundle.hpp" @@ -124,8 +125,8 @@ public: priv(Plater *plt) : plater{plt} {} }; -SLAImportJob::SLAImportJob(std::shared_ptr pri, Plater *plater) - : PlaterJob{std::move(pri), plater}, p{std::make_unique(plater)} +SLAImportJob::SLAImportJob(std::shared_ptr nm, Plater *plater) + : PlaterJob{nm, plater}, p{std::make_unique(plater)} {} SLAImportJob::~SLAImportJob() = default; diff --git a/src/slic3r/GUI/Jobs/SLAImportJob.hpp b/src/slic3r/GUI/Jobs/SLAImportJob.hpp index 583c98655..7bc4d5e7e 100644 --- a/src/slic3r/GUI/Jobs/SLAImportJob.hpp +++ b/src/slic3r/GUI/Jobs/SLAImportJob.hpp @@ -5,6 +5,8 @@ namespace Slic3r { namespace GUI { +class NotificationManager; + class SLAImportJob : public PlaterJob { class priv; @@ -16,7 +18,7 @@ protected: void finalize() override; public: - SLAImportJob(std::shared_ptr pri, Plater *plater); + SLAImportJob(std::shared_ptr nm, Plater *plater); ~SLAImportJob(); void reset(); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 51dbc201d..6d5fbf11c 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -155,13 +155,13 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S SetIcon(main_frame_icon(wxGetApp().get_app_mode())); // initialize status bar - m_statusbar = std::make_shared(this); - m_statusbar->set_font(GUI::wxGetApp().normal_font()); - if (wxGetApp().is_editor()) - m_statusbar->embed(this); - m_statusbar->set_status_text(_L("Version") + " " + - SLIC3R_VERSION + " - " + - _L("Remember to check for updates at https://github.com/prusa3d/PrusaSlicer/releases")); +// m_statusbar = std::make_shared(this); +// m_statusbar->set_font(GUI::wxGetApp().normal_font()); +// if (wxGetApp().is_editor()) +// m_statusbar->embed(this); +// m_statusbar->set_status_text(_L("Version") + " " + +// SLIC3R_VERSION + " - " + +// _L("Remember to check for updates at https://github.com/prusa3d/PrusaSlicer/releases")); // initialize tabpanel and menubar init_tabpanel(); @@ -1033,7 +1033,7 @@ void MainFrame::on_sys_color_changed() wxGetApp().init_label_colours(); #ifdef __WXMSW__ wxGetApp().UpdateDarkUI(m_tabpanel); - m_statusbar->update_dark_ui(); + // m_statusbar->update_dark_ui(); #ifdef _MSW_DARK_MODE // update common mode sizer if (!wxGetApp().tabs_as_menu()) diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index e87f94f65..487d002af 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -204,7 +204,7 @@ public: wxWindow* m_plater_page{ nullptr }; wxProgressDialog* m_progress_dialog { nullptr }; PrintHostQueueDialog* m_printhost_queue_dlg; - std::shared_ptr m_statusbar; +// std::shared_ptr m_statusbar; #ifdef __APPLE__ std::unique_ptr m_taskbar_icon; diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 172e38d53..0841efcb0 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -33,32 +33,32 @@ wxDEFINE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClic wxDEFINE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent); const NotificationManager::NotificationData NotificationManager::basic_notifications[] = { - {NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") }, - {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more."), + {NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotificationLevel, 10, _u8L("3D Mouse disconnected.") }, + {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotificationLevel, 20, _u8L("Configuration update is available."), _u8L("See more."), [](wxEvtHandler* evnthndlr) { if (evnthndlr != nullptr) wxPostEvent(evnthndlr, PresetUpdateAvailableClickedEvent(EVT_PRESET_UPDATE_AVAILABLE_CLICKED)); return true; } }, - {NotificationType::NewAppAvailable, NotificationLevel::ImportantNotification, 20, _u8L("New version is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr) { + {NotificationType::NewAppAvailable, NotificationLevel::ImportantNotificationLevel, 20, _u8L("New version is available."), _u8L("See Releases page."), [](wxEvtHandler* evnthndlr) { wxGetApp().open_browser_with_warning_dialog("https://github.com/prusa3d/PrusaSlicer/releases"); return true; }}, - {NotificationType::EmptyColorChangeCode, NotificationLevel::RegularNotification, 10, + {NotificationType::EmptyColorChangeCode, NotificationLevel::RegularNotificationLevel, 10, _u8L("You have just added a G-code for color change, but its value is empty.\n" "To export the G-code correctly, check the \"Color Change G-code\" in \"Printer Settings > Custom G-code\"") }, - {NotificationType::EmptyAutoColorChange, NotificationLevel::RegularNotification, 10, + {NotificationType::EmptyAutoColorChange, NotificationLevel::RegularNotificationLevel, 10, _u8L("No color change event was added to the print. The print does not look like a sign.") }, - {NotificationType::DesktopIntegrationSuccess, NotificationLevel::RegularNotification, 10, + {NotificationType::DesktopIntegrationSuccess, NotificationLevel::RegularNotificationLevel, 10, _u8L("Desktop integration was successful.") }, - {NotificationType::DesktopIntegrationFail, NotificationLevel::WarningNotification, 10, + {NotificationType::DesktopIntegrationFail, NotificationLevel::WarningNotificationLevel, 10, _u8L("Desktop integration failed.") }, - {NotificationType::UndoDesktopIntegrationSuccess, NotificationLevel::RegularNotification, 10, + {NotificationType::UndoDesktopIntegrationSuccess, NotificationLevel::RegularNotificationLevel, 10, _u8L("Undo desktop integration was successful.") }, - {NotificationType::UndoDesktopIntegrationFail, NotificationLevel::WarningNotification, 10, + {NotificationType::UndoDesktopIntegrationFail, NotificationLevel::WarningNotificationLevel, 10, _u8L("Undo desktop integration failed.") }, - //{NotificationType::NewAppAvailable, NotificationLevel::ImportantNotification, 20, _u8L("New vesion of PrusaSlicer is available.", _u8L("Download page.") }, - //{NotificationType::LoadingFailed, NotificationLevel::RegularNotification, 20, _u8L("Loading of model has Failed") }, - //{NotificationType::DeviceEjected, NotificationLevel::RegularNotification, 10, _u8L("Removable device has been safely ejected")} // if we want changeble text (like here name of device), we need to do it as CustomNotification + //{NotificationType::NewAppAvailable, NotificationLevel::ImportantNotificationLevel, 20, _u8L("New vesion of PrusaSlicer is available.", _u8L("Download page.") }, + //{NotificationType::LoadingFailed, NotificationLevel::RegularNotificationLevel, 20, _u8L("Loading of model has Failed") }, + //{NotificationType::DeviceEjected, NotificationLevel::RegularNotificationLevel, 10, _u8L("Removable device has been safely ejected")} // if we want changeble text (like here name of device), we need to do it as CustomNotification }; namespace { @@ -255,13 +255,13 @@ bool NotificationManager::PopNotification::push_background_color() push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); return true; } - if (m_data.level == NotificationLevel::ErrorNotification) { + if (m_data.level == NotificationLevel::ErrorNotificationLevel) { ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); backcolor.x += 0.3f; push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); return true; } - if (m_data.level == NotificationLevel::WarningNotification) { + if (m_data.level == NotificationLevel::WarningNotificationLevel) { ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg); backcolor.x += 0.3f; backcolor.y += 0.15f; @@ -276,9 +276,9 @@ void NotificationManager::PopNotification::count_spaces() m_line_height = ImGui::CalcTextSize("A").y; m_left_indentation = m_line_height; - if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) { + if (m_data.level == NotificationLevel::ErrorNotificationLevel || m_data.level == NotificationLevel::WarningNotificationLevel) { std::string text; - text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker); + text = (m_data.level == NotificationLevel::ErrorNotificationLevel ? ImGui::ErrorMarker : ImGui::WarningMarker); float picture_width = ImGui::CalcTextSize(text.c_str()).x; m_left_indentation = picture_width + m_line_height / 2; } @@ -505,9 +505,9 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img void NotificationManager::PopNotification::render_left_sign(ImGuiWrapper& imgui) { - if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) { + if (m_data.level == NotificationLevel::ErrorNotificationLevel || m_data.level == NotificationLevel::WarningNotificationLevel) { std::string text; - text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker); + text = (m_data.level == NotificationLevel::ErrorNotificationLevel ? ImGui::ErrorMarker : ImGui::WarningMarker); ImGui::SetCursorPosX(m_line_height / 3); ImGui::SetCursorPosY(m_window_height / 2 - m_line_height); imgui.text(text.c_str()); @@ -583,19 +583,23 @@ bool NotificationManager::PopNotification::update_state(bool paused, const int64 int64_t now = GLCanvas3D::timestamp_now(); + // reset fade opacity for non-closing notifications or hover during fading + if (m_state != EState::FadingOut && m_state != EState::ClosePending && m_state != EState::Finished) { + m_current_fade_opacity = 1.0f; + } + // reset timers - hovered state is set in render if (m_state == EState::Hovered) { - m_current_fade_opacity = 1.0f; m_state = EState::Unknown; init(); // Timers when not fading - } else if (m_state != EState::NotFading && m_state != EState::FadingOut && m_data.duration != 0 && !paused) { + } else if (m_state != EState::NotFading && m_state != EState::FadingOut && get_duration() != 0 && !paused) { int64_t up_time = now - m_notification_start; - if (up_time >= m_data.duration * 1000) { + if (up_time >= get_duration() * 1000) { m_state = EState::FadingOut; m_fading_start = now; } else { - m_next_render = m_data.duration * 1000 - up_time; + m_next_render = get_duration() * 1000 - up_time; } } // Timers when fading @@ -626,53 +630,6 @@ bool NotificationManager::PopNotification::update_state(bool paused, const int64 return false; } -NotificationManager::SlicingCompleteLargeNotification::SlicingCompleteLargeNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool large) : - NotificationManager::PopNotification(n, id_provider, evt_handler) -{ - set_large(large); -} -void NotificationManager::SlicingCompleteLargeNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) -{ - if (!m_is_large) - PopNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); - else { - ImVec2 win_size(win_size_x, win_size_y); - ImVec2 text1_size = ImGui::CalcTextSize(m_text1.c_str()); - float x_offset = m_left_indentation; - std::string fulltext = m_text1 + m_hypertext + m_text2; - ImVec2 text_size = ImGui::CalcTextSize(fulltext.c_str()); - float cursor_y = win_size.y / 2 - text_size.y / 2; - if (m_has_print_info) { - x_offset = 20; - cursor_y = win_size.y / 2 + win_size.y / 6 - text_size.y / 2; - ImGui::SetCursorPosX(x_offset); - ImGui::SetCursorPosY(cursor_y); - imgui.text(m_print_info.c_str()); - cursor_y = win_size.y / 2 - win_size.y / 6 - text_size.y / 2; - } - ImGui::SetCursorPosX(x_offset); - ImGui::SetCursorPosY(cursor_y); - imgui.text(m_text1.c_str()); - - render_hypertext(imgui, x_offset + text1_size.x + 4, cursor_y, m_hypertext); - } -} -void NotificationManager::SlicingCompleteLargeNotification::set_print_info(const std::string &info) -{ - m_print_info = info; - m_has_print_info = true; - if (m_is_large) - m_lines_count = 2; -} -void NotificationManager::SlicingCompleteLargeNotification::set_large(bool l) -{ - m_is_large = l; - //FIXME this information should not be lost (change m_data?) -// m_counting_down = !l; - m_hypertext = l ? _u8L("Export G-Code.") : std::string(); - m_state = l ? EState::Shown : EState::Hidden; - init(); -} //---------------ExportFinishedNotification----------- void NotificationManager::ExportFinishedNotification::count_spaces() { @@ -680,9 +637,9 @@ void NotificationManager::ExportFinishedNotification::count_spaces() m_line_height = ImGui::CalcTextSize("A").y; m_left_indentation = m_line_height; - if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) { + if (m_data.level == NotificationLevel::ErrorNotificationLevel || m_data.level == NotificationLevel::WarningNotificationLevel) { std::string text; - text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker); + text = (m_data.level == NotificationLevel::ErrorNotificationLevel ? ImGui::ErrorMarker : ImGui::WarningMarker); float picture_width = ImGui::CalcTextSize(text.c_str()).x; m_left_indentation = picture_width + m_line_height / 2; } @@ -793,6 +750,9 @@ void NotificationManager::ProgressBarNotification::init() { PopNotification::init(); //m_lines_count++; + if (m_endlines.empty()) { + m_endlines.push_back(0); + } if(m_lines_count >= 2) { m_lines_count = 3; m_multiline = true; @@ -897,8 +857,17 @@ void NotificationManager::ProgressBarNotification::render_bar(ImGuiWrapper& imgu ImVec2 lineEnd = ImVec2(win_pos_x - m_window_width_offset, win_pos_y + win_size_y / 2 + (m_multiline ? m_line_height / 2 : 0)); ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y / 2 + (m_multiline ? m_line_height / 2 : 0)); ImVec2 midPoint = ImVec2(lineStart.x + (lineEnd.x - lineStart.x) * m_percentage, lineStart.y); - ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(gray_color.x * 255), (int)(gray_color.y * 255), (int)(gray_color.z * 255), (1.0f * 255.f)), m_line_height * 0.2f); - ImGui::GetWindowDrawList()->AddLine(lineStart, midPoint, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.2f); + ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(gray_color.x * 255), (int)(gray_color.y * 255), (int)(gray_color.z * 255), (m_current_fade_opacity * 255.f)), m_line_height * 0.2f); + ImGui::GetWindowDrawList()->AddLine(lineStart, midPoint, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (m_current_fade_opacity * 255.f)), m_line_height * 0.2f); + if (m_render_percentage) { + std::string text; + std::stringstream stream; + stream << std::fixed << std::setprecision(2) << (int)(m_percentage * 100) << "%"; + text = stream.str(); + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - (m_multiline ? 0 : m_line_height / 4)); + imgui.text(text.c_str()); + } } //------PrintHostUploadNotification---------------- void NotificationManager::PrintHostUploadNotification::init() @@ -915,7 +884,7 @@ void NotificationManager::PrintHostUploadNotification::count_spaces() m_left_indentation = m_line_height; if (m_uj_state == UploadJobState::PB_ERROR) { std::string text; - text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker); + text = (m_data.level == NotificationLevel::ErrorNotificationLevel ? ImGui::ErrorMarker : ImGui::WarningMarker); float picture_width = ImGui::CalcTextSize(text.c_str()).x; m_left_indentation = picture_width + m_line_height / 2; } @@ -1102,15 +1071,382 @@ void NotificationManager::UpdatedItemsInfoNotification::render_left_sign(ImGuiWr imgui.text(text.c_str()); } +//------SlicingProgressNotificastion +void NotificationManager::SlicingProgressNotification::init() +{ + if (m_sp_state == SlicingProgressState::SP_PROGRESS) { + ProgressBarNotification::init(); + //if (m_state == EState::NotFading && m_percentage >= 1.0f) + // m_state = EState::Shown; + } + else { + PopNotification::init(); + } + +} +void NotificationManager::SlicingProgressNotification::set_progress_state(float percent) +{ + if (percent < 0.f) + set_progress_state(SlicingProgressState::SP_CANCELLED); + else if (percent >= 1.f) + set_progress_state(SlicingProgressState::SP_COMPLETED); + else + set_progress_state(SlicingProgressState::SP_PROGRESS, percent); +} +void NotificationManager::SlicingProgressNotification::set_progress_state(NotificationManager::SlicingProgressNotification::SlicingProgressState state, float percent/* = 0.f*/) +{ + switch (state) + { + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_NO_SLICING: + m_state = EState::Hidden; + set_percentage(-1); + m_has_print_info = false; + set_export_possible(false); + break; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_PROGRESS: + set_percentage(percent); + m_has_cancel_button = true; + break; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_CANCELLED: + set_percentage(-1); + m_has_cancel_button = false; + m_has_print_info = false; + set_export_possible(false); + break; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_COMPLETED: + set_percentage(1); + m_has_cancel_button = false; + m_has_print_info = false; + // m_export_possible is important only for PROGRESS state, thus we can reset it here + set_export_possible(false); + break; + default: + break; + } + m_sp_state = state; +} +void NotificationManager::SlicingProgressNotification::set_status_text(const std::string& text) +{ + switch (m_sp_state) + { + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_NO_SLICING: + m_state = EState::Hidden; + break; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_PROGRESS: + { + NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text + ".", m_is_fff ? _u8L("Export G-Code.") : _u8L("Export.") }; + update(data); + m_state = EState::NotFading; + } + break; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_CANCELLED: + { + NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text }; + update(data); + m_state = EState::Shown; + } + break; + case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_COMPLETED: + { + NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, _u8L("Slicing finished."), m_is_fff ? _u8L("Export G-Code.") : _u8L("Export.") }; + update(data); + m_state = EState::Shown; + } + break; + default: + break; + } +} +void NotificationManager::SlicingProgressNotification::set_print_info(const std::string& info) +{ + if (m_sp_state != SlicingProgressState::SP_COMPLETED) { + set_progress_state (SlicingProgressState::SP_COMPLETED); + } else { + m_has_print_info = true; + m_print_info = info; + } +} +void NotificationManager::SlicingProgressNotification::set_sidebar_collapsed(bool collapsed) +{ + m_sidebar_collapsed = collapsed; + if (m_sp_state == SlicingProgressState::SP_COMPLETED) + m_state = EState::Shown; +} + +void NotificationManager::SlicingProgressNotification::on_cancel_button() +{ + if (m_cancel_callback){ + m_cancel_callback(); + } +} +int NotificationManager::SlicingProgressNotification::get_duration() +{ + if (m_sp_state == SlicingProgressState::SP_CANCELLED) + return 10; + else if (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed) + return 5; + else + return 0; +} +bool NotificationManager::SlicingProgressNotification::update_state(bool paused, const int64_t delta) +{ + bool ret = ProgressBarNotification::update_state(paused, delta); + // sets Estate to hidden + if (get_state() == PopNotification::EState::ClosePending || get_state() == PopNotification::EState::Finished) + set_progress_state(SlicingProgressState::SP_NO_SLICING); + return ret; +} +void NotificationManager::SlicingProgressNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + if (m_sp_state == SlicingProgressState::SP_PROGRESS || (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed)) { + ProgressBarNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + /* // enable for hypertext during slicing (correct call of export_enabled needed) + if (m_multiline) { + // two lines text, one line bar + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(m_line_height / 4); + imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(m_line_height + m_line_height / 4); + std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0)); + imgui.text(line.c_str()); + if (m_sidebar_collapsed && m_sp_state == SlicingProgressState::SP_PROGRESS && m_export_possible) { + ImVec2 text_size = ImGui::CalcTextSize(line.c_str()); + render_hypertext(imgui, m_left_indentation + text_size.x + 4, m_line_height + m_line_height / 4, m_hypertext); + } + if (m_has_cancel_button) + render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + } + else { + //one line text, one line bar + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(m_line_height / 4); + std::string line = m_text1.substr(0, m_endlines[0]); + imgui.text(line.c_str()); + if (m_sidebar_collapsed && m_sp_state == SlicingProgressState::SP_PROGRESS && m_export_possible) { + ImVec2 text_size = ImGui::CalcTextSize(line.c_str()); + render_hypertext(imgui, m_left_indentation + text_size.x + 4, m_line_height / 4, m_hypertext); + } + if (m_has_cancel_button) + render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + } + */ + } else if (m_sp_state == SlicingProgressState::SP_COMPLETED) { + // "Slicing Finished" on line 1 + hypertext, print info on line + ImVec2 win_size(win_size_x, win_size_y); + ImVec2 text1_size = ImGui::CalcTextSize(m_text1.c_str()); + float x_offset = m_left_indentation; + std::string fulltext = m_text1 + m_hypertext + m_text2; + ImVec2 text_size = ImGui::CalcTextSize(fulltext.c_str()); + float cursor_y = win_size.y / 2 - text_size.y / 2; + if (m_sidebar_collapsed && m_has_print_info) { + x_offset = 20; + cursor_y = win_size.y / 2 + win_size.y / 6 - text_size.y / 2; + ImGui::SetCursorPosX(x_offset); + ImGui::SetCursorPosY(cursor_y); + imgui.text(m_print_info.c_str()); + cursor_y = win_size.y / 2 - win_size.y / 6 - text_size.y / 2; + } + ImGui::SetCursorPosX(x_offset); + ImGui::SetCursorPosY(cursor_y); + imgui.text(m_text1.c_str()); + if (m_sidebar_collapsed) + render_hypertext(imgui, x_offset + text1_size.x + 4, cursor_y, m_hypertext); + } else { + PopNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + } +} +void NotificationManager::SlicingProgressNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + if (!(m_sp_state == SlicingProgressState::SP_PROGRESS || (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed))) { + return; + } + //std::string text; + ProgressBarNotification::render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + /* + std::stringstream stream; + stream << std::fixed << std::setprecision(2) << (int)(m_percentage * 100) << "%"; + text = stream.str(); + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - (m_multiline ? 0 : m_line_height / 4)); + imgui.text(text.c_str()); + */ +} +void NotificationManager::SlicingProgressNotification::render_cancel_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + ImVec2 win_size(win_size_x, win_size_y); + ImVec2 win_pos(win_pos_x, win_pos_y); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + + + std::string button_text; + button_text = ImGui::CancelButton; + + if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - win_size.x / 10.f, win_pos.y), + ImVec2(win_pos.x, win_pos.y + win_size.y - (m_minimize_b_visible ? 2 * m_line_height : 0)), + true)) + { + button_text = ImGui::CancelHoverButton; + } + ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); + ImGui::SetCursorPosX(win_size.x - m_line_height * 2.75f); + ImGui::SetCursorPosY(win_size.y / 2 - button_size.y); + if (imgui.button(button_text.c_str(), button_size.x, button_size.y)) + { + on_cancel_button(); + } + + //invisible large button + ImGui::SetCursorPosX(win_size.x - m_line_height * 2.35f); + ImGui::SetCursorPosY(0); + if (imgui.button(" ", m_line_height * 2.125, win_size.y - (m_minimize_b_visible ? 2 * m_line_height : 0))) + { + on_cancel_button(); + } + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); +} + +void NotificationManager::SlicingProgressNotification::render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + // Do not render close button while showing progress - cancel button is rendered instead + if (m_sp_state != SlicingProgressState::SP_PROGRESS) { + ProgressBarNotification::render_close_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + } +} +//------ProgressIndicatorNotification------- +void NotificationManager::ProgressIndicatorNotification::set_status_text(const char* text) +{ + NotificationData data{ NotificationType::ProgressIndicator, NotificationLevel::ProgressBarNotificationLevel, 0, text }; + update(data); +} + +void NotificationManager::ProgressIndicatorNotification::init() +{ + // skip ProgressBarNotification::init (same code here) + PopNotification::init(); + if (m_endlines.empty()) { + m_endlines.push_back(0); + } + if (m_lines_count >= 2) { + m_lines_count = 3; + m_multiline = true; + while (m_endlines.size() < 3) + m_endlines.push_back(m_endlines.back()); + } + else { + m_lines_count = 2; + m_endlines.push_back(m_endlines.back()); + } + switch (m_progress_state) + { + case Slic3r::GUI::NotificationManager::ProgressIndicatorNotification::ProgressIndicatorState::PIS_HIDDEN: + m_state = EState::Hidden; + break; + case Slic3r::GUI::NotificationManager::ProgressIndicatorNotification::ProgressIndicatorState::PIS_PROGRESS_REQUEST: + case Slic3r::GUI::NotificationManager::ProgressIndicatorNotification::ProgressIndicatorState::PIS_PROGRESS_UPDATED: + m_state = EState::NotFading; + break; + case Slic3r::GUI::NotificationManager::ProgressIndicatorNotification::ProgressIndicatorState::PIS_COMPLETED: + m_state = EState::Shown; + break; + default: + break; + } +} +void NotificationManager::ProgressIndicatorNotification::set_percentage(float percent) +{ + ProgressBarNotification::set_percentage(percent); + if (percent >= 0.0f && percent < 1.0f) { + m_state = EState::NotFading; + m_has_cancel_button = true; + m_progress_state = ProgressIndicatorState::PIS_PROGRESS_REQUEST; + } else if (percent >= 1.0f) { + m_state = EState::Shown; + m_progress_state = ProgressIndicatorState::PIS_COMPLETED; + m_has_cancel_button = false; + } else { + m_progress_state = ProgressIndicatorState::PIS_HIDDEN; + m_state = EState::Hidden; + } +} +bool NotificationManager::ProgressIndicatorNotification::update_state(bool paused, const int64_t delta) +{ + if (m_progress_state == ProgressIndicatorState::PIS_PROGRESS_REQUEST) { + // percentage was changed (and it called schedule_extra_frame), now update must know this needs render + m_next_render = 0; + m_progress_state = ProgressIndicatorState::PIS_PROGRESS_UPDATED; + return true; + } + bool ret = ProgressBarNotification::update_state(paused, delta); + if (get_state() == PopNotification::EState::ClosePending || get_state() == PopNotification::EState::Finished) + // go to PIS_HIDDEN state + set_percentage(-1.0f); + return ret; +} + +void NotificationManager::ProgressIndicatorNotification::render_cancel_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + ImVec2 win_size(win_size_x, win_size_y); + ImVec2 win_pos(win_pos_x, win_pos_y); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + + + std::string button_text; + button_text = ImGui::CancelButton; + + if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - win_size.x / 10.f, win_pos.y), + ImVec2(win_pos.x, win_pos.y + win_size.y - (m_minimize_b_visible ? 2 * m_line_height : 0)), + true)) + { + button_text = ImGui::CancelHoverButton; + } + ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); + ImGui::SetCursorPosX(win_size.x - m_line_height * 2.75f); + ImGui::SetCursorPosY(win_size.y / 2 - button_size.y); + if (imgui.button(button_text.c_str(), button_size.x, button_size.y)) + { + on_cancel_button(); + } + + //invisible large button + ImGui::SetCursorPosX(win_size.x - m_line_height * 2.35f); + ImGui::SetCursorPosY(0); + if (imgui.button(" ", m_line_height * 2.125, win_size.y - (m_minimize_b_visible ? 2 * m_line_height : 0))) + { + on_cancel_button(); + } + ImGui::PopStyleColor(5); +} +void NotificationManager::ProgressIndicatorNotification::render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + // Do not render close button while showing progress - cancel button is rendered instead + if (m_percentage >= 1.0f) + { + ProgressBarNotification::render_close_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + } +} //------NotificationManager-------- NotificationManager::NotificationManager(wxEvtHandler* evt_handler) : m_evt_handler(evt_handler) { } -NotificationManager::~NotificationManager() -{ - HintDatabase::get_instance().uninit(); -} + void NotificationManager::push_notification(const NotificationType type, int timestamp) { auto it = std::find_if(std::begin(basic_notifications), std::end(basic_notifications), @@ -1121,7 +1457,7 @@ void NotificationManager::push_notification(const NotificationType type, int tim } void NotificationManager::push_notification(const std::string& text, int timestamp) { - push_notification_data({ NotificationType::CustomNotification, NotificationLevel::RegularNotification, 10, text }, timestamp); + push_notification_data({ NotificationType::CustomNotification, NotificationLevel::RegularNotificationLevel, 10, text }, timestamp); } void NotificationManager::push_notification(NotificationType type, @@ -1133,11 +1469,11 @@ void NotificationManager::push_notification(NotificationType type, { int duration = 0; switch (level) { - case NotificationLevel::RegularNotification: duration = 10; break; - case NotificationLevel::ErrorNotification: break; - case NotificationLevel::WarningNotification: break; - case NotificationLevel::ImportantNotification: break; - case NotificationLevel::ProgressBarNotification: break; + case NotificationLevel::RegularNotificationLevel: duration = 10; break; + case NotificationLevel::ErrorNotificationLevel: break; + case NotificationLevel::WarningNotificationLevel: break; + case NotificationLevel::ImportantNotificationLevel: break; + case NotificationLevel::ProgressBarNotificationLevel: break; default: assert(false); return; @@ -1146,18 +1482,19 @@ void NotificationManager::push_notification(NotificationType type, } void NotificationManager::push_validate_error_notification(const std::string& text) { - push_notification_data({ NotificationType::ValidateError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, 0); + push_notification_data({ NotificationType::ValidateError, NotificationLevel::ErrorNotificationLevel, 0, _u8L("ERROR:") + "\n" + text }, 0); + set_slicing_progress_hidden(); } void NotificationManager::push_slicing_error_notification(const std::string& text) { set_all_slicing_errors_gray(false); - push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, 0); - close_notification_of_type(NotificationType::SlicingComplete); + push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotificationLevel, 0, _u8L("ERROR:") + "\n" + text }, 0); + set_slicing_progress_hidden(); } void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, ObjectID oid, int warning_step) { - NotificationData data { NotificationType::SlicingWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }; + NotificationData data { NotificationType::SlicingWarning, NotificationLevel::WarningNotificationLevel, 0, _u8L("WARNING:") + "\n" + text }; auto notification = std::make_unique(data, m_id_provider, m_evt_handler); notification->object_id = oid; @@ -1168,7 +1505,7 @@ void NotificationManager::push_slicing_warning_notification(const std::string& t } void NotificationManager::push_plater_error_notification(const std::string& text) { - push_notification_data({ NotificationType::PlaterError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, 0); + push_notification_data({ NotificationType::PlaterError, NotificationLevel::ErrorNotificationLevel, 0, _u8L("ERROR:") + "\n" + text }, 0); } void NotificationManager::close_plater_error_notification(const std::string& text) @@ -1192,7 +1529,7 @@ void NotificationManager::push_plater_warning_notification(const std::string& te } } - NotificationData data{ NotificationType::PlaterWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }; + NotificationData data{ NotificationType::PlaterWarning, NotificationLevel::WarningNotificationLevel, 0, _u8L("WARNING:") + "\n" + text }; auto notification = std::make_unique(data, m_id_provider, m_evt_handler); push_notification_data(std::move(notification), 0); @@ -1252,49 +1589,12 @@ void NotificationManager::close_slicing_error_notification(const std::string& te } void NotificationManager::push_object_warning_notification(const std::string& text, ObjectID object_id, const std::string& hypertext/* = ""*/, std::function callback/* = std::function()*/) { - NotificationData data{ NotificationType::ObjectWarning, NotificationLevel::WarningNotification, 0, text, hypertext, callback }; + NotificationData data{ NotificationType::ObjectWarning, NotificationLevel::WarningNotificationLevel, 0, text, hypertext, callback }; auto notification = std::make_unique(data, m_id_provider, m_evt_handler); notification->object_id = object_id; notification->warning_step = 0; push_notification_data(std::move(notification), 0); } -void NotificationManager::push_slicing_complete_notification(int timestamp, bool large) -{ - std::string hypertext; - int time = 10; - if (has_slicing_error_notification()) - return; - if (large) { - hypertext = _u8L("Export G-Code."); - time = 0; - } - NotificationData data{ NotificationType::SlicingComplete, NotificationLevel::RegularNotification, time, _u8L("Slicing finished."), hypertext, - [](wxEvtHandler* evnthndlr){ - if (evnthndlr != nullptr) - wxPostEvent(evnthndlr, ExportGcodeNotificationClickedEvent(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED)); - return true; - } - }; - push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, large), timestamp); -} -void NotificationManager::set_slicing_complete_print_time(const std::string &info) -{ - for (std::unique_ptr ¬ification : m_pop_notifications) { - if (notification->get_type() == NotificationType::SlicingComplete) { - dynamic_cast(notification.get())->set_print_info(info); - break; - } - } -} -void NotificationManager::set_slicing_complete_large(bool large) -{ - for (std::unique_ptr ¬ification : m_pop_notifications) { - if (notification->get_type() == NotificationType::SlicingComplete) { - dynamic_cast(notification.get())->set_large(large); - break; - } - } -} void NotificationManager::close_notification_of_type(const NotificationType type) { for (std::unique_ptr ¬ification : m_pop_notifications) { @@ -1324,7 +1624,7 @@ void NotificationManager::remove_object_warnings_of_released_objects(const std:: void NotificationManager::push_exporting_finished_notification(const std::string& path, const std::string& dir_path, bool on_removable) { close_notification_of_type(NotificationType::ExportFinished); - NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotification, on_removable ? 0 : 20, _u8L("Exporting finished.") + "\n" + path }; + NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotificationLevel, on_removable ? 0 : 20, _u8L("Exporting finished.") + "\n" + path }; push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, on_removable, path, dir_path), 0); } @@ -1338,7 +1638,7 @@ void NotificationManager::push_upload_job_notification(int id, float filesize, } } std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host); - NotificationData data{ NotificationType::PrintHostUpload, NotificationLevel::ProgressBarNotification, 10, text }; + NotificationData data{ NotificationType::PrintHostUpload, NotificationLevel::ProgressBarNotificationLevel, 10, text }; push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, 0, id, filesize), 0); } void NotificationManager::set_upload_job_notification_percentage(int id, const std::string& filename, const std::string& host, float percentage) @@ -1380,6 +1680,153 @@ void NotificationManager::upload_job_notification_show_error(int id, const std:: } } } + +void NotificationManager::init_slicing_progress_notification(std::function cancel_callback) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::SlicingProgress) { + dynamic_cast(notification.get())->set_cancel_callback(cancel_callback); + return; + } + } + NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, std::string(),std::string(), + [](wxEvtHandler* evnthndlr) { + if (evnthndlr != nullptr) + wxPostEvent(evnthndlr, ExportGcodeNotificationClickedEvent(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED)); + return true; + } + }; + push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, cancel_callback), 0); +} +void NotificationManager::set_slicing_progress_percentage(const std::string& text, float percentage) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::SlicingProgress) { + SlicingProgressNotification* spn = dynamic_cast(notification.get()); + spn->set_progress_state(percentage); + spn->set_status_text(text); + wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); + return; + } + } + // Slicing progress notification was not found - init it thru plater so correct cancel callback function is appended + wxGetApp().plater()->init_notification_manager(); +} + +void NotificationManager::set_slicing_progress_hidden() +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::SlicingProgress) { + SlicingProgressNotification* notif = dynamic_cast(notification.get()); + notif->set_progress_state(SlicingProgressNotification::SlicingProgressState::SP_NO_SLICING); + wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); + return; + } + } + // Slicing progress notification was not found - init it thru plater so correct cancel callback function is appended + wxGetApp().plater()->init_notification_manager(); +} +void NotificationManager::set_slicing_complete_print_time(const std::string& info, bool sidebar_colapsed) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::SlicingProgress) { + dynamic_cast(notification.get())->set_sidebar_collapsed(sidebar_colapsed); + dynamic_cast(notification.get())->set_print_info(info); + break; + } + } +} +void NotificationManager::set_sidebar_collapsed(bool collapsed) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::SlicingProgress) { + dynamic_cast(notification.get())->set_sidebar_collapsed(collapsed); + break; + } + } +} +void NotificationManager::set_fff(bool fff) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::SlicingProgress) { + dynamic_cast(notification.get())->set_fff(fff); + break; + } + } +} +void NotificationManager::set_slicing_progress_export_possible() +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::SlicingProgress) { + dynamic_cast(notification.get())->set_export_possible(true); + break; + } + } +} +void NotificationManager::init_progress_indicator() +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::ProgressIndicator) { + return; + } + } + NotificationData data{ NotificationType::ProgressIndicator, NotificationLevel::ProgressBarNotificationLevel, 2}; + auto notification = std::make_unique(data, m_id_provider, m_evt_handler); + push_notification_data(std::move(notification), 0); +} + +void NotificationManager::progress_indicator_set_range(int range) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::ProgressIndicator) { + dynamic_cast(notification.get())->set_range(range); + return; + } + } + init_progress_indicator(); +} +void NotificationManager::progress_indicator_set_cancel_callback(CancelFn callback/* = CancelFn()*/) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::ProgressIndicator) { + dynamic_cast(notification.get())->set_cancel_callback(callback); + return; + } + } + init_progress_indicator(); +} +void NotificationManager::progress_indicator_set_progress(int pr) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::ProgressIndicator) { + dynamic_cast(notification.get())->set_progress(pr); + // Ask for rendering - needs to be done on every progress. Calls to here doesnt trigger IDLE event or rendering. + wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(100); + return; + } + } + init_progress_indicator(); +} +void NotificationManager::progress_indicator_set_status_text(const char* text) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::ProgressIndicator) { + dynamic_cast(notification.get())->set_status_text(text); + return; + } + } + init_progress_indicator(); +} +int NotificationManager::progress_indicator_get_range() const +{ + for (const std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::ProgressIndicator) { + return dynamic_cast(notification.get())->get_range(); + } + } + return 0; +} + void NotificationManager::push_hint_notification(bool open_next) { for (std::unique_ptr& notification : m_pop_notifications) { @@ -1389,7 +1836,7 @@ void NotificationManager::push_hint_notification(bool open_next) } } - NotificationData data{ NotificationType::DidYouKnowHint, NotificationLevel::RegularNotification, 300, "" }; + NotificationData data{ NotificationType::DidYouKnowHint, NotificationLevel::HintNotificationLevel, 300, "" }; // from user - open now if (!open_next) { push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, open_next), 0); @@ -1397,8 +1844,8 @@ void NotificationManager::push_hint_notification(bool open_next) // at startup - delay for half a second to let other notification pop up, than try every 30 seconds // show only if no notifications are shown } else { - auto condition = [this]() { - return this->get_notification_count() == 0; + auto condition = [&self = std::as_const(*this)]() { + return self.get_notification_count() == 0; }; push_delayed_notification(std::make_unique(data, m_id_provider, m_evt_handler, open_next), condition, 500, 30000); } @@ -1412,7 +1859,10 @@ bool NotificationManager::is_hint_notification_open() } return false; } - +void NotificationManager::deactivate_loaded_hints() +{ + HintDatabase::get_instance().uninit(); +} void NotificationManager::push_updated_item_info_notification(InfoItemType type) { for (std::unique_ptr& notification : m_pop_notifications) { @@ -1422,7 +1872,7 @@ void NotificationManager::push_updated_item_info_notification(InfoItemType type) } } - NotificationData data{ NotificationType::UpdatedItemsInfo, NotificationLevel::RegularNotification, 5, "" }; + NotificationData data{ NotificationType::UpdatedItemsInfo, NotificationLevel::RegularNotificationLevel, 5, "" }; auto notification = std::make_unique(data, m_id_provider, m_evt_handler, type); if (push_notification_data(std::move(notification), 0)) { (dynamic_cast(m_pop_notifications.back().get()))->add_type(type); @@ -1444,17 +1894,20 @@ bool NotificationManager::push_notification_data(std::unique_ptrget_current_canvas3D(); - + bool retval = false; if (this->activate_existing(notification.get())) { - m_pop_notifications.back()->update(notification->get_data()); - canvas.schedule_extra_frame(0); - return false; + if (m_initialized) { // ignore update action - it cant be initialized if canvas and imgui context is not ready + m_pop_notifications.back()->update(notification->get_data()); + } } else { m_pop_notifications.emplace_back(std::move(notification)); - canvas.schedule_extra_frame(0); - return true; + retval = true; } + if (!m_initialized) + return retval; + GLCanvas3D& canvas = *wxGetApp().plater()->get_current_canvas3D(); + canvas.schedule_extra_frame(0); + return retval; } void NotificationManager::push_delayed_notification(std::unique_ptr notification, std::function condition_callback, int64_t initial_delay, int64_t delay_interval) @@ -1608,6 +2061,8 @@ void NotificationManager::set_in_preview(bool preview) notification->hide(preview); if (notification->get_type() == NotificationType::SignDetected) notification->hide(!preview); + if (m_in_preview && notification->get_type() == NotificationType::DidYouKnowHint) + notification->close(); } } diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index eb95aec58..76dc9a688 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -6,6 +6,7 @@ #include "GLCanvas3D.hpp" #include "Event.hpp" #include "I18N.hpp" +#include "Jobs/ProgressIndicator.hpp" #include #include @@ -27,6 +28,8 @@ wxDECLARE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationCli using PresetUpdateAvailableClickedEvent = SimpleEvent; wxDECLARE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent); +using CancelFn = std::function; + class GLCanvas3D; class ImGuiWrapper; enum class InfoItemType; @@ -34,9 +37,6 @@ enum class InfoItemType; enum class NotificationType { CustomNotification, - // Notification on end of slicing and G-code processing (the full G-code preview is available). - // Contains a hyperlink to export the G-code to a removable media. - SlicingComplete, // SlicingNotPossible, // Notification on end of export to a removable media, with hyperling to eject the external media. // Obsolete by ExportFinished @@ -78,6 +78,10 @@ enum class NotificationType ProgressBar, // Progress bar with info from Print Host Upload Queue dialog. PrintHostUpload, + // Progress bar with cancel button, cannot be closed + // On end of slicing and G-code processing (the full G-code preview is available), + // contains a hyperlink to export the G-code to a removable media or hdd. + SlicingProgress, // Notification, when Color Change G-code is empty and user try to add color change on DoubleSlider. EmptyColorChangeCode, // Notification that custom supports/seams were deleted after mesh repair. @@ -100,6 +104,8 @@ enum class NotificationType // Shows when ObjectList::update_info_items finds information that should be stressed to the user // Might contain logo taken from gizmos UpdatedItemsInfo, + // Progress bar notification with methods to replace ProgressIndicator class. + ProgressIndicator }; class NotificationManager @@ -109,27 +115,31 @@ public: { // The notifications will be presented in the order of importance, thus these enum values // are sorted by the importance. - // "Good to know" notification, usually but not always with a quick fade-out. - RegularNotification = 1, + // Important notification with progress bar, no fade-out, might appear again after closing. Position at the bottom. + ProgressBarNotificationLevel = 1, + // "Did you know" notification with special icon and buttons, Position close to bottom. + HintNotificationLevel, + // "Good to know" notification, usually but not always with a quick fade-out. + RegularNotificationLevel, // Information notification without a fade-out or with a longer fade-out. - ImportantNotification, - // Important notification with progress bar, no fade-out, might appear again after closing. - ProgressBarNotification, + ImportantNotificationLevel, // Warning, no fade-out. - WarningNotification, - // Error, no fade-out. - ErrorNotification, + WarningNotificationLevel, + // Error, no fade-out. Top most position. + ErrorNotificationLevel, }; NotificationManager(wxEvtHandler* evt_handler); - ~NotificationManager(); + ~NotificationManager(){} + // init is called after canvas3d is created. Notifications added before init are not showed or updated + void init() { m_initialized = true; } // Push a prefabricated notification from basic_notifications (see the table at the end of this file). void push_notification(const NotificationType type, int timestamp = 0); - // Push a NotificationType::CustomNotification with NotificationLevel::RegularNotification and 10s fade out interval. + // Push a NotificationType::CustomNotification with NotificationLevel::RegularNotificationLevel and 10s fade out interval. void push_notification(const std::string& text, int timestamp = 0); - // Push a NotificationType::CustomNotification with provided notification level and 10s for RegularNotification. - // ErrorNotification and ImportantNotification are never faded out. + // Push a NotificationType::CustomNotification with provided notification level and 10s for RegularNotificationLevel. + // ErrorNotificationLevel and ImportantNotificationLevel are never faded out. void push_notification(NotificationType type, NotificationLevel level, const std::string& text, const std::string& hypertext = "", std::function callback = std::function(), int timestamp = 0); // Creates Validate Error notification with a custom text and no fade out. @@ -162,25 +172,44 @@ public: // Close object warnings, whose ObjectID is not in the list. // living_oids is expected to be sorted. void remove_object_warnings_of_released_objects(const std::vector& living_oids); - // Creates special notification slicing complete. - // If large = true (Plater side bar is closed), then printing time and export button is shown - // at the notification and fade-out is disabled. Otherwise the fade out time is set to 10s. - void push_slicing_complete_notification(int timestamp, bool large); - // Add a print time estimate to an existing SlicingComplete notification. - void set_slicing_complete_print_time(const std::string &info); // Called when the side bar changes its visibility, as the "slicing complete" notification supplements // the "slicing info" normally shown at the side bar. - void set_slicing_complete_large(bool large); + void set_sidebar_collapsed(bool collapsed); + // Set technology for correct text in SlicingProgress. + void set_fff(bool b); + void set_fdm(bool b) { set_fff(b); } + void set_sla(bool b) { set_fff(!b); } // Exporting finished, show this information with path, button to open containing folder and if ejectable - eject button void push_exporting_finished_notification(const std::string& path, const std::string& dir_path, bool on_removable); - // notification with progress bar + // notifications with progress bar + // print host upload void push_upload_job_notification(int id, float filesize, const std::string& filename, const std::string& host, float percentage = 0); void set_upload_job_notification_percentage(int id, const std::string& filename, const std::string& host, float percentage); void upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host); void upload_job_notification_show_error(int id, const std::string& filename, const std::string& host); + // slicing progress + void init_slicing_progress_notification(std::function cancel_callback); + // percentage negative = canceled, <0-1) = progress, 1 = completed + void set_slicing_progress_percentage(const std::string& text, float percentage); + // hides slicing progress notification imidietly + void set_slicing_progress_hidden(); + // Add a print time estimate to an existing SlicingProgress notification. Set said notification to SP_COMPLETED state. + void set_slicing_complete_print_time(const std::string& info, bool sidebar_colapsed); + void set_slicing_progress_export_possible(); + // ProgressIndicator notification + // init adds hidden instance of progress indi notif that should always live (goes to hidden instead of erasing) + void init_progress_indicator(); + // functions equal to ProgressIndicator class + void progress_indicator_set_range(int range); + void progress_indicator_set_cancel_callback(CancelFn callback = CancelFn()); + void progress_indicator_set_progress(int pr); + void progress_indicator_set_status_text(const char*); // utf8 char array + int progress_indicator_get_range() const; // Hint (did you know) notification void push_hint_notification(bool open_next); bool is_hint_notification_open(); + // Forces Hints to reload its content when next hint should be showed + void deactivate_loaded_hints(); void push_updated_item_info_notification(InfoItemType type); // Close old notification ExportFinished. void new_export_began(bool on_removable); @@ -267,7 +296,7 @@ private: virtual bool compare_text(const std::string& text) const; void hide(bool h) { if (is_finished()) return; m_state = h ? EState::Hidden : EState::Unknown; } // sets m_next_render with time of next mandatory rendering. Delta is time since last render. - bool update_state(bool paused, const int64_t delta); + virtual bool update_state(bool paused, const int64_t delta); int64_t next_render() const { return is_finished() ? 0 : m_next_render; } EState get_state() const { return m_state; } bool is_hovered() const { return m_state == EState::Hovered; } @@ -303,6 +332,8 @@ private: virtual void count_lines(); // returns true if PopStyleColor should be called later to pop this push virtual bool push_background_color(); + // used this function instead of reading directly m_data.duration. Some notifications might need to return changing value. + virtual int get_duration() { return m_data.duration; } const NotificationData m_data; // For reusing ImGUI windows. @@ -359,29 +390,7 @@ private: wxEvtHandler* m_evt_handler; }; - class SlicingCompleteLargeNotification : public PopNotification - { - public: - SlicingCompleteLargeNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool largeds); - void set_large(bool l); - bool get_large() { return m_is_large; } - void set_print_info(const std::string &info); - void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width) override - { - // This notification is always hidden if !large (means side bar is collapsed) - if (!get_large() && !is_finished()) - m_state = EState::Hidden; - PopNotification::render(canvas, initial_y, move_from_overlay, overlay_width); - } - protected: - void render_text(ImGuiWrapper& imgui, - const float win_size_x, const float win_size_y, - const float win_pos_x, const float win_pos_y) - override; - bool m_is_large; - bool m_has_print_info { false }; - std::string m_print_info; - }; + class SlicingWarningNotification : public PopNotification { @@ -405,7 +414,7 @@ private: { public: - ProgressBarNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage) : PopNotification(n, id_provider, evt_handler) { } + ProgressBarNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler) : PopNotification(n, id_provider, evt_handler) { } virtual void set_percentage(float percent) { m_percentage = percent; } protected: virtual void init() override; @@ -423,9 +432,10 @@ private: {} void render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) override {} - float m_percentage; + float m_percentage {0.0f}; bool m_has_cancel_button {false}; + bool m_render_percentage {false}; // local time of last hover for showing tooltip }; @@ -443,7 +453,7 @@ private: PB_COMPLETED }; PrintHostUploadNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage, int job_id, float filesize) - :ProgressBarNotification(n, id_provider, evt_handler, percentage) + :ProgressBarNotification(n, id_provider, evt_handler) , m_job_id(job_id) , m_file_size(filesize) { @@ -472,7 +482,117 @@ private: // Size of uploaded size to be displayed in MB float m_file_size; long m_hover_time{ 0 }; - UploadJobState m_uj_state{ UploadJobState::PB_PROGRESS }; + UploadJobState m_uj_state{ UploadJobState::PB_PROGRESS }; + }; + + class SlicingProgressNotification : public ProgressBarNotification + { + public: + // Inner state of notification, Each state changes bahaviour of the notification + enum class SlicingProgressState + { + SP_NO_SLICING, // hidden + SP_PROGRESS, // never fades outs, no close button, has cancel button + SP_CANCELLED, // fades after 10 seconds, simple message + SP_COMPLETED // Has export hyperlink and print info, fades after 20 sec if sidebar is shown, otherwise no fade out + }; + SlicingProgressNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, std::function callback) + : ProgressBarNotification(n, id_provider, evt_handler) + , m_cancel_callback(callback) + { + set_progress_state(SlicingProgressState::SP_NO_SLICING); + m_has_cancel_button = false; + m_render_percentage = true; + } + // sets text of notification - call after setting progress state + void set_status_text(const std::string& text); + // sets cancel button callback + void set_cancel_callback(std::function callback) { m_cancel_callback = callback; } + bool has_cancel_callback() const { return m_cancel_callback != nullptr; } + // sets SlicingProgressState, negative percent means canceled + void set_progress_state(float percent); + // sets SlicingProgressState, percent is used only at progress state. + void set_progress_state(SlicingProgressState state,float percent = 0.f); + // sets additional string of print info and puts notification into Completed state. + void set_print_info(const std::string& info); + // sets fading if in Completed state. + void set_sidebar_collapsed(bool collapsed); + // Calls inherited update_state and ensures Estate goes to hidden not closing. + bool update_state(bool paused, const int64_t delta) override; + // Switch between technology to provide correct text. + void set_fff(bool b) { m_is_fff = b; } + void set_fdm(bool b) { m_is_fff = b; } + void set_sla(bool b) { m_is_fff = !b; } + void set_export_possible(bool b) { m_export_possible = b; } + protected: + void init() override; + void count_lines() override + { + if (m_sp_state == SlicingProgressState::SP_PROGRESS) + ProgressBarNotification::count_lines(); + else + PopNotification::count_lines(); + } + void render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override; + void render_bar(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y) override; + void render_cancel_button(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y) override; + void render_close_button(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y) override; + void on_cancel_button(); + int get_duration() override; + std::function m_cancel_callback; + SlicingProgressState m_sp_state { SlicingProgressState::SP_PROGRESS }; + bool m_has_print_info { false }; + std::string m_print_info; + bool m_sidebar_collapsed { false }; + bool m_is_fff { true }; + // if true, it is possible show export hyperlink in state SP_PROGRESS + bool m_export_possible { false }; + }; + + class ProgressIndicatorNotification : public ProgressBarNotification + { + public: + enum class ProgressIndicatorState + { + PIS_HIDDEN, // hidden + PIS_PROGRESS_REQUEST, // progress was updated, request render on next update_state() call + PIS_PROGRESS_UPDATED, // render was requested + PIS_COMPLETED // both completed and canceled state. fades out into PIS_NO_SLICING + }; + ProgressIndicatorNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler) + : ProgressBarNotification(n, id_provider, evt_handler) + { + m_render_percentage = true; + } + // ProgressIndicator + void set_range(int range) { m_range = range; } + void set_cancel_callback(CancelFn callback) { m_cancel_callback = callback; } + void set_progress(int pr) { set_percentage((float)pr / (float)m_range); } + void set_status_text(const char*); // utf8 char array + int get_range() const { return m_range; } + // ProgressBarNotification + void init() override; + void set_percentage(float percent) override; + bool update_state(bool paused, const int64_t delta) override; + // Own + protected: + int m_range { 100 }; + CancelFn m_cancel_callback { nullptr }; + ProgressIndicatorState m_progress_state { ProgressIndicatorState::PIS_HIDDEN }; + + void render_close_button(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y) override; + void render_cancel_button(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y) override; + void on_cancel_button() { if (m_cancel_callback) m_cancel_callback(); } }; class ExportFinishedNotification : public PopNotification @@ -499,7 +619,7 @@ private: void render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override; - void render_eject_button(ImGuiWrapper& imgui, + void render_eject_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y); void render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y) override @@ -562,13 +682,15 @@ private: // If there is some error notification active, then the "Export G-code" notification after the slicing is finished is suppressed. bool has_slicing_error_notification(); + // set by init(), until false notifications are only added not updated and frame is not requested after push + bool m_initialized{ false }; // Target for wxWidgets events sent by clicking on the hyperlink available at some notifications. wxEvtHandler* m_evt_handler; // Cache of IDs to identify and reuse ImGUI windows. NotificationIDProvider m_id_provider; std::deque> m_pop_notifications; // delayed waiting notifications, first is remaining time - std::deque m_waiting_notifications; + std::vector m_waiting_notifications; //timestamps used for slicing finished - notification could be gone so it needs to be stored here std::unordered_set m_used_timestamps; // True if G-code preview is active. False if the Plater is active. diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ac76fe655..7d344c389 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1208,6 +1208,8 @@ void Sidebar::update_sliced_info_sizer() wxString t_est = std::isnan(ps.estimated_print_time) ? "N/A" : get_time_dhms(float(ps.estimated_print_time)); p->sliced_info->SetTextAndShow(siEstimatedTime, t_est, _L("Estimated printing time") + ":"); + p->plater->get_notification_manager()->set_slicing_complete_print_time(_utf8("Estimated printing time: ") + boost::nowide::narrow(t_est), p->plater->is_sidebar_collapsed()); + // Hide non-SLA sliced info parameters p->sliced_info->SetTextAndShow(siFilament_m, "N/A"); p->sliced_info->SetTextAndShow(siFilament_mm3, "N/A"); @@ -1296,10 +1298,7 @@ void Sidebar::update_sliced_info_sizer() new_label += format_wxstr("\n - %1%", _L("normal mode")); info_text += format_wxstr("\n%1%", short_time(ps.estimated_normal_print_time)); - // uncomment next line to not disappear slicing finished notif when colapsing sidebar before time estimate - //if (p->plater->is_sidebar_collapsed()) - p->plater->get_notification_manager()->set_slicing_complete_large(p->plater->is_sidebar_collapsed()); - p->plater->get_notification_manager()->set_slicing_complete_print_time("Estimated printing time: " + ps.estimated_normal_print_time); + p->plater->get_notification_manager()->set_slicing_complete_print_time(_utf8("Estimated printing time: ") + ps.estimated_normal_print_time, p->plater->is_sidebar_collapsed()); } if (ps.estimated_silent_print_time != "N/A") { @@ -1502,7 +1501,7 @@ struct Plater::priv GLToolbar view_toolbar; GLToolbar collapse_toolbar; Preview *preview; - NotificationManager* notification_manager { nullptr }; + std::shared_ptr notification_manager; ProjectDirtyStateManager dirty_state; @@ -1523,10 +1522,10 @@ struct Plater::priv public: Jobs(priv *_m) : m(_m) { - m_arrange_id = add_job(std::make_unique(m->statusbar(), m->q)); - m_fill_bed_id = add_job(std::make_unique(m->statusbar(), m->q)); - m_rotoptimize_id = add_job(std::make_unique(m->statusbar(), m->q)); - m_sla_import_id = add_job(std::make_unique(m->statusbar(), m->q)); + m_arrange_id = add_job(std::make_unique(m->notification_manager, m->q)); + m_fill_bed_id = add_job(std::make_unique(m->notification_manager, m->q)); + m_rotoptimize_id = add_job(std::make_unique(m->notification_manager, m->q)); + m_sla_import_id = add_job(std::make_unique(m->notification_manager, m->q)); } void arrange() @@ -1637,7 +1636,7 @@ struct Plater::priv void apply_free_camera_correction(bool apply = true); void update_ui_from_settings(); void update_main_toolbar_tooltips(); - std::shared_ptr statusbar(); +// std::shared_ptr statusbar(); std::string get_config(const std::string &key) const; BoundingBoxf bed_shape_bb() const; BoundingBox scaled_bed_shape_bb() const; @@ -1788,6 +1787,8 @@ struct Plater::priv // extension should contain the leading dot, i.e.: ".3mf" wxString get_project_filename(const wxString& extension = wxEmptyString) const; void set_project_filename(const wxString& filename); + // Call after plater and Canvas#D is initialized + void init_notification_manager(); // Caching last value of show_action_buttons parameter for show_action_buttons(), so that a callback which does not know this state will not override it. mutable bool ready_to_slice = { false }; @@ -1797,6 +1798,7 @@ struct Plater::priv std::string last_output_dir_path; bool inside_snapshot_capture() { return m_prevent_snapshots != 0; } bool process_completed_with_error { false }; + private: bool layers_height_allowed() const; @@ -1845,6 +1847,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) "support_material_contact_distance", "support_material_bottom_contact_distance", "raft_layers" })) , sidebar(new Sidebar(q)) + , notification_manager(std::make_shared(q)) , m_ui_jobs(this) , delayed_scene_refresh(false) , view_toolbar(GLToolbar::Radio, "View") @@ -2012,7 +2015,8 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) }); #endif /* _WIN32 */ - notification_manager = new NotificationManager(this->q); + //notification_manager = new NotificationManager(this->q); + if (wxGetApp().is_editor()) { this->q->Bind(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, [this](EjectDriveNotificationClickedEvent&) { this->q->eject_drive(); }); this->q->Bind(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, [this](ExportGcodeNotificationClickedEvent&) { this->q->export_gcode(true); }); @@ -2022,12 +2026,12 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) this->show_action_buttons(this->ready_to_slice); notification_manager->close_notification_of_type(NotificationType::ExportFinished); notification_manager->push_notification(NotificationType::CustomNotification, - NotificationManager::NotificationLevel::RegularNotification, + NotificationManager::NotificationLevel::RegularNotificationLevel, format(_L("Successfully unmounted. The device %s(%s) can now be safely removed from the computer."), evt.data.first.name, evt.data.first.path) ); } else { notification_manager->push_notification(NotificationType::CustomNotification, - NotificationManager::NotificationLevel::ErrorNotification, + NotificationManager::NotificationLevel::ErrorNotificationLevel, format(_L("Ejecting of device %s(%s) has failed."), evt.data.first.name, evt.data.first.path) ); } @@ -2074,8 +2078,7 @@ Plater::priv::~priv() { if (config != nullptr) delete config; - if (notification_manager != nullptr) - delete notification_manager; + notification_manager->deactivate_loaded_hints(); } void Plater::priv::update(unsigned int flags) @@ -2150,6 +2153,8 @@ void Plater::priv::collapse_sidebar(bool collapse) new_tooltip += " [Shift+Tab]"; int id = collapse_toolbar.get_item_id("collapse_sidebar"); collapse_toolbar.set_tooltip(id, new_tooltip); + + notification_manager->set_sidebar_collapsed(collapse); } @@ -2177,10 +2182,11 @@ void Plater::priv::update_main_toolbar_tooltips() view3D->get_canvas3d()->update_tooltip_for_settings_item_in_main_toolbar(); } -std::shared_ptr Plater::priv::statusbar() -{ - return main_frame->m_statusbar; -} +//std::shared_ptr Plater::priv::statusbar() +//{ +// return nullptr; +// return main_frame->m_statusbar; +//} std::string Plater::priv::get_config(const std::string &key) const { @@ -2325,7 +2331,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ for (std::string& name : names) notif_text += "\n - " + name; notification_manager->push_notification(NotificationType::CustomNotification, - NotificationManager::NotificationLevel::RegularNotification, notif_text); + NotificationManager::NotificationLevel::RegularNotificationLevel, notif_text); } } @@ -2467,7 +2473,7 @@ std::vector Plater::priv::load_files(const std::vector& input_ if (load_model) { wxGetApp().app_config->update_skein_dir(input_files[input_files.size() - 1].parent_path().make_preferred().string()); // XXX: Plater.pm had @loaded_files, but didn't seem to fill them with the filenames... - statusbar()->set_status_text(_L("Loaded")); +// statusbar()->set_status_text(_L("Loaded")); } // automatic selection of added objects @@ -2880,7 +2886,7 @@ void Plater::priv::split_object() // If we splited object which is contain some parts/modifiers then all non-solid parts (modifiers) were deleted if (current_model_object->volumes.size() > 1 && current_model_object->volumes.size() != new_objects.size()) notification_manager->push_notification(NotificationType::CustomNotification, - NotificationManager::NotificationLevel::RegularNotification, + NotificationManager::NotificationLevel::RegularNotificationLevel, _u8L("All non-solid parts (modifiers) were deleted")); Plater::TakeSnapshot snapshot(q, _L("Split to Objects")); @@ -2956,7 +2962,7 @@ void Plater::priv::process_validation_warning(const std::string& warning) const notification_manager->push_notification( NotificationType::ValidateWarning, - NotificationManager::NotificationLevel::WarningNotification, + NotificationManager::NotificationLevel::WarningNotificationLevel, _u8L("WARNING:") + "\n" + text, hypertext, action_fn ); } @@ -3002,6 +3008,8 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool // In SLA mode, we need to reload the 3D scene every time to show the support structures. if (printer_technology == ptSLA || (printer_technology == ptFFF && config->opt_bool("wipe_tower"))) return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE; + + notification_manager->set_slicing_progress_hidden(); } if ((invalidated != Print::APPLY_STATUS_UNCHANGED || force_validation) && ! background_process.empty()) { @@ -3074,9 +3082,9 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool else { // Background data is valid. - if ((return_state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 || - (return_state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0 ) - this->statusbar()->set_status_text(_L("Ready to slice")); +// if ((return_state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 || +// (return_state & UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE) != 0 ) +// this->statusbar()->set_status_text(_L("Ready to slice")); sidebar->set_btn_label(ActionButtonType::abExport, _(label_btn_export)); sidebar->set_btn_label(ActionButtonType::abSendGCode, _(label_btn_send)); @@ -3113,10 +3121,10 @@ bool Plater::priv::restart_background_process(unsigned int state) (state & UPDATE_BACKGROUND_PROCESS_RESTART) != 0 ) ) { // The print is valid and it can be started. if (this->background_process.start()) { - this->statusbar()->set_cancel_callback([this]() { - this->statusbar()->set_status_text(_L("Cancelling")); - this->background_process.stop(); - }); +// this->statusbar()->set_cancel_callback([this]() { +// this->statusbar()->set_status_text(_L("Cancelling")); +// this->background_process.stop(); +// }); if (!show_warning_dialog) on_slicing_began(); return true; @@ -3753,9 +3761,9 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) return; } - this->statusbar()->set_progress(evt.status.percent); - this->statusbar()->set_status_text(_(evt.status.text) + wxString::FromUTF8("…")); - //notification_manager->set_progress_bar_percentage("Slicing progress", (float)evt.status.percent / 100.0f); +// this->statusbar()->set_progress(evt.status.percent); +// this->statusbar()->set_status_text(_(evt.status.text) + wxString::FromUTF8("…")); + notification_manager->set_slicing_progress_percentage(evt.status.text, (float)evt.status.percent / 100.0f); } if (evt.status.flags & (PrintBase::SlicingStatus::RELOAD_SCENE | PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS)) { switch (this->printer_technology) { @@ -3806,7 +3814,6 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) void Plater::priv::on_slicing_completed(wxCommandEvent & evt) { - notification_manager->push_slicing_complete_notification(evt.GetInt(), is_sidebar_collapsed()); switch (this->printer_technology) { case ptFFF: this->update_fff_scene(); @@ -3829,8 +3836,8 @@ void Plater::priv::on_export_began(wxCommandEvent& evt) void Plater::priv::on_slicing_began() { clear_warnings(); - notification_manager->close_notification_of_type(NotificationType::SlicingComplete); notification_manager->close_notification_of_type(NotificationType::SignDetected); + notification_manager->close_notification_of_type(NotificationType::ExportFinished); } void Plater::priv::add_warning(const Slic3r::PrintStateBase::Warning& warning, size_t oid) { @@ -3895,8 +3902,9 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt) // At this point of time the thread should be either finished or canceled, // so the following call just confirms, that the produced data were consumed. this->background_process.stop(); - this->statusbar()->reset_cancel_callback(); - this->statusbar()->stop_busy(); +// this->statusbar()->reset_cancel_callback(); +// this->statusbar()->stop_busy(); + notification_manager->set_slicing_progress_export_possible(); // Reset the "export G-code path" name, so that the automatic background processing will be enabled again. this->background_process.reset_export(); @@ -3913,7 +3921,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt) show_error(q, message.first, message.second); } else notification_manager->push_slicing_error_notification(message.first); - this->statusbar()->set_status_text(from_u8(message.first)); +// this->statusbar()->set_status_text(from_u8(message.first)); if (evt.invalidate_plater()) { const wxString invalid_str = _L("Invalid data"); @@ -3923,8 +3931,10 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt) } has_error = true; } - if (evt.cancelled()) - this->statusbar()->set_status_text(_L("Cancelled")); + if (evt.cancelled()) { +// this->statusbar()->set_status_text(_L("Cancelled")); + this->notification_manager->set_slicing_progress_percentage(_utf8("Slicing Cancelled."), -1); + } this->sidebar->show_sliced_info_sizer(evt.success()); @@ -4128,6 +4138,20 @@ void Plater::priv::set_project_filename(const wxString& filename) wxGetApp().mainframe->add_to_recent_projects(filename); } +void Plater::priv::init_notification_manager() +{ + if (!notification_manager) + return; + notification_manager->init(); + + auto cancel_callback = [this]() { + this->background_process.stop(); + }; + notification_manager->init_slicing_progress_notification(cancel_callback); + notification_manager->set_fff(printer_technology == ptFFF); + notification_manager->init_progress_indicator(); +} + void Plater::priv::set_current_canvas_as_dirty() { if (current_panel == view3D) @@ -5566,7 +5590,7 @@ void Plater::export_stl(bool extended, bool selection_only) } Slic3r::store_stl(path_u8.c_str(), &mesh, true); - p->statusbar()->set_status_text(format_wxstr(_L("STL file exported to %s"), path)); +// p->statusbar()->set_status_text(format_wxstr(_L("STL file exported to %s"), path)); } void Plater::export_amf() @@ -5583,10 +5607,10 @@ void Plater::export_amf() bool full_pathnames = wxGetApp().app_config->get("export_sources_full_pathnames") == "1"; if (Slic3r::store_amf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames)) { // Success - p->statusbar()->set_status_text(format_wxstr(_L("AMF file exported to %s"), path)); +// p->statusbar()->set_status_text(format_wxstr(_L("AMF file exported to %s"), path)); } else { // Failure - p->statusbar()->set_status_text(format_wxstr(_L("Error exporting AMF file %s"), path)); +// p->statusbar()->set_status_text(format_wxstr(_L("Error exporting AMF file %s"), path)); } } @@ -5625,12 +5649,12 @@ bool Plater::export_3mf(const boost::filesystem::path& output_path) bool ret = Slic3r::store_3mf(path_u8.c_str(), &p->model, export_config ? &cfg : nullptr, full_pathnames, &thumbnail_data); if (ret) { // Success - p->statusbar()->set_status_text(format_wxstr(_L("3MF file exported to %s"), path)); +// p->statusbar()->set_status_text(format_wxstr(_L("3MF file exported to %s"), path)); p->set_project_filename(path); } else { // Failure - p->statusbar()->set_status_text(format_wxstr(_L("Error exporting 3MF file %s"), path)); +// p->statusbar()->set_status_text(format_wxstr(_L("Error exporting 3MF file %s"), path)); } return ret; } @@ -6204,6 +6228,8 @@ bool Plater::set_printer_technology(PrinterTechnology printer_technology) p->sidebar->get_searcher().set_printer_technology(printer_technology); + p->notification_manager->set_fff(printer_technology == ptFFF); + return ret; } @@ -6224,7 +6250,7 @@ void Plater::clear_before_change_mesh(int obj_idx) // snapshot_time is captured by copy so the lambda knows where to undo/redo to. get_notification_manager()->push_notification( NotificationType::CustomSupportsAndSeamRemovedAfterRepair, - NotificationManager::NotificationLevel::RegularNotification, + NotificationManager::NotificationLevel::RegularNotificationLevel, _u8L("Custom supports, seams and multimaterial painting were " "removed after repairing the mesh.")); // _u8L("Undo the repair"), @@ -6237,7 +6263,7 @@ void Plater::clear_before_change_mesh(int obj_idx) // else // notification_manager->push_notification( // NotificationType::CustomSupportsAndSeamRemovedAfterRepair, -// NotificationManager::NotificationLevel::RegularNotification, +// NotificationManager::NotificationLevel::RegularNotificationLevel, // _u8L("Cannot undo to before the mesh repair!")); // return true; // }); @@ -6503,14 +6529,14 @@ Mouse3DController& Plater::get_mouse3d_controller() return p->mouse3d_controller; } -const NotificationManager* Plater::get_notification_manager() const +std::shared_ptr Plater::get_notification_manager() { return p->notification_manager; } -NotificationManager* Plater::get_notification_manager() +void Plater::init_notification_manager() { - return p->notification_manager; + p->init_notification_manager(); } bool Plater::can_delete() const { return p->can_delete(); } diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index f1a493b0f..4a98797e5 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -359,11 +359,11 @@ public: void set_bed_shape() const; void set_bed_shape(const Pointfs& shape, const std::string& custom_texture, const std::string& custom_model, bool force_as_custom = false) const; - const NotificationManager* get_notification_manager() const; - NotificationManager* get_notification_manager(); + std::shared_ptr get_notification_manager(); + void init_notification_manager(); void bring_instance_forward(); - + // ROII wrapper for suppressing the Undo / Redo snapshot to be taken. class SuppressSnapshots { diff --git a/src/slic3r/GUI/ProgressStatusBar.cpp b/src/slic3r/GUI/ProgressStatusBar.cpp index 10c391161..18485659c 100644 --- a/src/slic3r/GUI/ProgressStatusBar.cpp +++ b/src/slic3r/GUI/ProgressStatusBar.cpp @@ -194,3 +194,4 @@ void ProgressStatusBar::hide_cancel_button() } } + diff --git a/src/slic3r/GUI/ProgressStatusBar.hpp b/src/slic3r/GUI/ProgressStatusBar.hpp index 73c046be6..3ce3c8579 100644 --- a/src/slic3r/GUI/ProgressStatusBar.hpp +++ b/src/slic3r/GUI/ProgressStatusBar.hpp @@ -25,6 +25,7 @@ namespace Slic3r { * of the Slicer main window. It consists of a message area to the left and a * progress indication area to the right with an optional cancel button. */ + class ProgressStatusBar : public ProgressIndicator { wxStatusBar *self; // we cheat! It should be the base class but: perl!