From e0c5309bc3b048f94b978342f8eb16486a635760 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 14 Oct 2020 12:55:00 +0200 Subject: [PATCH 01/15] wxEVT_CREATE and wxEVT_ACTIVATE is not being called on the main frame on application start-up, at least not on Windows. wxEVT_CREATE was called for some control deep in the Plater, however the event was delivered to the main frame and only for slicer, not for G-code viewer. Thus the callbacks for 3D Mouse were not registered for and the 3D mouse did not work on Windows. Fixed by calling the callback registration from the first execution of the Idle function. --- src/PrusaSlicer.cpp | 4 +- src/libslic3r/PrintBase.hpp | 2 +- src/slic3r/GUI/GUI_App.cpp | 7 ++- src/slic3r/GUI/GUI_App.hpp | 4 +- src/slic3r/GUI/MainFrame.cpp | 117 +++++++++++++++++------------------ src/slic3r/GUI/MainFrame.hpp | 3 + 6 files changed, 71 insertions(+), 66 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index b41894ebb..ccae13815 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -588,9 +588,9 @@ int CLI::run(int argc, char **argv) // gui->autosave = m_config.opt_string("autosave"); GUI::GUI_App::SetInstance(gui); #if ENABLE_GCODE_VIEWER - gui->m_after_init_loads.set_params(load_configs, m_extra_config, m_input_files, start_as_gcodeviewer); + gui->after_init_loads.set_params(load_configs, m_extra_config, m_input_files, start_as_gcodeviewer); #else - gui->m_after_init_loads.set_params(load_configs, m_extra_config, m_input_files); + gui->after_init_loads.set_params(load_configs, m_extra_config, m_input_files); #endif // ENABLE_GCODE_VIEWER /* #if ENABLE_GCODE_VIEWER diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 647c24c1c..66851f16e 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -406,7 +406,7 @@ public: // set to an ObjectID of a Print or a PrintObject based on flags // (whether UPDATE_PRINT_STEP_WARNINGS or UPDATE_PRINT_OBJECT_STEP_WARNINGS is set). ObjectID warning_object_id; - // For which Print or PrintObject step a new warning is beeing issued? + // For which Print or PrintObject step a new warning is being issued? int warning_step { -1 }; }; typedef std::function status_callback_type; diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index d11ca1f38..f5624bb6a 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -533,7 +533,7 @@ static void generic_exception_handle() } } -void GUI_App::AFTER_INIT_LOADS::on_loads(GUI_App* gui) +void GUI_App::AfterInitLoads::on_loads(GUI_App* gui) { if (!gui->initialized()) return; @@ -847,7 +847,10 @@ bool GUI_App::on_init_inner() static bool update_gui_after_init = true; if (update_gui_after_init) { update_gui_after_init = false; - m_after_init_loads.on_loads(this); +#ifdef WIN32 + this->mainframe->register_win32_callbacks(); +#endif + this->after_init_loads.on_loads(this); } // Preset updating & Configwizard are done after the above initializations, diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index dd2d54c0d..fa2872a53 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -143,7 +143,7 @@ private: size_t m_instance_hash_int; // parameters needed for the after OnInit() loads - struct AFTER_INIT_LOADS + struct AfterInitLoads { std::vector m_load_configs; DynamicPrintConfig m_extra_config; @@ -272,7 +272,7 @@ public: PresetUpdater* preset_updater{ nullptr }; MainFrame* mainframe{ nullptr }; Plater* plater_{ nullptr }; - AFTER_INIT_LOADS m_after_init_loads; + AfterInitLoads after_init_loads; PresetUpdater* get_preset_updater() { return preset_updater; } diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 8db0bba5b..67ccd385e 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -217,65 +217,6 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S update_title(); // declare events - Bind(wxEVT_CREATE, [this](wxWindowCreateEvent& event) { - -#ifdef _WIN32 - //static GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED }; - //static GUID GUID_DEVINTERFACE_DISK = { 0x53f56307, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b }; - //static GUID GUID_DEVINTERFACE_VOLUME = { 0x71a27cdd, 0x812a, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f }; - static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 }; - - // Register USB HID (Human Interface Devices) notifications to trigger the 3DConnexion enumeration. - DEV_BROADCAST_DEVICEINTERFACE NotificationFilter = { 0 }; - NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); - NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; - NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_HID; - m_hDeviceNotify = ::RegisterDeviceNotification(this->GetHWND(), &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); - -// or register for file handle change? -// DEV_BROADCAST_HANDLE NotificationFilter = { 0 }; -// NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE); -// NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE; - - // Using Win32 Shell API to register for media insert / removal events. - LPITEMIDLIST ppidl; - if (SHGetSpecialFolderLocation(this->GetHWND(), CSIDL_DESKTOP, &ppidl) == NOERROR) { - SHChangeNotifyEntry shCNE; - shCNE.pidl = ppidl; - shCNE.fRecursive = TRUE; - // Returns a positive integer registration identifier (ID). - // Returns zero if out of memory or in response to invalid parameters. - m_ulSHChangeNotifyRegister = SHChangeNotifyRegister(this->GetHWND(), // Hwnd to receive notification - SHCNE_DISKEVENTS, // Event types of interest (sources) - SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED, - //SHCNE_UPDATEITEM, // Events of interest - use SHCNE_ALLEVENTS for all events - WM_USER_MEDIACHANGED, // Notification message to be sent upon the event - 1, // Number of entries in the pfsne array - &shCNE); // Array of SHChangeNotifyEntry structures that - // contain the notifications. This array should - // always be set to one when calling SHChnageNotifyRegister - // or SHChangeNotifyDeregister will not work properly. - assert(m_ulSHChangeNotifyRegister != 0); // Shell notification failed - } else { - // Failed to get desktop location - assert(false); - } - - { - static constexpr int device_count = 1; - RAWINPUTDEVICE devices[device_count] = { 0 }; - // multi-axis mouse (SpaceNavigator, etc.) - devices[0].usUsagePage = 0x01; - devices[0].usUsage = 0x08; - if (! RegisterRawInputDevices(devices, device_count, sizeof(RAWINPUTDEVICE))) - BOOST_LOG_TRIVIAL(error) << "RegisterRawInputDevices failed"; - } -#endif // _WIN32 - - // propagate event - event.Skip(); - }); - Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& event) { if (event.CanVeto() && !wxGetApp().check_unsaved_changes()) { event.Veto(); @@ -286,6 +227,8 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S event.Skip(); }); + //FIXME it seems this method is not called on application start-up, at least not on Windows. Why? + // The same applies to wxEVT_CREATE, it is not being called on startup on Windows. Bind(wxEVT_ACTIVATE, [this](wxActivateEvent& event) { if (m_plater != nullptr && event.GetActive()) m_plater->on_activate(); @@ -656,6 +599,62 @@ void MainFrame::init_tabpanel() } } +#ifdef WIN32 +void MainFrame::register_win32_callbacks() +{ + //static GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED }; + //static GUID GUID_DEVINTERFACE_DISK = { 0x53f56307, 0xb6bf, 0x11d0, 0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b }; + //static GUID GUID_DEVINTERFACE_VOLUME = { 0x71a27cdd, 0x812a, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, 0x2b, 0xe2, 0x09, 0x2f }; + static GUID GUID_DEVINTERFACE_HID = { 0x4D1E55B2, 0xF16F, 0x11CF, 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 }; + + // Register USB HID (Human Interface Devices) notifications to trigger the 3DConnexion enumeration. + DEV_BROADCAST_DEVICEINTERFACE NotificationFilter = { 0 }; + NotificationFilter.dbcc_size = sizeof(DEV_BROADCAST_DEVICEINTERFACE); + NotificationFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; + NotificationFilter.dbcc_classguid = GUID_DEVINTERFACE_HID; + m_hDeviceNotify = ::RegisterDeviceNotification(this->GetHWND(), &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); + +// or register for file handle change? +// DEV_BROADCAST_HANDLE NotificationFilter = { 0 }; +// NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE); +// NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE; + + // Using Win32 Shell API to register for media insert / removal events. + LPITEMIDLIST ppidl; + if (SHGetSpecialFolderLocation(this->GetHWND(), CSIDL_DESKTOP, &ppidl) == NOERROR) { + SHChangeNotifyEntry shCNE; + shCNE.pidl = ppidl; + shCNE.fRecursive = TRUE; + // Returns a positive integer registration identifier (ID). + // Returns zero if out of memory or in response to invalid parameters. + m_ulSHChangeNotifyRegister = SHChangeNotifyRegister(this->GetHWND(), // Hwnd to receive notification + SHCNE_DISKEVENTS, // Event types of interest (sources) + SHCNE_MEDIAINSERTED | SHCNE_MEDIAREMOVED, + //SHCNE_UPDATEITEM, // Events of interest - use SHCNE_ALLEVENTS for all events + WM_USER_MEDIACHANGED, // Notification message to be sent upon the event + 1, // Number of entries in the pfsne array + &shCNE); // Array of SHChangeNotifyEntry structures that + // contain the notifications. This array should + // always be set to one when calling SHChnageNotifyRegister + // or SHChangeNotifyDeregister will not work properly. + assert(m_ulSHChangeNotifyRegister != 0); // Shell notification failed + } else { + // Failed to get desktop location + assert(false); + } + + { + static constexpr int device_count = 1; + RAWINPUTDEVICE devices[device_count] = { 0 }; + // multi-axis mouse (SpaceNavigator, etc.) + devices[0].usUsagePage = 0x01; + devices[0].usUsage = 0x08; + if (! RegisterRawInputDevices(devices, device_count, sizeof(RAWINPUTDEVICE))) + BOOST_LOG_TRIVIAL(error) << "RegisterRawInputDevices failed"; + } +} +#endif // _WIN32 + void MainFrame::create_preset_tabs() { wxGetApp().update_label_colours_from_appconfig(); diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 9be9bbad9..3a8443cb8 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -156,6 +156,9 @@ public: void create_preset_tabs(); void add_created_tab(Tab* panel); bool is_active_and_shown_tab(Tab* tab); + // Register Win32 RawInput callbacks (3DConnexion) and removable media insert / remove callbacks. + // Called from wxEVT_ACTIVATE, as wxEVT_CREATE was not reliable (bug in wxWidgets?). + void register_win32_callbacks(); #if ENABLE_GCODE_VIEWER void init_menubar_as_editor(); void init_menubar_as_gcodeviewer(); From dd2cd62a4f119853ab6d1b5779b5faa20a00d87e Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 14 Oct 2020 12:57:40 +0200 Subject: [PATCH 02/15] WIP Review of NotificationManager: Fixed some typos, added some comments. --- src/slic3r/GUI/NotificationManager.cpp | 6 +++--- src/slic3r/GUI/NotificationManager.hpp | 29 +++++++++++++++++++++----- src/slic3r/GUI/Plater.cpp | 2 +- src/slic3r/Utils/PresetUpdater.cpp | 2 +- 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index e05931d87..4a63a82b0 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -25,7 +25,7 @@ namespace GUI { wxDEFINE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent); wxDEFINE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClickedEvent); -wxDEFINE_EVENT(EVT_PRESET_UPDATE_AVIABLE_CLICKED, PresetUpdateAviableClickedEvent); +wxDEFINE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent); namespace Notifications_Internal{ void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, float current_fade_opacity) @@ -531,11 +531,11 @@ void NotificationManager::PopNotification::on_text_click() if (m_evt_handler != nullptr) wxPostEvent(m_evt_handler, ExportGcodeNotificationClickedEvent(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED)); break; - case NotificationType::PresetUpdateAviable : + case NotificationType::PresetUpdateAvailable : //wxGetApp().plater()->export_gcode(false); assert(m_evt_handler != nullptr); if (m_evt_handler != nullptr) - wxPostEvent(m_evt_handler, PresetUpdateAviableClickedEvent(EVT_PRESET_UPDATE_AVIABLE_CLICKED)); + wxPostEvent(m_evt_handler, PresetUpdateAvailableClickedEvent(EVT_PRESET_UPDATE_AVAILABLE_CLICKED)); break; case NotificationType::NewAppAviable: wxLaunchDefaultBrowser("https://github.com/prusa3d/PrusaSlicer/releases"); diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 1972c9244..ecd103051 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -16,8 +16,8 @@ using EjectDriveNotificationClickedEvent = SimpleEvent; wxDECLARE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent); using ExportGcodeNotificationClickedEvent = SimpleEvent; wxDECLARE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClickedEvent); -using PresetUpdateAviableClickedEvent = SimpleEvent; -wxDECLARE_EVENT(EVT_PRESET_UPDATE_AVIABLE_CLICKED, PresetUpdateAviableClickedEvent); +using PresetUpdateAvailableClickedEvent = SimpleEvent; +wxDECLARE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent); class GLCanvas3D; class ImGuiWrapper; @@ -25,17 +25,35 @@ class ImGuiWrapper; 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, + // Not used. SlicingNotPossible, + // Notification on end of export to a removable media, with hyperling to eject the external media. ExportToRemovableFinished, + // Works on OSX only. + //FIXME Do we want to have it on Linux and Windows? Is it possible to get the Disconnect event on Windows? Mouse3dDisconnected, + // Not used. Mouse3dConnected, + // Not used. NewPresetsAviable, + // Notification on the start of PrusaSlicer, when a new PrusaSlicer version is published. + // Contains a hyperlink to open a web browser pointing to the PrusaSlicer download location. NewAppAviable, - PresetUpdateAviable, + // Notification on the start of PrusaSlicer, when updates of system profiles are detected. + // Contains a hyperlink to execute installation of the new system profiles. + PresetUpdateAvailable, + // Not used. LoadingFailed, - ValidateError, // currently not used - instead Slicing error is used for both slicing and validate errors + // Not used - instead Slicing error is used for both slicing and validate errors. + ValidateError, + // Slicing error produced by BackgroundSlicingProcess::validate() or by the BackgroundSlicingProcess background + // thread thowing a SlicingError exception. SlicingError, + // Slicing warnings, issued by the slicing process. + // Slicing warnings are registered for a Print step or a PrintObject step, SlicingWarning, PlaterError, PlaterWarning, @@ -260,12 +278,13 @@ private: //prepared (basic) notifications const std::vector basic_notifications = { + // Currently not used. {NotificationType::SlicingNotPossible, NotificationLevel::RegularNotification, 10, _u8L("Slicing is not possible.")}, {NotificationType::ExportToRemovableFinished, NotificationLevel::ImportantNotification, 0, _u8L("Exporting finished."), _u8L("Eject drive.") }, {NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") }, {NotificationType::Mouse3dConnected, NotificationLevel::RegularNotification, 5, _u8L("3D Mouse connected.") }, {NotificationType::NewPresetsAviable, NotificationLevel::ImportantNotification, 20, _u8L("New Presets are available."), _u8L("See here.") }, - {NotificationType::PresetUpdateAviable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more.")}, + {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more.")}, {NotificationType::NewAppAviable, NotificationLevel::ImportantNotification, 20, _u8L("New version is available."), _u8L("See Releases page.")}, //{NotificationType::NewAppAviable, NotificationLevel::ImportantNotification, 20, _u8L("New vesion of PrusaSlicer is available.", _u8L("Download page.") }, //{NotificationType::LoadingFailed, NotificationLevel::RegularNotification, 20, _u8L("Loading of model has Failed") }, diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ae6ebf912..f3e6fdd37 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2023,7 +2023,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) #endif // ENABLE_GCODE_VIEWER 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); }); - this->q->Bind(EVT_PRESET_UPDATE_AVIABLE_CLICKED, [this](PresetUpdateAviableClickedEvent&) { wxGetApp().get_preset_updater()->on_update_notification_confirm(); }); + this->q->Bind(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, [this](PresetUpdateAvailableClickedEvent&) { wxGetApp().get_preset_updater()->on_update_notification_confirm(); }); this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this, q](RemovableDriveEjectEvent &evt) { if (evt.data.second) { this->show_action_buttons(this->ready_to_slice); diff --git a/src/slic3r/Utils/PresetUpdater.cpp b/src/slic3r/Utils/PresetUpdater.cpp index 14b9fb0c4..b424bafc4 100644 --- a/src/slic3r/Utils/PresetUpdater.cpp +++ b/src/slic3r/Utils/PresetUpdater.cpp @@ -826,7 +826,7 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3 } } else { p->set_waiting_updates(updates); - GUI::wxGetApp().plater()->get_notification_manager()->push_notification(GUI::NotificationType::PresetUpdateAviable, *(GUI::wxGetApp().plater()->get_current_canvas3D())); + GUI::wxGetApp().plater()->get_notification_manager()->push_notification(GUI::NotificationType::PresetUpdateAvailable, *(GUI::wxGetApp().plater()->get_current_canvas3D())); } // MsgUpdateConfig will show after the notificaation is clicked From cadebab07b921b9f02f26d897daf8a21abf7aa51 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 14 Oct 2020 14:18:04 +0200 Subject: [PATCH 03/15] Notifications refactoring: Reusing ImGUI windows, commenting out dead code. --- src/slic3r/GUI/NotificationManager.cpp | 51 ++++++++++++++++----- src/slic3r/GUI/NotificationManager.hpp | 61 ++++++++++++++++---------- 2 files changed, 77 insertions(+), 35 deletions(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 4a63a82b0..a11e4c188 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -36,11 +36,34 @@ namespace Notifications_Internal{ ImGui::PushStyleColor(idx, col); } } -//ScalableBitmap bmp_icon; + +#if 1 +// Reuse ImGUI Windows. +int NotificationManager::NotificationIDProvider::allocate_id() +{ + int id; + if (m_released_ids.empty()) + id = ++m_next_id; + else { + id = m_released_ids.back(); + m_released_ids.pop_back(); + } + return id; +} +void NotificationManager::NotificationIDProvider::release_id(int id) +{ + m_released_ids.push_back(id); +} +#else +// Don't reuse ImGUI Windows, allocate a new ID every time. +int NotificationManager::NotificationIDProvider::allocate_id() { return ++ m_next_id; } +void NotificationManager::NotificationIDProvider::release_id(int) {} +#endif + //------PopNotification-------- -NotificationManager::PopNotification::PopNotification(const NotificationData &n, const int id, wxEvtHandler* evt_handler) : +NotificationManager::PopNotification::PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler) : m_data (n) - , m_id (id) + , m_id_provider (id_provider) , m_remaining_time (n.duration) , m_last_remaining_time (n.duration) , m_counting_down (n.duration != 0) @@ -71,7 +94,6 @@ NotificationManager::PopNotification::RenderResult NotificationManager::PopNotif Size cnv_size = canvas.get_canvas_size(); ImGuiWrapper& imgui = *wxGetApp().imgui(); bool shown = true; - std::string name; ImVec2 mouse_pos = ImGui::GetMousePos(); float right_gap = SPACE_RIGHT_PANEL + (move_from_overlay ? overlay_width + m_line_height * 5 : (move_from_slope ? slope_width /*+ m_line_height * 0.3f*/ : 0)); @@ -134,8 +156,15 @@ NotificationManager::PopNotification::RenderResult NotificationManager::PopNotif } //name of window - probably indentifies window and is shown so last_end add whitespaces according to id - for (size_t i = 0; i < m_id; i++) - name += " "; + if (! m_id) + m_id = m_id_provider.allocate_id(); + std::string name; + { + // Create a unique ImGUI window name. The name may be recycled using a name of an already released notification. + char buf[32]; + sprintf(buf, "!!Ntfctn%d", m_id); + name = buf; + } if (imgui.begin(name, &shown, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar )) { if (shown) { @@ -562,8 +591,8 @@ bool NotificationManager::PopNotification::compare_text(const std::string& text) return false; } -NotificationManager::SlicingCompleteLargeNotification::SlicingCompleteLargeNotification(const NotificationData& n, const int id, wxEvtHandler* evt_handler, bool large) : - NotificationManager::PopNotification(n, id, evt_handler) +NotificationManager::SlicingCompleteLargeNotification::SlicingCompleteLargeNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool large) : + NotificationManager::PopNotification(n, id_provider, evt_handler) { set_large(large); } @@ -654,7 +683,7 @@ void NotificationManager::push_slicing_warning_notification(const std::string& t { NotificationData data { NotificationType::SlicingWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }; - auto notification = std::make_unique(data, m_next_id++, m_evt_handler); + auto notification = std::make_unique(data, m_id_provider, m_evt_handler); notification->set_object_id(oid); notification->set_warning_step(warning_step); if (push_notification_data(std::move(notification), canvas, 0)) { @@ -730,7 +759,7 @@ void NotificationManager::push_slicing_complete_notification(GLCanvas3D& canvas, time = 0; } NotificationData data{ NotificationType::SlicingComplete, NotificationLevel::RegularNotification, time, _u8L("Slicing finished."), hypertext }; - push_notification_data(std::make_unique(data, m_next_id++, m_evt_handler, large), + push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, large), canvas, timestamp); } void NotificationManager::set_slicing_complete_print_time(std::string info) @@ -778,7 +807,7 @@ void NotificationManager::compare_warning_oids(const std::vector& living } bool NotificationManager::push_notification_data(const NotificationData ¬ification_data, GLCanvas3D& canvas, int timestamp) { - return push_notification_data(std::make_unique(notification_data, m_next_id++, m_evt_handler), canvas, timestamp); + return push_notification_data(std::make_unique(notification_data, m_id_provider, m_evt_handler), canvas, timestamp); } bool NotificationManager::push_notification_data(std::unique_ptr notification, GLCanvas3D& canvas, int timestamp) { diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index ecd103051..2b51c720a 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -28,37 +28,33 @@ enum class NotificationType // 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, - // Not used. - SlicingNotPossible, +// SlicingNotPossible, // Notification on end of export to a removable media, with hyperling to eject the external media. ExportToRemovableFinished, // Works on OSX only. //FIXME Do we want to have it on Linux and Windows? Is it possible to get the Disconnect event on Windows? Mouse3dDisconnected, - // Not used. - Mouse3dConnected, - // Not used. - NewPresetsAviable, +// Mouse3dConnected, +// NewPresetsAviable, // Notification on the start of PrusaSlicer, when a new PrusaSlicer version is published. // Contains a hyperlink to open a web browser pointing to the PrusaSlicer download location. NewAppAviable, // Notification on the start of PrusaSlicer, when updates of system profiles are detected. // Contains a hyperlink to execute installation of the new system profiles. PresetUpdateAvailable, - // Not used. - LoadingFailed, +// LoadingFailed, // Not used - instead Slicing error is used for both slicing and validate errors. - ValidateError, +// ValidateError, // Slicing error produced by BackgroundSlicingProcess::validate() or by the BackgroundSlicingProcess background // thread thowing a SlicingError exception. SlicingError, // Slicing warnings, issued by the slicing process. - // Slicing warnings are registered for a Print step or a PrintObject step, + // Slicing warnings are registered for a particular Print milestone or a PrintObject and its milestone. SlicingWarning, + // Object partially outside the print volume. Cannot slice. PlaterError, - PlaterWarning, - ApplyError - + // Object fully outside the print volume, or extrusion outside the print volume. Slicing is not disabled. + PlaterWarning }; class NotificationManager @@ -121,6 +117,20 @@ private: const std::string text2 = std::string(); }; + // Cache of IDs to identify and reuse ImGUI windows. + class NotificationIDProvider + { + public: + int allocate_id(); + void release_id(int id); + + private: + // Next ID used for naming the ImGUI windows. + int m_next_id{ 1 }; + // IDs of ImGUI windows, which were released and they are ready for reuse. + std::vector m_released_ids; + }; + //Pop notification - shows only once to user. class PopNotification { @@ -133,8 +143,8 @@ private: Countdown, Hovered }; - PopNotification(const NotificationData &n, const int id, wxEvtHandler* evt_handler); - virtual ~PopNotification() = default; + PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler); + virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); } RenderResult render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width, bool move_from_slope, float slope_width); // close will dissapear notification on next render void close() { m_close_pending = true; } @@ -154,6 +164,7 @@ private: void set_paused(bool p) { m_paused = p; } bool compare_text(const std::string& text); void hide(bool h) { m_hidden = h; } + protected: // Call after every size change void init(); @@ -179,7 +190,8 @@ private: const NotificationData m_data; - int m_id; + NotificationIDProvider &m_id_provider; + int m_id { 0 }; bool m_initialized { false }; // Main text std::string m_text1; @@ -227,7 +239,7 @@ private: class SlicingCompleteLargeNotification : public PopNotification { public: - SlicingCompleteLargeNotification(const NotificationData& n, const int id, wxEvtHandler* evt_handler, bool largeds); + SlicingCompleteLargeNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool largeds); void set_large(bool l); bool get_large() { return m_is_large; } @@ -246,7 +258,7 @@ private: class SlicingWarningNotification : public PopNotification { public: - SlicingWarningNotification(const NotificationData& n, const int id, wxEvtHandler* evt_handler) : PopNotification(n, id, evt_handler) {} + SlicingWarningNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler) : PopNotification(n, id_provider, evt_handler) {} void set_object_id(size_t id) { object_id = id; } const size_t get_object_id() { return object_id; } void set_warning_step(int ws) { warning_step = ws; } @@ -265,25 +277,26 @@ private: void sort_notifications(); bool has_error_notification(); + // 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; - int m_next_id { 1 }; long m_last_time { 0 }; bool m_hovered { false }; //timestamps used for slining finished - notification could be gone so it needs to be stored here std::unordered_set m_used_timestamps; bool m_in_preview { false }; bool m_move_from_overlay { false }; - bool m_move_from_slope{ false }; + bool m_move_from_slope { false }; //prepared (basic) notifications const std::vector basic_notifications = { - // Currently not used. - {NotificationType::SlicingNotPossible, NotificationLevel::RegularNotification, 10, _u8L("Slicing is not possible.")}, +// {NotificationType::SlicingNotPossible, NotificationLevel::RegularNotification, 10, _u8L("Slicing is not possible.")}, {NotificationType::ExportToRemovableFinished, NotificationLevel::ImportantNotification, 0, _u8L("Exporting finished."), _u8L("Eject drive.") }, {NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") }, - {NotificationType::Mouse3dConnected, NotificationLevel::RegularNotification, 5, _u8L("3D Mouse connected.") }, - {NotificationType::NewPresetsAviable, NotificationLevel::ImportantNotification, 20, _u8L("New Presets are available."), _u8L("See here.") }, +// {NotificationType::Mouse3dConnected, NotificationLevel::RegularNotification, 5, _u8L("3D Mouse connected.") }, +// {NotificationType::NewPresetsAviable, NotificationLevel::ImportantNotification, 20, _u8L("New Presets are available."), _u8L("See here.") }, {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more.")}, {NotificationType::NewAppAviable, NotificationLevel::ImportantNotification, 20, _u8L("New version is available."), _u8L("See Releases page.")}, //{NotificationType::NewAppAviable, NotificationLevel::ImportantNotification, 20, _u8L("New vesion of PrusaSlicer is available.", _u8L("Download page.") }, From 83bd7ce7abaab235d8c8bb7f03a2214696a2e588 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 14 Oct 2020 13:02:03 +0200 Subject: [PATCH 04/15] instance check - command line analysis - not return if only 1 argument --- src/slic3r/GUI/InstanceCheck.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/InstanceCheck.cpp b/src/slic3r/GUI/InstanceCheck.cpp index a8b1b8657..31115c6aa 100644 --- a/src/slic3r/GUI/InstanceCheck.cpp +++ b/src/slic3r/GUI/InstanceCheck.cpp @@ -35,9 +35,9 @@ namespace instance_check_internal }; static CommandLineAnalysis process_command_line(int argc, char** argv) { - CommandLineAnalysis ret { false }; - if (argc < 2) - return ret; + CommandLineAnalysis ret; + //if (argc < 2) + // return ret; std::vector arguments { argv[0] }; for (size_t i = 1; i < argc; ++i) { const std::string token = argv[i]; From 447f4b83030815f71d74242789066faa13593909 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 14 Oct 2020 16:48:56 +0200 Subject: [PATCH 05/15] Polishing of NotificationManager: Fixed pairing of PrintObjects with slicing warning notifications. Removed or commented out dead code. Added documentation. --- src/libslic3r/Print.cpp | 10 +++++ src/libslic3r/Print.hpp | 2 + src/libslic3r/PrintBase.hpp | 2 + src/libslic3r/SLAPrint.cpp | 10 +++++ src/libslic3r/SLAPrint.hpp | 2 + src/slic3r/GUI/GLCanvas3D.cpp | 11 +++--- src/slic3r/GUI/NotificationManager.cpp | 52 ++++++++++---------------- src/slic3r/GUI/NotificationManager.hpp | 44 +++++++++++++--------- src/slic3r/GUI/Plater.cpp | 24 ++++++------ 9 files changed, 89 insertions(+), 68 deletions(-) diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 01e46d227..3061693a7 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -577,6 +577,16 @@ void Print::config_diffs( } } +std::vector Print::print_object_ids() const +{ + std::vector out; + // Reserve one more for the caller to append the ID of the Print itself. + out.reserve(m_objects.size() + 1); + for (const PrintObject *print_object : m_objects) + out.emplace_back(print_object->id()); + return out; +} + Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_config) { #ifdef _DEBUG diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index a389ef00d..29cdc7249 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -370,6 +370,8 @@ public: // a cancellation callback is executed to stop the background processing before the operation. void clear() override; bool empty() const override { return m_objects.empty(); } + // List of existing PrintObject IDs, to remove notifications for non-existent IDs. + std::vector print_object_ids() const override; ApplyStatus apply(const Model &model, DynamicPrintConfig config) override; diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp index 66851f16e..bfbabd06b 100644 --- a/src/libslic3r/PrintBase.hpp +++ b/src/libslic3r/PrintBase.hpp @@ -348,6 +348,8 @@ public: // The Print is empty either after clear() or after apply() over an empty model, // or after apply() over a model, where no object is printable (all outside the print volume). virtual bool empty() const = 0; + // List of existing PrintObject IDs, to remove notifications for non-existent IDs. + virtual std::vector print_object_ids() const = 0; // Validate the print, return empty string if valid, return error if process() cannot (or should not) be started. virtual std::string validate() const { return std::string(); } diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp index a2d2ff620..54cf55cab 100644 --- a/src/libslic3r/SLAPrint.cpp +++ b/src/libslic3r/SLAPrint.cpp @@ -175,6 +175,16 @@ static std::vector sla_instances(const ModelObject &mo return instances; } +std::vector SLAPrint::print_object_ids() const +{ + std::vector out; + // Reserve one more for the caller to append the ID of the Print itself. + out.reserve(m_objects.size() + 1); + for (const SLAPrintObject *print_object : m_objects) + out.emplace_back(print_object->id()); + return out; +} + SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, DynamicPrintConfig config) { #ifdef _DEBUG diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp index 5ca1b2b8e..a4305e0c3 100644 --- a/src/libslic3r/SLAPrint.hpp +++ b/src/libslic3r/SLAPrint.hpp @@ -420,6 +420,8 @@ public: void clear() override; bool empty() const override { return m_objects.empty(); } + // List of existing PrintObject IDs, to remove notifications for non-existent IDs. + std::vector print_object_ids() const; ApplyStatus apply(const Model &model, DynamicPrintConfig config) override; void set_task(const TaskParams ¶ms) override; void process() override; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index e87fa383d..18b1aaa2c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -640,16 +640,17 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool error = true; break; } - if(state) { + auto ¬ification_manager = *wxGetApp().plater()->get_notification_manager(); + if (state) { if(error) - wxGetApp().plater()->get_notification_manager()->push_plater_error_notification(text,*(wxGetApp().plater()->get_current_canvas3D())); + notification_manager.push_plater_error_notification(text,*(wxGetApp().plater()->get_current_canvas3D())); else - wxGetApp().plater()->get_notification_manager()->push_plater_warning_notification(text, *(wxGetApp().plater()->get_current_canvas3D())); + notification_manager.push_plater_warning_notification(text, *(wxGetApp().plater()->get_current_canvas3D())); } else { if (error) - wxGetApp().plater()->get_notification_manager()->close_plater_error_notification(text); + notification_manager.close_plater_error_notification(text); else - wxGetApp().plater()->get_notification_manager()->close_plater_warning_notification(text); + notification_manager.close_plater_warning_notification(text); } /* diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index a11e4c188..922f5f91f 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -625,7 +625,7 @@ void NotificationManager::SlicingCompleteLargeNotification::render_text(ImGuiWra } } -void NotificationManager::SlicingCompleteLargeNotification::set_print_info(std::string info) +void NotificationManager::SlicingCompleteLargeNotification::set_print_info(const std::string &info) { m_print_info = info; m_has_print_info = true; @@ -679,13 +679,13 @@ void NotificationManager::push_slicing_error_notification(const std::string& tex push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, canvas, 0); close_notification_of_type(NotificationType::SlicingComplete); } -void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, size_t oid, int warning_step) +void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, ObjectID oid, int warning_step) { NotificationData data { NotificationType::SlicingWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }; auto notification = std::make_unique(data, m_id_provider, m_evt_handler); - notification->set_object_id(oid); - notification->set_warning_step(warning_step); + notification->object_id = oid; + notification->warning_step = warning_step; if (push_notification_data(std::move(notification), canvas, 0)) { notification->set_gray(gray); } @@ -732,6 +732,7 @@ void NotificationManager::set_all_slicing_warnings_gray(bool g) } } } +/* void NotificationManager::set_slicing_warning_gray(const std::string& text, bool g) { for (std::unique_ptr ¬ification : m_pop_notifications) { @@ -740,6 +741,7 @@ void NotificationManager::set_slicing_warning_gray(const std::string& text, bool } } } +*/ void NotificationManager::close_slicing_errors_and_warnings() { for (std::unique_ptr ¬ification : m_pop_notifications) { @@ -752,7 +754,7 @@ void NotificationManager::push_slicing_complete_notification(GLCanvas3D& canvas, { std::string hypertext; int time = 10; - if (has_error_notification()) + if (has_slicing_error_notification()) return; if (large) { hypertext = _u8L("Export G-Code."); @@ -762,7 +764,7 @@ void NotificationManager::push_slicing_complete_notification(GLCanvas3D& canvas, push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, large), canvas, timestamp); } -void NotificationManager::set_slicing_complete_print_time(std::string info) +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) { @@ -788,22 +790,14 @@ void NotificationManager::close_notification_of_type(const NotificationType type } } } -void NotificationManager::compare_warning_oids(const std::vector& living_oids) +void NotificationManager::remove_slicing_warnings_of_released_objects(const std::vector& living_oids) { - for (std::unique_ptr ¬ification : m_pop_notifications) { + for (std::unique_ptr ¬ification : m_pop_notifications) if (notification->get_type() == NotificationType::SlicingWarning) { - auto w = dynamic_cast(notification.get()); - bool found = false; - for (size_t oid : living_oids) { - if (w->get_object_id() == oid) { - found = true; - break; - } - } - if (!found) + if (! std::binary_search(living_oids.begin(), living_oids.end(), + static_cast(notification.get())->object_id)) notification->close(); } - } } bool NotificationManager::push_notification_data(const NotificationData ¬ification_data, GLCanvas3D& canvas, int timestamp) { @@ -839,7 +833,7 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay sort_notifications(); // iterate thru notifications and render them / erease them for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) { - if ((*it)->get_finished()) { + if (! (*it)->get_finished()) { it = m_pop_notifications.erase(it); } else { (*it)->set_paused(m_hovered); @@ -885,7 +879,8 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay void NotificationManager::sort_notifications() { - std::sort(m_pop_notifications.begin(), m_pop_notifications.end(), [](const std::unique_ptr &n1, const std::unique_ptr &n2) { + // Stable sorting, so that the order of equal ranges is stable. + std::stable_sort(m_pop_notifications.begin(), m_pop_notifications.end(), [](const std::unique_ptr &n1, const std::unique_ptr &n2) { int n1l = (int)n1->get_data().level; int n2l = (int)n2->get_data().level; if (n1l == n2l && n1->get_is_gray() && !n2->get_is_gray()) @@ -907,7 +902,7 @@ bool NotificationManager::find_older(NotificationManager::PopNotification* notif auto w1 = dynamic_cast(notification); auto w2 = dynamic_cast(it->get()); if (w1 != nullptr && w2 != nullptr) { - if (!(*it)->compare_text(text) || w1->get_object_id() != w2->get_object_id()) { + if (!(*it)->compare_text(text) || w1->object_id != w2->object_id) { continue; } } else { @@ -931,18 +926,11 @@ void NotificationManager::set_in_preview(bool preview) notification->hide(preview); } } -bool NotificationManager::has_error_notification() +bool NotificationManager::has_slicing_error_notification() { - for (std::unique_ptr ¬ification : m_pop_notifications) { - if (notification->get_data().level == NotificationLevel::ErrorNotification) - return true; - } - return false; -} - -void NotificationManager::dpi_changed() -{ - + return std::any_of(m_pop_notifications.begin(), m_pop_notifications.end(), [](auto &n) { + return n->get_type() == NotificationType::SlicingError; + }); } }//namespace GUI diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 2b51c720a..ab3d4a447 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -4,6 +4,8 @@ #include "Event.hpp" #include "I18N.hpp" +#include + #include #include #include @@ -78,30 +80,37 @@ public: // creates Slicing Error notification with custom text void push_slicing_error_notification(const std::string& text, GLCanvas3D& canvas); // creates Slicing Warning notification with custom text - void push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, size_t oid, int warning_step); + void push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, ObjectID oid, int warning_step); // marks slicing errors as gray void set_all_slicing_errors_gray(bool g); // marks slicing warings as gray void set_all_slicing_warnings_gray(bool g); - void set_slicing_warning_gray(const std::string& text, bool g); - // imidietly stops showing slicing errors +// void set_slicing_warning_gray(const std::string& text, bool g); + // immediately stops showing slicing errors void close_slicing_errors_and_warnings(); - void compare_warning_oids(const std::vector& living_oids); + // Release those slicing warnings, which refer to an ObjectID, which is not in the list. + // living_oids is expected to be sorted. + void remove_slicing_warnings_of_released_objects(const std::vector& living_oids); + // Object partially outside of the printer working space, cannot print. void push_plater_error_notification(const std::string& text, GLCanvas3D& canvas); + // Object fully out of the printer working space and such. void push_plater_warning_notification(const std::string& text, GLCanvas3D& canvas); - // Closes error or warning of same text + // Closes error or warning of the same text void close_plater_error_notification(const std::string& text); void close_plater_warning_notification(const std::string& text); // creates special notification slicing complete // if large = true prints printing time and export button void push_slicing_complete_notification(GLCanvas3D& canvas, int timestamp, bool large); - void set_slicing_complete_print_time(std::string info); + // 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); // renders notifications in queue and deletes expired ones void render_notifications(GLCanvas3D& canvas, float overlay_width, float slope_width); // finds and closes all notifications of given type void close_notification_of_type(const NotificationType type); - void dpi_changed(); + // Which view is active? Plater or G-code preview? Hide warnings in G-code preview. void set_in_preview(bool preview); // Move to left to avoid colision with variable layer height gizmo void set_move_from_overlay(bool move) { m_move_from_overlay = move; } @@ -113,8 +122,8 @@ private: NotificationLevel level; const int duration; const std::string text1; - const std::string hypertext = std::string(); - const std::string text2 = std::string(); + const std::string hypertext; + const std::string text2; }; // Cache of IDs to identify and reuse ImGUI windows. @@ -190,6 +199,7 @@ private: const NotificationData m_data; + // For reusing ImGUI windows. NotificationIDProvider &m_id_provider; int m_id { 0 }; bool m_initialized { false }; @@ -233,6 +243,7 @@ private: //if multiline = true, notification is showing all lines(>2) bool m_multiline { false }; int m_lines_count{ 1 }; + // Target for wxWidgets events sent by clicking on the hyperlink available at some notifications. wxEvtHandler* m_evt_handler; }; @@ -243,7 +254,7 @@ private: void set_large(bool l); bool get_large() { return m_is_large; } - void set_print_info(std::string info); + void set_print_info(const std::string &info); protected: virtual void render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, @@ -259,13 +270,8 @@ private: { public: SlicingWarningNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler) : PopNotification(n, id_provider, evt_handler) {} - void set_object_id(size_t id) { object_id = id; } - const size_t get_object_id() { return object_id; } - void set_warning_step(int ws) { warning_step = ws; } - const int get_warning_step() { return warning_step; } - protected: - size_t object_id; - int warning_step; + ObjectID object_id; + int warning_step; }; //pushes notification into the queue of notifications that are rendered @@ -274,8 +280,10 @@ private: bool push_notification_data(std::unique_ptr notification, GLCanvas3D& canvas, int timestamp); //finds older notification of same type and moves it to the end of queue. returns true if found bool find_older(NotificationManager::PopNotification* notification); + // Put the more important notifications to the bottom of the list. void sort_notifications(); - bool has_error_notification(); + // 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(); // Target for wxWidgets events sent by clicking on the hyperlink available at some notifications. wxEvtHandler* m_evt_handler; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index f3e6fdd37..902adaacb 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1714,7 +1714,8 @@ struct Plater::priv void clear_warnings(); void add_warning(const Slic3r::PrintStateBase::Warning &warning, size_t oid); - void actualizate_warnings(const Model& model, size_t print_oid); + // Update notification manager with the current state of warnings produced by the background process (slicing). + void actualize_slicing_warnings(const PrintBase &print); // Displays dialog window with list of warnings. // Returns true if user clicks OK. // Returns true if current_warnings vector is empty without showning the dialog @@ -2885,8 +2886,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool //actualizate warnings if (invalidated != Print::APPLY_STATUS_UNCHANGED) { - actualizate_warnings(this->q->model(), this->background_process.current_print()->id().id); - notification_manager->set_all_slicing_warnings_gray(true); + actualize_slicing_warnings(*this->background_process.current_print()); show_warning_dialog = false; process_completed_with_error = false; } @@ -3474,7 +3474,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) // Now process state.warnings. for (auto const& warning : state.warnings) { if (warning.current) { - notification_manager->push_slicing_warning_notification(warning.message, false, *q->get_current_canvas3D(), object_id.id, warning_step); + notification_manager->push_slicing_warning_notification(warning.message, false, *q->get_current_canvas3D(), object_id, warning_step); add_warning(warning, object_id.id); } } @@ -3520,19 +3520,17 @@ void Plater::priv::add_warning(const Slic3r::PrintStateBase::Warning& warning, s } current_warnings.emplace_back(std::pair(warning, oid)); } -void Plater::priv::actualizate_warnings(const Model& model, size_t print_oid) +void Plater::priv::actualize_slicing_warnings(const PrintBase &print) { - if (model.objects.size() == 0) { + std::vector ids = print.print_object_ids(); + if (ids.empty()) { clear_warnings(); return; } - std::vector living_oids; - living_oids.push_back(model.id().id); - living_oids.push_back(print_oid); - for (auto it = model.objects.begin(); it != model.objects.end(); ++it) { - living_oids.push_back((*it)->id().id); - } - notification_manager->compare_warning_oids(living_oids); + ids.emplace_back(print.id()); + std::sort(ids.begin(), ids.end()); + notification_manager->remove_slicing_warnings_of_released_objects(ids); + notification_manager->set_all_slicing_warnings_gray(true); } void Plater::priv::clear_warnings() { From 2aa76063a126b15d111232f50b2c218b03b4a178 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 14 Oct 2020 17:17:14 +0200 Subject: [PATCH 06/15] NotificationManager: Removed space reservation for "Slope visualization" dialog, which is gone. --- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.hpp | 5 +-- src/slic3r/GUI/NotificationManager.cpp | 60 +++++++++++--------------- src/slic3r/GUI/NotificationManager.hpp | 9 ++-- 4 files changed, 33 insertions(+), 43 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 18b1aaa2c..c2717761f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2088,7 +2088,7 @@ void GLCanvas3D::render() wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this); - wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overelay_window_width(), get_slope_window_width()); + wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width()); wxGetApp().imgui()->render(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 886944488..a76d9f4a0 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -243,7 +243,7 @@ private: static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y); static Rect get_bar_rect_screen(const GLCanvas3D& canvas); static Rect get_bar_rect_viewport(const GLCanvas3D& canvas); - static float get_overelay_window_width() { return LayersEditing::s_overelay_window_width; } + static float get_overlay_window_width() { return LayersEditing::s_overelay_window_width; } float object_max_z() const { return m_object_max_z; } @@ -885,8 +885,7 @@ private: bool _activate_search_toolbar_item(); bool _deactivate_collapse_toolbar_items(); - float get_overelay_window_width() { return LayersEditing::get_overelay_window_width(); } - float get_slope_window_width() { return Slope::get_window_width(); } + float get_overlay_window_width() { return LayersEditing::get_overlay_window_width(); } static std::vector _parse_colors(const std::vector& colors); diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 922f5f91f..06bd1faca 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -12,13 +12,8 @@ #include #include - - - -#define NOTIFICATION_MAX_MOVE 3.0f - -#define GAP_WIDTH 10.0f -#define SPACE_RIGHT_PANEL 10.0f +static constexpr float GAP_WIDTH = 10.0f; +static constexpr float SPACE_RIGHT_PANEL = 10.0f; namespace Slic3r { namespace GUI { @@ -28,7 +23,7 @@ wxDEFINE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClic wxDEFINE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent); namespace Notifications_Internal{ - void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, float current_fade_opacity) + static inline void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, float current_fade_opacity) { if (fading_out) ImGui::PushStyleColor(idx, ImVec4(col.x, col.y, col.z, col.w * current_fade_opacity)); @@ -74,7 +69,7 @@ NotificationManager::PopNotification::PopNotification(const NotificationData &n, { //init(); } -NotificationManager::PopNotification::RenderResult NotificationManager::PopNotification::render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width, bool move_from_slope, float slope_width) +NotificationManager::PopNotification::RenderResult NotificationManager::PopNotification::render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width) { if (!m_initialized) { init(); @@ -95,7 +90,7 @@ NotificationManager::PopNotification::RenderResult NotificationManager::PopNotif ImGuiWrapper& imgui = *wxGetApp().imgui(); bool shown = true; ImVec2 mouse_pos = ImGui::GetMousePos(); - float right_gap = SPACE_RIGHT_PANEL + (move_from_overlay ? overlay_width + m_line_height * 5 : (move_from_slope ? slope_width /*+ m_line_height * 0.3f*/ : 0)); + float right_gap = SPACE_RIGHT_PANEL + (move_from_overlay ? overlay_width + m_line_height * 5 : 0); if (m_line_height != ImGui::CalcTextSize("A").y) init(); @@ -263,12 +258,9 @@ void NotificationManager::PopNotification::init() } void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& imgui) { - if (m_multiline) { - m_window_height = m_lines_count * m_line_height; - }else - { - m_window_height = 2 * m_line_height; - } + m_window_height = m_multiline ? + m_lines_count * m_line_height : + 2 * m_line_height; m_window_height += 1 * m_line_height; // top and bottom } @@ -622,14 +614,13 @@ void NotificationManager::SlicingCompleteLargeNotification::render_text(ImGuiWra 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) + if (m_is_large) m_lines_count = 2; } void NotificationManager::SlicingCompleteLargeNotification::set_large(bool l) @@ -813,17 +804,17 @@ bool NotificationManager::push_notification_data(std::unique_ptrfind_older(notification.get())) { - m_pop_notifications.emplace_back(std::move(notification)); - canvas.request_extra_frame(); - return true; - } else { + if (this->activate_existing(notification.get())) { m_pop_notifications.back()->update(notification->get_data()); canvas.request_extra_frame(); return false; + } else { + m_pop_notifications.emplace_back(std::move(notification)); + canvas.request_extra_frame(); + return true; } } -void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay_width, float slope_width) +void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay_width) { float last_x = 0.0f; float current_height = 0.0f; @@ -837,7 +828,7 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay it = m_pop_notifications.erase(it); } else { (*it)->set_paused(m_hovered); - PopNotification::RenderResult res = (*it)->render(canvas, last_x, m_move_from_overlay, overlay_width, m_move_from_slope, slope_width); + PopNotification::RenderResult res = (*it)->render(canvas, last_x, m_move_from_overlay, overlay_width); if (res != PopNotification::RenderResult::Finished) { last_x = (*it)->get_top() + GAP_WIDTH; current_height = std::max(current_height, (*it)->get_current_top()); @@ -889,20 +880,20 @@ void NotificationManager::sort_notifications() }); } -bool NotificationManager::find_older(NotificationManager::PopNotification* notification) +bool NotificationManager::activate_existing(const NotificationManager::PopNotification* notification) { - NotificationType type = notification->get_type(); - std::string text = notification->get_data().text1; + NotificationType new_type = notification->get_type(); + const std::string &new_text = notification->get_data().text1; for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end(); ++it) { - if((*it)->get_type() == type && !(*it)->get_finished()) { - if (type == NotificationType::CustomNotification || type == NotificationType::PlaterWarning) { - if (!(*it)->compare_text(text)) + if ((*it)->get_type() == new_type && !(*it)->get_finished()) { + if (new_type == NotificationType::CustomNotification || new_type == NotificationType::PlaterWarning) { + if (!(*it)->compare_text(new_text)) continue; - }else if (type == NotificationType::SlicingWarning) { + } else if (new_type == NotificationType::SlicingWarning) { auto w1 = dynamic_cast(notification); auto w2 = dynamic_cast(it->get()); if (w1 != nullptr && w2 != nullptr) { - if (!(*it)->compare_text(text) || w1->object_id != w2->object_id) { + if (!(*it)->compare_text(new_text) || w1->object_id != w2->object_id) { continue; } } else { @@ -918,7 +909,7 @@ bool NotificationManager::find_older(NotificationManager::PopNotification* notif return false; } -void NotificationManager::set_in_preview(bool preview) +void NotificationManager::set_in_preview(bool preview) { m_in_preview = preview; for (std::unique_ptr ¬ification : m_pop_notifications) { @@ -926,6 +917,7 @@ void NotificationManager::set_in_preview(bool preview) notification->hide(preview); } } + bool NotificationManager::has_slicing_error_notification() { return std::any_of(m_pop_notifications.begin(), m_pop_notifications.end(), [](auto &n) { diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index ab3d4a447..b5b2850f0 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -107,7 +107,7 @@ public: // the "slicing info" normally shown at the side bar. void set_slicing_complete_large(bool large); // renders notifications in queue and deletes expired ones - void render_notifications(GLCanvas3D& canvas, float overlay_width, float slope_width); + void render_notifications(GLCanvas3D& canvas, float overlay_width); // finds and closes all notifications of given type void close_notification_of_type(const NotificationType type); // Which view is active? Plater or G-code preview? Hide warnings in G-code preview. @@ -154,7 +154,7 @@ private: }; PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler); virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); } - RenderResult render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width, bool move_from_slope, float slope_width); + RenderResult render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width); // close will dissapear notification on next render void close() { m_close_pending = true; } // data from newer notification of same type @@ -279,7 +279,7 @@ private: bool push_notification_data(const NotificationData& notification_data, GLCanvas3D& canvas, int timestamp); bool push_notification_data(std::unique_ptr notification, GLCanvas3D& canvas, int timestamp); //finds older notification of same type and moves it to the end of queue. returns true if found - bool find_older(NotificationManager::PopNotification* notification); + bool activate_existing(const NotificationManager::PopNotification* notification); // Put the more important notifications to the bottom of the list. void sort_notifications(); // If there is some error notification active, then the "Export G-code" notification after the slicing is finished is suppressed. @@ -292,11 +292,10 @@ private: std::deque> m_pop_notifications; long m_last_time { 0 }; bool m_hovered { false }; - //timestamps used for slining finished - notification could be gone so it needs to be stored here + //timestamps used for slicing finished - notification could be gone so it needs to be stored here std::unordered_set m_used_timestamps; bool m_in_preview { false }; bool m_move_from_overlay { false }; - bool m_move_from_slope { false }; //prepared (basic) notifications const std::vector basic_notifications = { From 607c2377499b4fd7bffa2dd6f9425f37e5a3d90e Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 14 Oct 2020 17:17:14 +0200 Subject: [PATCH 07/15] NotificationManager: Removed space reservation for "Slope visualization" dialog, which is gone. --- src/slic3r/GUI/GLCanvas3D.cpp | 2 +- src/slic3r/GUI/GLCanvas3D.hpp | 5 +- src/slic3r/GUI/NotificationManager.cpp | 64 +++++++++++--------------- src/slic3r/GUI/NotificationManager.hpp | 9 ++-- 4 files changed, 35 insertions(+), 45 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 18b1aaa2c..c2717761f 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2088,7 +2088,7 @@ void GLCanvas3D::render() wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this); - wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overelay_window_width(), get_slope_window_width()); + wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width()); wxGetApp().imgui()->render(); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 886944488..a76d9f4a0 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -243,7 +243,7 @@ private: static bool bar_rect_contains(const GLCanvas3D& canvas, float x, float y); static Rect get_bar_rect_screen(const GLCanvas3D& canvas); static Rect get_bar_rect_viewport(const GLCanvas3D& canvas); - static float get_overelay_window_width() { return LayersEditing::s_overelay_window_width; } + static float get_overlay_window_width() { return LayersEditing::s_overelay_window_width; } float object_max_z() const { return m_object_max_z; } @@ -885,8 +885,7 @@ private: bool _activate_search_toolbar_item(); bool _deactivate_collapse_toolbar_items(); - float get_overelay_window_width() { return LayersEditing::get_overelay_window_width(); } - float get_slope_window_width() { return Slope::get_window_width(); } + float get_overlay_window_width() { return LayersEditing::get_overlay_window_width(); } static std::vector _parse_colors(const std::vector& colors); diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 922f5f91f..64bafd37b 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -12,13 +12,8 @@ #include #include - - - -#define NOTIFICATION_MAX_MOVE 3.0f - -#define GAP_WIDTH 10.0f -#define SPACE_RIGHT_PANEL 10.0f +static constexpr float GAP_WIDTH = 10.0f; +static constexpr float SPACE_RIGHT_PANEL = 10.0f; namespace Slic3r { namespace GUI { @@ -28,7 +23,7 @@ wxDEFINE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClic wxDEFINE_EVENT(EVT_PRESET_UPDATE_AVAILABLE_CLICKED, PresetUpdateAvailableClickedEvent); namespace Notifications_Internal{ - void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, float current_fade_opacity) + static inline void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, float current_fade_opacity) { if (fading_out) ImGui::PushStyleColor(idx, ImVec4(col.x, col.y, col.z, col.w * current_fade_opacity)); @@ -74,7 +69,7 @@ NotificationManager::PopNotification::PopNotification(const NotificationData &n, { //init(); } -NotificationManager::PopNotification::RenderResult NotificationManager::PopNotification::render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width, bool move_from_slope, float slope_width) +NotificationManager::PopNotification::RenderResult NotificationManager::PopNotification::render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width) { if (!m_initialized) { init(); @@ -95,7 +90,7 @@ NotificationManager::PopNotification::RenderResult NotificationManager::PopNotif ImGuiWrapper& imgui = *wxGetApp().imgui(); bool shown = true; ImVec2 mouse_pos = ImGui::GetMousePos(); - float right_gap = SPACE_RIGHT_PANEL + (move_from_overlay ? overlay_width + m_line_height * 5 : (move_from_slope ? slope_width /*+ m_line_height * 0.3f*/ : 0)); + float right_gap = SPACE_RIGHT_PANEL + (move_from_overlay ? overlay_width + m_line_height * 5 : 0); if (m_line_height != ImGui::CalcTextSize("A").y) init(); @@ -263,12 +258,9 @@ void NotificationManager::PopNotification::init() } void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& imgui) { - if (m_multiline) { - m_window_height = m_lines_count * m_line_height; - }else - { - m_window_height = 2 * m_line_height; - } + m_window_height = m_multiline ? + m_lines_count * m_line_height : + 2 * m_line_height; m_window_height += 1 * m_line_height; // top and bottom } @@ -622,14 +614,13 @@ void NotificationManager::SlicingCompleteLargeNotification::render_text(ImGuiWra 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) + if (m_is_large) m_lines_count = 2; } void NotificationManager::SlicingCompleteLargeNotification::set_large(bool l) @@ -813,17 +804,17 @@ bool NotificationManager::push_notification_data(std::unique_ptrfind_older(notification.get())) { - m_pop_notifications.emplace_back(std::move(notification)); - canvas.request_extra_frame(); - return true; - } else { + if (this->activate_existing(notification.get())) { m_pop_notifications.back()->update(notification->get_data()); canvas.request_extra_frame(); return false; + } else { + m_pop_notifications.emplace_back(std::move(notification)); + canvas.request_extra_frame(); + return true; } } -void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay_width, float slope_width) +void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay_width) { float last_x = 0.0f; float current_height = 0.0f; @@ -837,7 +828,7 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay it = m_pop_notifications.erase(it); } else { (*it)->set_paused(m_hovered); - PopNotification::RenderResult res = (*it)->render(canvas, last_x, m_move_from_overlay, overlay_width, m_move_from_slope, slope_width); + PopNotification::RenderResult res = (*it)->render(canvas, last_x, m_move_from_overlay, overlay_width); if (res != PopNotification::RenderResult::Finished) { last_x = (*it)->get_top() + GAP_WIDTH; current_height = std::max(current_height, (*it)->get_current_top()); @@ -889,20 +880,20 @@ void NotificationManager::sort_notifications() }); } -bool NotificationManager::find_older(NotificationManager::PopNotification* notification) +bool NotificationManager::activate_existing(const NotificationManager::PopNotification* notification) { - NotificationType type = notification->get_type(); - std::string text = notification->get_data().text1; + NotificationType new_type = notification->get_type(); + const std::string &new_text = notification->get_data().text1; for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end(); ++it) { - if((*it)->get_type() == type && !(*it)->get_finished()) { - if (type == NotificationType::CustomNotification || type == NotificationType::PlaterWarning) { - if (!(*it)->compare_text(text)) + if ((*it)->get_type() == new_type && !(*it)->get_finished()) { + if (new_type == NotificationType::CustomNotification || new_type == NotificationType::PlaterWarning) { + if (!(*it)->compare_text(new_text)) continue; - }else if (type == NotificationType::SlicingWarning) { - auto w1 = dynamic_cast(notification); - auto w2 = dynamic_cast(it->get()); + } else if (new_type == NotificationType::SlicingWarning) { + auto w1 = dynamic_cast(notification); + auto w2 = dynamic_cast(it->get()); if (w1 != nullptr && w2 != nullptr) { - if (!(*it)->compare_text(text) || w1->object_id != w2->object_id) { + if (!(*it)->compare_text(new_text) || w1->object_id != w2->object_id) { continue; } } else { @@ -918,7 +909,7 @@ bool NotificationManager::find_older(NotificationManager::PopNotification* notif return false; } -void NotificationManager::set_in_preview(bool preview) +void NotificationManager::set_in_preview(bool preview) { m_in_preview = preview; for (std::unique_ptr ¬ification : m_pop_notifications) { @@ -926,6 +917,7 @@ void NotificationManager::set_in_preview(bool preview) notification->hide(preview); } } + bool NotificationManager::has_slicing_error_notification() { return std::any_of(m_pop_notifications.begin(), m_pop_notifications.end(), [](auto &n) { diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index ab3d4a447..b5b2850f0 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -107,7 +107,7 @@ public: // the "slicing info" normally shown at the side bar. void set_slicing_complete_large(bool large); // renders notifications in queue and deletes expired ones - void render_notifications(GLCanvas3D& canvas, float overlay_width, float slope_width); + void render_notifications(GLCanvas3D& canvas, float overlay_width); // finds and closes all notifications of given type void close_notification_of_type(const NotificationType type); // Which view is active? Plater or G-code preview? Hide warnings in G-code preview. @@ -154,7 +154,7 @@ private: }; PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler); virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); } - RenderResult render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width, bool move_from_slope, float slope_width); + RenderResult render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width); // close will dissapear notification on next render void close() { m_close_pending = true; } // data from newer notification of same type @@ -279,7 +279,7 @@ private: bool push_notification_data(const NotificationData& notification_data, GLCanvas3D& canvas, int timestamp); bool push_notification_data(std::unique_ptr notification, GLCanvas3D& canvas, int timestamp); //finds older notification of same type and moves it to the end of queue. returns true if found - bool find_older(NotificationManager::PopNotification* notification); + bool activate_existing(const NotificationManager::PopNotification* notification); // Put the more important notifications to the bottom of the list. void sort_notifications(); // If there is some error notification active, then the "Export G-code" notification after the slicing is finished is suppressed. @@ -292,11 +292,10 @@ private: std::deque> m_pop_notifications; long m_last_time { 0 }; bool m_hovered { false }; - //timestamps used for slining finished - notification could be gone so it needs to be stored here + //timestamps used for slicing finished - notification could be gone so it needs to be stored here std::unordered_set m_used_timestamps; bool m_in_preview { false }; bool m_move_from_overlay { false }; - bool m_move_from_slope { false }; //prepared (basic) notifications const std::vector basic_notifications = { From adeab9b4607bf33eb6bf6da36ba330f577ab3035 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Wed, 14 Oct 2020 17:51:51 +0200 Subject: [PATCH 08/15] Fixed bugs introduced in refactoring of NotificationManager. --- src/slic3r/GUI/NotificationManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 64bafd37b..9e6438ca4 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -678,7 +678,7 @@ void NotificationManager::push_slicing_warning_notification(const std::string& t notification->object_id = oid; notification->warning_step = warning_step; if (push_notification_data(std::move(notification), canvas, 0)) { - notification->set_gray(gray); + m_pop_notifications.back()->set_gray(gray); } } void NotificationManager::push_plater_error_notification(const std::string& text, GLCanvas3D& canvas) @@ -824,7 +824,7 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay sort_notifications(); // iterate thru notifications and render them / erease them for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) { - if (! (*it)->get_finished()) { + if ((*it)->get_finished()) { it = m_pop_notifications.erase(it); } else { (*it)->set_paused(m_hovered); From 6eee0c043ce330a146516dd8373d5d529f3660bd Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 14 Oct 2020 18:17:31 +0200 Subject: [PATCH 09/15] order of checking lockfile in instance check --- src/slic3r/GUI/InstanceCheck.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/slic3r/GUI/InstanceCheck.cpp b/src/slic3r/GUI/InstanceCheck.cpp index 31115c6aa..77d35a3e1 100644 --- a/src/slic3r/GUI/InstanceCheck.cpp +++ b/src/slic3r/GUI/InstanceCheck.cpp @@ -254,7 +254,8 @@ bool instance_check(int argc, char** argv, bool app_config_single_instance) GUI::wxGetApp().init_single_instance_checker(lock_name + ".lock", data_dir() + "/cache/"); if (cla.should_send.value() && GUI::wxGetApp().single_instance_checker()->IsAnotherRunning()) { #else // mac & linx - if (*cla.should_send && instance_check_internal::get_lock(lock_name + ".lock", data_dir() + "/cache/")) { + // get_lock() creates the lockfile therefore *cla.should_send is checked after + if (instance_check_internal::get_lock(lock_name + ".lock", data_dir() + "/cache/"&& *cla.should_send)) { #endif instance_check_internal::send_message(cla.cl_string, lock_name); BOOST_LOG_TRIVIAL(info) << "instance check: Another instance found. This instance will terminate."; From 263759aca667f0802356badb31383cccfee9c9e7 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 15 Oct 2020 07:45:36 +0200 Subject: [PATCH 10/15] Fix of Compile error in InstanceCheck.cpp on Linux (#4877) --- src/slic3r/GUI/InstanceCheck.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/slic3r/GUI/InstanceCheck.cpp b/src/slic3r/GUI/InstanceCheck.cpp index 77d35a3e1..263a1683c 100644 --- a/src/slic3r/GUI/InstanceCheck.cpp +++ b/src/slic3r/GUI/InstanceCheck.cpp @@ -255,7 +255,7 @@ bool instance_check(int argc, char** argv, bool app_config_single_instance) if (cla.should_send.value() && GUI::wxGetApp().single_instance_checker()->IsAnotherRunning()) { #else // mac & linx // get_lock() creates the lockfile therefore *cla.should_send is checked after - if (instance_check_internal::get_lock(lock_name + ".lock", data_dir() + "/cache/"&& *cla.should_send)) { + if (instance_check_internal::get_lock(lock_name + ".lock", data_dir() + "/cache/") && *cla.should_send) { #endif instance_check_internal::send_message(cla.cl_string, lock_name); BOOST_LOG_TRIVIAL(info) << "instance check: Another instance found. This instance will terminate."; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 902adaacb..cd898b4cd 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -3483,7 +3483,6 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt) void Plater::priv::on_slicing_completed(wxCommandEvent & evt) { - //notification_manager->push_notification(NotificationType::SlicingComplete, *q->get_current_canvas3D(), evt.GetInt()); notification_manager->push_slicing_complete_notification(*q->get_current_canvas3D(), evt.GetInt(), is_sidebar_collapsed()); switch (this->printer_technology) { From cc7eaef493a7b528babf0334b8911b1e079f1eaf Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 15 Oct 2020 07:54:01 +0200 Subject: [PATCH 11/15] Fix of Cmd line output does not always show correct output file name #4872 --- src/PrusaSlicer.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/PrusaSlicer.cpp b/src/PrusaSlicer.cpp index ccae13815..0663eddbb 100644 --- a/src/PrusaSlicer.cpp +++ b/src/PrusaSlicer.cpp @@ -518,9 +518,12 @@ int CLI::run(int argc, char **argv) outfile_final = sla_print.print_statistics().finalize_output_path(outfile); sla_archive.export_print(outfile_final, sla_print); } - if (outfile != outfile_final && Slic3r::rename_file(outfile, outfile_final)) { - boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; - return 1; + if (outfile != outfile_final) { + if (Slic3r::rename_file(outfile, outfile_final)) { + boost::nowide::cerr << "Renaming file " << outfile << " to " << outfile_final << " failed" << std::endl; + return 1; + } + outfile = outfile_final; } boost::nowide::cout << "Slicing result exported to " << outfile << std::endl; } catch (const std::exception &ex) { From 19a115260a01c937150f4afa67b97b0069c49afa Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 15 Oct 2020 07:58:13 +0200 Subject: [PATCH 12/15] A little bit cheaper triangle random sampling + documentation. --- src/libslic3r/SLA/SupportPointGenerator.cpp | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/SLA/SupportPointGenerator.cpp b/src/libslic3r/SLA/SupportPointGenerator.cpp index 7e884b6e3..77cee77a9 100644 --- a/src/libslic3r/SLA/SupportPointGenerator.cpp +++ b/src/libslic3r/SLA/SupportPointGenerator.cpp @@ -357,13 +357,26 @@ std::vector sample_expolygon(const ExPolygon &expoly, float samples_per_m double r = random_triangle(rng); size_t idx_triangle = std::min(std::upper_bound(areas.begin(), areas.end(), (float)r) - areas.begin(), areas.size() - 1) * 3; // Select a random point on the triangle. - double u = float(std::sqrt(random_float(rng))); - double v = float(random_float(rng)); const Vec2f &a = triangles[idx_triangle ++]; const Vec2f &b = triangles[idx_triangle++]; const Vec2f &c = triangles[idx_triangle]; - const Vec2f x = a * (1.f - u) + b * (u * (1.f - v)) + c * (v * u); - out.emplace_back(x); +#if 0 + // https://www.cs.princeton.edu/~funk/tog02.pdf + // page 814, formula 1. + double u = float(std::sqrt(random_float(rng))); + double v = float(random_float(rng)); + out.emplace_back(a * (1.f - u) + b * (u * (1.f - v)) + c * (v * u)); +#else + // Greg Turk, Graphics Gems + // https://devsplorer.wordpress.com/2019/08/07/find-a-random-point-on-a-plane-using-barycentric-coordinates-in-unity/ + double u = float(random_float(rng)); + double v = float(random_float(rng)); + if (u + v >= 1.f) { + u = 1.f - u; + v = 1.f - v; + } + out.emplace_back(a + u * (b - a) + v * (c - a)); +#endif } } return out; From 87206cd6950869eeb0f1a7d968e083fdddd7c998 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 15 Oct 2020 09:20:05 +0200 Subject: [PATCH 13/15] NotificationManager documentation improvements --- src/slic3r/GUI/NotificationManager.cpp | 7 +++++-- src/slic3r/GUI/NotificationManager.hpp | 23 +++++++++++++++-------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 9e6438ca4..eb54d3f27 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -9,9 +9,11 @@ #include #include -#include +#include #include +#include + static constexpr float GAP_WIDTH = 10.0f; static constexpr float SPACE_RIGHT_PANEL = 10.0f; @@ -638,7 +640,8 @@ NotificationManager::NotificationManager(wxEvtHandler* evt_handler) : void NotificationManager::push_notification(const NotificationType type, GLCanvas3D& canvas, int timestamp) { auto it = std::find_if(basic_notifications.begin(), basic_notifications.end(), - boost::bind(&NotificationData::type, _1) == type); + std::bind(&NotificationData::type, _1) == type); + assert(it != basic_notifications.end()); if (it != basic_notifications.end()) push_notification_data( *it, canvas, timestamp); } diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index b5b2850f0..ea43523d5 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -72,14 +72,16 @@ public: NotificationManager(wxEvtHandler* evt_handler); - // only type means one of basic_notification (see below) + // Push a prefabricated notification from basic_notifications (see the table at the end of this file). void push_notification(const NotificationType type, GLCanvas3D& canvas, int timestamp = 0); - // only text means Undefined type + // Push a NotificationType::CustomNotification with NotificationLevel::RegularNotification and 10s fade out interval. void push_notification(const std::string& text, GLCanvas3D& canvas, int timestamp = 0); + // Push a NotificationType::CustomNotification with provided notification level and 10s for RegularNotification. + // ErrorNotification and ImportantNotification are never faded out. void push_notification(const std::string& text, NotificationLevel level, GLCanvas3D& canvas, int timestamp = 0); - // creates Slicing Error notification with custom text + // Creates Slicing Error notification with a custom text and no fade out. void push_slicing_error_notification(const std::string& text, GLCanvas3D& canvas); - // creates Slicing Warning notification with custom text + // Creates Slicing Warning notification with a custom text and no fade out. void push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, ObjectID oid, int warning_step); // marks slicing errors as gray void set_all_slicing_errors_gray(bool g); @@ -91,15 +93,16 @@ public: // Release those slicing warnings, which refer to an ObjectID, which is not in the list. // living_oids is expected to be sorted. void remove_slicing_warnings_of_released_objects(const std::vector& living_oids); - // Object partially outside of the printer working space, cannot print. + // Object partially outside of the printer working space, cannot print. No fade out. void push_plater_error_notification(const std::string& text, GLCanvas3D& canvas); - // Object fully out of the printer working space and such. + // Object fully out of the printer working space and such. No fade out. void push_plater_warning_notification(const std::string& text, GLCanvas3D& canvas); // Closes error or warning of the same text void close_plater_error_notification(const std::string& text); void close_plater_warning_notification(const std::string& text); - // creates special notification slicing complete - // if large = true prints printing time and export button + // 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(GLCanvas3D& canvas, int timestamp, bool large); // Add a print time estimate to an existing SlicingComplete notification. void set_slicing_complete_print_time(const std::string &info); @@ -120,6 +123,7 @@ private: struct NotificationData { NotificationType type; NotificationLevel level; + // Fade out time const int duration; const std::string text1; const std::string hypertext; @@ -290,11 +294,14 @@ private: // Cache of IDs to identify and reuse ImGUI windows. NotificationIDProvider m_id_provider; std::deque> m_pop_notifications; + // Last render time for fade out control. long m_last_time { 0 }; bool m_hovered { false }; //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. bool m_in_preview { false }; + // True if the layer editing is enabled in Plater, so that the notifications are shifted left of it. bool m_move_from_overlay { false }; //prepared (basic) notifications From d87ca6bdc1d411e7600f934e2e53f55f98ecc2f1 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 15 Oct 2020 09:20:00 +0200 Subject: [PATCH 14/15] bring_forward on recieved other instance msg --- src/slic3r/GUI/InstanceCheckMac.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/slic3r/GUI/InstanceCheckMac.mm b/src/slic3r/GUI/InstanceCheckMac.mm index 7b3f1b222..9969b1a7b 100644 --- a/src/slic3r/GUI/InstanceCheckMac.mm +++ b/src/slic3r/GUI/InstanceCheckMac.mm @@ -19,6 +19,7 @@ -(void)message_update:(NSNotification *)msg { + [self bring_forward]; //pass message Slic3r::GUI::wxGetApp().other_instance_message_handler()->handle_message(std::string([msg.userInfo[@"data"] UTF8String])); } From b25548594d29e8121c795e82f6b8a1810f2a51c4 Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Thu, 15 Oct 2020 09:56:33 +0200 Subject: [PATCH 15/15] Notifications: Revert of substitution of boost::bind with std::bind, does not compile on all platforms. Further polishing and documentation. --- src/slic3r/GUI/GUI_App.cpp | 2 +- src/slic3r/GUI/NotificationManager.cpp | 47 +++++++++++++------------- src/slic3r/GUI/NotificationManager.hpp | 23 ++++++++----- 3 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index f5624bb6a..1e4cff2e1 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -773,7 +773,7 @@ bool GUI_App::on_init_inner() app_config->save(); if (this->plater_ != nullptr) { if (*Semver::parse(SLIC3R_VERSION) < *Semver::parse(into_u8(evt.GetString()))) { - this->plater_->get_notification_manager()->push_notification(NotificationType::NewAppAviable, *(this->plater_->get_current_canvas3D())); + this->plater_->get_notification_manager()->push_notification(NotificationType::NewAppAvailable, *(this->plater_->get_current_canvas3D())); } } }); diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index eb54d3f27..cb499b3c6 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -560,7 +559,7 @@ void NotificationManager::PopNotification::on_text_click() if (m_evt_handler != nullptr) wxPostEvent(m_evt_handler, PresetUpdateAvailableClickedEvent(EVT_PRESET_UPDATE_AVAILABLE_CLICKED)); break; - case NotificationType::NewAppAviable: + case NotificationType::NewAppAvailable: wxLaunchDefaultBrowser("https://github.com/prusa3d/PrusaSlicer/releases"); break; default: @@ -640,7 +639,7 @@ NotificationManager::NotificationManager(wxEvtHandler* evt_handler) : void NotificationManager::push_notification(const NotificationType type, GLCanvas3D& canvas, int timestamp) { auto it = std::find_if(basic_notifications.begin(), basic_notifications.end(), - std::bind(&NotificationData::type, _1) == type); + boost::bind(&NotificationData::type, _1) == type); assert(it != basic_notifications.end()); if (it != basic_notifications.end()) push_notification_data( *it, canvas, timestamp); @@ -651,21 +650,16 @@ void NotificationManager::push_notification(const std::string& text, GLCanvas3D& } void NotificationManager::push_notification(const std::string& text, NotificationManager::NotificationLevel level, GLCanvas3D& canvas, int timestamp) { - switch (level) - { - case Slic3r::GUI::NotificationManager::NotificationLevel::RegularNotification: - push_notification_data({ NotificationType::CustomNotification, level, 10, text }, canvas, timestamp); - break; - case Slic3r::GUI::NotificationManager::NotificationLevel::ErrorNotification: - push_notification_data({ NotificationType::CustomNotification, level, 0, text }, canvas, timestamp); - - break; - case Slic3r::GUI::NotificationManager::NotificationLevel::ImportantNotification: - push_notification_data({ NotificationType::CustomNotification, level, 0, text }, canvas, timestamp); - break; + int duration = 0; + switch (level) { + case NotificationLevel::RegularNotification: duration = 10; break; + case NotificationLevel::ErrorNotification: break; + case NotificationLevel::ImportantNotification: break; default: - break; + assert(false); + return; } + push_notification_data({ NotificationType::CustomNotification, level, duration, text }, canvas, timestamp); } void NotificationManager::push_slicing_error_notification(const std::string& text, GLCanvas3D& canvas) { @@ -823,7 +817,7 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay float current_height = 0.0f; bool request_next_frame = false; bool render_main = false; - bool hovered = false; + bool hovered = false; sort_notifications(); // iterate thru notifications and render them / erease them for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) { @@ -854,23 +848,30 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay if (!top_level_wnd->IsActive()) return; - if (!m_hovered && m_last_time < wxGetLocalTime()) { - if (wxGetLocalTime() - m_last_time == 1) + // Control the fade-out. + // time in seconds + long now = wxGetLocalTime(); + // Pausing fade-out when the mouse is over some notification. + if (!m_hovered && m_last_time < now) { - for(auto ¬ification : m_pop_notifications) + if (now - m_last_time == 1) { - notification->substract_remaining_time(); + for (auto ¬ification : m_pop_notifications) + { + notification->substract_remaining_time(); + } } + m_last_time = now; } - m_last_time = wxGetLocalTime(); } if (request_next_frame) + //FIXME this is very expensive for fade-out control. + // If any of the notifications is fading out, 100% of the CPU/GPU is consumed. canvas.request_extra_frame(); } - void NotificationManager::sort_notifications() { // Stable sorting, so that the order of equal ranges is stable. diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index ea43523d5..49de00a9f 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -40,7 +40,7 @@ enum class NotificationType // NewPresetsAviable, // Notification on the start of PrusaSlicer, when a new PrusaSlicer version is published. // Contains a hyperlink to open a web browser pointing to the PrusaSlicer download location. - NewAppAviable, + NewAppAvailable, // Notification on the start of PrusaSlicer, when updates of system profiles are detected. // Contains a hyperlink to execute installation of the new system profiles. PresetUpdateAvailable, @@ -64,10 +64,16 @@ class NotificationManager public: enum class NotificationLevel : int { - ErrorNotification = 4, - WarningNotification = 3, - ImportantNotification = 2, - RegularNotification = 1, + // 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, + // Information notification without a fade-out or with a longer fade-out. + ImportantNotification, + // Warning, no fade-out. + WarningNotification, + // Error, no fade-out. + ErrorNotification, }; NotificationManager(wxEvtHandler* evt_handler); @@ -294,8 +300,9 @@ private: // Cache of IDs to identify and reuse ImGUI windows. NotificationIDProvider m_id_provider; std::deque> m_pop_notifications; - // Last render time for fade out control. + // Last render time in seconds for fade out control. long m_last_time { 0 }; + // When mouse hovers over some notification, the fade-out of all notifications is suppressed. bool m_hovered { false }; //timestamps used for slicing finished - notification could be gone so it needs to be stored here std::unordered_set m_used_timestamps; @@ -312,8 +319,8 @@ private: // {NotificationType::Mouse3dConnected, NotificationLevel::RegularNotification, 5, _u8L("3D Mouse connected.") }, // {NotificationType::NewPresetsAviable, NotificationLevel::ImportantNotification, 20, _u8L("New Presets are available."), _u8L("See here.") }, {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more.")}, - {NotificationType::NewAppAviable, NotificationLevel::ImportantNotification, 20, _u8L("New version is available."), _u8L("See Releases page.")}, - //{NotificationType::NewAppAviable, NotificationLevel::ImportantNotification, 20, _u8L("New vesion of PrusaSlicer is available.", _u8L("Download page.") }, + {NotificationType::NewAppAvailable, NotificationLevel::ImportantNotification, 20, _u8L("New version is available."), _u8L("See Releases page.")}, + //{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 };