Merge remote-tracking branch 'origin/et_animations'

This commit is contained in:
enricoturri1966 2020-12-04 10:33:09 +01:00
commit 15b56c9950
8 changed files with 382 additions and 77 deletions

View file

@ -89,6 +89,7 @@
#define ENABLE_2_3_0_BETA2 1
#define ENABLE_ARROW_KEYS_WITH_SLIDERS (1 && ENABLE_2_3_0_BETA2)
#define ENABLE_NEW_NOTIFICATIONS_FADE_OUT (1 && ENABLE_2_3_0_BETA2)
#endif // _prusaslicer_technologies_h_

View file

@ -636,9 +636,9 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool
auto &notification_manager = *wxGetApp().plater()->get_notification_manager();
if (state) {
if(error)
notification_manager.push_plater_error_notification(text,*(wxGetApp().plater()->get_current_canvas3D()));
notification_manager.push_plater_error_notification(text);
else
notification_manager.push_plater_warning_notification(text, *(wxGetApp().plater()->get_current_canvas3D()));
notification_manager.push_plater_warning_notification(text);
} else {
if (error)
notification_manager.close_plater_error_notification(text);
@ -1728,8 +1728,7 @@ void GLCanvas3D::render()
m_tooltip.render(m_mouse.position, *this);
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this);
wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width());
wxGetApp().plater()->get_notification_manager()->render_notifications(get_overlay_window_width());
wxGetApp().imgui()->render();
@ -2384,6 +2383,14 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
if (!m_initialized)
return;
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
NotificationManager* notification_mgr = wxGetApp().plater()->get_notification_manager();
if (notification_mgr->requires_update())
notification_mgr->update_notifications();
m_dirty |= notification_mgr->requires_render();
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
m_dirty |= m_main_toolbar.update_items_state();
m_dirty |= m_undoredo_toolbar.update_items_state();
m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state();
@ -2391,12 +2398,24 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera());
m_dirty |= mouse3d_controller_applied;
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
if (!m_dirty) {
if (notification_mgr->requires_update())
evt.RequestMore();
return;
}
#else
if (!m_dirty)
return;
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
_refresh_if_shown_on_screen();
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
if (m_extra_frame_requested || mouse3d_controller_applied || notification_mgr->requires_update()) {
#else
if (m_extra_frame_requested || mouse3d_controller_applied) {
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
m_dirty = true;
m_extra_frame_requested = false;
evt.RequestMore();
@ -2531,7 +2550,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt)
case WXK_BACK:
case WXK_DELETE:
post_event(SimpleEvent(EVT_GLTOOLBAR_DELETE_ALL)); break;
default: evt.Skip();
default: evt.Skip();
}
}
else if ((evt.GetModifiers() & shiftMask) != 0) {

View file

@ -820,7 +820,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::NewAppAvailable, *(this->plater_->get_current_canvas3D()));
this->plater_->get_notification_manager()->push_notification(NotificationType::NewAppAvailable);
}
}
});

View file

@ -602,7 +602,7 @@ void Mouse3DController::disconnected()
m_params_by_device[m_device_str] = m_params_ui;
m_device_str.clear();
m_connected = false;
wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::Mouse3dDisconnected, *(wxGetApp().plater()->get_current_canvas3D()));
wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::Mouse3dDisconnected);
wxGetApp().plater()->CallAfter([]() {
Plater *plater = wxGetApp().plater();

View file

@ -18,6 +18,9 @@
static constexpr float GAP_WIDTH = 10.0f;
static constexpr float SPACE_RIGHT_PANEL = 10.0f;
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
static constexpr float FADING_OUT_DURATION = 2.0f;
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
namespace Slic3r {
namespace GUI {
@ -134,6 +137,96 @@ NotificationManager::PopNotification::PopNotification(const NotificationData &n,
{
//init();
}
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width)
{
if (m_hidden) {
m_top_y = initial_y - GAP_WIDTH;
return;
}
Size cnv_size = canvas.get_canvas_size();
ImGuiWrapper& imgui = *wxGetApp().imgui();
ImVec2 mouse_pos = ImGui::GetMousePos();
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();
set_next_window_size(imgui);
// top y of window
m_top_y = initial_y + m_window_height;
ImVec2 win_pos(1.0f * (float)cnv_size.get_width() - right_gap, 1.0f * (float)cnv_size.get_height() - m_top_y);
imgui.set_next_window_pos(win_pos.x, win_pos.y, ImGuiCond_Always, 1.0f, 0.0f);
imgui.set_next_window_size(m_window_width, m_window_height, ImGuiCond_Always);
// find if hovered
m_hovered = false;
if (mouse_pos.x < win_pos.x && mouse_pos.x > win_pos.x - m_window_width && mouse_pos.y > win_pos.y && mouse_pos.y < win_pos.y + m_window_height) {
ImGui::SetNextWindowFocus();
m_hovered = true;
}
// color change based on fading out
bool fading_pop = false;
if (m_fading_out) {
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_fading_out, m_current_fade_opacity);
Notifications_Internal::push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), m_fading_out, m_current_fade_opacity);
fading_pop = true;
}
// background color
if (m_is_gray) {
ImVec4 backcolor(0.7f, 0.7f, 0.7f, 0.5f);
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
}
else if (m_data.level == NotificationLevel::ErrorNotification) {
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
backcolor.x += 0.3f;
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
}
else if (m_data.level == NotificationLevel::WarningNotification) {
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
backcolor.x += 0.3f;
backcolor.y += 0.15f;
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
}
// name of window - probably indentifies window and is shown so last_end add whitespaces according to id
if (m_id == 0)
m_id = m_id_provider.allocate_id();
std::string name = "!!Ntfctn" + std::to_string(m_id);
if (imgui.begin(name, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar)) {
ImVec2 win_size = ImGui::GetWindowSize();
//FIXME: dont forget to us this for texts
//GUI::format(_utf8(L()));
/*
//countdown numbers
ImGui::SetCursorPosX(15);
ImGui::SetCursorPosY(15);
imgui.text(std::to_string(m_remaining_time).c_str());
*/
render_left_sign(imgui);
render_text(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
render_close_button(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
m_minimize_b_visible = false;
if (m_multiline && m_lines_count > 3)
render_minimize_button(imgui, win_pos.x, win_pos.y);
}
imgui.end();
if (m_is_gray || m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification)
ImGui::PopStyleColor();
if (fading_pop)
ImGui::PopStyleColor(2);
}
#else
NotificationManager::PopNotification::RenderResult NotificationManager::PopNotification::render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width)
{
if (!m_initialized) {
@ -268,6 +361,7 @@ NotificationManager::PopNotification::RenderResult NotificationManager::PopNotif
ImGui::PopStyleColor();
return ret_val;
}
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::PopNotification::count_spaces()
{
//determine line width
@ -528,6 +622,7 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img
ImGui::PopStyleColor();
ImGui::PopStyleColor();
}
#if !ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::PopNotification::render_countdown(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
/*
@ -575,6 +670,7 @@ void NotificationManager::PopNotification::render_countdown(ImGuiWrapper& imgui,
m_countdown_frame++;
*/
}
#endif // !ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::PopNotification::render_left_sign(ImGuiWrapper& imgui)
{
if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) {
@ -643,6 +739,52 @@ bool NotificationManager::PopNotification::compare_text(const std::string& text)
return false;
}
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::PopNotification::update_state()
{
if (!m_initialized)
init();
if (m_hidden) {
m_state = EState::Static;
return;
}
if (m_hovered) {
// reset fading
m_fading_out = false;
m_current_fade_opacity = 1.0f;
m_remaining_time = m_data.duration;
}
if (m_counting_down) {
if (m_fading_out && m_current_fade_opacity <= 0.0f)
m_finished = true;
else if (!m_fading_out && m_remaining_time == 0) {
m_fading_out = true;
m_fading_start = wxGetLocalTimeMillis();
}
}
if (m_finished) {
m_state = EState::Finished;
return;
}
if (m_close_pending) {
m_finished = true;
m_state = EState::ClosePending;
return;
}
if (m_fading_out) {
if (!m_paused) {
wxMilliClock_t curr_time = wxGetLocalTimeMillis() - m_fading_start;
m_current_fade_opacity = std::clamp(1.0f - 0.001f * static_cast<float>(curr_time.GetValue()) / FADING_OUT_DURATION, 0.0f, 1.0f);
}
m_state = EState::FadingOut;
}
}
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
NotificationManager::SlicingCompleteLargeNotification::SlicingCompleteLargeNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool large) :
NotificationManager::PopNotification(n, id_provider, evt_handler)
{
@ -849,19 +991,19 @@ NotificationManager::NotificationManager(wxEvtHandler* evt_handler) :
m_evt_handler(evt_handler)
{
}
void NotificationManager::push_notification(const NotificationType type, GLCanvas3D& canvas, int timestamp)
void NotificationManager::push_notification(const NotificationType type, int timestamp)
{
auto it = std::find_if(basic_notifications.begin(), basic_notifications.end(),
boost::bind(&NotificationData::type, boost::placeholders::_1) == type);
assert(it != basic_notifications.end());
if (it != basic_notifications.end())
push_notification_data( *it, canvas, timestamp);
push_notification_data(*it, timestamp);
}
void NotificationManager::push_notification(const std::string& text, GLCanvas3D& canvas, int timestamp)
void NotificationManager::push_notification(const std::string& text, int timestamp)
{
push_notification_data({ NotificationType::CustomNotification, NotificationLevel::RegularNotification, 10, text }, canvas, timestamp );
push_notification_data({ NotificationType::CustomNotification, NotificationLevel::RegularNotification, 10, text }, timestamp);
}
void NotificationManager::push_notification(const std::string& text, NotificationManager::NotificationLevel level, GLCanvas3D& canvas, int timestamp)
void NotificationManager::push_notification(const std::string& text, NotificationManager::NotificationLevel level, int timestamp)
{
int duration = 0;
switch (level) {
@ -872,32 +1014,32 @@ void NotificationManager::push_notification(const std::string& text, Notificatio
assert(false);
return;
}
push_notification_data({ NotificationType::CustomNotification, level, duration, text }, canvas, timestamp);
push_notification_data({ NotificationType::CustomNotification, level, duration, text }, timestamp);
}
void NotificationManager::push_slicing_error_notification(const std::string& text, GLCanvas3D& canvas)
void NotificationManager::push_slicing_error_notification(const std::string& text)
{
set_all_slicing_errors_gray(false);
push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, canvas, 0);
push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, 0);
close_notification_of_type(NotificationType::SlicingComplete);
}
void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, ObjectID oid, int warning_step)
void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, ObjectID oid, int warning_step)
{
NotificationData data { NotificationType::SlicingWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text };
auto notification = std::make_unique<NotificationManager::SlicingWarningNotification>(data, m_id_provider, m_evt_handler);
notification->object_id = oid;
notification->warning_step = warning_step;
if (push_notification_data(std::move(notification), canvas, 0)) {
if (push_notification_data(std::move(notification), 0)) {
m_pop_notifications.back()->set_gray(gray);
}
}
void NotificationManager::push_plater_error_notification(const std::string& text, GLCanvas3D& canvas)
void NotificationManager::push_plater_error_notification(const std::string& text)
{
push_notification_data({ NotificationType::PlaterError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, canvas, 0);
push_notification_data({ NotificationType::PlaterError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, 0);
}
void NotificationManager::push_plater_warning_notification(const std::string& text, GLCanvas3D& canvas)
void NotificationManager::push_plater_warning_notification(const std::string& text)
{
push_notification_data({ NotificationType::PlaterWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }, canvas, 0);
push_notification_data({ NotificationType::PlaterWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }, 0);
// dissaper if in preview
set_in_preview(m_in_preview);
}
@ -951,7 +1093,7 @@ void NotificationManager::close_slicing_errors_and_warnings()
}
}
}
void NotificationManager::push_slicing_complete_notification(GLCanvas3D& canvas, int timestamp, bool large)
void NotificationManager::push_slicing_complete_notification(int timestamp, bool large)
{
std::string hypertext;
int time = 10;
@ -963,8 +1105,7 @@ void NotificationManager::push_slicing_complete_notification(GLCanvas3D& canvas,
}
NotificationData data{ NotificationType::SlicingComplete, NotificationLevel::RegularNotification, time, _u8L("Slicing finished."), hypertext, [](wxEvtHandler* evnthndlr){
if (evnthndlr != nullptr) wxPostEvent(evnthndlr, ExportGcodeNotificationClickedEvent(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED)); return true; } };
push_notification_data(std::make_unique<NotificationManager::SlicingCompleteLargeNotification>(data, m_id_provider, m_evt_handler, large),
canvas, timestamp);
push_notification_data(std::make_unique<NotificationManager::SlicingCompleteLargeNotification>(data, m_id_provider, m_evt_handler, large), timestamp);
}
void NotificationManager::set_slicing_complete_print_time(const std::string &info)
{
@ -1001,38 +1142,41 @@ void NotificationManager::remove_slicing_warnings_of_released_objects(const std:
notification->close();
}
}
void NotificationManager::push_exporting_finished_notification(GLCanvas3D& canvas, std::string path, std::string dir_path, bool on_removable)
void NotificationManager::push_exporting_finished_notification(const std::string& path, const std::string& dir_path, bool on_removable)
{
close_notification_of_type(NotificationType::ExportFinished);
NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotification, 0, _u8L("Exporting finished.") +"\n"+ path };
push_notification_data(std::make_unique<NotificationManager::ExportFinishedNotification>(data, m_id_provider, m_evt_handler, on_removable, path, dir_path),
canvas, 0);
NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotification, 0, _u8L("Exporting finished.") + "\n" + path };
push_notification_data(std::make_unique<NotificationManager::ExportFinishedNotification>(data, m_id_provider, m_evt_handler, on_removable, path, dir_path), 0);
}
void NotificationManager::push_progress_bar_notification(const std::string& text, GLCanvas3D& canvas, float percentage)
void NotificationManager::push_progress_bar_notification(const std::string& text, float percentage)
{
NotificationData data{ NotificationType::ProgressBar, NotificationLevel::ProgressBarNotification, 0, text };
push_notification_data(std::make_unique<NotificationManager::ProgressBarNotification>(data, m_id_provider, m_evt_handler, 0),canvas, 0);
push_notification_data(std::make_unique<NotificationManager::ProgressBarNotification>(data, m_id_provider, m_evt_handler, 0), 0);
}
void NotificationManager::set_progress_bar_percentage(const std::string& text, float percentage, GLCanvas3D& canvas)
void NotificationManager::set_progress_bar_percentage(const std::string& text, float percentage)
{
bool found = false;
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::ProgressBar && notification->compare_text(text)) {
dynamic_cast<ProgressBarNotification*>(notification.get())->set_percentage(percentage);
canvas.request_extra_frame();
wxGetApp().plater()->get_current_canvas3D()->request_extra_frame();
found = true;
}
}
if (!found) {
push_progress_bar_notification(text, canvas, percentage);
push_progress_bar_notification(text, percentage);
}
}
bool NotificationManager::push_notification_data(const NotificationData &notification_data, GLCanvas3D& canvas, int timestamp)
bool NotificationManager::push_notification_data(const NotificationData& notification_data, int timestamp)
{
return push_notification_data(std::make_unique<PopNotification>(notification_data, m_id_provider, m_evt_handler), canvas, timestamp);
return push_notification_data(std::make_unique<PopNotification>(notification_data, m_id_provider, m_evt_handler), timestamp);
}
bool NotificationManager::push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, GLCanvas3D& canvas, int timestamp)
bool NotificationManager::push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, int timestamp)
{
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
m_requires_update = true;
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
// if timestamped notif, push only new one
if (timestamp != 0) {
if (m_used_timestamps.find(timestamp) == m_used_timestamps.end()) {
@ -1041,6 +1185,9 @@ bool NotificationManager::push_notification_data(std::unique_ptr<NotificationMan
return false;
}
}
GLCanvas3D& canvas = *wxGetApp().plater()->get_current_canvas3D();
if (this->activate_existing(notification.get())) {
m_pop_notifications.back()->update(notification->get_data());
canvas.request_extra_frame();
@ -1051,7 +1198,22 @@ bool NotificationManager::push_notification_data(std::unique_ptr<NotificationMan
return true;
}
}
void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay_width)
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::render_notifications(float overlay_width)
{
sort_notifications();
GLCanvas3D& canvas = *wxGetApp().plater()->get_current_canvas3D();
float last_y = 0.0f;
for (const auto& notification : m_pop_notifications) {
notification->render(canvas, last_y, m_move_from_overlay && !m_in_preview, overlay_width);
if (notification->get_state() != PopNotification::EState::Finished)
last_y = notification->get_top() + GAP_WIDTH;
}
}
#else
void NotificationManager::render_notifications(float overlay_width)
{
float last_x = 0.0f;
float current_height = 0.0f;
@ -1059,9 +1221,12 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay
bool render_main = false;
bool hovered = false;
sort_notifications();
// iterate thru notifications and render them / erease them
GLCanvas3D& canvas = *wxGetApp().plater()->get_current_canvas3D();
// iterate thru notifications and render them / erase them
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
if ((*it)->get_finished()) {
if ((*it)->is_finished()) {
it = m_pop_notifications.erase(it);
} else {
(*it)->set_paused(m_hovered);
@ -1111,6 +1276,7 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay
// If any of the notifications is fading out, 100% of the CPU/GPU is consumed.
canvas.request_extra_frame();
}
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::sort_notifications()
{
@ -1118,7 +1284,7 @@ void NotificationManager::sort_notifications()
std::stable_sort(m_pop_notifications.begin(), m_pop_notifications.end(), [](const std::unique_ptr<PopNotification> &n1, const std::unique_ptr<PopNotification> &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())
if (n1l == n2l && n1->is_gray() && !n2->is_gray())
return true;
return (n1l < n2l);
});
@ -1129,7 +1295,7 @@ bool NotificationManager::activate_existing(const NotificationManager::PopNotifi
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() == new_type && !(*it)->get_finished()) {
if ((*it)->get_type() == new_type && !(*it)->is_finished()) {
if (new_type == NotificationType::CustomNotification || new_type == NotificationType::PlaterWarning) {
if (!(*it)->compare_text(new_text))
continue;
@ -1162,6 +1328,78 @@ void NotificationManager::set_in_preview(bool preview)
}
}
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void NotificationManager::update_notifications()
{
static size_t last_size = 0;
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
std::unique_ptr<PopNotification>& notification = *it;
if (notification->get_state() == PopNotification::EState::Finished)
it = m_pop_notifications.erase(it);
else {
notification->set_paused(m_hovered);
notification->update_state();
++it;
}
}
m_requires_update = false;
for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->requires_update()) {
m_requires_update = true;
break;
}
}
// update hovering state
m_hovered = false;
for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->is_hovered()) {
m_hovered = true;
break;
}
}
size_t curr_size = m_pop_notifications.size();
m_requires_render = m_hovered || (last_size != curr_size);
last_size = curr_size;
if (!m_requires_render) {
for (const std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->requires_render()) {
m_requires_render = true;
break;
}
}
}
// actualizate timers
wxWindow* p = dynamic_cast<wxWindow*>(wxGetApp().plater());
while (p->GetParent() != nullptr)
p = p->GetParent();
wxTopLevelWindow* top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
if (!top_level_wnd->IsActive())
return;
{
// 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) {
if (now - m_last_time >= 1) {
for (auto& notification : m_pop_notifications) {
if (notification->get_state() != PopNotification::EState::Static)
notification->substract_remaining_time();
}
}
m_last_time = now;
}
}
}
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
bool NotificationManager::has_slicing_error_notification()
{
return std::any_of(m_pop_notifications.begin(), m_pop_notifications.end(), [](auto &n) {

View file

@ -87,16 +87,16 @@ public:
NotificationManager(wxEvtHandler* evt_handler);
// 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);
void push_notification(const NotificationType type, int timestamp = 0);
// Push a NotificationType::CustomNotification with NotificationLevel::RegularNotification and 10s fade out interval.
void push_notification(const std::string& text, GLCanvas3D& canvas, int timestamp = 0);
void push_notification(const std::string& text, int timestamp = 0);
// Push a NotificationType::CustomNotification with provided notification level and 10s for RegularNotification.
// ErrorNotification and ImportantNotification are never faded out.
void push_notification(const std::string& text, NotificationLevel level, GLCanvas3D& canvas, int timestamp = 0);
void push_notification(const std::string& text, NotificationLevel level, int timestamp = 0);
// Creates Slicing Error notification with a custom text and no fade out.
void push_slicing_error_notification(const std::string& text, GLCanvas3D& canvas);
void push_slicing_error_notification(const std::string& 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);
void push_slicing_warning_notification(const std::string& text, bool gray, ObjectID oid, int warning_step);
// marks slicing errors as gray
void set_all_slicing_errors_gray(bool g);
// marks slicing warings as gray
@ -108,39 +108,45 @@ public:
// living_oids is expected to be sorted.
void remove_slicing_warnings_of_released_objects(const std::vector<ObjectID>& living_oids);
// Object partially outside of the printer working space, cannot print. No fade out.
void push_plater_error_notification(const std::string& text, GLCanvas3D& canvas);
void push_plater_error_notification(const std::string& text);
// Object fully out of the printer working space and such. No fade out.
void push_plater_warning_notification(const std::string& text, GLCanvas3D& canvas);
void push_plater_warning_notification(const std::string& 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 (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);
void push_slicing_complete_notification(int timestamp, bool large);
// Add a print time estimate to an existing SlicingComplete notification.
void set_slicing_complete_print_time(const std::string &info);
// Called when the side bar changes its visibility, as the "slicing complete" notification supplements
// the "slicing info" normally shown at the side bar.
void set_slicing_complete_large(bool large);
// Exporting finished, show this information with path, button to open containing folder and if ejectable - eject button
void push_exporting_finished_notification(GLCanvas3D& canvas, std::string path, std::string dir_path, bool on_removable);
void push_exporting_finished_notification(const std::string& path, const std::string& dir_path, bool on_removable);
// notification with progress bar
void push_progress_bar_notification(const std::string& text, GLCanvas3D& canvas, float percentage = 0);
void set_progress_bar_percentage(const std::string& text, float percentage, GLCanvas3D& canvas);
void push_progress_bar_notification(const std::string& text, float percentage = 0);
void set_progress_bar_percentage(const std::string& text, float percentage);
// Close old notification ExportFinished.
void new_export_began(bool on_removable);
// finds ExportFinished notification and closes it if it was to removable device
void device_ejected();
// renders notifications in queue and deletes expired ones
void render_notifications(GLCanvas3D& canvas, float overlay_width);
void render_notifications(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.
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; }
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void update_notifications();
bool requires_update() const { return m_requires_update; }
bool requires_render() const { return m_requires_render; }
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
private:
// duration 0 means not disapearing
struct NotificationData {
@ -175,6 +181,17 @@ private:
class PopNotification
{
public:
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
enum class EState
{
Unknown,
Static,
Countdown,
FadingOut,
ClosePending,
Finished
};
#else
enum class RenderResult
{
Finished,
@ -183,27 +200,41 @@ private:
Countdown,
Hovered
};
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler);
virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); }
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width);
#else
RenderResult render(GLCanvas3D& canvas, const float& initial_y, bool move_from_overlay, float overlay_width);
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
// close will dissapear notification on next render
void close() { m_close_pending = true; }
// data from newer notification of same type
void update(const NotificationData& n);
bool get_finished() const { return m_finished || m_close_pending; }
bool is_finished() const { return m_finished || m_close_pending; }
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
bool is_hovered() const { return m_hovered; }
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
// returns top after movement
float get_top() const { return m_top_y; }
//returns top in actual frame
float get_current_top() const { return m_top_y; }
const NotificationType get_type() const { return m_data.type; }
const NotificationData get_data() const { return m_data; }
const bool get_is_gray() const { return m_is_gray; }
const NotificationData get_data() const { return m_data; }
const bool is_gray() const { return m_is_gray; }
// Call equals one second down
void substract_remaining_time() { m_remaining_time--; }
void set_gray(bool g) { m_is_gray = g; }
void set_paused(bool p) { m_paused = p; }
bool compare_text(const std::string& text);
void hide(bool h) { m_hidden = h; }
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void update_state();
bool requires_render() const { return m_fading_out || m_close_pending || m_finished; }
bool requires_update() const { return m_state != EState::Static; }
EState get_state() const { return m_state; }
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
protected:
// Call after every size change
@ -218,9 +249,11 @@ private:
virtual void render_close_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x , const float win_pos_y);
#if !ENABLE_NEW_NOTIFICATIONS_FADE_OUT
void render_countdown(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x , const float win_pos_y);
#endif // !ENABLE_NEW_NOTIFICATIONS_FADE_OUT
virtual void render_hypertext(ImGuiWrapper& imgui,
const float text_x, const float text_y,
const std::string text,
@ -237,7 +270,10 @@ private:
// For reusing ImGUI windows.
NotificationIDProvider &m_id_provider;
int m_id { 0 };
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
EState m_state { EState::Unknown };
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
int m_id { 0 };
bool m_initialized { false };
// Main text
std::string m_text1;
@ -252,15 +288,22 @@ private:
bool m_paused { false };
int m_countdown_frame { 0 };
bool m_fading_out { false };
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
wxMilliClock_t m_fading_start { 0LL };
#else
// total time left when fading beggins
float m_fading_time { 0.0f };
float m_current_fade_opacity { 1.f };
float m_fading_time{ 0.0f };
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
float m_current_fade_opacity { 1.0f };
// If hidden the notif is alive but not visible to user
bool m_hidden { false };
// m_finished = true - does not render, marked to delete
bool m_finished { false };
// Will go to m_finished next render
bool m_close_pending { false };
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
bool m_hovered { false };
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
// variables to count positions correctly
// all space without text
float m_window_width_offset;
@ -366,8 +409,8 @@ private:
//pushes notification into the queue of notifications that are rendered
//can be used to create custom notification
bool push_notification_data(const NotificationData& notification_data, GLCanvas3D& canvas, int timestamp);
bool push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, GLCanvas3D& canvas, int timestamp);
bool push_notification_data(const NotificationData& notification_data, int timestamp);
bool push_notification_data(std::unique_ptr<NotificationManager::PopNotification> notification, int timestamp);
//finds older notification of same type and moves it to the end of queue. returns true if found
bool activate_existing(const NotificationManager::PopNotification* notification);
// Put the more important notifications to the bottom of the list.
@ -390,6 +433,10 @@ private:
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 };
#if ENABLE_NEW_NOTIFICATIONS_FADE_OUT
bool m_requires_update{ false };
bool m_requires_render{ false };
#endif // ENABLE_NEW_NOTIFICATIONS_FADE_OUT
//prepared (basic) notifications
const std::vector<NotificationData> basic_notifications = {

View file

@ -2115,12 +2115,12 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
if (evt.data.second) {
this->show_action_buttons(this->ready_to_slice);
notification_manager->close_notification_of_type(NotificationType::ExportFinished);
notification_manager->push_notification(format(_L("Successfully unmounted. The device %s(%s) can now be safely removed from the computer."),evt.data.first.name, evt.data.first.path),
NotificationManager::NotificationLevel::RegularNotification, *q->get_current_canvas3D());
} else {
notification_manager->push_notification(format(_L("Ejecting of device %s(%s) has failed."), evt.data.first.name, evt.data.first.path),
NotificationManager::NotificationLevel::ErrorNotification, *q->get_current_canvas3D());
}
notification_manager->push_notification(format(_L("Successfully unmounted. The device %s(%s) can now be safely removed from the computer."), evt.data.first.name, evt.data.first.path),
NotificationManager::NotificationLevel::RegularNotification);
} else {
notification_manager->push_notification(format(_L("Ejecting of device %s(%s) has failed."), evt.data.first.name, evt.data.first.path),
NotificationManager::NotificationLevel::ErrorNotification);
}
});
this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this, q](RemovableDrivesChangedEvent &) {
this->show_action_buttons(this->ready_to_slice);
@ -2948,7 +2948,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
} else {
// The print is not valid.
// Show error as notification.
notification_manager->push_slicing_error_notification(err, *q->get_current_canvas3D());
notification_manager->push_slicing_error_notification(err);
return_state |= UPDATE_BACKGROUND_PROCESS_INVALID;
}
} else if (! this->delayed_error_message.empty()) {
@ -3509,7 +3509,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
this->statusbar()->set_progress(evt.status.percent);
this->statusbar()->set_status_text(_(evt.status.text) + wxString::FromUTF8(""));
//notification_manager->set_progress_bar_percentage("Slicing progress", (float)evt.status.percent / 100.0f, *q->get_current_canvas3D());
//notification_manager->set_progress_bar_percentage("Slicing progress", (float)evt.status.percent / 100.0f);
}
if (evt.status.flags & (PrintBase::SlicingStatus::RELOAD_SCENE | PrintBase::SlicingStatus::RELOAD_SLA_SUPPORT_POINTS)) {
switch (this->printer_technology) {
@ -3551,8 +3551,8 @@ 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, warning_step);
add_warning(warning, object_id.id);
notification_manager->push_slicing_warning_notification(warning.message, false, object_id, warning_step);
add_warning(warning, object_id.id);
}
}
}
@ -3560,7 +3560,7 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
void Plater::priv::on_slicing_completed(wxCommandEvent & evt)
{
notification_manager->push_slicing_complete_notification(*q->get_current_canvas3D(), evt.GetInt(), is_sidebar_collapsed());
notification_manager->push_slicing_complete_notification(evt.GetInt(), is_sidebar_collapsed());
switch (this->printer_technology) {
case ptFFF:
this->update_fff_scene();
@ -3655,7 +3655,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
else
show_error(q, message.first, message.second);
} else
notification_manager->push_slicing_error_notification(message.first, *q->get_current_canvas3D());
notification_manager->push_slicing_error_notification(message.first);
this->statusbar()->set_status_text(from_u8(message.first));
if (evt.invalidate_plater())
{
@ -3701,10 +3701,10 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
// If writing to removable drive was scheduled, show notification with eject button
if (exporting_status == ExportingStatus::EXPORTING_TO_REMOVABLE && !has_error) {
show_action_buttons(false);
notification_manager->push_exporting_finished_notification(*q->get_current_canvas3D(), last_output_path, last_output_dir_path, true);
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, true);
wxGetApp().removable_drive_manager()->set_exporting_finished(true);
}else if (exporting_status == ExportingStatus::EXPORTING_TO_LOCAL && !has_error)
notification_manager->push_exporting_finished_notification(*q->get_current_canvas3D(), last_output_path, last_output_dir_path, false);
notification_manager->push_exporting_finished_notification(last_output_path, last_output_dir_path, false);
}
exporting_status = ExportingStatus::NOT_EXPORTING;
}

View file

@ -827,7 +827,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::PresetUpdateAvailable, *(GUI::wxGetApp().plater()->get_current_canvas3D()));
GUI::wxGetApp().plater()->get_notification_manager()->push_notification(GUI::NotificationType::PresetUpdateAvailable);
}
// MsgUpdateConfig will show after the notificaation is clicked