mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-07-25 03:42:05 +00:00
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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
560
src/slic3r/GUI/DailyTips.cpp
Normal file
560
src/slic3r/GUI/DailyTips.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}}
|
||||
70
src/slic3r/GUI/DailyTips.hpp
Normal file
70
src/slic3r/GUI/DailyTips.hpp
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
451
src/slic3r/GUI/SlicingProgressNotification.cpp
Normal file
451
src/slic3r/GUI/SlicingProgressNotification.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
83
src/slic3r/GUI/SlicingProgressNotification.hpp
Normal file
83
src/slic3r/GUI/SlicingProgressNotification.hpp
Normal 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
|
||||
Reference in New Issue
Block a user