#include "SlicingProgressNotification.hpp" #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif #include namespace Slic3r { namespace GUI { namespace { inline void push_style_color(ImGuiCol idx, const ImVec4& col, bool fading_out, float current_fade_opacity) { if (fading_out) ImGui::PushStyleColor(idx, ImVec4(col.x, col.y, col.z, col.w * current_fade_opacity)); else ImGui::PushStyleColor(idx, col); } } void NotificationManager::SlicingProgressNotification::on_change_color_mode(bool is_dark) { PopNotification::on_change_color_mode(is_dark); m_dailytips_panel->on_change_color_mode(is_dark); } void NotificationManager::SlicingProgressNotification::init() { if (m_sp_state == SlicingProgressState::SP_PROGRESS) { PopNotification::init(); if (m_endlines.empty()) { m_endlines.push_back(0); } if (m_lines_count >= 2) { m_lines_count = 3; m_multiline = true; while (m_endlines.size() < 3) m_endlines.push_back(m_endlines.back()); } else { m_lines_count = 2; m_endlines.push_back(m_endlines.back()); m_multiline = false; } if (m_state == EState::Shown) m_state = EState::NotFading; } else { PopNotification::init(); } } bool NotificationManager::SlicingProgressNotification::set_progress_state(float percent) { if (percent < 0.f) return true;//set_progress_state(SlicingProgressState::SP_CANCELLED); else if (percent >= 1.f) { m_before_complete_start = GLCanvas3D::timestamp_now(); return set_progress_state(SlicingProgressState::SP_COMPLETED); } else return set_progress_state(SlicingProgressState::SP_PROGRESS, percent); } bool NotificationManager::SlicingProgressNotification::set_progress_state(NotificationManager::SlicingProgressNotification::SlicingProgressState state, float percent/* = 0.f*/) { switch (state) { case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_NO_SLICING: m_state = EState::Hidden; set_percentage(-1); m_has_print_info = false; set_export_possible(false); m_sp_state = state; return true; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_BEGAN: m_state = EState::Hidden; set_percentage(-1); m_has_print_info = false; set_export_possible(false); m_sp_state = state; m_current_fade_opacity = 1; return true; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_PROGRESS: if ((m_sp_state != SlicingProgressState::SP_BEGAN && m_sp_state != SlicingProgressState::SP_PROGRESS) || percent < m_percentage) return false; set_percentage(percent); m_sp_state = state; m_current_fade_opacity = 1; return true; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_CANCELLED: set_percentage(-1); m_has_print_info = false; set_export_possible(false); m_sp_state = state; return true; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_COMPLETED: if (m_sp_state != SlicingProgressState::SP_BEGAN && m_sp_state != SlicingProgressState::SP_PROGRESS) return false; set_percentage(1); m_has_print_info = false; // m_export_possible is important only for SP_PROGRESS state, thus we can reset it here set_export_possible(false); m_sp_state = state; return true; default: break; } return false; } void NotificationManager::SlicingProgressNotification::set_status_text(const std::string& text) { switch (m_sp_state) { case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_NO_SLICING: m_state = EState::Hidden; break; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_PROGRESS: { NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text + "." }; update(data); m_state = EState::NotFading; } break; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_CANCELLED: { NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, text }; update(data); m_state = EState::Shown; } break; case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_COMPLETED: { NotificationData data{ NotificationType::SlicingProgress, NotificationLevel::ProgressBarNotificationLevel, 0, _u8L("Slice ok.") }; update(data); m_state = EState::Shown; } break; default: break; } } void NotificationManager::SlicingProgressNotification::set_print_info(const std::string& info) { if (m_sp_state != SlicingProgressState::SP_COMPLETED) { set_progress_state (SlicingProgressState::SP_COMPLETED); } else { m_has_print_info = true; m_print_info = info; } } void NotificationManager::SlicingProgressNotification::set_sidebar_collapsed(bool collapsed) { m_sidebar_collapsed = collapsed; if (m_sp_state == SlicingProgressState::SP_COMPLETED && collapsed) m_state = EState::NotFading; } void NotificationManager::SlicingProgressNotification::on_cancel_button() { if (m_cancel_callback){ if (!m_cancel_callback()) { set_progress_state(SlicingProgressState::SP_NO_SLICING); } } } int NotificationManager::SlicingProgressNotification::get_duration() { if (m_sp_state == SlicingProgressState::SP_CANCELLED) return 3; else if (m_sp_state == SlicingProgressState::SP_COMPLETED) return 3; else return 0; } bool NotificationManager::SlicingProgressNotification::update_state(bool paused, const int64_t delta) { bool ret = PopNotification::update_state(paused, delta); if (m_sp_state == SlicingProgressState::SP_COMPLETED) ret = true; // sets Estate to hidden if (get_state() == PopNotification::EState::ClosePending || get_state() == PopNotification::EState::Finished) set_progress_state(SlicingProgressState::SP_NO_SLICING); return ret; } void NotificationManager::SlicingProgressNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width, float right_margin) { if (m_state == EState::Unknown || m_state == PopNotification::EState::Hovered) init(); ImGuiWrapper& imgui = *wxGetApp().imgui(); float scale = imgui.get_font_size() / 15.0f; bool fading_pop = false; if (m_state == EState::FadingOut) { push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), true, m_current_fade_opacity); push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), true, m_current_fade_opacity); push_style_color(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4(ImGuiCol_ButtonHovered), true, m_current_fade_opacity); fading_pop = true; } use_bbl_theme(); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8 * scale, 0)); // for debug //ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, m_WindowRadius / 4); //m_is_dark ? push_style_color(ImGuiCol_Border, { 62 / 255.f, 62 / 255.f, 69 / 255.f, 1.f }, true, m_current_fade_opacity) : push_style_color(ImGuiCol_Border, m_CurrentColor, true, m_current_fade_opacity); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); push_style_color(ImGuiCol_Border, { 0, 0, 0, 0 }, true, m_current_fade_opacity); Size cnv_size = canvas.get_canvas_size(); //m_window_width = 600.f * scale; //if (m_sp_state == SlicingProgressNotification::SlicingProgressState::SP_COMPLETED || m_sp_state == SlicingProgressNotification::SlicingProgressState::SP_CANCELLED) // m_window_width = m_line_height * 25; const ImVec2 progress_child_window_padding = ImVec2(15.f, 0.f) * scale; const ImVec2 dailytips_child_window_padding = m_dailytips_panel->is_expanded() ? ImVec2(15.f, 10.f) * scale : ImVec2(15.f, 0.f) * scale; const ImVec2 bottom_padding = ImVec2(0.f, 0.f) * scale; const float progress_panel_width = (m_window_width - 2 * progress_child_window_padding.x); const float progress_panel_height = (58.0f * scale); const float dailytips_panel_width = (m_window_width - 2 * dailytips_child_window_padding.x); const float gcodeviewer_height = wxGetApp().plater()->get_preview_canvas3D()->get_gcode_viewer().get_legend_height(); //const float dailytips_panel_height = std::min(380.0f * scale, std::max(90.0f, (cnv_size.get_height() - gcodeviewer_height - progress_panel_height - dailytips_child_window_padding.y - initial_y - m_line_height * 4))); const float dailytips_panel_height = 380.0f * scale; float right_gap = right_margin + (move_from_overlay ? overlay_width + m_line_height * 5 : 0); m_window_pos = ImVec2((float)cnv_size.get_width() - right_gap - m_window_width, (float)cnv_size.get_height() - m_top_y); imgui.set_next_window_pos(m_window_pos.x, m_window_pos.y, ImGuiCond_Always, 0.0f, 0.0f); m_window_height = progress_panel_height + m_dailytips_panel->get_size().y + progress_child_window_padding.y + dailytips_child_window_padding.y + bottom_padding.y; m_top_y = initial_y + m_window_height; ImGui::SetNextWindowSizeConstraints(ImVec2(m_window_width, m_window_height), ImVec2(m_window_width, m_window_height)); // 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); int window_flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; int child_window_flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; if (imgui.begin(name, window_flags)) { ImGuiWindow* parent_window = ImGui::GetCurrentWindow(); //if (m_sp_state == SlicingProgressState::SP_CANCELLED || m_sp_state == SlicingProgressState::SP_COMPLETED) { // ImVec2 button_size = ImVec2(38.f, 38.f) * scale; // float button_right_margin_x = 3.0f * scale; // ImVec2 button_pos = m_window_pos + ImVec2(m_window_width - button_size.x - button_right_margin_x, (m_window_height - button_size.y) / 2.0f); // float text_left_margin_x = 15.0f * scale; // ImVec2 text_pos = m_window_pos + ImVec2(text_left_margin_x, m_window_height / 2.0f - m_line_height * 1.2f); // ImVec2 view_dailytips_text_pos = m_window_pos + ImVec2(text_left_margin_x, m_window_height / 2.0f + m_line_height * 0.2f); // bbl_render_left_sign(imgui, m_window_width, m_window_height, m_window_pos.x + m_window_width, m_window_pos.y); // render_text(text_pos); // render_close_button(button_pos, button_size); // render_show_dailytips(view_dailytips_text_pos); //} if (m_sp_state == SlicingProgressState::SP_CANCELLED || m_sp_state == SlicingProgressState::SP_PROGRESS || m_sp_state == SlicingProgressState::SP_COMPLETED) { std::string child_name = "##SlicingProgressPanel" + std::to_string(parent_window->ID); ImGui::SetNextWindowPos(parent_window->Pos + progress_child_window_padding); if (ImGui::BeginChild(child_name.c_str(), ImVec2(progress_panel_width, progress_panel_height), false, child_window_flags)) { ImVec2 child_window_pos = ImGui::GetWindowPos(); ImVec2 button_size = ImVec2(38.f, 38.f) * scale; ImVec2 button_pos = child_window_pos + ImVec2(progress_panel_width - button_size.x, (progress_panel_height - button_size.y) / 2.0f); float margin_x = 8.0f * scale; ImVec2 progress_bar_pos = child_window_pos + ImVec2(0, progress_panel_height / 2.0f); ImVec2 progress_bar_size = ImVec2(progress_panel_width - button_size.x - margin_x, 4.0f * scale); ImVec2 text_pos = ImVec2(progress_bar_pos.x, progress_bar_pos.y - m_line_height * 1.2f); render_text(text_pos); render_close_button(button_pos, button_size); if (m_sp_state == SlicingProgressState::SP_PROGRESS) { render_bar(progress_bar_pos, progress_bar_size); render_cancel_button(button_pos, button_size); } } ImGui::EndChild(); // Separator Line ImVec2 separator_min = ImVec2(ImGui::GetCursorScreenPos().x + progress_child_window_padding.x, ImGui::GetCursorScreenPos().y); ImVec2 separator_max = ImVec2(ImGui::GetCursorScreenPos().x + progress_child_window_padding.x + progress_panel_width, ImGui::GetCursorScreenPos().y); ImGui::GetCurrentWindow()->DrawList->AddLine(separator_min, separator_max, ImColor(238, 238, 238, (int)(255 * m_current_fade_opacity))); child_name = "##DailyTipsPanel" + std::to_string(parent_window->ID); ImVec2 dailytips_pos = ImGui::GetCursorScreenPos() + dailytips_child_window_padding; ImVec2 dailytips_size = ImVec2(dailytips_panel_width, dailytips_panel_height); m_dailytips_panel->set_position(dailytips_pos); m_dailytips_panel->set_size(dailytips_size); m_dailytips_panel->set_fade_opacity(m_current_fade_opacity); ImGui::SetNextWindowPos(dailytips_pos); if (ImGui::BeginChild(child_name.c_str(), ImVec2(dailytips_panel_width, dailytips_panel_height), false, child_window_flags)) { render_dailytips_panel(dailytips_pos, dailytips_size); } ImGui::EndChild(); } if (ImGui::IsMouseHoveringRect(ImGui::GetWindowPos(), ImGui::GetWindowPos() + ImGui::GetWindowSize(), true)) { set_hovered(); } } imgui.end(); ImGui::PopStyleVar(2); ImGui::PopStyleColor(1); restore_default_theme(); if (fading_pop) ImGui::PopStyleColor(3); } void Slic3r::GUI::NotificationManager::SlicingProgressNotification::render_text(const ImVec2& pos) { ImGuiWrapper& imgui = *wxGetApp().imgui(); float scale = imgui.get_font_size() / 15.0f; ImVec2 icon_size = ImVec2(38.f, 38.f) * scale; if (m_sp_state == SlicingProgressState::SP_COMPLETED) { // complete icon ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); ImGui::SetCursorScreenPos(pos); std::wstring icon_text; icon_text = ImGui::CompleteIcon; imgui.button(icon_text.c_str()); ImGui::PopStyleColor(5); // complete text imgui.push_bold_font(); ImGui::SetCursorScreenPos(ImVec2(pos.x + icon_size.x + ImGui::CalcTextSize(" ").x, pos.y + (icon_size.y - m_line_height) / 2)); imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); imgui.pop_bold_font(); return; } if (m_sp_state == SlicingProgressState::SP_CANCELLED) { imgui.push_bold_font(); ImGui::SetCursorScreenPos(ImVec2(pos.x + ImGui::CalcTextSize(" ").x, pos.y + (icon_size.y - m_line_height) / 2)); imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); imgui.pop_bold_font(); } if(m_sp_state == SlicingProgressState::SP_PROGRESS) { //one line text ImGui::SetCursorScreenPos(pos); imgui.text(m_text1.substr(0, m_endlines[0]).c_str()); } } void Slic3r::GUI::NotificationManager::SlicingProgressNotification::render_bar(const ImVec2& pos, const ImVec2& size) { if (m_sp_state != SlicingProgressState::SP_PROGRESS) return; ImGuiWrapper& imgui = *wxGetApp().imgui(); //ImColor progress_color = ImColor(0, 174, 66, (int)(255 * m_current_fade_opacity)); ImColor progress_color = ImColor(33, 95, 154, (int)(255 * m_current_fade_opacity)); ImColor bg_color = ImColor(217, 217, 217, (int)(255 * m_current_fade_opacity)); ImVec2 lineStart = pos; ImVec2 lineEnd = lineStart + size; ImVec2 midPoint = ImVec2(lineStart.x + (lineEnd.x - lineStart.x) * m_percentage, lineEnd.y); ImGui::GetWindowDrawList()->AddRectFilled(lineStart, lineEnd, bg_color); ImGui::GetWindowDrawList()->AddRectFilled(lineStart, midPoint, progress_color); // percentage text ImVec2 text_pos = ImVec2(pos.x, pos.y + size.y + m_line_height * 0.2f); std::string text; std::stringstream stream; stream << std::fixed << std::setprecision(2) << (int)(m_percentage * 100) << "%"; text = stream.str(); ImGui::SetCursorScreenPos(text_pos); imgui.text(text.c_str()); } void NotificationManager::SlicingProgressNotification::render_dailytips_panel(const ImVec2& pos, const ImVec2& size) { m_dailytips_panel->render(); } void NotificationManager::SlicingProgressNotification::render_show_dailytips(const ImVec2& pos) { if (m_sp_state != SlicingProgressState::SP_COMPLETED && m_sp_state != SlicingProgressState::SP_CANCELLED) return; ImGuiWrapper& imgui = *wxGetApp().imgui(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_Text, ImColor(31, 142, 234).Value); ImGui::SetCursorScreenPos(pos); std::wstring button_text; button_text = ImGui::OpenArrowIcon; imgui.button(_L("View all Daily tips") + " " + button_text); //click behavior if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true)) { //underline ImVec2 lineEnd = ImGui::GetItemRectMax(); lineEnd.x -= ImGui::CalcTextSize("A").x / 2; lineEnd.y -= 2; ImVec2 lineStart = lineEnd; lineStart.x = ImGui::GetItemRectMin().x; ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, ImColor(31, 142, 234)); if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) on_show_dailytips(); } ImGui::PopStyleColor(4); } void NotificationManager::SlicingProgressNotification::on_show_dailytips() { wxGetApp().plater()->get_dailytips()->open(); } void Slic3r::GUI::NotificationManager::SlicingProgressNotification::render_cancel_button(const ImVec2& pos, const ImVec2& size) { if (m_sp_state == SlicingProgressState::SP_PROGRESS) { ImGuiWrapper& imgui = *wxGetApp().imgui(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); ImVec2 button_size = size; ImVec2 button_pos = pos; ImGui::SetCursorScreenPos(button_pos); std::wstring button_text; button_text = ImGui::CancelButton; if (ImGui::IsMouseHoveringRect(button_pos, button_pos + button_size, true)) { button_text = ImGui::CancelHoverButton; if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) on_cancel_button(); } imgui.button(button_text); ImGui::PopStyleColor(5); } } void NotificationManager::SlicingProgressNotification::render_close_button(const ImVec2& pos, const ImVec2& size) { if (m_sp_state == SlicingProgressState::SP_CANCELLED || m_sp_state == SlicingProgressState::SP_COMPLETED) { ImGuiWrapper& imgui = *wxGetApp().imgui(); ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f)); push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f)); ImVec2 button_size = size; ImVec2 button_pos = pos; ImGui::SetCursorScreenPos(button_pos); std::wstring button_text; button_text = m_is_dark ? ImGui::CloseNotifDarkButton : ImGui::CloseNotifButton; if (ImGui::IsMouseHoveringRect(button_pos, button_pos + button_size, true)) { button_text = m_is_dark ? ImGui::CloseNotifHoverDarkButton : ImGui::CloseNotifHoverButton; if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) close(); } imgui.button(button_text); ImGui::PopStyleColor(5); } } }}