ENH: refactor DailyTips

jira: new

1. Refactor the UI:
	put dailytips into slicing notification
	add image for dailytips
	adjust Layout and UI control
	adapts retina scale, adapts dark mode color
2. New Features
	ability to expand/collapse the dailytips
	ability to freely go to next/prev page of dailytips
	show a random dailytip each time when begin to slice
	ability to remember the default statet add .
	of whether expand the dailytips
3. Remove original hintNotification related logic

Change-Id: I99bfa8c19c9417d25cb2f6e205f5e66b7680b189
This commit is contained in:
liz.li
2023-10-18 20:39:18 +08:00
committed by Lane.Wei
parent 16ae34d906
commit dd666a6313
38 changed files with 1349 additions and 387 deletions

View File

@@ -199,6 +199,14 @@ namespace ImGui
const wchar_t CloseBlockNotifHoverButton = 0x0834;
const wchar_t BlockNotifErrorIcon = 0x0835;
const wchar_t PrevArrowBtnIcon = 0x0836;
const wchar_t PrevArrowHoverBtnIcon = 0x0837;
const wchar_t NextArrowBtnIcon = 0x0838;
const wchar_t NextArrowHoverBtnIcon = 0x0839;
const wchar_t OpenArrowIcon = 0x0840;
const wchar_t CollapseArrowIcon = 0x0841;
const wchar_t ExpandArrowIcon = 0x0842;
// void MyFunction(const char* name, const MyMatrix44& v);
}

View File

@@ -82,6 +82,8 @@ set(SLIC3R_GUI_SOURCES
GUI/AuxiliaryDialog.hpp
GUI/Auxiliary.cpp
GUI/Auxiliary.hpp
GUI/DailyTips.cpp
GUI/DailyTips.hpp
GUI/Project.cpp
GUI/Project.hpp
GUI/BackgroundSlicingProcess.cpp
@@ -103,6 +105,8 @@ set(SLIC3R_GUI_SOURCES
GUI/OpenGLManager.cpp
GUI/Selection.hpp
GUI/Selection.cpp
GUI/SlicingProgressNotification.cpp
GUI/SlicingProgressNotification.hpp
GUI/Gizmos/GLGizmosManager.cpp
GUI/Gizmos/GLGizmosManager.hpp
GUI/Gizmos/GLGizmosCommon.cpp
@@ -271,7 +275,7 @@ set(SLIC3R_GUI_SOURCES
GUI/3DBed.hpp
GUI/Camera.cpp
GUI/Camera.hpp
GUI/CameraUtils.cpp
GUI/CameraUtils.cpp
GUI/CameraUtils.hpp
GUI/wxExtensions.cpp
GUI/wxExtensions.hpp
@@ -374,7 +378,7 @@ set(SLIC3R_GUI_SOURCES
GUI/DragCanvas.hpp
GUI/PublishDialog.cpp
GUI/PublishDialog.hpp
GUI/RecenterDialog.cpp
GUI/RecenterDialog.cpp
GUI/RecenterDialog.hpp
GUI/PrivacyUpdateDialog.cpp
GUI/PrivacyUpdateDialog.hpp
@@ -402,13 +406,13 @@ set(SLIC3R_GUI_SOURCES
GUI/CalibrationWizard.cpp
GUI/CalibrationWizardPage.cpp
GUI/CalibrationWizardPage.hpp
GUI/CalibrationWizardStartPage.cpp
GUI/CalibrationWizardStartPage.cpp
GUI/CalibrationWizardStartPage.hpp
GUI/CalibrationWizardPresetPage.cpp
GUI/CalibrationWizardPresetPage.cpp
GUI/CalibrationWizardPresetPage.hpp
GUI/CalibrationWizardCaliPage.cpp
GUI/CalibrationWizardCaliPage.cpp
GUI/CalibrationWizardCaliPage.hpp
GUI/CalibrationWizardSavePage.cpp
GUI/CalibrationWizardSavePage.cpp
GUI/CalibrationWizardSavePage.hpp
GUI/calib_dlg.cpp
GUI/calib_dlg.hpp

View File

@@ -0,0 +1,560 @@
#include "DailyTips.hpp"
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include <imgui/imgui_internal.h>
namespace Slic3r { namespace GUI {
struct DailyTipsData {
std::string main_text;
std::string wiki_url;
std::string img_url;
std::string additional_text; // currently not used
std::string hyper_text; // currently not used
std::function<void(void)> hypertext_callback; // currently not used
};
class DailyTipsDataRenderer {
public:
DailyTipsDataRenderer() = default;
~DailyTipsDataRenderer();
void update_data(const DailyTipsData& data);
void render(const ImVec2& pos, const ImVec2& size) const;
bool has_image() const;
protected:
void load_texture_from_img_url(const std::string url);
void open_wiki() const;
// relative to the window's upper-left position
void render_img(const ImVec2& start_pos, const ImVec2& size) const;
void render_text(const ImVec2& start_pos, const ImVec2& size) const;
private:
DailyTipsData m_data;
GLTexture* m_texture{ nullptr };
GLTexture* m_placeholder_texture{ nullptr };
};
DailyTipsDataRenderer::~DailyTipsDataRenderer() {
if (m_texture)
delete m_texture;
if (m_placeholder_texture)
delete m_placeholder_texture;
}
void DailyTipsDataRenderer::update_data(const DailyTipsData& data)
{
m_data = data;
load_texture_from_img_url(m_data.img_url);
}
void DailyTipsDataRenderer::load_texture_from_img_url(const std::string url)
{
if (m_texture) {
delete m_texture;
m_texture = nullptr;
}
if (!url.empty()) {
m_texture = new GLTexture();
m_texture->load_from_file(Slic3r::resources_dir() + "/" + url, true, GLTexture::None, false);
}
else {
if (!m_placeholder_texture) {
m_placeholder_texture = new GLTexture();
m_placeholder_texture->load_from_file(Slic3r::resources_dir() + "/images/dailytips_placeholder.png", true, GLTexture::None, false);
}
}
}
void DailyTipsDataRenderer::open_wiki() const
{
if (!m_data.wiki_url.empty())
{
wxGetApp().open_browser_with_warning_dialog(m_data.wiki_url);
}
}
void DailyTipsDataRenderer::render(const ImVec2& pos, const ImVec2& size) const
{
ImGuiWrapper& imgui = *wxGetApp().imgui();
ImGuiWindow* parent_window = ImGui::GetCurrentWindow();
int window_flags = parent_window->Flags;
std::string name = "##DailyTipsDataRenderer" + std::to_string(parent_window->ID);
ImGui::SetNextWindowPos(pos);
if (ImGui::BeginChild(name.c_str(), size, false, window_flags)) {
ImVec2 img_size = ImVec2(size.x, 9.0f / 16.0f * size.x);
render_img({0, 0}, img_size);
float img_text_gap = ImGui::CalcTextSize("A").y;
render_text({0, img_size.y + img_text_gap }, size);
}
ImGui::EndChild();
}
bool DailyTipsDataRenderer::has_image() const
{
return !m_data.img_url.empty();
}
void DailyTipsDataRenderer::render_img(const ImVec2& start_pos, const ImVec2& size) const
{
if (has_image())
ImGui::Image((ImTextureID)(intptr_t)m_texture->get_id(), size);
else {
ImGui::Image((ImTextureID)(intptr_t)m_placeholder_texture->get_id(), size);
}
}
void DailyTipsDataRenderer::render_text(const ImVec2& start_pos, const ImVec2& size) const
{
ImGuiWrapper& imgui = *wxGetApp().imgui();
// main text
// first line is headline (for hint notification it must be divided by \n)
std::string title_line;
std::string content_lines;
size_t end_pos = m_data.main_text.find_first_of('\n');
if (end_pos != std::string::npos) {
title_line = m_data.main_text.substr(0, end_pos);
title_line = ImGui::ColorMarkerStart + title_line + ImGui::ColorMarkerEnd;
content_lines = m_data.main_text.substr(end_pos + 1);
}
ImGui::SetCursorPosY(start_pos.y);
imgui.text(title_line);
bool is_zh = false;
for (int i = 0; i < content_lines.size() - 1; i += 2) {
if ((content_lines[i] & 0x80) && (content_lines[i + 1] & 0x80))
is_zh = true;
}
if (!is_zh) {
// problem in Chinese with spaces
imgui.text_wrapped(content_lines, size.x);
}
else {
Label* wrapped_text = new Label(wxGetApp().GetTopWindow());
wrapped_text->Hide();
wrapped_text->SetLabelText(wxString::FromUTF8(content_lines));
wrapped_text->Wrap(size.x + ImGui::CalcTextSize("A").x * 5.0f);
std::string wrapped_content_lines = wrapped_text->GetLabel().ToUTF8().data();
wrapped_text->Destroy();
imgui.text(wrapped_content_lines);
}
// wiki
if (!m_data.wiki_url.empty()) {
std::string tips_line = _u8L("For more information, please check out Wiki");
std::string wiki_part_text = _u8L("Wiki");
std::string first_part_text = tips_line.substr(0, tips_line.find(wiki_part_text));
ImVec2 wiki_part_size = ImGui::CalcTextSize(wiki_part_text.c_str());
ImVec2 first_part_size = ImGui::CalcTextSize(first_part_text.c_str());
ImVec2 link_start_pos = ImGui::GetCursorScreenPos();
//text
imgui.text(first_part_text);
ImColor HyperColor = ImColor(31, 142, 234).Value;
ImVec2 wiki_part_rect_min = ImVec2(link_start_pos.x + first_part_size.x, link_start_pos.y);
ImVec2 wiki_part_rect_max = wiki_part_rect_min + wiki_part_size;
ImGui::PushStyleColor(ImGuiCol_Text, HyperColor.Value);
ImGui::SetCursorScreenPos(wiki_part_rect_min);
imgui.text(wiki_part_text.c_str());
ImGui::PopStyleColor();
//click behavior
if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true))
{
//underline
ImVec2 lineEnd = ImGui::GetItemRectMax();
lineEnd.y -= 2.0f;
ImVec2 lineStart = lineEnd;
lineStart.x = ImGui::GetItemRectMin().x;
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, HyperColor);
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
open_wiki();
}
}
}
int DailyTipsPanel::uid = 0;
DailyTipsPanel::DailyTipsPanel(bool can_expand)
: DailyTipsPanel(ImVec2(0, 0), ImVec2(0, 0), can_expand)
{
}
void DailyTipsPanel::set_position(const ImVec2& pos)
{
m_pos = pos;
}
void DailyTipsPanel::set_size(const ImVec2& size)
{
m_width = size.x;
m_height = size.y;
m_content_height = m_height - m_header_height - m_footer_height;
}
ImVec2 DailyTipsPanel::get_size()
{
return ImVec2(m_width, m_height);
}
DailyTipsPanel::DailyTipsPanel(const ImVec2& pos, const ImVec2& size, bool can_expand)
: m_pos(pos),
m_width(size.x),
m_height(size.y),
m_can_expand(can_expand)
{
m_dailytips_renderer = std::make_unique<DailyTipsDataRenderer>();
m_is_expanded = wxGetApp().app_config->get("show_hints") == "true";
m_uid = (DailyTipsPanel::uid++);
}
void DailyTipsPanel::render()
{
m_header_height = m_can_expand ? 38.0f * m_scale : 0;
m_footer_height = 38.0f * m_scale;
m_content_height = m_height - m_header_height - m_footer_height;
if (!m_first_enter) {
retrieve_data_from_hint_database(HintDataNavigation::Curr);
m_first_enter = true;
}
push_styles();
if (m_can_expand) {
if (m_is_expanded) {
m_height = m_header_height + m_content_height + m_footer_height;
}
else {
m_height = m_footer_height;
}
}
ImGui::SetNextWindowPos(m_pos);
ImGui::SetNextWindowSizeConstraints(ImVec2(m_width, m_height), ImVec2(m_width, m_height));
int window_flags = ImGuiWindowFlags_NoTitleBar
| ImGuiWindowFlags_NoCollapse
| ImGuiWindowFlags_NoMove
| ImGuiWindowFlags_NoResize
| ImGuiWindowFlags_NoScrollbar
| ImGuiWindowFlags_NoScrollWithMouse;
if (ImGui::BeginChild((std::string("##DailyTipsPanel") + std::to_string(m_uid)).c_str(), ImVec2(m_width, m_height), false, window_flags)) {
if (m_can_expand) {
if (m_is_expanded) {
render_header(m_pos, { m_width, m_header_height });
m_dailytips_renderer->render({ m_pos.x, m_pos.y + m_header_height }, { m_width, m_content_height });
render_controller_buttons({ m_pos.x, m_pos.y + m_height - m_footer_height }, { m_width, m_footer_height });
}
else {
render_controller_buttons({ m_pos.x, m_pos.y + m_height - m_footer_height }, { m_width, m_footer_height });
}
}
else {
m_dailytips_renderer->render({ m_pos.x, m_pos.y }, { m_width, m_content_height });
render_controller_buttons({ m_pos.x, m_pos.y + m_height - m_footer_height }, { m_width, m_footer_height });
}
//{// for debug
// ImVec2 vMin = ImGui::GetWindowContentRegionMin();
// ImVec2 vMax = ImGui::GetWindowContentRegionMax();
// vMin += ImGui::GetWindowPos();
// vMax += ImGui::GetWindowPos();
// ImGui::GetForegroundDrawList()->AddRect(vMin, vMax, IM_COL32(180, 180, 255, 255));
//}
}
ImGui::EndChild();
pop_styles();
}
void DailyTipsPanel::retrieve_data_from_hint_database(HintDataNavigation nav)
{
HintData* hint_data = HintDatabase::get_instance().get_hint(nav);
if (hint_data != nullptr)
{
DailyTipsData data{ hint_data->text,
hint_data->documentation_link,
hint_data->image_url,
hint_data->follow_text,
hint_data->hypertext,
hint_data->callback
};
m_dailytips_renderer->update_data(data);
}
}
void DailyTipsPanel::expand(bool expand)
{
if (!m_can_expand)
return;
m_is_expanded = expand;
wxGetApp().app_config->set_bool("show_hints", expand);
}
void DailyTipsPanel::collapse()
{
if (!m_can_expand)
return;
m_is_expanded = false;
wxGetApp().app_config->set_bool("show_hints", false);
}
bool DailyTipsPanel::is_expanded()
{
return m_is_expanded;
}
void DailyTipsPanel::set_scale(float scale)
{
m_scale = scale;
}
void DailyTipsPanel::render_header(const ImVec2& pos, const ImVec2& size)
{
ImGuiWrapper& imgui = *wxGetApp().imgui();
ImGuiWindow* parent_window = ImGui::GetCurrentWindow();
int window_flags = parent_window->Flags;
std::string name = "##DailyTipsPanelHeader" + std::to_string(parent_window->ID);
ImGui::SetNextWindowPos(pos);
if (ImGui::BeginChild(name.c_str(), size, false, window_flags)) {
ImVec2 text_pos = pos + ImVec2(0, (size.y - ImGui::CalcTextSize("A").y) / 2);
ImGui::SetCursorScreenPos(text_pos);
imgui.push_bold_font();
imgui.text(_u8L("Daily Tips"));
imgui.pop_bold_font();
}
ImGui::EndChild();
}
void DailyTipsPanel::render_controller_buttons(const ImVec2& pos, const ImVec2& size)
{
ImGuiWrapper& imgui = *wxGetApp().imgui();
ImGuiWindow* parent_window = ImGui::GetCurrentWindow();
int window_flags = parent_window->Flags;
std::string name = "##DailyTipsPanelControllers" + std::to_string(parent_window->ID);
ImGui::SetNextWindowPos(pos);
if (ImGui::BeginChild(name.c_str(), size, false, window_flags)) {
ImVec2 button_size = ImVec2(size.y, size.y);
float button_margin_x = 8.0f;
std::wstring button_text;
// collapse / expand
ImVec2 btn_pos = pos + ImVec2(0, (size.y - ImGui::CalcTextSize("A").y) / 2);
ImGui::SetCursorScreenPos(btn_pos);
if (m_can_expand) {
if (m_is_expanded) {
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(144, 144, 144).Value);
button_text = ImGui::CollapseArrowIcon;
imgui.button((_u8L("Collapse") + button_text).c_str());
ImVec2 collapse_btn_size = ImGui::CalcTextSize((_u8L("Collapse")).c_str());
collapse_btn_size.x += button_size.x / 2.0f;
if (ImGui::IsMouseHoveringRect(btn_pos, btn_pos + collapse_btn_size, 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(144, 144, 144));
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
collapse();
}
ImGui::PopStyleColor(4);
}
else {
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));
// for bold font text, split text and icon-font button
imgui.push_bold_font();
imgui.button((_u8L("Daily Tips")).c_str());
imgui.pop_bold_font();
ImVec2 expand_btn_size = ImGui::CalcTextSize((_u8L("Daily Tips")).c_str());
ImGui::SetCursorScreenPos(ImVec2(btn_pos.x + expand_btn_size.x + ImGui::CalcTextSize(" ").x, btn_pos.y));
std::wstring button_text;
button_text = ImGui::ExpandArrowIcon;
imgui.button(button_text.c_str());
expand_btn_size.x += 19.0f * m_scale;
if (ImGui::IsMouseHoveringRect(btn_pos, btn_pos + expand_btn_size, true))
{
//underline
ImVec2 lineEnd = ImGui::GetItemRectMax();
lineEnd.x -= ImGui::CalcTextSize("A").x / 2;
lineEnd.y -= 2;
ImVec2 lineStart = lineEnd;
lineStart.x = ImGui::GetItemRectMin().x - expand_btn_size.x;
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, ImColor(38, 46, 48));
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
expand();
}
ImGui::PopStyleColor(3);
ImGui::EndChild();
return;
}
}
// page index
m_page_index = HintDatabase::get_instance().get_index() + 1;
m_pages_count = HintDatabase::get_instance().get_count();
std::string text_str = std::to_string(m_page_index) + "/" + std::to_string(m_pages_count);
float text_item_width = ImGui::CalcTextSize(text_str.c_str()).x;
ImGui::PushItemWidth(text_item_width);
float text_pos_x = (pos + size).x - button_margin_x * 2 - button_size.x * 2 - text_item_width;
float text_pos_y = pos.y + (size.y - ImGui::CalcTextSize("A").y) / 2;
ImGui::SetCursorScreenPos(ImVec2(text_pos_x, text_pos_y));
imgui.text(text_str);
ImGui::PopItemWidth();
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_Border, ImVec4(.0f, .0f, .0f, .0f));
ImGui::PushStyleColor(ImGuiCol_Text, ImColor(255, 255, 255).Value);// for icon-font button
// prev button
ImVec2 prev_button_pos = pos + size + ImVec2(-button_margin_x - button_size.x * 2, -size.y);
ImGui::SetCursorScreenPos(prev_button_pos);
button_text = ImGui::PrevArrowBtnIcon;
if (ImGui::IsMouseHoveringRect(prev_button_pos, prev_button_pos + button_size, true))
{
button_text = ImGui::PrevArrowHoverBtnIcon;
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
retrieve_data_from_hint_database(HintDataNavigation::Prev);
}
imgui.button(button_text.c_str());
// next button
ImVec2 next_button_pos = pos + size + ImVec2(-button_size.x, -size.y);
ImGui::SetCursorScreenPos(next_button_pos);
button_text = ImGui::NextArrowBtnIcon;
if (ImGui::IsMouseHoveringRect(next_button_pos, next_button_pos + button_size, true))
{
button_text = ImGui::NextArrowHoverBtnIcon;
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left))
retrieve_data_from_hint_database(HintDataNavigation::Next);
}
imgui.button(button_text.c_str());
ImGui::PopStyleColor(5);
}
ImGui::EndChild();
}
void DailyTipsPanel::push_styles()
{
ImGuiWrapper& imgui = *wxGetApp().imgui();
imgui.push_common_window_style(m_scale);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
// framePadding cannot be zero. Otherwise, there is a problem with icon font button display
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1.0f, 1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(0.0f, 0.0f));
}
void DailyTipsPanel::pop_styles()
{
ImGuiWrapper& imgui = *wxGetApp().imgui();
imgui.pop_common_window_style();
ImGui::PopStyleVar(5);
}
DailyTipsWindow::DailyTipsWindow()
{
m_panel = new DailyTipsPanel(false);
}
void DailyTipsWindow::open()
{
m_show = true;
m_panel->retrieve_data_from_hint_database(HintDataNavigation::Curr);
}
void DailyTipsWindow::close()
{
m_show = false;
}
void DailyTipsWindow::render()
{
if (!m_show)
return;
//if (m_show)
// ImGui::OpenPopup((_u8L("Daily Tips")).c_str());
ImGuiWrapper& imgui = *wxGetApp().imgui();
const Size& cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size();
ImVec2 center = ImVec2(cnv_size.get_width() * 0.5f, cnv_size.get_height() * 0.5f);
ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
ImVec2 padding = ImVec2(25, 25) * m_scale;
imgui.push_menu_style(m_scale);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, padding);
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.f * m_scale);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 3) * m_scale);
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(10, 7) * m_scale);
ImGui::PushStyleColor(ImGuiCol_TitleBgActive, m_is_dark ? ImVec4(54 / 255.0f, 54 / 255.0f, 60 / 255.0f, 1.00f) : ImVec4(245 / 255.0f, 245 / 255.0f, 245 / 255.0f, 1.00f));
ImGui::GetCurrentContext()->DimBgRatio = 1.0f;
int windows_flag =
ImGuiWindowFlags_NoCollapse
| ImGuiWindowFlags_AlwaysAutoResize
| ImGuiWindowFlags_NoResize
| ImGuiWindowFlags_NoScrollbar
| ImGuiWindowFlags_NoScrollWithMouse;
imgui.push_bold_font();
//if (ImGui::BeginPopupModal((_u8L("Daily Tips")).c_str(), NULL, windows_flag))
if (ImGui::Begin((_u8L("Daily Tips")).c_str(), &m_show, windows_flag))
{
imgui.pop_bold_font();
ImVec2 panel_pos = ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin();
ImVec2 panel_size = ImVec2(400.0f, 435.0f) * m_scale;
m_panel->set_position(panel_pos);
m_panel->set_size(panel_size);
m_panel->render();
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape))) {
m_show = false;
ImGui::CloseCurrentPopup();
}
ImGui::End();
//ImGui::EndPopup();
}
else {
imgui.pop_bold_font();
}
ImGui::PopStyleVar(4);
ImGui::PopStyleColor();
imgui.pop_menu_style();
}
void DailyTipsWindow::set_scale(float scale)
{
m_scale = scale;
m_panel->set_scale(scale);
}
void DailyTipsWindow::on_change_color_mode(bool is_dark)
{
m_is_dark = is_dark;
}
}}

View File

@@ -0,0 +1,70 @@
#ifndef slic3r_GUI_DailyTips_hpp_
#define slic3r_GUI_DailyTips_hpp_
#include "HintNotification.hpp"
//#include <wx/time.h>
#include <string>
#include <vector>
#include <memory>
namespace Slic3r { namespace GUI {
class DailyTipsDataRenderer;
class DailyTipsPanel {
static int uid;
public:
DailyTipsPanel(bool can_expand = true);
DailyTipsPanel(const ImVec2& pos, const ImVec2& size, bool can_expand = true);
void set_position(const ImVec2& pos);
void set_size(const ImVec2& size);
ImVec2 get_size();
void render();
void retrieve_data_from_hint_database(HintDataNavigation nav);
void expand(bool expand = true);
void collapse();
bool is_expanded();
void set_scale(float scale);
protected:
void render_header(const ImVec2& pos, const ImVec2& size);
void render_controller_buttons(const ImVec2& pos, const ImVec2& size);
void push_styles();
void pop_styles();
private:
std::unique_ptr<DailyTipsDataRenderer> m_dailytips_renderer;
size_t m_page_index{ 0 };
int m_pages_count;
bool m_is_expanded{ true };
bool m_can_expand{ true };
ImVec2 m_pos;
float m_width;
float m_height;
float m_header_height;
float m_content_height;
float m_footer_height;
int m_uid;
bool m_first_enter{ false };
float m_scale = 1.0f;
};
class DailyTipsWindow {
public:
DailyTipsWindow();
void open();
void close();
void render();
void set_scale(float scale);
void on_change_color_mode(bool is_dark);
private:
DailyTipsPanel* m_panel{ nullptr };
bool m_show{ false };
float m_scale = 1.0f;
bool m_is_dark{ false };
};
}}
#endif

View File

@@ -36,6 +36,7 @@
#include "I18N.hpp"
#include "NotificationManager.hpp"
#include "format.hpp"
#include "DailyTips.hpp"
#if ENABLE_RETINA_GL
#include "slic3r/Utils/RetinaHelper.hpp"
@@ -1266,6 +1267,8 @@ void GLCanvas3D::on_change_color_mode(bool is_dark, bool reinit) {
wxGetApp().imgui()->on_change_color_mode(is_dark);
// Notification
wxGetApp().plater()->get_notification_manager()->on_change_color_mode(is_dark);
// DailyTips Window
wxGetApp().plater()->get_dailytips()->on_change_color_mode(is_dark);
// Preview Slider
IMSlider* m_layers_slider = get_gcode_viewer().get_layers_slider();
IMSlider* m_moves_slider = get_gcode_viewer().get_moves_slider();
@@ -1984,6 +1987,7 @@ void GLCanvas3D::render(bool only_init)
bottom_margin = SLIDER_BOTTOM_MARGIN;
}
wxGetApp().plater()->get_notification_manager()->render_notifications(*this, get_overlay_window_width(), bottom_margin, right_margin);
wxGetApp().plater()->get_dailytips()->render();
}
wxGetApp().imgui()->render();
@@ -7003,6 +7007,7 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale()
auto* m_notification = wxGetApp().plater()->get_notification_manager();
m_notification->set_scale(sc);
wxGetApp().plater()->get_dailytips()->set_scale(sc);
#endif
return;
@@ -7028,6 +7033,7 @@ void GLCanvas3D::_check_and_update_toolbar_icon_scale()
auto* m_notification = wxGetApp().plater()->get_notification_manager();
m_notification->set_scale(sc);
wxGetApp().plater()->get_dailytips()->set_scale(sc);
#else
//BBS: GUI refactor: GLToolbar
m_main_toolbar.set_icons_size(GLGizmosManager::Default_Icons_Size * scale);

View File

@@ -1150,14 +1150,6 @@ void GUI_App::post_init()
this->mainframe->load_config(this->init_params->extra_config);
}*/
// BBS: to be checked
#if 1
// show "Did you know" notification
if (app_config->get("show_hints") == "true" && !is_gcode_viewer()) {
plater_->get_notification_manager()->push_hint_notification(false);
}
#endif
//BBS: check crash log
auto log_dir_path = boost::filesystem::path(data_dir()) / "log";
if (boost::filesystem::exists(log_dir_path))

View File

@@ -307,6 +307,12 @@ void HintDatabase::init()
{
load_hints_from_file(std::move(boost::filesystem::path(resources_dir()) / "data" / "hints.ini"));
m_initialized = true;
init_random_hint_id();
}
void HintDatabase::init_random_hint_id()
{
srand(time(NULL));
m_hint_id = rand() % m_loaded_hints.size();
}
void HintDatabase::load_hints_from_file(const boost::filesystem::path& path)
{
@@ -340,6 +346,7 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path)
std::string enabled_tags;
// optional link to documentation (accessed from button)
std::string documentation_link;
std::string img_url;
// randomized weighted order variables
size_t weight = 1;
bool was_displayed = is_used(id_string);
@@ -404,6 +411,9 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path)
if (dict.find("documentation_link") != dict.end()) {
documentation_link = dict["documentation_link"];
}
if (dict.find("image") != dict.end()) {
img_url = dict["image"];
}
if (dict.find("weight") != dict.end()) {
weight = (size_t)std::max(1, std::atoi(dict["weight"].c_str()));
@@ -414,7 +424,7 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path)
//link to internet
if (dict["hypertext_type"] == "link") {
std::string hypertext_link = dict["hypertext_link"];
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [hypertext_link]() { launch_browser_if_allowed(hypertext_link); } };
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, img_url, [hypertext_link]() { launch_browser_if_allowed(hypertext_link); } };
m_loaded_hints.emplace_back(hint_data);
// highlight settings
}
@@ -422,28 +432,28 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path)
std::string opt = dict["hypertext_settings_opt"];
Preset::Type type = static_cast<Preset::Type>(std::atoi(dict["hypertext_settings_type"].c_str()));
std::wstring category = boost::nowide::widen(dict["hypertext_settings_category"]);
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [opt, type, category]() { GUI::wxGetApp().sidebar().jump_to_option(opt, type, category); } };
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, img_url, [opt, type, category]() { GUI::wxGetApp().sidebar().jump_to_option(opt, type, category); } };
m_loaded_hints.emplace_back(hint_data);
// open preferences
}
else if (dict["hypertext_type"] == "preferences") {
std::string page = dict["hypertext_preferences_page"];
std::string item = dict["hypertext_preferences_item"];
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, [page, item]() { wxGetApp().open_preferences(1, page); } };// 1 is to modify
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, img_url, [page, item]() { wxGetApp().open_preferences(1, page); } };// 1 is to modify
m_loaded_hints.emplace_back(hint_data);
}
else if (dict["hypertext_type"] == "plater") {
std::string item = dict["hypertext_plater_item"];
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [item]() { wxGetApp().plater()->canvas3D()->highlight_toolbar_item(item); } };
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, img_url, [item]() { wxGetApp().plater()->canvas3D()->highlight_toolbar_item(item); } };
m_loaded_hints.emplace_back(hint_data);
}
else if (dict["hypertext_type"] == "gizmo") {
std::string item = dict["hypertext_gizmo_item"];
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [item]() { wxGetApp().plater()->canvas3D()->highlight_gizmo(item); } };
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, img_url, [item]() { wxGetApp().plater()->canvas3D()->highlight_gizmo(item); } };
m_loaded_hints.emplace_back(hint_data);
}
else if (dict["hypertext_type"] == "gallery") {
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, []() {
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, img_url, []() {
// Deselect all objects, otherwise gallery wont show.
wxGetApp().plater()->canvas3D()->deselect_all();
//wxGetApp().obj_list()->load_shape_object_from_gallery(); }
@@ -453,23 +463,23 @@ void HintDatabase::load_hints_from_file(const boost::filesystem::path& path)
else if (dict["hypertext_type"] == "menubar") {
wxString menu(_("&" + dict["hypertext_menubar_menu_name"]));
wxString item(_(dict["hypertext_menubar_item_name"]));
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, [menu, item]() { wxGetApp().mainframe->open_menubar_item(menu, item); } };
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, true, documentation_link, img_url, [menu, item]() { wxGetApp().mainframe->open_menubar_item(menu, item); } };
m_loaded_hints.emplace_back(hint_data);
}
}
else {
// plain text without hypertext
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link };
HintData hint_data{ id_string, text1, weight, was_displayed, hypertext_text, follow_text, disabled_tags, enabled_tags, false, documentation_link, img_url };
m_loaded_hints.emplace_back(hint_data);
}
}
}
}
HintData* HintDatabase::get_hint(bool new_hint/* = true*/)
HintData* HintDatabase::get_hint(HintDataNavigation nav)
{
if (!m_initialized) {
init();
new_hint = true;
nav = HintDataNavigation::Random;
}
if (m_loaded_hints.empty())
{
@@ -479,20 +489,34 @@ HintData* HintDatabase::get_hint(bool new_hint/* = true*/)
try
{
if (new_hint)
m_hint_id = get_next();
if (nav == HintDataNavigation::Next)
m_hint_id = get_next_hint_id();
if(nav == HintDataNavigation::Prev)
m_hint_id = get_prev_hint_id();
if (nav == HintDataNavigation::Curr)
;
if (nav == HintDataNavigation::Random)
init_random_hint_id();
}
catch (const std::exception&)
{
return nullptr;
}
return &m_loaded_hints[m_hint_id];
}
size_t HintDatabase::get_next()
size_t HintDatabase::get_next_hint_id()
{
return m_hint_id < m_loaded_hints.size() - 1 ? m_hint_id + 1 : 0;
}
size_t HintDatabase::get_prev_hint_id()
{
return m_hint_id > 0 ? m_hint_id - 1 : m_loaded_hints.size() - 1;
}
size_t HintDatabase::get_random_next()
{
if (!m_sorted_hints)
{
@@ -1110,7 +1134,7 @@ void NotificationManager::HintNotification::open_documentation()
}
void NotificationManager::HintNotification::retrieve_data(bool new_hint/* = true*/)
{
HintData* hint_data = HintDatabase::get_instance().get_hint(new_hint);
HintData* hint_data = HintDatabase::get_instance().get_hint(new_hint ? HintDataNavigation::Next : HintDataNavigation::Curr);
if (hint_data == nullptr)
close();

View File

@@ -18,9 +18,17 @@ struct HintData
std::string enabled_tags;
bool runtime_disable; // if true - hyperlink will check before every click if not in disabled mode
std::string documentation_link;
std::string image_url;
std::function<void(void)> callback{ nullptr };
};
enum class HintDataNavigation {
Curr,
Prev,
Next,
Random,
};
class HintDatabase
{
public:
@@ -40,7 +48,8 @@ public:
void operator=(HintDatabase const&) = delete;
// return true if HintData filled;
HintData* get_hint(bool new_hint = true);
HintData* get_hint(HintDataNavigation nav);
size_t get_index() { return m_hint_id; }
size_t get_count() {
if (!m_initialized)
return 0;
@@ -51,12 +60,15 @@ public:
void uninit();
private:
void init();
void init_random_hint_id();
void load_hints_from_file(const boost::filesystem::path& path);
bool is_used(const std::string& id);
void set_used(const std::string& id);
void clear_used();
// Returns position in m_loaded_hints with next hint chosed randomly with weights
size_t get_next();
size_t get_next_hint_id();
size_t get_prev_hint_id();
size_t get_random_next();
size_t m_hint_id;
bool m_initialized{ false };
std::vector<HintData> m_loaded_hints;

View File

@@ -54,8 +54,8 @@ static const std::map<const wchar_t, std::string> font_icons = {
{ImGui::MinimalizeHoverButton , "notification_minimalize_hover" },
{ImGui::RightArrowButton , "notification_right" },
{ImGui::RightArrowHoverButton , "notification_right_hover" },
{ImGui::PreferencesButton , "notification_preferences" },
{ImGui::PreferencesHoverButton , "notification_preferences_hover"},
//{ImGui::PreferencesButton , "notification_preferences" },
//{ImGui::PreferencesHoverButton , "notification_preferences_hover"},
#if ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
{ImGui::SliderFloatEditBtnIcon, "edit_button" },
#endif // ENABLE_ENHANCED_IMGUI_SLIDER_FLOAT
@@ -73,8 +73,8 @@ static const std::map<const wchar_t, std::string> font_icons = {
{ImGui::MinimalizeHoverDarkButton , "notification_minimalize_hover_dark" },
{ImGui::RightArrowDarkButton , "notification_right_dark" },
{ImGui::RightArrowHoverDarkButton , "notification_right_hover_dark" },
{ImGui::PreferencesDarkButton , "notification_preferences_dark" },
{ImGui::PreferencesHoverDarkButton , "notification_preferences_hover_dark"},
//{ImGui::PreferencesDarkButton , "notification_preferences_dark" },
//{ImGui::PreferencesHoverDarkButton , "notification_preferences_hover_dark"},
{ImGui::CircleButtonDarkIcon , "circle_paint_dark" },
{ImGui::TriangleButtonDarkIcon , "triangle_paint_dark" },
@@ -93,6 +93,10 @@ static const std::map<const wchar_t, std::string> font_icons = {
{ImGui::CloseBlockNotifButton , "block_notification_close" },
{ImGui::CloseBlockNotifHoverButton , "block_notification_close_hover" },
{ImGui::CollapseArrowIcon, "notification_collapse" },
{ImGui::ExpandArrowIcon, "notification_expand" },
{ImGui::OpenArrowIcon, "notification_arrow_open" },
};
static const std::map<const wchar_t, std::string> font_icons_large = {
{ImGui::CloseNotifButton , "notification_close" },
@@ -110,15 +114,19 @@ static const std::map<const wchar_t, std::string> font_icons_large = {
// {ImGui::CustomSeamMarker , "seam" },
// {ImGui::MmuSegmentationMarker , "mmu_segmentation" },
// {ImGui::VarLayerHeightMarker , "layers" },
{ImGui::DocumentationButton , "notification_documentation" },
{ImGui::DocumentationHoverButton, "notification_documentation_hover"},
//{ImGui::DocumentationButton , "notification_documentation" },
//{ImGui::DocumentationHoverButton, "notification_documentation_hover"},
//{ImGui::InfoMarker , "notification_info" },
// dark mode icon
{ImGui::CloseNotifDarkButton , "notification_close_dark" },
{ImGui::CloseNotifHoverDarkButton , "notification_close_hover_dark" },
{ImGui::DocumentationDarkButton , "notification_documentation_dark" },
{ImGui::DocumentationHoverDarkButton, "notification_documentation_hover_dark"},
//{ImGui::DocumentationDarkButton , "notification_documentation_dark" },
//{ImGui::DocumentationHoverDarkButton, "notification_documentation_hover_dark"},
{ImGui::BlockNotifErrorIcon, "block_notification_error" },
{ImGui::PrevArrowBtnIcon, "notification_arrow_left" },
{ImGui::PrevArrowHoverBtnIcon, "notification_arrow_left_hovered" },
{ImGui::NextArrowBtnIcon, "notification_arrow_right" },
{ImGui::NextArrowHoverBtnIcon, "notification_arrow_right_hovered" },
};
static const std::map<const wchar_t, std::string> font_icons_extra_large = {

View File

@@ -58,6 +58,7 @@
#include "NetworkTestDialog.hpp"
#include "ConfigWizard.hpp"
#include "Widgets/WebView.hpp"
#include "DailyTips.hpp"
#ifdef _WIN32
#include <dbt.h>
@@ -2119,7 +2120,7 @@ static wxMenu* generate_help_menu()
[](wxCommandEvent&) { Slic3r::GUI::desktop_open_datadir_folder(); });
append_menu_item(helpMenu, wxID_ANY, _L("Show Tip of the Day"), _L("Show Tip of the Day"), [](wxCommandEvent&) {
wxGetApp().plater()->get_notification_manager()->push_hint_notification(false);
wxGetApp().plater()->get_dailytips()->open();
wxGetApp().plater()->get_current_canvas3D()->set_as_dirty();
});

View File

@@ -1,6 +1,7 @@
#include "NotificationManager.hpp"
#include "HintNotification.hpp"
#include "SlicingProgressNotification.hpp"
#include "GUI.hpp"
#include "ImGuiWrapper.hpp"
#include "wxExtensions.hpp"
@@ -222,7 +223,6 @@ void NotificationManager::PopNotification::restore_default_theme()
void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width, float right_margin)
{
if (m_state == EState::Unknown)
init();
@@ -251,11 +251,11 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
// top y of window
m_top_y = initial_y + m_window_height;
// position of upper-right corner
ImVec2 win_pos(1.0f * (float)cnv_size.get_width() - right_gap, 1.0f * (float)cnv_size.get_height() - m_top_y);
imgui.set_next_window_pos(win_pos.x, win_pos.y, ImGuiCond_Always, 1.0f, 0.0f);
imgui.set_next_window_size(m_window_width, m_window_height, ImGuiCond_Always);
// find if hovered FIXME: do it only in update state?
if (m_state == EState::Hovered) {
init();
@@ -284,11 +284,11 @@ void NotificationManager::PopNotification::render(GLCanvas3D& canvas, float init
use_bbl_theme();
if (imgui.begin(name, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
int window_flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
if (imgui.begin(name, window_flags)) {
ImVec2 win_size = ImGui::GetWindowSize();
bbl_render_left_sign(imgui, win_size.x, win_size.y, win_pos.x, win_pos.y);
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);
@@ -1410,275 +1410,6 @@ void NotificationManager::PrintHostUploadNotification::render_cancel_button(ImGu
}
ImGui::PopStyleColor(5);
}
//------SlicingProgressNotification
void NotificationManager::SlicingProgressNotification::init()
{
if (m_sp_state == SlicingProgressState::SP_PROGRESS) {
ProgressBarNotification::init();
//if (m_state == EState::NotFading && m_percentage >= 1.0f)
// m_state = EState::Shown;
}
else {
PopNotification::init();
}
}
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)
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_has_cancel_button = true;
m_sp_state = state;
m_current_fade_opacity = 1;
return true;
case Slic3r::GUI::NotificationManager::SlicingProgressNotification::SlicingProgressState::SP_CANCELLED:
set_percentage(-1);
m_has_cancel_button = false;
m_has_print_info = false;
set_export_possible(false);
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_cancel_button = false;
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 2;
else if (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed)
return 2;
else
return 0;
}
bool NotificationManager::SlicingProgressNotification::update_state(bool paused, const int64_t delta)
{
bool ret = ProgressBarNotification::update_state(paused, delta);
// sets Estate to hidden
if (get_state() == PopNotification::EState::ClosePending || get_state() == PopNotification::EState::Finished)
set_progress_state(SlicingProgressState::SP_NO_SLICING);
return ret;
}
void NotificationManager::SlicingProgressNotification::render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
if (m_sp_state == SlicingProgressState::SP_PROGRESS /*|| (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed)*/) {
ProgressBarNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
/* // enable for hypertext during slicing (correct call of export_enabled needed)
if (m_multiline) {
// two lines text, one line bar
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(m_line_height / 4);
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(m_line_height + m_line_height / 4);
std::string line = m_text1.substr(m_endlines[0] + (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0), m_endlines[1] - m_endlines[0] - (m_text1[m_endlines[0]] == '\n' || m_text1[m_endlines[0]] == ' ' ? 1 : 0));
imgui.text(line.c_str());
if (m_sidebar_collapsed && m_sp_state == SlicingProgressState::SP_PROGRESS && m_export_possible) {
ImVec2 text_size = ImGui::CalcTextSize(line.c_str());
render_hypertext(imgui, m_left_indentation + text_size.x + 4, m_line_height + m_line_height / 4, m_hypertext);
}
if (m_has_cancel_button)
render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
}
else {
//one line text, one line bar
ImGui::SetCursorPosX(m_left_indentation);
ImGui::SetCursorPosY(m_line_height / 4);
std::string line = m_text1.substr(0, m_endlines[0]);
imgui.text(line.c_str());
if (m_sidebar_collapsed && m_sp_state == SlicingProgressState::SP_PROGRESS && m_export_possible) {
ImVec2 text_size = ImGui::CalcTextSize(line.c_str());
render_hypertext(imgui, m_left_indentation + text_size.x + 4, m_line_height / 4, m_hypertext);
}
if (m_has_cancel_button)
render_cancel_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
}
*/
} else if (m_sp_state == SlicingProgressState::SP_COMPLETED && m_sidebar_collapsed) {
// "Slicing Finished" on line 1 + hypertext, print info on line
ImVec2 win_size(win_size_x, win_size_y);
ImVec2 text1_size = ImGui::CalcTextSize(m_text1.c_str());
float x_offset = m_left_indentation;
std::string fulltext = m_text1 + m_hypertext + m_text2;
ImVec2 text_size = ImGui::CalcTextSize(fulltext.c_str());
float cursor_y = win_size.y / 2 - text_size.y / 2;
if (m_sidebar_collapsed && m_has_print_info) {
x_offset = 20;
cursor_y = win_size.y / 2 + win_size.y / 6 - text_size.y / 2;
ImGui::SetCursorPosX(x_offset);
ImGui::SetCursorPosY(cursor_y);
imgui.text(m_print_info.c_str());
cursor_y = win_size.y / 2 - win_size.y / 6 - text_size.y / 2;
}
ImGui::SetCursorPosX(x_offset);
ImGui::SetCursorPosY(cursor_y);
imgui.text(m_text1.c_str());
if (m_sidebar_collapsed)
render_hypertext(imgui, x_offset + text1_size.x + 4, cursor_y, m_hypertext);
} else {
PopNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
}
}
void NotificationManager::SlicingProgressNotification::render_bar(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
if (m_sp_state != SlicingProgressState::SP_PROGRESS) {
return;
}
ProgressBarNotification::render_bar(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
}
void NotificationManager::SlicingProgressNotification::render_hypertext(ImGuiWrapper& imgui,const float text_x, const float text_y, const std::string text, bool more)
{
if (m_sp_state == SlicingProgressState::SP_COMPLETED && !m_sidebar_collapsed)
return;
ProgressBarNotification::render_hypertext(imgui, text_x, text_y, text, more);
}
void NotificationManager::SlicingProgressNotification::render_cancel_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
ImVec2 win_size(win_size_x, win_size_y);
ImVec2 win_pos(win_pos_x, win_pos_y);
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_state == EState::FadingOut, m_current_fade_opacity);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f));
std::string button_text;
button_text = ImGui::CancelButton;
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos.x - win_size.x / 10.f, win_pos.y),
ImVec2(win_pos.x, win_pos.y + win_size.y - (m_minimize_b_visible ? 2 * m_line_height : 0)),
true))
{
button_text = ImGui::CancelHoverButton;
}
ImVec2 button_pic_size = ImGui::CalcTextSize(button_text.c_str());
ImVec2 button_size(button_pic_size.x * 1.25f, button_pic_size.y * 1.25f);
ImGui::SetCursorPosX(win_size.x - m_line_height * 2.75f);
ImGui::SetCursorPosY(win_size.y / 2 - button_size.y);
if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
{
on_cancel_button();
}
//invisible large button
ImGui::SetCursorPosX(win_size.x - m_line_height * 2.35f);
ImGui::SetCursorPosY(0);
if (imgui.button(" ", m_line_height * 2.125, win_size.y - (m_minimize_b_visible ? 2 * m_line_height : 0)))
{
on_cancel_button();
}
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
}
void NotificationManager::SlicingProgressNotification::render_close_button(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y)
{
// Do not render close button while showing progress - cancel button is rendered instead
if (m_sp_state != SlicingProgressState::SP_PROGRESS) {
ProgressBarNotification::render_close_button(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
}
}
//------ProgressIndicatorNotification-------
void NotificationManager::ProgressIndicatorNotification::set_status_text(const char* text)
{
@@ -2357,6 +2088,7 @@ int NotificationManager::progress_indicator_get_range() const
void NotificationManager::push_hint_notification(bool open_next)
{
return;
for (std::unique_ptr<PopNotification>& notification : m_pop_notifications) {
if (notification->get_type() == NotificationType::DidYouKnowHint) {
(dynamic_cast<HintNotification*>(notification.get()))->open_next();
@@ -2475,6 +2207,7 @@ void NotificationManager::render_notifications(GLCanvas3D &canvas, float overlay
float bottom_up_last_y = bottom_margin * m_scale;
int i = 0;
for (const auto& notification : m_pop_notifications) {
if (notification->get_data().level == NotificationLevel::ErrorNotificationLevel || notification->get_data().level == NotificationLevel::SeriousWarningNotificationLevel) {
notification->bbl_render_block_notification(canvas, bottom_up_last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin * m_scale);
@@ -2482,13 +2215,19 @@ void NotificationManager::render_notifications(GLCanvas3D &canvas, float overlay
bottom_up_last_y = notification->get_top() + GAP_WIDTH;
}
else {
if (notification->get_state() != PopNotification::EState::Hidden) {
if (notification->get_state() != PopNotification::EState::Hidden && notification->get_state() != PopNotification::EState::Finished) {
i++;
notification->render(canvas, bottom_up_last_y, m_move_from_overlay && !m_in_preview, overlay_width * m_scale, right_margin * m_scale);
if (notification->get_state() != PopNotification::EState::Finished)
bottom_up_last_y = notification->get_top() + GAP_WIDTH;
}
}
}
for (const auto& notification : m_pop_notifications) {
if (notification->get_data().type == NotificationType::SlicingProgress && notification->get_state() != PopNotification::EState::Hidden && notification->get_state() != PopNotification::EState::Finished) {
;// assert(i <= 1);
}
}
m_last_render = GLCanvas3D::timestamp_now();
}
@@ -2955,7 +2694,10 @@ void NotificationManager::bbl_chose_sole_text_notification(NotificationType sTyp
void NotificationManager::set_scale(float scale)
{
if(m_scale != scale)m_scale = scale;
if(m_scale != scale) m_scale = scale;
for (auto& notif : m_pop_notifications) {
notif->set_scale(scale);
}
}

View File

@@ -416,6 +416,7 @@ private:
void reset_timer() { m_notification_start = GLCanvas3D::timestamp_now(); m_state = EState::Shown; }
void set_Multiline(bool Multi) { m_multiline = Multi; }
void on_change_color_mode(bool is_dark);
void set_scale(float scale) { m_scale = scale; }
protected:
// Call after every size change
@@ -548,6 +549,8 @@ private:
size_t m_lines_count{ 1 };
// Target for wxWidgets events sent by clicking on the hyperlink available at some notifications.
wxEvtHandler* m_evt_handler;
float m_scale = 1.0f;
};
@@ -642,74 +645,6 @@ private:
long m_hover_time{ 0 };
UploadJobState m_uj_state{ UploadJobState::PB_PROGRESS };
};
class SlicingProgressNotification : public ProgressBarNotification
{
public:
// Inner state of notification, Each state changes bahaviour of the notification
enum class SlicingProgressState
{
SP_NO_SLICING, // hidden
SP_BEGAN, // still hidden but allows to go to SP_PROGRESS state. This prevents showing progress after slicing was canceled.
SP_PROGRESS, // never fades outs, no close button, has cancel button
SP_CANCELLED, // fades after 10 seconds, simple message
SP_COMPLETED // Has export hyperlink and print info, fades after 20 sec if sidebar is shown, otherwise no fade out
};
SlicingProgressNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, std::function<bool()> callback)
: ProgressBarNotification(n, id_provider, evt_handler)
, m_cancel_callback(callback)
{
set_progress_state(SlicingProgressState::SP_NO_SLICING);
m_has_cancel_button = false;
m_render_percentage = true;
}
// sets text of notification - call after setting progress state
void set_status_text(const std::string& text);
// sets cancel button callback
void set_cancel_callback(std::function<bool()> callback) { m_cancel_callback = callback; }
bool has_cancel_callback() const { return m_cancel_callback != nullptr; }
// sets SlicingProgressState, negative percent means canceled, returns true if state was set succesfully.
bool set_progress_state(float percent);
// sets SlicingProgressState, percent is used only at progress state. Returns true if state was set succesfully.
bool set_progress_state(SlicingProgressState state,float percent = 0.f);
// sets additional string of print info and puts notification into Completed state.
void set_print_info(const std::string& info);
// sets fading if in Completed state.
void set_sidebar_collapsed(bool collapsed);
// Calls inherited update_state and ensures Estate goes to hidden not closing.
bool update_state(bool paused, const int64_t delta) override;
// Switch between technology to provide correct text.
void set_fff(bool b) { m_is_fff = b; }
void set_fdm(bool b) { m_is_fff = b; }
void set_sla(bool b) { m_is_fff = !b; }
void set_export_possible(bool b) { m_export_possible = b; }
protected:
void init() override;
void render_text(ImGuiWrapper& imgui, const float win_size_x, const float win_size_y, const float win_pos_x, const float win_pos_y) override;
void render_bar(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y) override;
void render_cancel_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y) override;
void render_close_button(ImGuiWrapper& imgui,
const float win_size_x, const float win_size_y,
const float win_pos_x, const float win_pos_y) override;
void render_hypertext(ImGuiWrapper& imgui,
const float text_x, const float text_y,
const std::string text,
bool more = false) override ;
void on_cancel_button();
int get_duration() override;
// if returns false, process was already canceled
std::function<bool()> m_cancel_callback;
SlicingProgressState m_sp_state { SlicingProgressState::SP_PROGRESS };
bool m_has_print_info { false };
std::string m_print_info;
bool m_sidebar_collapsed { false };
bool m_is_fff { true };
// if true, it is possible show export hyperlink in state SP_PROGRESS
bool m_export_possible { false };
};
class ProgressIndicatorNotification : public ProgressBarNotification
{
@@ -807,6 +742,9 @@ private:
std::vector<std::pair<InfoItemType, size_t>> m_types_and_counts;
};
// in SlicingProgressNotification.hpp
class SlicingProgressNotification;
// in HintNotification.hpp
class HintNotification;
@@ -941,7 +879,7 @@ private:
};
public:
void set_scale(float scale = 1.0);
float m_scale = 1.0;
float m_scale = 1.0f;
};
}//namespace GUI

View File

@@ -134,6 +134,7 @@
#include "PhysicalPrinterDialog.hpp"
#include "PrintHostDialogs.hpp"
#include "PlateSettingsDialog.hpp"
#include "DailyTips.hpp"
using boost::optional;
namespace fs = boost::filesystem;
@@ -12871,6 +12872,12 @@ NotificationManager * Plater::get_notification_manager()
return p->notification_manager.get();
}
DailyTipsWindow* Plater::get_dailytips() const
{
static DailyTipsWindow* dailytips_win = new DailyTipsWindow();
return dailytips_win;
}
const NotificationManager * Plater::get_notification_manager() const
{
return p->notification_manager.get();

View File

@@ -71,6 +71,7 @@ class ObjectList;
class GLCanvas3D;
class Mouse3DController;
class NotificationManager;
class DailyTipsWindow;
struct Camera;
class GLToolbar;
class PlaterPresetComboBox;
@@ -586,6 +587,7 @@ public:
const NotificationManager* get_notification_manager() const;
NotificationManager* get_notification_manager();
DailyTipsWindow* get_dailytips() const;
//BBS: show message in status bar
void show_status_message(std::string s);

View File

@@ -998,7 +998,7 @@ wxWindow* PreferencesDialog::create_general_page()
auto item_mouse_zoom_settings = create_item_checkbox(_L("Zoom to mouse position"), page, _L("Zoom in towards the mouse pointer's position in the 3D view, rather than the 2D window center."), 50, "zoom_to_mouse");
auto item_hints = create_item_checkbox(_L("Show \"Tip of the day\" notification after start"), page, _L("If enabled, useful hints are displayed at startup."), 50, "show_hints");
//auto item_hints = create_item_checkbox(_L("Show \"Tip of the day\" notification after start"), page, _L("If enabled, useful hints are displayed at startup."), 50, "show_hints");
auto item_calc_mode = create_item_checkbox(_L("Flushing volumes: Auto-calculate everytime the color changed."), page, _L("If enabled, auto-calculate everytime the color changed."), 50, "auto_calculate");
auto title_presets = create_item_title(_L("Presets"), page, _L("Presets"));
auto item_user_sync = create_item_checkbox(_L("Auto sync user presets(Printer/Filament/Process)"), page, _L("User Sync"), 50, "sync_user_preset");
@@ -1056,7 +1056,7 @@ wxWindow* PreferencesDialog::create_general_page()
sizer_page->Add(item_region, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_currency, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_mouse_zoom_settings, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_hints, 0, wxTOP, FromDIP(3));
//sizer_page->Add(item_hints, 0, wxTOP, FromDIP(3));
sizer_page->Add(item_calc_mode, 0, wxTOP, FromDIP(3));
sizer_page->Add(title_presets, 0, wxTOP | wxEXPAND, FromDIP(20));
sizer_page->Add(item_user_sync, 0, wxTOP, FromDIP(3));

View File

@@ -0,0 +1,451 @@
#include "SlicingProgressNotification.hpp"
#ifndef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS
#endif
#include <imgui/imgui_internal.h>
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::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)
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);
if (m_sp_state == SlicingProgressState::SP_BEGAN) {
wxGetApp().plater()->get_dailytips()->close();
m_dailytips_panel->retrieve_data_from_hint_database(HintDataNavigation::Random);
}
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 && !m_sidebar_collapsed)
return 5;
else
return 0;
}
bool NotificationManager::SlicingProgressNotification::update_state(bool paused, const int64_t delta)
{
bool ret = PopNotification::update_state(paused, delta);
// sets Estate to hidden
if (get_state() == PopNotification::EState::ClosePending || get_state() == PopNotification::EState::Finished)
set_progress_state(SlicingProgressState::SP_NO_SLICING);
return ret;
}
void NotificationManager::SlicingProgressNotification::render(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();
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 * m_scale, 0));
if (m_sp_state == SlicingProgressNotification::SlicingProgressState::SP_COMPLETED || m_sp_state == SlicingProgressNotification::SlicingProgressState::SP_CANCELLED)
{
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);
}
else {
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
push_style_color(ImGuiCol_Border, { 0, 0, 0, 0 }, true, m_current_fade_opacity);
}
const ImVec2 progress_child_window_padding = ImVec2(25.f, 5.f) * m_scale;
const ImVec2 dailytips_child_window_padding = ImVec2(25.f, 2.f) * m_scale;
const ImVec2 bottom_padding = ImVec2(25.f, 20.f) * m_scale;
const float progress_panel_width = (m_window_width - 2 * progress_child_window_padding.x);
const float progress_panel_height = (78.0f * m_scale);
const float dailytips_panel_width = (m_window_width - 2 * dailytips_child_window_padding.x);
const float dailytips_panel_height = (395.0f * m_scale);
Size cnv_size = canvas.get_canvas_size();
float right_gap = right_margin + (move_from_overlay ? overlay_width + m_line_height * 5 : 0);
ImVec2 window_pos((float)cnv_size.get_width() - right_gap - m_window_width, (float)cnv_size.get_height() - m_top_y);
imgui.set_next_window_pos(window_pos.x, window_pos.y, ImGuiCond_Always, 0.0f, 0.0f);
// dynamically resize window by progress state
if (m_sp_state == SlicingProgressNotification::SlicingProgressState::SP_COMPLETED || m_sp_state == SlicingProgressNotification::SlicingProgressState::SP_CANCELLED)
m_window_height = 64.0f * m_scale;
else
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) * m_scale;
float button_right_margin_x = 3.0f * m_scale;
ImVec2 button_pos = 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 * m_scale;
ImVec2 text_pos = window_pos + ImVec2(text_left_margin_x, m_window_height / 2.0f - m_line_height * 1.2f);
ImVec2 view_dailytips_text_pos = 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, window_pos.x + m_window_width, 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_PROGRESS) {
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) * m_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 * m_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 * m_scale);
ImVec2 text_pos = ImVec2(progress_bar_pos.x, progress_bar_pos.y - m_line_height * 1.2f);
render_text(text_pos);
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));
child_name = "##DailyTipsPanel" + std::to_string(parent_window->ID);
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos() + dailytips_child_window_padding);
if (ImGui::BeginChild(child_name.c_str(), ImVec2(dailytips_panel_width, dailytips_panel_height), false, child_window_flags)) {
ImVec2 child_window_pos = ImGui::GetWindowPos();
ImVec2 dailytips_pos = child_window_pos;
ImVec2 dailytips_size = ImVec2(dailytips_panel_width, dailytips_panel_height);
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();
//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 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->set_scale(m_scale);
m_dailytips_panel->set_position(pos);
m_dailytips_panel->set_size(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((_u8L("View all Daily tips") + " " + button_text).c_str());
//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.c_str());
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.c_str());
ImGui::PopStyleColor(5);
}
}
}}

View File

@@ -0,0 +1,83 @@
#ifndef slic3r_GUI_SlicingProgressNotification_hpp_
#define slic3r_GUI_SlicingProgressNotification_hpp_
#include "DailyTips.hpp"
#include "NotificationManager.hpp"
namespace Slic3r { namespace GUI {
class NotificationManager::SlicingProgressNotification : public NotificationManager::PopNotification
{
public:
// Inner state of notification, Each state changes bahaviour of the notification
enum class SlicingProgressState
{
SP_NO_SLICING, // hidden
SP_BEGAN, // still hidden but allows to go to SP_PROGRESS state. This prevents showing progress after slicing was canceled.
SP_PROGRESS, // never fades outs, no close button, has cancel button
SP_CANCELLED, // fades after 10 seconds, simple message
SP_COMPLETED // Has export hyperlink and print info, fades after 20 sec if sidebar is shown, otherwise no fade out
};
SlicingProgressNotification(const NotificationData& n, NotificationIDProvider& id_provider, wxEvtHandler* evt_handler, std::function<bool()> callback)
: PopNotification(n, id_provider, evt_handler)
, m_cancel_callback(callback)
, m_dailytips_panel(new DailyTipsPanel(true))
{
set_progress_state(SlicingProgressState::SP_NO_SLICING);
}
void set_percentage(float percent) { m_percentage = percent; }
DailyTipsPanel* get_dailytips_panel() { return m_dailytips_panel; }
SlicingProgressState get_progress_state() { return m_sp_state; }
// sets text of notification - call after setting progress state
void set_status_text(const std::string& text);
// sets cancel button callback
void set_cancel_callback(std::function<bool()> callback) { m_cancel_callback = callback; }
bool has_cancel_callback() const { return m_cancel_callback != nullptr; }
// sets SlicingProgressState, negative percent means canceled, returns true if state was set succesfully.
bool set_progress_state(float percent);
// sets SlicingProgressState, percent is used only at progress state. Returns true if state was set succesfully.
bool set_progress_state(SlicingProgressState state, float percent = 0.f);
// sets additional string of print info and puts notification into Completed state.
void set_print_info(const std::string& info);
// sets fading if in Completed state.
void set_sidebar_collapsed(bool collapsed);
// Calls inherited update_state and ensures Estate goes to hidden not closing.
bool update_state(bool paused, const int64_t delta) override;
// Switch between technology to provide correct text.
void set_fff(bool b) { m_is_fff = b; }
void set_export_possible(bool b) { m_export_possible = b; }
protected:
void init() override;
void render(GLCanvas3D& canvas, float initial_y, bool move_from_overlay, float overlay_width, float right_margin) override;
/* PARAMS: pos is relative to screen */
void render_text(const ImVec2& pos);
void render_bar(const ImVec2& pos, const ImVec2& size);
void render_cancel_button(const ImVec2& pos, const ImVec2& size);
void render_close_button(const ImVec2& pos, const ImVec2& size);
void render_dailytips_panel(const ImVec2& pos, const ImVec2& size);
void render_show_dailytips(const ImVec2& pos);
void on_show_dailytips();
void on_cancel_button();
int get_duration() override;
protected:
float m_percentage{ 0.0f };
// if returns false, process was already canceled
std::function<bool()> m_cancel_callback;
SlicingProgressState m_sp_state{ SlicingProgressState::SP_PROGRESS };
bool m_sidebar_collapsed{ false };
// if true, it is possible show export hyperlink in state SP_PROGRESS
bool m_export_possible{ false };
DailyTipsPanel* m_dailytips_panel{ nullptr };
/* currently not used */
bool m_has_print_info{ false };
std::string m_print_info;
bool m_is_fff{ true };
};
}}
#endif