From c41df487bb5821a9271e547ab97d424e1e9b6afa Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 8 Feb 2021 16:14:35 +0100 Subject: [PATCH 01/10] Notifications management and rendering refactoring. With warning notification Model out of bed reworked to not show after dismiss. --- src/slic3r/GUI/3DScene.cpp | 51 ++++ src/slic3r/GUI/3DScene.hpp | 1 + src/slic3r/GUI/GLCanvas3D.cpp | 65 +++-- src/slic3r/GUI/GLCanvas3D.hpp | 3 +- src/slic3r/GUI/NotificationManager.cpp | 385 ++++++++++--------------- src/slic3r/GUI/NotificationManager.hpp | 112 ++++--- 6 files changed, 293 insertions(+), 324 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 4cab8f3db9..6c226cd74d 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -845,6 +845,57 @@ bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, M return contained_min_one; } +bool GLVolumeCollection::check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut) +{ + if (config == nullptr) + return false; + + const ConfigOptionPoints* opt = dynamic_cast(config->option("bed_shape")); + if (opt == nullptr) + return false; + + BoundingBox bed_box_2D = get_extents(Polygon::new_scale(opt->values)); + BoundingBoxf3 print_volume(Vec3d(unscale(bed_box_2D.min(0)), unscale(bed_box_2D.min(1)), 0.0), Vec3d(unscale(bed_box_2D.max(0)), unscale(bed_box_2D.max(1)), config->opt_float("max_print_height"))); + // Allow the objects to protrude below the print bed + print_volume.min(2) = -1e10; + print_volume.min(0) -= BedEpsilon; + print_volume.min(1) -= BedEpsilon; + print_volume.max(0) += BedEpsilon; + print_volume.max(1) += BedEpsilon; + + bool contained_min_one = false; + + partlyOut = false; + fullyOut = false; + for (GLVolume* volume : this->volumes) + { + if ((volume == nullptr) || volume->is_modifier || (volume->is_wipe_tower && !volume->shader_outside_printer_detection_enabled) || ((volume->composite_id.volume_id < 0) && !volume->shader_outside_printer_detection_enabled)) + continue; + + const BoundingBoxf3& bb = volume->transformed_convex_hull_bounding_box(); + bool contained = print_volume.contains(bb); + + volume->is_outside = !contained; + if (!volume->printable) + continue; + + if (contained) + contained_min_one = true; + + if (volume->is_outside) { + if (print_volume.intersects(bb)) + partlyOut = true; + else + fullyOut = true; + } + } + /* + if (out_state != nullptr) + *out_state = state; + */ + return contained_min_one; +} + void GLVolumeCollection::reset_outside_state() { for (GLVolume* volume : this->volumes) diff --git a/src/slic3r/GUI/3DScene.hpp b/src/slic3r/GUI/3DScene.hpp index e4d9c60672..2ae2a36b29 100644 --- a/src/slic3r/GUI/3DScene.hpp +++ b/src/slic3r/GUI/3DScene.hpp @@ -569,6 +569,7 @@ public: // returns true if all the volumes are completely contained in the print volume // returns the containment state in the given out_state, if non-null bool check_outside_state(const DynamicPrintConfig* config, ModelInstanceEPrintVolumeState* out_state); + bool check_outside_state(const DynamicPrintConfig* config, bool& partlyOut, bool& fullyOut); void reset_outside_state(); void update_colors_by_extruder(const DynamicPrintConfig* config); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a45f61cabd..0a2b5cd655 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -641,6 +641,7 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool error = true; break; } + BOOST_LOG_TRIVIAL(error) << state << " : " << text ; auto ¬ification_manager = *wxGetApp().plater()->get_notification_manager(); if (state) { if(error) @@ -1620,9 +1621,6 @@ void GLCanvas3D::render() wxGetApp().plater()->init_environment_texture(); #endif // ENABLE_ENVIRONMENT_MAP - m_render_timer.Stop(); - m_extra_frame_requested_delayed = std::numeric_limits::max(); - const Size& cnv_size = get_canvas_size(); // Probably due to different order of events on Linux/GTK2, when one switched from 3D scene // to preview, this was called before canvas had its final size. It reported zero width @@ -1754,7 +1752,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(get_overlay_window_width()); + wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width()); wxGetApp().imgui()->render(); @@ -2238,24 +2236,24 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // checks for geometry outside the print volume to render it accordingly if (!m_volumes.empty()) { - ModelInstanceEPrintVolumeState state; - - const bool contained_min_one = m_volumes.check_outside_state(m_config, &state); + bool partlyOut = false; + bool fullyOut = false; + const bool contained_min_one = m_volumes.check_outside_state(m_config, partlyOut, fullyOut); #if ENABLE_WARNING_TEXTURE_REMOVAL - _set_warning_notification(EWarning::ObjectClashed, state == ModelInstancePVS_Partly_Outside); - _set_warning_notification(EWarning::ObjectOutside, state == ModelInstancePVS_Fully_Outside); - if (printer_technology != ptSLA || state == ModelInstancePVS_Inside) + _set_warning_notification(EWarning::ObjectClashed, partlyOut); + _set_warning_notification(EWarning::ObjectOutside, fullyOut); + if (printer_technology != ptSLA || !contained_min_one) _set_warning_notification(EWarning::SlaSupportsOutside, false); #else - _set_warning_texture(WarningTexture::ObjectClashed, state == ModelInstancePVS_Partly_Outside); - _set_warning_texture(WarningTexture::ObjectOutside, state == ModelInstancePVS_Fully_Outside); - if(printer_technology != ptSLA || state == ModelInstancePVS_Inside) + _set_warning_texture(WarningTexture::ObjectClashed, partlyOut); + _set_warning_texture(WarningTexture::ObjectOutside, fullyOut); + if(printer_technology != ptSLA || !contained_min_one) _set_warning_texture(WarningTexture::SlaSupportsOutside, false); #endif // ENABLE_WARNING_TEXTURE_REMOVAL post_event(Event(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, - contained_min_one && !m_model->objects.empty() && state != ModelInstancePVS_Partly_Outside)); + contained_min_one && !m_model->objects.empty() && !partlyOut)); } else { #if ENABLE_WARNING_TEXTURE_REMOVAL @@ -2442,13 +2440,13 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt) if (!m_initialized) return; - // FIXME 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(); m_dirty |= wxGetApp().plater()->get_collapse_toolbar().update_items_state(); bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera()); m_dirty |= mouse3d_controller_applied; + m_dirty |= wxGetApp().plater()->get_notification_manager()->update_notifications(*this); if (!m_dirty) return; @@ -2982,30 +2980,39 @@ void GLCanvas3D::on_timer(wxTimerEvent& evt) void GLCanvas3D::on_render_timer(wxTimerEvent& evt) { - // If slicer is not top window -> restart timer with one second to try again - wxWindow* p = dynamic_cast(wxGetApp().plater()); - while (p->GetParent() != nullptr) - p = p->GetParent(); - wxTopLevelWindow* top_level_wnd = dynamic_cast(p); - if (!top_level_wnd->IsActive()) { - request_extra_frame_delayed(1000); - return; - } - //render(); - m_dirty = true; - wxWakeUpIdle(); + // no need to do anything here + // right after this event is recieved, idle event is fired + + //m_dirty = true; + //wxWakeUpIdle(); } -void GLCanvas3D::request_extra_frame_delayed(int miliseconds) + +void GLCanvas3D::schedule_extra_frame(int miliseconds) { + // Schedule idle event right now + if (miliseconds == 0) + { + // We want to wakeup idle evnt but most likely this is call inside render cycle so we need to wait + if (m_in_render) + miliseconds = 33; + else { + m_dirty = true; + wxWakeUpIdle(); + return; + } + } + // Start timer int64_t now = timestamp_now(); + // Timer is not running if (! m_render_timer.IsRunning()) { m_extra_frame_requested_delayed = miliseconds; m_render_timer.StartOnce(miliseconds); m_render_timer_start = now; + // Timer is running - restart only if new period is shorter than remaning period } else { const int64_t remaining_time = (m_render_timer_start + m_extra_frame_requested_delayed) - now; - if (miliseconds < remaining_time) { + if (miliseconds + 20 < remaining_time) { m_render_timer.Stop(); m_extra_frame_requested_delayed = miliseconds; m_render_timer.StartOnce(miliseconds); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 10294931fe..f4d862b66c 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -743,7 +743,8 @@ public: void msw_rescale(); void request_extra_frame() { m_extra_frame_requested = true; } - void request_extra_frame_delayed(int miliseconds); + + void schedule_extra_frame(int miliseconds); int get_main_toolbar_item_id(const std::string& name) const { return m_main_toolbar.get_item_id(name); } void force_main_toolbar_left_action(int item_id) { m_main_toolbar.force_left_action(item_id, *this); } diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index a6fd9cfd3c..41c8e8f6fc 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -22,9 +22,6 @@ static constexpr float SPACE_RIGHT_PANEL = 10.0f; static constexpr float FADING_OUT_DURATION = 2.0f; // Time in Miliseconds after next render when fading out is requested static constexpr int FADING_OUT_TIMEOUT = 100; -// If timeout is changed to higher than 1 second, substract_time call should be revorked -//static constexpr int MAX_TIMEOUT_MILISECONDS = 1000; -//static constexpr int MAX_TIMEOUT_SECONDS = 1; namespace Slic3r { namespace GUI { @@ -131,35 +128,29 @@ void NotificationManager::NotificationIDProvider::release_id(int) {} NotificationManager::PopNotification::PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler) : m_data (n) , m_id_provider (id_provider) - , m_remaining_time (n.duration) - , m_last_remaining_time (n.duration) - , m_counting_down (n.duration != 0) , m_text1 (n.text1) , m_hypertext (n.hypertext) , m_text2 (n.text2) , m_evt_handler (evt_handler) , m_notification_start (GLCanvas3D::timestamp_now()) -{ - //init(); -} +{} void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width) { - if (!m_initialized) + + if (m_state == EState::Unknown) init(); - if (m_hidden) { + if (m_state == EState::Hidden) { m_top_y = initial_y - GAP_WIDTH; return; } - if (m_fading_out) - m_last_render_fading = GLCanvas3D::timestamp_now(); - - Size cnv_size = canvas.get_canvas_size(); + 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); + ImVec2 mouse_pos = ImGui::GetMousePos(); + float right_gap = SPACE_RIGHT_PANEL + (move_from_overlay ? overlay_width + m_line_height * 5 : 0); + bool fading_pop = false; if (m_line_height != ImGui::CalcTextSize("A").y) init(); @@ -174,54 +165,46 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init imgui.set_next_window_size(m_window_width, m_window_height, ImGuiCond_Always); // find if hovered - m_hovered = false; + if (m_state == EState::Hovered) + m_state = EState::Shown; + 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; + m_state = EState::Hovered; } - + // 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); + if (m_state == EState::FadingOut) { + Notifications_Internal::push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), true, m_current_fade_opacity); + Notifications_Internal::push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), true, 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); + Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, 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); + Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, 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); + Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_state == EState::FadingOut, m_current_fade_opacity); } - - // name of window - probably indentifies window and is shown so last_end add whitespaces according to id + + // name of window indentifies window - has to be unique string 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); @@ -253,6 +236,7 @@ void NotificationManager::PopNotification::count_spaces() m_window_width_offset = m_left_indentation + m_line_height * 3.f; m_window_width = m_line_height * 25; } + void NotificationManager::PopNotification::init() { std::string text = m_text1 + " " + m_hypertext; @@ -306,7 +290,7 @@ void NotificationManager::PopNotification::init() } if (m_lines_count == 3) m_multiline = true; - m_initialized = true; + m_state = EState::Shown; } void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& imgui) { @@ -423,8 +407,8 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui, m_multiline = true; set_next_window_size(imgui); } - else { - m_close_pending = on_text_click(); + else if (on_text_click()) { + close(); } } ImGui::PopStyleColor(); @@ -432,12 +416,12 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui, ImGui::PopStyleColor(); //hover color - ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f);//ImGui::GetStyleColorVec4(ImGuiCol_Button); + ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f); if (ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly)) orange_color.y += 0.2f; //text - Notifications_Internal::push_style_color(ImGuiCol_Text, orange_color, m_fading_out, m_current_fade_opacity); + Notifications_Internal::push_style_color(ImGuiCol_Text, orange_color, m_state == EState::FadingOut, m_current_fade_opacity); ImGui::SetCursorPosX(text_x); ImGui::SetCursorPosY(text_y); imgui.text(text.c_str()); @@ -448,7 +432,7 @@ void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui, lineEnd.y -= 2; ImVec2 lineStart = lineEnd; lineStart.x = ImGui::GetItemRectMin().x; - ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.w * 255.f * (m_fading_out ? m_current_fade_opacity : 1.f)))); + ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.w * 255.f * (m_state == EState::FadingOut ? m_current_fade_opacity : 1.f)))); } @@ -458,12 +442,11 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img ImVec2 win_pos(win_pos_x, win_pos_y); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); - Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity); - Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity); + Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); - //button - if part if treggered std::string button_text; button_text = ImGui::CloseNotifButton; @@ -479,7 +462,7 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img ImGui::SetCursorPosY(win_size.y / 2 - button_size.y); if (imgui.button(button_text.c_str(), button_size.x, button_size.y)) { - m_close_pending = true; + close(); } //invisible large button @@ -487,7 +470,7 @@ void NotificationManager::PopNotification::render_close_button(ImGuiWrapper& img ImGui::SetCursorPosY(0); if (imgui.button(" ", m_line_height * 2.125, win_size.y - ( m_minimize_b_visible ? 2 * m_line_height : 0))) { - m_close_pending = true; + close(); } ImGui::PopStyleColor(); ImGui::PopStyleColor(); @@ -510,9 +493,9 @@ void NotificationManager::PopNotification::render_minimize_button(ImGuiWrapper& { ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); - Notifications_Internal::push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_fading_out, m_current_fade_opacity); - Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity); - Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity); + Notifications_Internal::push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_state == EState::FadingOut, m_current_fade_opacity); + Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); //button - if part if treggered @@ -564,71 +547,56 @@ bool NotificationManager::PopNotification::compare_text(const std::string& text) return false; } -void NotificationManager::PopNotification::update_state() +void NotificationManager::PopNotification::update_state(bool paused, const int64_t delta) { - if (!m_initialized) + if (m_state == EState::Unknown) init(); m_next_render = std::numeric_limits::max(); - if (m_hidden) { - m_state = EState::Hidden; + if (m_state == EState::Hidden) { return; } int64_t now = GLCanvas3D::timestamp_now(); - if (m_hovered) { - // reset fading - m_fading_out = false; + // reset timers - hovered state is set in render + if (m_state == EState::Hovered) { m_current_fade_opacity = 1.0f; - m_remaining_time = m_data.duration; m_notification_start = now; - } - - - - if (m_counting_down) { + // Timers when not fading + } else if (m_data.duration != 0 && !paused) { int64_t up_time = now - m_notification_start; - - if (m_fading_out && m_current_fade_opacity <= 0.0f) - m_finished = true; - else if (!m_fading_out && /*m_remaining_time <=0*/up_time >= m_data.duration * 1000) { - m_fading_out = true; - m_fading_start = now; - m_last_render_fading = now; - } else if (!m_fading_out) { - m_next_render = m_data.duration * 1000 - up_time;//std::min(/*m_data.duration * 1000 - up_time*/m_remaining_time * 1000, MAX_TIMEOUT_MILISECONDS); - } - + if (m_state != EState::FadingOut && up_time >= m_data.duration * 1000) { + m_state = EState::FadingOut; + m_fading_start = now; + } else if (m_state != EState::FadingOut) { + m_next_render = m_data.duration * 1000 - up_time; + } } - - if (m_finished) { + // Timers when fading + if (m_state == EState::FadingOut && !paused) { + int64_t curr_time = now - m_fading_start; + int64_t next_render = FADING_OUT_TIMEOUT - delta; + m_current_fade_opacity = std::clamp(1.0f - 0.001f * static_cast(curr_time) / FADING_OUT_DURATION, 0.0f, 1.0f); + if (m_current_fade_opacity <= 0.0f) + m_state = EState::Finished; + else if (next_render < 0) + m_next_render = 0; + else + m_next_render = next_render; + } + + if (m_state == EState::Finished) { + m_next_render = 0; + return; + } + + if (m_state == EState::ClosePending) { m_state = EState::Finished; m_next_render = 0; return; } - if (m_close_pending) { - m_finished = true; - m_state = EState::ClosePending; - m_next_render = 0; - return; - } - if (m_fading_out) { - if (!m_paused) { - m_state = EState::FadingOutStatic; - int64_t curr_time = now - m_fading_start; - int64_t no_render_time = now - m_last_render_fading; - m_current_fade_opacity = std::clamp(1.0f - 0.001f * static_cast(curr_time) / FADING_OUT_DURATION, 0.0f, 1.0f); - auto next_render = FADING_OUT_TIMEOUT - no_render_time; - if (next_render <= 0) { - //m_last_render_fading = GLCanvas3D::timestamp_now(); - m_state = EState::FadingOutRender; - m_next_render = 0; - } else - m_next_render = next_render; - } - } } NotificationManager::SlicingCompleteLargeNotification::SlicingCompleteLargeNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool large) : @@ -672,9 +640,10 @@ void NotificationManager::SlicingCompleteLargeNotification::set_print_info(const void NotificationManager::SlicingCompleteLargeNotification::set_large(bool l) { m_is_large = l; - m_counting_down = !l; + //FIXME this information should not be lost (change m_data?) +// m_counting_down = !l; m_hypertext = l ? _u8L("Export G-Code.") : std::string(); - m_hidden = !l; + m_state = l ? EState::Shown : EState::Hidden; } //---------------ExportFinishedNotification----------- void NotificationManager::ExportFinishedNotification::count_spaces() @@ -733,8 +702,8 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW ImVec2 win_pos(win_pos_x, win_pos_y); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); - Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity); - Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity); + Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); std::string button_text; @@ -768,7 +737,7 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW assert(m_evt_handler != nullptr); if (m_evt_handler != nullptr) wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED)); - m_close_pending = true; + close(); } //invisible large button @@ -779,7 +748,7 @@ void NotificationManager::ExportFinishedNotification::render_eject_button(ImGuiW assert(m_evt_handler != nullptr); if (m_evt_handler != nullptr) wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED)); - m_close_pending = true; + close(); } ImGui::PopStyleColor(); ImGui::PopStyleColor(); @@ -807,22 +776,12 @@ void NotificationManager::ProgressBarNotification::render_text(ImGuiWrapper& img void NotificationManager::ProgressBarNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f); - float invisible_length = 0;//((float)(m_data.duration - m_remaining_time) / (float)m_data.duration * win_size_x); - //invisible_length -= win_size_x / ((float)m_data.duration * 60.f) * (60 - m_countdown_frame); + float invisible_length = 0; + ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length - m_window_width_offset, win_pos_y + win_size_y/2 + m_line_height / 2); ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y/2 + m_line_height / 2); ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.7f); - /* - //countdown line - ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button); - float invisible_length = ((float)(m_data.duration - m_remaining_time) / (float)m_data.duration * win_size_x); - invisible_length -= win_size_x / ((float)m_data.duration * 60.f) * (60 - m_countdown_frame); - ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length, win_pos_y + win_size_y - 5); - ImVec2 lineStart = ImVec2(win_pos_x - win_size_x, win_pos_y + win_size_y - 5); - ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.picture_width * 255.f * (m_fading_out ? m_current_fade_opacity : 1.f))), 2.f); - if (!m_paused) - m_countdown_frame++; - */ + } //------NotificationManager-------- NotificationManager::NotificationManager(wxEvtHandler* evt_handler) : @@ -881,12 +840,7 @@ void NotificationManager::push_plater_error_notification(const std::string& text { push_notification_data({ NotificationType::PlaterError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, 0); } -void NotificationManager::push_plater_warning_notification(const std::string& text) -{ - push_notification_data({ NotificationType::PlaterWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }, 0); - // dissaper if in preview - set_in_preview(m_in_preview); -} + void NotificationManager::close_plater_error_notification(const std::string& text) { for (std::unique_ptr ¬ification : m_pop_notifications) { @@ -895,11 +849,32 @@ void NotificationManager::close_plater_error_notification(const std::string& tex } } } + +void NotificationManager::push_plater_warning_notification(const std::string& text) +{ + // Find if was not hidden + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::PlaterWarning && notification->compare_text(_u8L("WARNING:") + "\n" + text)) { + if (notification->get_state() == PopNotification::EState::Hidden) { + //dynamic_cast(notification.get())->show(); + return; + } + } + } + + NotificationData data{ NotificationType::PlaterWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }; + + auto notification = std::make_unique(data, m_id_provider, m_evt_handler); + push_notification_data(std::move(notification), 0); + // dissaper if in preview + set_in_preview(m_in_preview); +} + void NotificationManager::close_plater_warning_notification(const std::string& text) { for (std::unique_ptr ¬ification : m_pop_notifications) { if (notification->get_type() == NotificationType::PlaterWarning && notification->compare_text(_u8L("WARNING:") + "\n" + text)) { - notification->close(); + dynamic_cast(notification.get())->real_close(); } } } @@ -1008,7 +983,8 @@ void NotificationManager::set_progress_bar_percentage(const std::string& text, f for (std::unique_ptr& notification : m_pop_notifications) { if (notification->get_type() == NotificationType::ProgressBar && notification->compare_text(text)) { dynamic_cast(notification.get())->set_percentage(percentage); - wxGetApp().plater()->get_current_canvas3D()->request_extra_frame(); + // FIX ME: this is massive gpu eater (render every frame) + wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); found = true; } } @@ -1035,20 +1011,19 @@ bool NotificationManager::push_notification_data(std::unique_ptractivate_existing(notification.get())) { m_pop_notifications.back()->update(notification->get_data()); - canvas.request_extra_frame_delayed(33); + canvas.schedule_extra_frame(0); return false; } else { m_pop_notifications.emplace_back(std::move(notification)); - canvas.request_extra_frame_delayed(33); + canvas.schedule_extra_frame(0); return true; } } -void NotificationManager::render_notifications(float overlay_width) +void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay_width) { sort_notifications(); - - GLCanvas3D& canvas = *wxGetApp().plater()->get_current_canvas3D(); + float last_y = 0.0f; for (const auto& notification : m_pop_notifications) { @@ -1059,9 +1034,54 @@ void NotificationManager::render_notifications(float overlay_width) } } - update_notifications(); + m_last_render = GLCanvas3D::timestamp_now(); } +bool NotificationManager::update_notifications(GLCanvas3D& canvas) +{ + // no update if not top window + wxWindow* p = dynamic_cast(wxGetApp().plater()); + while (p->GetParent() != nullptr) + p = p->GetParent(); + wxTopLevelWindow* top_level_wnd = dynamic_cast(p); + if (!top_level_wnd->IsActive()) + return false; + + // next_render() returns numeric_limits::max if no need for frame + const int64_t max = std::numeric_limits::max(); + int64_t next_render = max; + const int64_t time_since_render = GLCanvas3D::timestamp_now() - m_last_render; + // During render, each notification detects if its currently hovered and changes its state to EState::Hovered + // If any notification is hovered, all restarts its countdown + bool hover = false; + for (const std::unique_ptr& notification : m_pop_notifications) { + if (notification->is_hovered()) { + hover = true; + break; + } + } + // update state of all notif and erase finished + for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) { + std::unique_ptr& notification = *it; + notification->update_state(hover, time_since_render); + next_render = std::min(next_render, notification->next_render()); + if (notification->get_state() == PopNotification::EState::Finished) + it = m_pop_notifications.erase(it); + else + ++it; + } + + // render needed right now + if (next_render < 20) + return true; + // request next frame + if (next_render < max) + canvas.schedule_extra_frame(int(next_render)); + + return false; +} +>>>>>>> 6df0d8ff81... Notifications management and rendering refactoring. + void NotificationManager::sort_notifications() { // Stable sorting, so that the order of equal ranges is stable. @@ -1112,103 +1132,6 @@ void NotificationManager::set_in_preview(bool preview) } } -void NotificationManager::update_notifications() -{ - // no update if not top window - wxWindow* p = dynamic_cast(wxGetApp().plater()); - while (p->GetParent() != nullptr) - p = p->GetParent(); - wxTopLevelWindow* top_level_wnd = dynamic_cast(p); - if (!top_level_wnd->IsActive()) - return; - - //static size_t last_size = m_pop_notifications.size(); - - //request frames - int64_t next_render = std::numeric_limits::max(); - for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) { - std::unique_ptr& notification = *it; - notification->set_paused(m_hovered); - notification->update_state(); - next_render = std::min(next_render, notification->next_render()); - if (notification->get_state() == PopNotification::EState::Finished) - it = m_pop_notifications.erase(it); - else { - - ++it; - } - } - /* - m_requires_update = false; - for (const std::unique_ptr& notification : m_pop_notifications) { - if (notification->requires_update()) { - m_requires_update = true; - break; - } - } - */ - // update hovering state - m_hovered = false; - for (const std::unique_ptr& notification : m_pop_notifications) { - if (notification->is_hovered()) { - m_hovered = true; - break; - } - } - - /* - // Reuire render if some notification was just deleted. - size_t curr_size = m_pop_notifications.size(); - m_requires_render = m_hovered || (last_size != curr_size); - last_size = curr_size; - - // Ask notification if it needs render - if (!m_requires_render) { - for (const std::unique_ptr& notification : m_pop_notifications) { - if (notification->requires_render()) { - m_requires_render = true; - break; - } - } - } - // Make sure there will be update after last notification erased - if (m_requires_render) - m_requires_update = true; - */ - - - if (next_render == 0) - wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(33); //few milliseconds to get from GLCanvas::render - else if (next_render < std::numeric_limits::max()) - wxGetApp().plater()->get_current_canvas3D()->request_extra_frame_delayed(int(next_render)); - - /* - // actualizate timers - wxWindow* p = dynamic_cast(wxGetApp().plater()); - while (p->GetParent() != nullptr) - p = p->GetParent(); - wxTopLevelWindow* top_level_wnd = dynamic_cast(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 >= MAX_TIMEOUT_SECONDS) { - for (auto& notification : m_pop_notifications) { - //if (notification->get_state() != PopNotification::EState::Static) - notification->substract_remaining_time(MAX_TIMEOUT_SECONDS); - } - m_last_time = now; - } - } - } - */ -} - 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 62c4ea845e..4c584d3663 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -147,14 +147,15 @@ public: // 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(float overlay_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. 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; } - + // perform update_state on each notification and ask for more frames if needed, return true for render needed + bool update_notifications(GLCanvas3D& canvas); private: // duration 0 means not disapearing struct NotificationData { @@ -192,23 +193,24 @@ private: enum class EState { - Unknown, + Unknown, // NOT initialized Hidden, - FadingOutRender, // Requesting Render - FadingOutStatic, + Shown, // Requesting Render at some time if duration != 0 + FadingOut, // Requesting Render at some time ClosePending, // Requesting Render Finished, // Requesting Render + Hovered, // Followed by Shown + Paused }; PopNotification(const NotificationData &n, NotificationIDProvider &id_provider, wxEvtHandler* evt_handler); virtual ~PopNotification() { if (m_id) m_id_provider.release_id(m_id); } void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width); // close will dissapear notification on next render - void close() { m_close_pending = true; } + virtual void close() { m_state = EState::ClosePending; } // data from newer notification of same type void update(const NotificationData& n); - bool is_finished() const { return m_finished || m_close_pending; } - bool is_hovered() const { return m_hovered; } + bool is_finished() const { return m_state == EState::ClosePending || m_state == EState::Finished; } // returns top after movement float get_top() const { return m_top_y; } //returns top in actual frame @@ -216,21 +218,15 @@ private: const NotificationType get_type() const { return m_data.type; } 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(int seconds) { m_remaining_time -= seconds; } 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; } - // sets m_next_render with time of next mandatory rendering - void update_state(); - int64_t next_render() const { return m_next_render; } - /* - bool requires_render() const { return m_state == EState::FadingOutRender || m_state == EState::ClosePending || m_state == EState::Finished; } - bool requires_update() const { return m_state != EState::Hidden; } - */ - EState get_state() const { return m_state; } - protected: + void hide(bool h) { m_state = h ? EState::Hidden : EState::Unknown; } + // sets m_next_render with time of next mandatory rendering. Delta is time since last render. + void update_state(bool paused, const int64_t delta); + int64_t next_render() const { return is_finished() ? 0 : m_next_render; } + EState get_state() const { return m_state; } + bool is_hovered() const { return m_state == EState::Hovered; } + // Call after every size change void init(); // Part of init() @@ -254,45 +250,36 @@ private: // Hypertext action, returns true if notification should close. // Action is stored in NotificationData::callback as std::function virtual bool on_text_click(); - + protected: const NotificationData m_data; - // For reusing ImGUI windows. NotificationIDProvider &m_id_provider; + int m_id{ 0 }; + // State for rendering EState m_state { EState::Unknown }; - int m_id { 0 }; - bool m_initialized { false }; + // Time values for rendering fade-out + + int64_t m_fading_start{ 0LL }; + + // first appereance of notification or last hover; + int64_t m_notification_start; + // time to next must-do render + int64_t m_next_render{ std::numeric_limits::max() }; + float m_current_fade_opacity{ 1.0f }; + + // Notification data + // Main text std::string m_text1; // Clickable text std::string m_hypertext; // Aditional text after hypertext - currently not used std::string m_text2; - // Countdown variables - long m_remaining_time; - bool m_counting_down; - long m_last_remaining_time; - bool m_paused { false }; - int m_countdown_frame { 0 }; - bool m_fading_out { false }; - int64_t m_fading_start { 0LL }; - // time of last done render when fading - int64_t m_last_render_fading { 0LL }; - // first appereance of notification or last hover; - int64_t m_notification_start; - // time to next must-do render - int64_t m_next_render { std::numeric_limits::max() }; - 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 }; - bool m_hovered { false }; - // variables to count positions correctly + + // inner variables to position notification window, texts and buttons correctly + // all space without text float m_window_width_offset; // Space on left side without text @@ -302,9 +289,7 @@ private: float m_window_width { 450.0f }; //Distance from bottom of notifications to top of this notification float m_top_y { 0.0f }; - - // Height of text - // Used as basic scaling unit! + // Height of text - Used as basic scaling unit! float m_line_height; std::vector m_endlines; // Gray are f.e. eorrors when its uknown if they are still valid @@ -344,6 +329,15 @@ private: int warning_step; }; + class PlaterWarningNotification : public PopNotification + { + public: + PlaterWarningNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler) : PopNotification(n, id_provider, evt_handler) {} + virtual void close() { m_state = EState::Hidden; } + void real_close() { m_state = EState::ClosePending; } + void show() { m_state = EState::Unknown; } + }; + class ProgressBarNotification : public PopNotification { public: @@ -405,33 +399,25 @@ private: void sort_notifications(); // 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(); - // perform update_state on each notification and ask for more frames if needed - void update_notifications(); - + // 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; - // 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; // 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 }; + // Timestamp of last rendering + int64_t m_last_render { 0LL }; //prepared (basic) notifications const std::vector basic_notifications = { -// {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::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more."), + {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 10, _u8L("Configuration update is available."), _u8L("See more."), [](wxEvtHandler* evnthndlr) { if (evnthndlr != nullptr) wxPostEvent(evnthndlr, PresetUpdateAvailableClickedEvent(EVT_PRESET_UPDATE_AVAILABLE_CLICKED)); From 32dd1f6e7c3e2ebbf9fc111d2b428a165c1227ee Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 8 Feb 2021 16:22:52 +0100 Subject: [PATCH 02/10] notification time correction --- src/slic3r/GUI/NotificationManager.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 4c584d3663..63492e61c4 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -417,7 +417,7 @@ private: //prepared (basic) notifications const std::vector basic_notifications = { {NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") }, - {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 10, _u8L("Configuration update is available."), _u8L("See more."), + {NotificationType::PresetUpdateAvailable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more."), [](wxEvtHandler* evnthndlr) { if (evnthndlr != nullptr) wxPostEvent(evnthndlr, PresetUpdateAvailableClickedEvent(EVT_PRESET_UPDATE_AVAILABLE_CLICKED)); From 80f0d305c18a5e562631d32592b19ff2f2d3d518 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 8 Feb 2021 17:42:20 +0100 Subject: [PATCH 03/10] request frame change in notification --- src/slic3r/GUI/NotificationManager.cpp | 38 ++++++++++++++++---------- src/slic3r/GUI/NotificationManager.hpp | 3 +- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 41c8e8f6fc..ab2e466500 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -547,15 +547,17 @@ bool NotificationManager::PopNotification::compare_text(const std::string& text) return false; } -void NotificationManager::PopNotification::update_state(bool paused, const int64_t delta) +bool NotificationManager::PopNotification::update_state(bool paused, const int64_t delta) { - if (m_state == EState::Unknown) + if (m_state == EState::Unknown) { init(); + return true; + } m_next_render = std::numeric_limits::max(); if (m_state == EState::Hidden) { - return; + return false; } int64_t now = GLCanvas3D::timestamp_now(); @@ -581,22 +583,25 @@ void NotificationManager::PopNotification::update_state(bool paused, const int64 m_current_fade_opacity = std::clamp(1.0f - 0.001f * static_cast(curr_time) / FADING_OUT_DURATION, 0.0f, 1.0f); if (m_current_fade_opacity <= 0.0f) m_state = EState::Finished; - else if (next_render < 0) - m_next_render = 0; + else if (next_render <= 20) { + m_next_render = FADING_OUT_TIMEOUT; + return true; + } else m_next_render = next_render; } if (m_state == EState::Finished) { - m_next_render = 0; - return; + //m_next_render = 0; + return true; } if (m_state == EState::ClosePending) { m_state = EState::Finished; - m_next_render = 0; - return; + //m_next_render = 0; + return true; } + return false; } NotificationManager::SlicingCompleteLargeNotification::SlicingCompleteLargeNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, bool large) : @@ -1034,6 +1039,7 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay } } + BOOST_LOG_TRIVIAL(error) << "render " << GLCanvas3D::timestamp_now() - m_last_render; m_last_render = GLCanvas3D::timestamp_now(); } @@ -1051,6 +1057,7 @@ bool NotificationManager::update_notifications(GLCanvas3D& canvas) const int64_t max = std::numeric_limits::max(); int64_t next_render = max; const int64_t time_since_render = GLCanvas3D::timestamp_now() - m_last_render; + bool request_render = false; // During render, each notification detects if its currently hovered and changes its state to EState::Hovered // If any notification is hovered, all restarts its countdown bool hover = false; @@ -1063,7 +1070,7 @@ bool NotificationManager::update_notifications(GLCanvas3D& canvas) // update state of all notif and erase finished for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) { std::unique_ptr& notification = *it; - notification->update_state(hover, time_since_render); + request_render |= notification->update_state(hover, time_since_render); next_render = std::min(next_render, notification->next_render()); if (notification->get_state() == PopNotification::EState::Finished) it = m_pop_notifications.erase(it); @@ -1071,16 +1078,19 @@ bool NotificationManager::update_notifications(GLCanvas3D& canvas) ++it; } + BOOST_LOG_TRIVIAL(error) << "update " << request_render << " : " << next_render <<" : " << GLCanvas3D::timestamp_now() - m_last_update; + m_last_update = GLCanvas3D::timestamp_now(); + //BOOST_LOG_TRIVIAL(error) << time_since_render << ":" << next_render; + // render needed right now - if (next_render < 20) - return true; + //if (next_render < 20) + // request_render = true; // request next frame if (next_render < max) canvas.schedule_extra_frame(int(next_render)); - return false; + return request_render; } ->>>>>>> 6df0d8ff81... Notifications management and rendering refactoring. void NotificationManager::sort_notifications() { diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 63492e61c4..0d1cd99966 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -222,7 +222,7 @@ private: bool compare_text(const std::string& text); void hide(bool h) { m_state = h ? EState::Hidden : EState::Unknown; } // sets m_next_render with time of next mandatory rendering. Delta is time since last render. - void update_state(bool paused, const int64_t delta); + bool update_state(bool paused, const int64_t delta); int64_t next_render() const { return is_finished() ? 0 : m_next_render; } EState get_state() const { return m_state; } bool is_hovered() const { return m_state == EState::Hovered; } @@ -413,6 +413,7 @@ private: bool m_move_from_overlay { false }; // Timestamp of last rendering int64_t m_last_render { 0LL }; + int64_t m_last_update { 0LL }; //prepared (basic) notifications const std::vector basic_notifications = { From bad12b5683015a58a17d634717143dec0adca0a1 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Mon, 8 Feb 2021 19:12:32 +0100 Subject: [PATCH 04/10] cleanup --- src/slic3r/GUI/NotificationManager.cpp | 5 ----- src/slic3r/GUI/NotificationManager.hpp | 1 - 2 files changed, 6 deletions(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index ab2e466500..28feb65d05 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -1039,7 +1039,6 @@ void NotificationManager::render_notifications(GLCanvas3D& canvas, float overlay } } - BOOST_LOG_TRIVIAL(error) << "render " << GLCanvas3D::timestamp_now() - m_last_render; m_last_render = GLCanvas3D::timestamp_now(); } @@ -1078,10 +1077,6 @@ bool NotificationManager::update_notifications(GLCanvas3D& canvas) ++it; } - BOOST_LOG_TRIVIAL(error) << "update " << request_render << " : " << next_render <<" : " << GLCanvas3D::timestamp_now() - m_last_update; - m_last_update = GLCanvas3D::timestamp_now(); - //BOOST_LOG_TRIVIAL(error) << time_since_render << ":" << next_render; - // render needed right now //if (next_render < 20) // request_render = true; diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 0d1cd99966..768f941a7b 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -413,7 +413,6 @@ private: bool m_move_from_overlay { false }; // Timestamp of last rendering int64_t m_last_render { 0LL }; - int64_t m_last_update { 0LL }; //prepared (basic) notifications const std::vector basic_notifications = { From 6e325ee3221fe359ea951be3eae5f86adc3ff189 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Tue, 9 Feb 2021 09:19:59 +0100 Subject: [PATCH 05/10] cleanup --- src/slic3r/GUI/NotificationManager.cpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 28feb65d05..7e2a6b880e 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -549,13 +549,14 @@ bool NotificationManager::PopNotification::compare_text(const std::string& text) bool NotificationManager::PopNotification::update_state(bool paused, const int64_t delta) { + + m_next_render = std::numeric_limits::max(); + if (m_state == EState::Unknown) { init(); return true; } - m_next_render = std::numeric_limits::max(); - if (m_state == EState::Hidden) { return false; } @@ -581,24 +582,24 @@ bool NotificationManager::PopNotification::update_state(bool paused, const int64 int64_t curr_time = now - m_fading_start; int64_t next_render = FADING_OUT_TIMEOUT - delta; m_current_fade_opacity = std::clamp(1.0f - 0.001f * static_cast(curr_time) / FADING_OUT_DURATION, 0.0f, 1.0f); - if (m_current_fade_opacity <= 0.0f) + if (m_current_fade_opacity <= 0.0f) { m_state = EState::Finished; - else if (next_render <= 20) { + return true; + } else if (next_render <= 20) { m_next_render = FADING_OUT_TIMEOUT; return true; - } - else + } else { m_next_render = next_render; + return false; + } } if (m_state == EState::Finished) { - //m_next_render = 0; return true; } if (m_state == EState::ClosePending) { m_state = EState::Finished; - //m_next_render = 0; return true; } return false; @@ -1077,10 +1078,7 @@ bool NotificationManager::update_notifications(GLCanvas3D& canvas) ++it; } - // render needed right now - //if (next_render < 20) - // request_render = true; - // request next frame + // request next frame in future if (next_render < max) canvas.schedule_extra_frame(int(next_render)); From bf032524ebe8f767836875978c9f9938342c976a Mon Sep 17 00:00:00 2001 From: David Kocik Date: Wed, 3 Mar 2021 09:24:16 +0100 Subject: [PATCH 06/10] notifications - minor changes in logic --- src/slic3r/GUI/NotificationManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 7e2a6b880e..930174e3f5 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -568,12 +568,12 @@ bool NotificationManager::PopNotification::update_state(bool paused, const int64 m_current_fade_opacity = 1.0f; m_notification_start = now; // Timers when not fading - } else if (m_data.duration != 0 && !paused) { + } else if (m_state != EState::FadingOut && m_data.duration != 0 && !paused) { int64_t up_time = now - m_notification_start; - if (m_state != EState::FadingOut && up_time >= m_data.duration * 1000) { + if (up_time >= m_data.duration * 1000) { m_state = EState::FadingOut; m_fading_start = now; - } else if (m_state != EState::FadingOut) { + } else { m_next_render = m_data.duration * 1000 - up_time; } } From 6716492efa3c218da57a60c3937bb9777a20b25c Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 4 Mar 2021 21:56:07 +0100 Subject: [PATCH 07/10] Printhost upload progress bar notification --- src/slic3r/GUI/GUI_App.cpp | 5 ++ src/slic3r/GUI/GUI_App.hpp | 17 ++--- src/slic3r/GUI/NotificationManager.cpp | 87 +++++++++++++++++++++----- src/slic3r/GUI/NotificationManager.hpp | 37 +++++++++-- src/slic3r/GUI/PrintHostDialogs.cpp | 25 ++++++++ 5 files changed, 143 insertions(+), 28 deletions(-) diff --git a/src/slic3r/GUI/GUI_App.cpp b/src/slic3r/GUI/GUI_App.cpp index 2fde30cd13..ecc5f46a7c 100644 --- a/src/slic3r/GUI/GUI_App.cpp +++ b/src/slic3r/GUI/GUI_App.cpp @@ -1978,6 +1978,11 @@ wxNotebook* GUI_App::tab_panel() const return mainframe->m_tabpanel; } +NotificationManager* GUI_App::notification_manager() +{ + return plater_->get_notification_manager(); +} + // extruders count from selected printer preset int GUI_App::extruders_cnt() const { diff --git a/src/slic3r/GUI/GUI_App.hpp b/src/slic3r/GUI/GUI_App.hpp index 5572c50712..f1ee0746a0 100644 --- a/src/slic3r/GUI/GUI_App.hpp +++ b/src/slic3r/GUI/GUI_App.hpp @@ -43,6 +43,7 @@ class ObjectSettings; class ObjectList; class ObjectLayers; class Plater; +class NotificationManager; struct GUI_InitParams; @@ -226,14 +227,14 @@ public: void MacOpenFiles(const wxArrayString &fileNames) override; #endif /* __APPLE */ - Sidebar& sidebar(); - ObjectManipulation* obj_manipul(); - ObjectSettings* obj_settings(); - ObjectList* obj_list(); - ObjectLayers* obj_layers(); - Plater* plater(); - Model& model(); - + Sidebar& sidebar(); + ObjectManipulation* obj_manipul(); + ObjectSettings* obj_settings(); + ObjectList* obj_list(); + ObjectLayers* obj_layers(); + Plater* plater(); + Model& model(); + NotificationManager* notification_manager(); // Parameters extracted from the command line to be passed to GUI after initialization. const GUI_InitParams* init_params { nullptr }; diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 930174e3f5..c9cf4d8cc9 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -359,12 +359,14 @@ void NotificationManager::PopNotification::render_text(ImGuiWrapper& imgui, cons ImGui::SetCursorPosY(win_size.y / 2 - win_size.y / 6 - m_line_height / 2); imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); // line2 - std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0)); - cursor_y = win_size.y / 2 + win_size.y / 6 - m_line_height / 2; - ImGui::SetCursorPosX(x_offset); - ImGui::SetCursorPosY(cursor_y); - imgui.text(line.c_str()); - cursor_x = x_offset + ImGui::CalcTextSize(line.c_str()).x; + if (m_text1.length() > m_endlines[0]) { + std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0)); + cursor_y = win_size.y / 2 + win_size.y / 6 - m_line_height / 2; + ImGui::SetCursorPosX(x_offset); + ImGui::SetCursorPosY(cursor_y); + imgui.text(line.c_str()); + cursor_x = x_offset + ImGui::CalcTextSize(line.c_str()).x; + } } else { ImGui::SetCursorPosX(x_offset); ImGui::SetCursorPosY(cursor_y); @@ -776,17 +778,52 @@ void NotificationManager::ProgressBarNotification::init() } void NotificationManager::ProgressBarNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { - PopNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + // line1 - we do not print any more text than what fits on line 1. Line 2 is bar. + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(win_size_y / 2 - win_size_y / 6 - m_line_height / 2); + imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); } void NotificationManager::ProgressBarNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { - ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f); - float invisible_length = 0; - - ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length - m_window_width_offset, win_pos_y + win_size_y/2 + m_line_height / 2); - ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y/2 + m_line_height / 2); - ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.7f); + switch (m_pb_state) + { + case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_PROGRESS: + { + ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f); + ImVec4 gray_color = ImVec4(.34f, .34f, .34f, 1.0f); + float invisible_length = 0; + ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length - m_window_width_offset, win_pos_y + win_size_y / 2 + m_line_height / 2); + ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y / 2 + m_line_height / 2); + float full_lenght = lineEnd.x - lineStart.x; + ImVec2 midPoint = ImVec2(lineStart.x + full_lenght * m_percentage, lineStart.y); + ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(gray_color.x * 255), (int)(gray_color.y * 255), (int)(gray_color.z * 255), (1.0f * 255.f)), m_line_height * 0.7f); + ImGui::GetWindowDrawList()->AddLine(lineStart, midPoint, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.7f); + break; + } + case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_ERROR: + { + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2); + imgui.text(_u8L("ERROR")); + break; + } + case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_CANCELLED: + { + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2); + imgui.text(_u8L("CANCELED")); + break; + } + case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_COMPLETED: + { + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2); + imgui.text(_u8L("COMPLETED")); + break; + } + } + } //------NotificationManager-------- @@ -989,7 +1026,6 @@ void NotificationManager::set_progress_bar_percentage(const std::string& text, f for (std::unique_ptr& notification : m_pop_notifications) { if (notification->get_type() == NotificationType::ProgressBar && notification->compare_text(text)) { dynamic_cast(notification.get())->set_percentage(percentage); - // FIX ME: this is massive gpu eater (render every frame) wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); found = true; } @@ -998,6 +1034,26 @@ void NotificationManager::set_progress_bar_percentage(const std::string& text, f push_progress_bar_notification(text, percentage); } } +void NotificationManager::progress_bar_show_canceled(const std::string& text) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::ProgressBar && notification->compare_text(text)) { + dynamic_cast(notification.get())->cancel(); + wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); + break; + } + } +} +void NotificationManager::progress_bar_show_error(const std::string& text) +{ + for (std::unique_ptr& notification : m_pop_notifications) { + if (notification->get_type() == NotificationType::ProgressBar && notification->compare_text(text)) { + dynamic_cast(notification.get())->error(); + wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); + break; + } + } +} bool NotificationManager::push_notification_data(const NotificationData& notification_data, int timestamp) { return push_notification_data(std::make_unique(notification_data, m_id_provider, m_evt_handler), timestamp); @@ -1103,7 +1159,8 @@ bool NotificationManager::activate_existing(const NotificationManager::PopNotifi 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)->is_finished()) { - if (new_type == NotificationType::CustomNotification || new_type == NotificationType::PlaterWarning) { + if (std::find(m_multiple_types.begin(), m_multiple_types.end(), new_type) != m_multiple_types.end()) { + //if (new_type == NotificationType::CustomNotification || new_type == NotificationType::PlaterWarning || new_type == NotificationType::ProgressBar) { if (!(*it)->compare_text(new_text)) continue; } else if (new_type == NotificationType::SlicingWarning) { diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 768f941a7b..2baaf70546 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -142,6 +142,8 @@ public: // notification with progress bar void push_progress_bar_notification(const std::string& text, float percentage = 0); void set_progress_bar_percentage(const std::string& text, float percentage); + void progress_bar_show_canceled(const std::string& text); + void progress_bar_show_error(const std::string& text); // Close old notification ExportFinished. void new_export_began(bool on_removable); // finds ExportFinished notification and closes it if it was to removable device @@ -228,7 +230,7 @@ private: bool is_hovered() const { return m_state == EState::Hovered; } // Call after every size change - void init(); + virtual void init(); // Part of init() virtual void count_spaces(); // Calculetes correct size but not se it in imgui! @@ -341,8 +343,28 @@ private: class ProgressBarNotification : public PopNotification { public: + enum class ProgressBarState + { + PB_PROGRESS, + PB_ERROR, + PB_CANCELLED, + PB_COMPLETED + }; ProgressBarNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage) : PopNotification(n, id_provider, evt_handler) { set_percentage(percentage); } - void set_percentage(float percent) { m_percentage = percent; if (percent >= 1.0f) m_progress_complete = true; else m_progress_complete = false; } + void set_percentage(float percent) + { + if (m_pb_state == ProgressBarState::PB_CANCELLED) + return; + m_percentage = percent; + if (percent >= 1.0f) + m_pb_state = ProgressBarState::PB_COMPLETED; + else if (percent < 0.0f ) + m_pb_state = ProgressBarState::PB_ERROR; + else + m_pb_state = ProgressBarState::PB_PROGRESS; + } + void cancel() { m_pb_state = ProgressBarState::PB_CANCELLED; } + void error() { m_pb_state = ProgressBarState::PB_ERROR; } protected: virtual void init(); virtual void render_text(ImGuiWrapper& imgui, @@ -351,8 +373,12 @@ private: void render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y); - bool m_progress_complete{ false }; - float m_percentage; + float m_percentage; + ProgressBarState m_pb_state { ProgressBarState::PB_PROGRESS }; + }; + + class PrintHostUploadNotification : public ProgressBarNotification + { }; class ExportFinishedNotification : public PopNotification @@ -413,7 +439,8 @@ private: bool m_move_from_overlay { false }; // Timestamp of last rendering int64_t m_last_render { 0LL }; - + // Notification types that can be shown multiple types at once (compared by text) + const std::vector m_multiple_types = { NotificationType::CustomNotification, NotificationType::PlaterWarning, NotificationType::ProgressBar }; //prepared (basic) notifications const std::vector basic_notifications = { {NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") }, diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index a094b70e9a..921337d4a0 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -25,6 +25,7 @@ #include "wxExtensions.hpp" #include "MainFrame.hpp" #include "libslic3r/AppConfig.hpp" +#include "NotificationManager.hpp" namespace fs = boost::filesystem; @@ -280,6 +281,9 @@ void PrintHostQueueDialog::append_job(const PrintHostJob &job) job_list->AppendItem(fields, static_cast(ST_NEW)); // Both strings are UTF-8 encoded. upload_names.emplace_back(job.printhost->get_host(), job.upload_data.upload_path.string()); + + std::string notification_text = "[" + std::to_string(job_list->GetItemCount()) + "] " + job.upload_data.upload_path.string() + " -> " + job.printhost->get_host(); + wxGetApp().notification_manager()->push_progress_bar_notification(notification_text); } void PrintHostQueueDialog::on_dpi_changed(const wxRect &suggested_rect) @@ -345,6 +349,15 @@ void PrintHostQueueDialog::on_progress(Event &evt) } on_list_select(); + + if (evt.progress > 0) + { + wxVariant nm, hst; + job_list->GetValue(nm, evt.job_id, COL_FILENAME); + job_list->GetValue(hst, evt.job_id, COL_HOST); + std::string notification_text = "[" + std::to_string(evt.job_id + 1) + "] " + boost::nowide::narrow(nm.GetString()) + " -> " + boost::nowide::narrow(hst.GetString()); + wxGetApp().notification_manager()->set_progress_bar_percentage(notification_text, 100 / evt.progress); + } } void PrintHostQueueDialog::on_error(Event &evt) @@ -360,6 +373,12 @@ void PrintHostQueueDialog::on_error(Event &evt) on_list_select(); GUI::show_error(nullptr, errormsg); + + wxVariant nm, hst; + job_list->GetValue(nm, evt.job_id, COL_FILENAME); + job_list->GetValue(hst, evt.job_id, COL_HOST); + std::string notification_text = "[" + std::to_string(evt.job_id + 1) + "] " + boost::nowide::narrow(nm.GetString()) + " -> " + boost::nowide::narrow(hst.GetString()); + wxGetApp().notification_manager()->progress_bar_show_error(notification_text); } void PrintHostQueueDialog::on_cancel(Event &evt) @@ -370,6 +389,12 @@ void PrintHostQueueDialog::on_cancel(Event &evt) job_list->SetValue(wxVariant(0), evt.job_id, COL_PROGRESS); on_list_select(); + + wxVariant nm, hst; + job_list->GetValue(nm, evt.job_id, COL_FILENAME); + job_list->GetValue(hst, evt.job_id, COL_HOST); + std::string notification_text = "[" + std::to_string(evt.job_id + 1) + "] " + boost::nowide::narrow(nm.GetString()) + " -> " + boost::nowide::narrow(hst.GetString()); + wxGetApp().notification_manager()->progress_bar_show_canceled(notification_text); } void PrintHostQueueDialog::get_active_jobs(std::vector>& ret) From 44bfb914ab03d1e77ecbc50eeb7865dc76351150 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Sat, 6 Mar 2021 11:26:29 +0100 Subject: [PATCH 08/10] progress bar notification - percentage text --- src/slic3r/GUI/NotificationManager.cpp | 39 +++++++++----------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index c9cf4d8cc9..a5777cd552 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -786,44 +786,33 @@ void NotificationManager::ProgressBarNotification::render_text(ImGuiWrapper& img } void NotificationManager::ProgressBarNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { - switch (m_pb_state) - { + std::string text; + switch (m_pb_state) { case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_PROGRESS: { - ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f); - ImVec4 gray_color = ImVec4(.34f, .34f, .34f, 1.0f); - float invisible_length = 0; - ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length - m_window_width_offset, win_pos_y + win_size_y / 2 + m_line_height / 2); - ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y / 2 + m_line_height / 2); - float full_lenght = lineEnd.x - lineStart.x; - ImVec2 midPoint = ImVec2(lineStart.x + full_lenght * m_percentage, lineStart.y); + text = std::to_string((int)(m_percentage * 100)) + "%"; + ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f); + ImVec4 gray_color = ImVec4(.34f, .34f, .34f, 1.0f); + ImVec2 lineEnd = ImVec2(win_pos_x - m_window_width_offset, win_pos_y + win_size_y / 2 + m_line_height / 2); + ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation + ImGui::CalcTextSize(text.c_str()).x, win_pos_y + win_size_y / 2 + m_line_height / 2); + ImVec2 midPoint = ImVec2(lineStart.x + (lineEnd.x - lineStart.x) * m_percentage, lineStart.y); ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(gray_color.x * 255), (int)(gray_color.y * 255), (int)(gray_color.z * 255), (1.0f * 255.f)), m_line_height * 0.7f); ImGui::GetWindowDrawList()->AddLine(lineStart, midPoint, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.7f); break; } case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_ERROR: - { - ImGui::SetCursorPosX(m_left_indentation); - ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2); - imgui.text(_u8L("ERROR")); + text = _u8L("ERROR"); break; - } case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_CANCELLED: - { - ImGui::SetCursorPosX(m_left_indentation); - ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2); - imgui.text(_u8L("CANCELED")); + text = _u8L("CANCELED"); break; - } case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_COMPLETED: - { - ImGui::SetCursorPosX(m_left_indentation); - ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2); - imgui.text(_u8L("COMPLETED")); + text = _u8L("COMPLETED"); break; } - } - + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2); + imgui.text(text.c_str()); } //------NotificationManager-------- From 62c2095fe8297688c254ef70d9742f18fffe1b77 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Thu, 11 Mar 2021 13:33:31 +0100 Subject: [PATCH 09/10] Print host upload notification with more info and cancel button --- resources/icons/notification_cancel.svg | 67 +++++++ resources/icons/notification_cancel_hover.svg | 67 +++++++ src/imgui/imconfig.h | 2 + src/slic3r/GUI/ImGuiWrapper.cpp | 4 +- src/slic3r/GUI/NotificationManager.cpp | 175 +++++++++++++++--- src/slic3r/GUI/NotificationManager.hpp | 92 +++++---- src/slic3r/GUI/PrintHostDialogs.cpp | 12 +- 7 files changed, 350 insertions(+), 69 deletions(-) create mode 100644 resources/icons/notification_cancel.svg create mode 100644 resources/icons/notification_cancel_hover.svg diff --git a/resources/icons/notification_cancel.svg b/resources/icons/notification_cancel.svg new file mode 100644 index 0000000000..d849e24c61 --- /dev/null +++ b/resources/icons/notification_cancel.svg @@ -0,0 +1,67 @@ + +image/svg+xml + + + + + + + diff --git a/resources/icons/notification_cancel_hover.svg b/resources/icons/notification_cancel_hover.svg new file mode 100644 index 0000000000..746d053e48 --- /dev/null +++ b/resources/icons/notification_cancel_hover.svg @@ -0,0 +1,67 @@ + +image/svg+xml + + + + + + + diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index d52294acd2..1ee719288c 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -123,6 +123,8 @@ namespace ImGui const char ErrorMarker = 0x11; const char EjectButton = 0x12; const char EjectHoverButton = 0x13; + const char CancelButton = 0x14; + const char CancelHoverButton = 0x15; // void MyFunction(const char* name, const MyMatrix44& v); } diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 1ed4b492fd..db7af046bf 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -51,7 +51,9 @@ static const std::map font_icons_large = { {ImGui::EjectButton , "notification_eject_sd" }, {ImGui::EjectHoverButton , "notification_eject_sd_hover" }, {ImGui::WarningMarker , "notification_warning" }, - {ImGui::ErrorMarker , "notification_error" } + {ImGui::ErrorMarker , "notification_error" }, + {ImGui::CancelButton , "notification_cancel" }, + {ImGui::CancelHoverButton , "notification_cancel_hover" }, }; const ImVec4 ImGuiWrapper::COL_GREY_DARK = { 0.333f, 0.333f, 0.333f, 1.0f }; diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index a5777cd552..21df0e86b9 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -5,6 +5,7 @@ #include "Plater.hpp" #include "GLCanvas3D.hpp" #include "ImGuiWrapper.hpp" +#include "PrintHostDialogs.hpp" #include "wxExtensions.hpp" @@ -776,44 +777,157 @@ void NotificationManager::ProgressBarNotification::init() m_lines_count++; m_endlines.push_back(m_endlines.back()); } +void NotificationManager::ProgressBarNotification::count_spaces() +{ + //determine line width + m_line_height = ImGui::CalcTextSize("A").y; + + m_left_indentation = m_line_height; + if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) { + std::string text; + text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker); + float picture_width = ImGui::CalcTextSize(text.c_str()).x; + m_left_indentation = picture_width + m_line_height / 2; + } + m_window_width_offset = m_line_height * (m_has_cancel_button ? 6 : 4); + m_window_width = m_line_height * 25; +} + void NotificationManager::ProgressBarNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { // line1 - we do not print any more text than what fits on line 1. Line 2 is bar. ImGui::SetCursorPosX(m_left_indentation); ImGui::SetCursorPosY(win_size_y / 2 - win_size_y / 6 - m_line_height / 2); imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); + if (m_has_cancel_button) + render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + } void NotificationManager::ProgressBarNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f); + ImVec4 gray_color = ImVec4(.34f, .34f, .34f, 1.0f); + ImVec2 lineEnd = ImVec2(win_pos_x - m_window_width_offset, win_pos_y + win_size_y / 2 + m_line_height / 4); + ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation, win_pos_y + win_size_y / 2 + m_line_height / 4); + ImVec2 midPoint = ImVec2(lineStart.x + (lineEnd.x - lineStart.x) * m_percentage, lineStart.y); + ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(gray_color.x * 255), (int)(gray_color.y * 255), (int)(gray_color.z * 255), (1.0f * 255.f)), m_line_height * 0.2f); + ImGui::GetWindowDrawList()->AddLine(lineStart, midPoint, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.2f); +} +//------PrintHostUploadNotification---------------- +void NotificationManager::PrintHostUploadNotification::set_percentage(float percent) +{ + if (m_uj_state == UploadJobState::PB_CANCELLED) + return; + m_percentage = percent; + if (percent >= 1.0f) { + m_uj_state = UploadJobState::PB_COMPLETED; + m_has_cancel_button = false; + } else if (percent < 0.0f) { + error(); + } else { + m_uj_state = UploadJobState::PB_PROGRESS; + m_has_cancel_button = true; + } +} +void NotificationManager::PrintHostUploadNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) { std::string text; - switch (m_pb_state) { - case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_PROGRESS: + switch (m_uj_state) { + case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_PROGRESS: { - text = std::to_string((int)(m_percentage * 100)) + "%"; - ImVec4 orange_color = ImVec4(.99f, .313f, .0f, 1.0f); - ImVec4 gray_color = ImVec4(.34f, .34f, .34f, 1.0f); - ImVec2 lineEnd = ImVec2(win_pos_x - m_window_width_offset, win_pos_y + win_size_y / 2 + m_line_height / 2); - ImVec2 lineStart = ImVec2(win_pos_x - win_size_x + m_left_indentation + ImGui::CalcTextSize(text.c_str()).x, win_pos_y + win_size_y / 2 + m_line_height / 2); - ImVec2 midPoint = ImVec2(lineStart.x + (lineEnd.x - lineStart.x) * m_percentage, lineStart.y); - ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(gray_color.x * 255), (int)(gray_color.y * 255), (int)(gray_color.z * 255), (1.0f * 255.f)), m_line_height * 0.7f); - ImGui::GetWindowDrawList()->AddLine(lineStart, midPoint, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (1.0f * 255.f)), m_line_height * 0.7f); + ProgressBarNotification::render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); + float uploaded = m_file_size / 100 * m_percentage; + std::stringstream stream; + stream << std::fixed << std::setprecision(3) << (int)(m_percentage * 100) << "% - " << uploaded << " of " << m_file_size << "MB uploaded"; + text = stream.str(); + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 /*- m_line_height / 4 * 3*/); break; } - case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_ERROR: + case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_ERROR: text = _u8L("ERROR"); + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2); break; - case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_CANCELLED: + case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_CANCELLED: text = _u8L("CANCELED"); + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2); break; - case Slic3r::GUI::NotificationManager::ProgressBarNotification::ProgressBarState::PB_COMPLETED: + case Slic3r::GUI::NotificationManager::PrintHostUploadNotification::UploadJobState::PB_COMPLETED: text = _u8L("COMPLETED"); + ImGui::SetCursorPosX(m_left_indentation); + ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2); break; } - ImGui::SetCursorPosX(m_left_indentation); - ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 - m_line_height / 2); + imgui.text(text.c_str()); +} +void NotificationManager::PrintHostUploadNotification::render_cancel_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) +{ + ImVec2 win_size(win_size_x, win_size_y); + ImVec2 win_pos(win_pos_x, win_pos_y); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); + Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); + + std::string button_text; + button_text = ImGui::CancelButton; + + if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - m_line_height * 5.f, win_pos.y), + ImVec2(win_pos.x - m_line_height * 2.5f, win_pos.y + win_size.y), + true)) + { + button_text = ImGui::CancelHoverButton; + // tooltip + long time_now = wxGetLocalTime(); + if (m_hover_time > 0 && m_hover_time < time_now) { + ImGui::PushStyleColor(ImGuiCol_PopupBg, ImGuiWrapper::COL_WINDOW_BACKGROUND); + ImGui::BeginTooltip(); + imgui.text(_u8L("Cancel upload") + " " + GUI::shortkey_ctrl_prefix() + "T"); + ImGui::EndTooltip(); + ImGui::PopStyleColor(); + } + if (m_hover_time == 0) + m_hover_time = time_now; + } + else + m_hover_time = 0; + + ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str()); + ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f); + ImGui::SetCursorPosX(win_size.x - m_line_height * 5.0f); + ImGui::SetCursorPosY(win_size.y / 2 - button_size.y); + if (imgui.button(button_text.c_str(), button_size.x, button_size.y)) + { + assert(m_evt_handler != nullptr); + if (m_evt_handler != nullptr) { + auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_CANCEL, m_job_id, m_job_id); + wxQueueEvent(m_evt_handler, evt); + } + } + + //invisible large button + ImGui::SetCursorPosX(win_size.x - m_line_height * 4.625f); + ImGui::SetCursorPosY(0); + if (imgui.button(" ", m_line_height * 2.f, win_size.y)) + { + assert(m_evt_handler != nullptr); + if (m_evt_handler != nullptr) { + auto evt = new PrintHostQueueDialog::Event(GUI::EVT_PRINTHOST_CANCEL, m_job_id, m_job_id); + wxQueueEvent(m_evt_handler, evt); + } + } + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + ImGui::PopStyleColor(); + } //------NotificationManager-------- NotificationManager::NotificationManager(wxEvtHandler* evt_handler) : @@ -1004,40 +1118,47 @@ void NotificationManager::push_exporting_finished_notification(const std::string NotificationData data{ NotificationType::ExportFinished, NotificationLevel::RegularNotification, on_removable ? 0 : 20, _u8L("Exporting finished.") + "\n" + path }; push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, on_removable, path, dir_path), 0); } -void NotificationManager::push_progress_bar_notification(const std::string& text, float percentage) + +void NotificationManager::push_upload_job_notification(wxEvtHandler* evt_handler, int id, float filesize, const std::string& filename, const std::string& host, float percentage) { - NotificationData data{ NotificationType::ProgressBar, NotificationLevel::ProgressBarNotification, 0, text }; - push_notification_data(std::make_unique(data, m_id_provider, m_evt_handler, 0), 0); + std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host); + NotificationData data{ NotificationType::PrintHostUpload, NotificationLevel::ProgressBarNotification, 0, text }; + push_notification_data(std::make_unique(data, m_id_provider, evt_handler, 0, id, filesize), 0); } -void NotificationManager::set_progress_bar_percentage(const std::string& text, float percentage) +void NotificationManager::set_upload_job_notification_percentage(int id, const std::string& filename, const std::string& host, float percentage) { + std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host); bool found = false; for (std::unique_ptr& notification : m_pop_notifications) { if (notification->get_type() == NotificationType::ProgressBar && notification->compare_text(text)) { - dynamic_cast(notification.get())->set_percentage(percentage); + dynamic_cast(notification.get())->set_percentage(percentage); wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); found = true; } } + /* if (!found) { - push_progress_bar_notification(text, percentage); + push_upload_job_notification(id, filename, host, percentage); } + */ } -void NotificationManager::progress_bar_show_canceled(const std::string& text) +void NotificationManager::upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host) { + std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host); for (std::unique_ptr& notification : m_pop_notifications) { - if (notification->get_type() == NotificationType::ProgressBar && notification->compare_text(text)) { - dynamic_cast(notification.get())->cancel(); + if (notification->get_type() == NotificationType::PrintHostUpload && notification->compare_text(text)) { + dynamic_cast(notification.get())->cancel(); wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); break; } } } -void NotificationManager::progress_bar_show_error(const std::string& text) +void NotificationManager::upload_job_notification_show_error(int id, const std::string& filename, const std::string& host) { + std::string text = PrintHostUploadNotification::get_upload_job_text(id, filename, host); for (std::unique_ptr& notification : m_pop_notifications) { - if (notification->get_type() == NotificationType::ProgressBar && notification->compare_text(text)) { - dynamic_cast(notification.get())->error(); + if (notification->get_type() == NotificationType::PrintHostUpload && notification->compare_text(text)) { + dynamic_cast(notification.get())->error(); wxGetApp().plater()->get_current_canvas3D()->schedule_extra_frame(0); break; } diff --git a/src/slic3r/GUI/NotificationManager.hpp b/src/slic3r/GUI/NotificationManager.hpp index 2baaf70546..4b32a716ff 100644 --- a/src/slic3r/GUI/NotificationManager.hpp +++ b/src/slic3r/GUI/NotificationManager.hpp @@ -66,6 +66,8 @@ enum class NotificationType PlaterWarning, // Progress bar instead of text. ProgressBar, + // Progress bar with info from Print Host Upload Queue dialog. + PrintHostUpload, // Notification, when Color Change G-code is empty and user try to add color change on DoubleSlider. EmptyColorChangeCode, // Notification that custom supports/seams were deleted after mesh repair. @@ -140,10 +142,10 @@ public: // Exporting finished, show this information with path, button to open containing folder and if ejectable - eject button void push_exporting_finished_notification(const std::string& path, const std::string& dir_path, bool on_removable); // notification with progress bar - void push_progress_bar_notification(const std::string& text, float percentage = 0); - void set_progress_bar_percentage(const std::string& text, float percentage); - void progress_bar_show_canceled(const std::string& text); - void progress_bar_show_error(const std::string& text); + void push_upload_job_notification(wxEvtHandler* evt_handler, int id, float filesize, const std::string& filename, const std::string& host, float percentage = 0); + void set_upload_job_notification_percentage(int id, const std::string& filename, const std::string& host, float percentage); + void upload_job_notification_show_canceled(int id, const std::string& filename, const std::string& host); + void upload_job_notification_show_error(int id, const std::string& filename, const std::string& host); // Close old notification ExportFinished. void new_export_began(bool on_removable); // finds ExportFinished notification and closes it if it was to removable device @@ -340,45 +342,69 @@ private: void show() { m_state = EState::Unknown; } }; + class ProgressBarNotification : public PopNotification { public: - enum class ProgressBarState - { - PB_PROGRESS, - PB_ERROR, - PB_CANCELLED, - PB_COMPLETED - }; + ProgressBarNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage) : PopNotification(n, id_provider, evt_handler) { set_percentage(percentage); } - void set_percentage(float percent) - { - if (m_pb_state == ProgressBarState::PB_CANCELLED) - return; - m_percentage = percent; - if (percent >= 1.0f) - m_pb_state = ProgressBarState::PB_COMPLETED; - else if (percent < 0.0f ) - m_pb_state = ProgressBarState::PB_ERROR; - else - m_pb_state = ProgressBarState::PB_PROGRESS; - } - void cancel() { m_pb_state = ProgressBarState::PB_CANCELLED; } - void error() { m_pb_state = ProgressBarState::PB_ERROR; } + virtual void set_percentage(float percent) { m_percentage = percent; } protected: - virtual void init(); + virtual void init() override; + virtual void count_spaces() override; virtual void render_text(ImGuiWrapper& imgui, - const float win_size_x, const float win_size_y, - const float win_pos_x, const float win_pos_y); - void render_bar(ImGuiWrapper& imgui, - const float win_size_x, const float win_size_y, - const float win_pos_x, const float win_pos_y); + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y); + virtual void render_bar(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y); + virtual void render_cancel_button(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y) + {} float m_percentage; - ProgressBarState m_pb_state { ProgressBarState::PB_PROGRESS }; + + bool m_has_cancel_button {false}; + // local time of last hover for showing tooltip + }; + + class PrintHostUploadNotification : public ProgressBarNotification { + public: + enum class UploadJobState + { + PB_PROGRESS, + PB_ERROR, + PB_CANCELLED, + PB_COMPLETED + }; + PrintHostUploadNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, float percentage, int job_id, float filesize) + :ProgressBarNotification(n, id_provider, evt_handler, percentage) + , m_job_id(job_id) + , m_file_size(filesize) + { + m_has_cancel_button = true; + } + static std::string get_upload_job_text(int id, const std::string& filename, const std::string& host) { return "[" + std::to_string(id) + "] " + filename + " -> " + host; } + virtual void set_percentage(float percent); + void cancel() { m_uj_state = UploadJobState::PB_CANCELLED; m_has_cancel_button = false; } + void error() { m_uj_state = UploadJobState::PB_ERROR; m_has_cancel_button = false; } + protected: + virtual void render_bar(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y); + virtual void render_cancel_button(ImGuiWrapper& imgui, + const float win_size_x, const float win_size_y, + const float win_pos_x, const float win_pos_y); + // Identifies job in cancel callback + int m_job_id; + // Size of uploaded size to be displayed in MB + float m_file_size; + long m_hover_time{ 0 }; + UploadJobState m_uj_state{ UploadJobState::PB_PROGRESS }; }; class ExportFinishedNotification : public PopNotification @@ -440,7 +466,7 @@ private: // Timestamp of last rendering int64_t m_last_render { 0LL }; // Notification types that can be shown multiple types at once (compared by text) - const std::vector m_multiple_types = { NotificationType::CustomNotification, NotificationType::PlaterWarning, NotificationType::ProgressBar }; + const std::vector m_multiple_types = { NotificationType::CustomNotification, NotificationType::PlaterWarning, NotificationType::ProgressBar, NotificationType::PrintHostUpload }; //prepared (basic) notifications const std::vector basic_notifications = { {NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") }, diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index 921337d4a0..f3a1fae98a 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -282,8 +282,7 @@ void PrintHostQueueDialog::append_job(const PrintHostJob &job) // Both strings are UTF-8 encoded. upload_names.emplace_back(job.printhost->get_host(), job.upload_data.upload_path.string()); - std::string notification_text = "[" + std::to_string(job_list->GetItemCount()) + "] " + job.upload_data.upload_path.string() + " -> " + job.printhost->get_host(); - wxGetApp().notification_manager()->push_progress_bar_notification(notification_text); + wxGetApp().notification_manager()->push_upload_job_notification(this, job_list->GetItemCount(), 2.64931f, job.upload_data.upload_path.string(), job.printhost->get_host()); } void PrintHostQueueDialog::on_dpi_changed(const wxRect &suggested_rect) @@ -355,8 +354,7 @@ void PrintHostQueueDialog::on_progress(Event &evt) wxVariant nm, hst; job_list->GetValue(nm, evt.job_id, COL_FILENAME); job_list->GetValue(hst, evt.job_id, COL_HOST); - std::string notification_text = "[" + std::to_string(evt.job_id + 1) + "] " + boost::nowide::narrow(nm.GetString()) + " -> " + boost::nowide::narrow(hst.GetString()); - wxGetApp().notification_manager()->set_progress_bar_percentage(notification_text, 100 / evt.progress); + wxGetApp().notification_manager()->set_upload_job_notification_percentage(evt.job_id + 1, boost::nowide::narrow(nm.GetString()), boost::nowide::narrow(hst.GetString()), 100 / evt.progress); } } @@ -377,8 +375,7 @@ void PrintHostQueueDialog::on_error(Event &evt) wxVariant nm, hst; job_list->GetValue(nm, evt.job_id, COL_FILENAME); job_list->GetValue(hst, evt.job_id, COL_HOST); - std::string notification_text = "[" + std::to_string(evt.job_id + 1) + "] " + boost::nowide::narrow(nm.GetString()) + " -> " + boost::nowide::narrow(hst.GetString()); - wxGetApp().notification_manager()->progress_bar_show_error(notification_text); + wxGetApp().notification_manager()->upload_job_notification_show_error(evt.job_id + 1, boost::nowide::narrow(nm.GetString()), boost::nowide::narrow(hst.GetString())); } void PrintHostQueueDialog::on_cancel(Event &evt) @@ -393,8 +390,7 @@ void PrintHostQueueDialog::on_cancel(Event &evt) wxVariant nm, hst; job_list->GetValue(nm, evt.job_id, COL_FILENAME); job_list->GetValue(hst, evt.job_id, COL_HOST); - std::string notification_text = "[" + std::to_string(evt.job_id + 1) + "] " + boost::nowide::narrow(nm.GetString()) + " -> " + boost::nowide::narrow(hst.GetString()); - wxGetApp().notification_manager()->progress_bar_show_canceled(notification_text); + wxGetApp().notification_manager()->upload_job_notification_show_canceled(evt.job_id + 1, boost::nowide::narrow(nm.GetString()), boost::nowide::narrow(hst.GetString())); } void PrintHostQueueDialog::get_active_jobs(std::vector>& ret) From 15765eb99b65a82abc172bc065ca84dfa7423ed8 Mon Sep 17 00:00:00 2001 From: David Kocik Date: Fri, 12 Mar 2021 10:19:13 +0100 Subject: [PATCH 10/10] Commented Print host upload notification until its tested --- src/slic3r/GUI/NotificationManager.cpp | 2 +- src/slic3r/GUI/PrintHostDialogs.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/slic3r/GUI/NotificationManager.cpp b/src/slic3r/GUI/NotificationManager.cpp index 21df0e86b9..266814e09c 100644 --- a/src/slic3r/GUI/NotificationManager.cpp +++ b/src/slic3r/GUI/NotificationManager.cpp @@ -839,7 +839,7 @@ void NotificationManager::PrintHostUploadNotification::render_bar(ImGuiWrapper& ProgressBarNotification::render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y); float uploaded = m_file_size / 100 * m_percentage; std::stringstream stream; - stream << std::fixed << std::setprecision(3) << (int)(m_percentage * 100) << "% - " << uploaded << " of " << m_file_size << "MB uploaded"; + stream << std::fixed << std::setprecision(2) << (int)(m_percentage * 100) << "% - " << uploaded << " of " << m_file_size << "MB uploaded"; text = stream.str(); ImGui::SetCursorPosX(m_left_indentation); ImGui::SetCursorPosY(win_size_y / 2 + win_size_y / 6 /*- m_line_height / 4 * 3*/); diff --git a/src/slic3r/GUI/PrintHostDialogs.cpp b/src/slic3r/GUI/PrintHostDialogs.cpp index f3a1fae98a..c8df141e9f 100644 --- a/src/slic3r/GUI/PrintHostDialogs.cpp +++ b/src/slic3r/GUI/PrintHostDialogs.cpp @@ -282,7 +282,7 @@ void PrintHostQueueDialog::append_job(const PrintHostJob &job) // Both strings are UTF-8 encoded. upload_names.emplace_back(job.printhost->get_host(), job.upload_data.upload_path.string()); - wxGetApp().notification_manager()->push_upload_job_notification(this, job_list->GetItemCount(), 2.64931f, job.upload_data.upload_path.string(), job.printhost->get_host()); + //wxGetApp().notification_manager()->push_upload_job_notification(this, job_list->GetItemCount(), 0, job.upload_data.upload_path.string(), job.printhost->get_host()); } void PrintHostQueueDialog::on_dpi_changed(const wxRect &suggested_rect)