ENH: refactor DailyTips

jira: new

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

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

View File

@ -65,6 +65,7 @@
[hint:3D Scene Operations]
text = 3D Scene Operations\nDid you know how to control view and object/part selection with mouse and touchpanel in the 3D scene?
documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/3d-scene-operations
image = images/dailytips_3DScene.PNG
[hint:Cut Tool]
text = Cut Tool\nDid you know that you can cut a model at any angle and position with the cutting tool?
@ -85,14 +86,17 @@ documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/auto-arr
[hint:Auto-Orient]
text = Auto-Orient\nDid you know that you can rotate objects to an optimal orientation for printing by a simple click?
documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/auto-orientation
image = images/dailytips_AutoArrange.PNG
[hint:Lay on Face]
text = Lay on Face\nDid you know that you can quickly orient a model so that one of its faces sits on the print bed? Select the \"Place on face\" function or press the <b>F</b> key.
documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/lay-on-face
image = images/dailytips_LayOnFace.PNG
[hint:Object List]
text = Object List\nDid you know that you can view all objects/parts in a list and change settings for each object/part?
documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/object-list
image = images/dailytips_ObjectList.PNG
#[hint:Search Functionality]
#text = Search Functionality\nDid you know that you use the Search tool to quickly find a specific Bambu Studio setting? Or use the familiar shortcut <b>Ctrl+F</b>.
@ -100,10 +104,12 @@ documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/object-l
[hint:Simplify Model]
text = Simplify Model\nDid you know that you can reduce the number of triangles in a mesh using the Simplify mesh feature? Right-click the model and select Simplify model. Read more in the documentation.
documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/simplify-model
image = images/dailytips_SimplifyModel.PNG
[hint:Slicing Parameter Table]
text = Slicing Parameter Table\nDid you know that you can view all objects/parts on a table and change settings for each object/part?
documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/parameter-table
image = images/dailytips_SlicingParamTable.PNG
[hint:Split to Objects/Parts]
text = Split to Objects/Parts\nDid you know that you can split a big object into small ones for easy colorizing or printing?
@ -112,6 +118,7 @@ documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/split-to
[hint:Subtract a Part]
text = Subtract a Part\nDid you know that you can subtract one mesh from another using the Negative part modifier? That way you can, for example, create easily resizable holes directly in Bambu Studio. Read more in the documentation.
documentation_link = https://wiki.bambulab.com/en/software/bambu-studio/subtract-a-part
image = images/dailytips_SubtractPart.png
[hint:STEP]
text = STEP\nDid you know that you can improve your print quality by slicing a STEP file instead of an STL?\nBambu Studio supports slicing STEP files, providing smoother results than a lower resolution STL. Give it a try!
@ -120,6 +127,7 @@ documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/step
[hint:Z seam location]
text = Z seam location\nDid you know that you can customize the location of the Z seam, and even paint it on your print, to have it in a less visible location? This improves the overall look of your model. Check it out!
documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/Seam
image = images/dailytips_ZSeamLocation.png
[hint:Fine-tuning for flow rate]
text = Fine-tuning for flow rate\nDid you know that flow rate can be fine-tuned for even better-looking prints? Depending on the material, you can improve the overall finish of the printed model by doing some fine-tuning.
@ -128,6 +136,7 @@ documentation_link= https://wiki.bambulab.com/en/x1/manual/manual-flow-rate-tuni
[hint:Split your prints into plates]
text = Split your prints into plates\nDid you know that you can split a model that has a lot of parts into individual plates ready to print? This will simplify the process of keeping track of all the parts.
documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/plates_management
image = images/dailytips_SplitIntoPlates.png
[hint:Speed up your print with Adaptive Layer Height]
text = Speed up your print with Adaptive Layer Height\nDid you know that you can print a model even faster, by using the Adaptive Layer Height option? Check it out!
@ -140,6 +149,7 @@ documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/support-p
[hint:Different types of supports]
text = Different types of supports\nDid you know that you can choose from multiple types of supports? Tree supports work great for organic models, while saving filament and improving print speed. Check them out!
documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/support
image = images/dailytips_TypesOfSupports.png
[hint:Printing Silk Filament]
text = Printing Silk Filament\nDid you know that Silk filament needs special consideration to print it successfully? Higher temperature and lower speed are always recommended for the best results.
@ -148,6 +158,7 @@ documentation_link= https://wiki.bambulab.com/en/x1/manual/printing-with-silk-fi
[hint:Brim for better adhesion]
text = Brim for better adhesion\nDid you know that when printing models have a small contact interface with the printing surface, it's recommended to use a brim?
documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/auto-brim
image = images/dailytips_Brim.png
[hint:Set parameters for multiple objects]
text = Set parameters for multiple objects\nDid you know that you can set slicing parameters for all selected objects at one time?
@ -156,6 +167,7 @@ documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/set-param
[hint:Stack objects]
text = Stack objects\nDid you know that you can stack objects as a whole one?
documentation_link= https://wiki.bambulab.com/en/software/bambu-studio/stacking-objects
image = images/dailytips_StackObject.png
[hint:Flush into support/objects/infill]
text = Flush into support/objects/infill\nDid you know that you can save the wasted filament by flushing them into support/objects/infill during filament change?

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 479 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 724 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

View File

@ -0,0 +1,10 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_14849_19005)">
<path d="M1.5 12C1.5 9.21523 2.60625 6.54451 4.57538 4.57538C6.54451 2.60625 9.21523 1.5 12 1.5C14.7848 1.5 17.4555 2.60625 19.4246 4.57538C21.3938 6.54451 22.5 9.21523 22.5 12C22.5 14.7848 21.3938 17.4555 19.4246 19.4246C17.4555 21.3938 14.7848 22.5 12 22.5C9.21523 22.5 6.54451 21.3938 4.57538 19.4246C2.60625 17.4555 1.5 14.7848 1.5 12ZM24 12C24 8.8174 22.7357 5.76516 20.4853 3.51472C18.2348 1.26428 15.1826 0 12 0C8.8174 0 5.76516 1.26428 3.51472 3.51472C1.26428 5.76516 0 8.8174 0 12C0 15.1826 1.26428 18.2348 3.51472 20.4853C5.76516 22.7357 8.8174 24 12 24C15.1826 24 18.2348 22.7357 20.4853 20.4853C22.7357 18.2348 24 15.1826 24 12ZM6.22031 11.4703L5.69063 12L6.22031 12.5297L10.7203 17.0297L11.25 17.5594L12.3094 16.5L11.7797 15.9703L8.55938 12.75H17.25H18V11.25H17.25H8.55938L11.7797 8.02969L12.3094 7.5L11.25 6.44062L10.7203 6.97031L6.22031 11.4703Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_14849_19005">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.5 12C1.5 9.21523 2.60625 6.54451 4.57538 4.57538C6.54451 2.60625 9.21523 1.5 12 1.5C14.7848 1.5 17.4555 2.60625 19.4246 4.57538C21.3938 6.54451 22.5 9.21523 22.5 12C22.5 14.7848 21.3938 17.4555 19.4246 19.4246C17.4555 21.3938 14.7848 22.5 12 22.5C9.21523 22.5 6.54451 21.3938 4.57538 19.4246C2.60625 17.4555 1.5 14.7848 1.5 12ZM24 12C24 8.8174 22.7357 5.76516 20.4853 3.51472C18.2348 1.26428 15.1826 0 12 0C8.8174 0 5.76516 1.26428 3.51472 3.51472C1.26428 5.76516 0 8.8174 0 12C0 15.1826 1.26428 18.2348 3.51472 20.4853C5.76516 22.7357 8.8174 24 12 24C15.1826 24 18.2348 22.7357 20.4853 20.4853C22.7357 18.2348 24 15.1826 24 12ZM6.22031 11.4703L5.69063 12L6.22031 12.5297L10.7203 17.0297L11.25 17.5594L12.3094 16.5L11.7797 15.9703L8.55938 12.75H17.25H18V11.25H17.25H8.55938L11.7797 8.02969L12.3094 7.5L11.25 6.44062L10.7203 6.97031L6.22031 11.4703Z" fill="#00AE42"/>
</svg>

After

Width:  |  Height:  |  Size: 982 B

View File

@ -0,0 +1,10 @@
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_4_36)">
<path d="M13.7688 7.45642C13.9156 7.60017 14 7.79392 14 8.00017C14 8.20642 13.9156 8.40017 13.7688 8.54392L8.26875 13.7939C7.96875 14.0814 7.49375 14.0689 7.20937 13.7689C6.925 13.4689 6.93437 12.9939 7.23437 12.7095L11.3781 8.75017H0.749999C0.334374 8.75017 -9.90004e-07 8.41579 -9.53674e-07 8.00017C-9.17334e-07 7.58454 0.334374 7.25017 0.749999 7.25017H11.3781L7.23125 3.29392C6.93125 3.00641 6.92188 2.53454 7.20625 2.23454C7.49063 1.93454 7.96563 1.92517 8.26563 2.20954L13.7656 7.45954L13.7688 7.45642Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_4_36">
<rect width="14" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 764 B

View File

@ -0,0 +1,10 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_14849_19007)">
<path d="M22.5 12C22.5 14.7848 21.3938 17.4555 19.4246 19.4246C17.4555 21.3938 14.7848 22.5 12 22.5C9.21523 22.5 6.54451 21.3938 4.57538 19.4246C2.60625 17.4555 1.5 14.7848 1.5 12C1.5 9.21523 2.60625 6.54451 4.57538 4.57538C6.54451 2.60625 9.21523 1.5 12 1.5C14.7848 1.5 17.4555 2.60625 19.4246 4.57538C21.3938 6.54451 22.5 9.21523 22.5 12ZM-8.58275e-07 12C-1.13651e-06 15.1826 1.26428 18.2348 3.51472 20.4853C5.76515 22.7357 8.8174 24 12 24C15.1826 24 18.2348 22.7357 20.4853 20.4853C22.7357 18.2348 24 15.1826 24 12C24 8.8174 22.7357 5.76516 20.4853 3.51472C18.2348 1.26428 15.1826 1.13651e-06 12 8.58275e-07C8.8174 5.80044e-07 5.76516 1.26428 3.51472 3.51472C1.26428 5.76515 -5.80044e-07 8.8174 -8.58275e-07 12ZM17.7797 12.5297L18.3094 12L17.7797 11.4703L13.2797 6.97031L12.75 6.44063L11.6906 7.5L12.2203 8.02969L15.4406 11.25L6.75 11.25L6 11.25L6 12.75L6.75 12.75L15.4406 12.75L12.2203 15.9703L11.6906 16.5L12.75 17.5594L13.2797 17.0297L17.7797 12.5297Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_14849_19007">
<rect width="24" height="24" fill="white" transform="translate(24 24) rotate(-180)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M22.5 12C22.5 14.7848 21.3938 17.4555 19.4246 19.4246C17.4555 21.3938 14.7848 22.5 12 22.5C9.21523 22.5 6.54451 21.3938 4.57538 19.4246C2.60625 17.4555 1.5 14.7848 1.5 12C1.5 9.21523 2.60625 6.54451 4.57538 4.57538C6.54451 2.60625 9.21523 1.5 12 1.5C14.7848 1.5 17.4555 2.60625 19.4246 4.57538C21.3938 6.54451 22.5 9.21523 22.5 12ZM0 12C-2.78235e-07 15.1826 1.26428 18.2348 3.51472 20.4853C5.76515 22.7357 8.8174 24 12 24C15.1826 24 18.2348 22.7357 20.4853 20.4853C22.7357 18.2348 24 15.1826 24 12C24 8.8174 22.7357 5.76516 20.4853 3.51472C18.2348 1.26428 15.1826 2.78235e-07 12 0C8.8174 -2.78231e-07 5.76516 1.26428 3.51472 3.51472C1.26428 5.76515 2.78231e-07 8.8174 0 12ZM17.7797 12.5297L18.3094 12L17.7797 11.4703L13.2797 6.97031L12.75 6.44063L11.6906 7.5L12.2203 8.02969L15.4406 11.25H6.75H6V12.75H6.75H15.4406L12.2203 15.9703L11.6906 16.5L12.75 17.5594L13.2797 17.0297L17.7797 12.5297Z" fill="#00AE42"/>
</svg>

After

Width:  |  Height:  |  Size: 1021 B

View File

@ -0,0 +1,3 @@
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6.64648 1.64698C6.84023 1.45323 7.15898 1.45323 7.35274 1.64698L12.3527 6.64698C12.5465 6.84073 12.5465 7.15948 12.3527 7.35323C12.159 7.54698 11.8402 7.54698 11.6465 7.35323L6.99961 2.70636L2.35273 7.35323C2.15898 7.54698 1.84023 7.54698 1.64648 7.35323C1.45273 7.15948 1.45273 6.84073 1.64648 6.64698L6.64648 1.64698ZM1.64648 12.647L6.64648 7.64698C6.84023 7.45323 7.15898 7.45323 7.35273 7.64698L12.3527 12.647C12.5465 12.8407 12.5465 13.1595 12.3527 13.3532C12.159 13.547 11.8402 13.547 11.6465 13.3532L6.99961 8.70636L2.35273 13.3532C2.15898 13.547 1.84023 13.547 1.64648 13.3532C1.45273 13.1595 1.45273 12.8407 1.64648 12.647Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 762 B

View File

@ -0,0 +1,3 @@
<svg width="14" height="16" viewBox="0 0 14 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.35352 14.353C7.15977 14.5468 6.84102 14.5468 6.64727 14.353L1.64727 9.35303C1.45352 9.15928 1.45352 8.84053 1.64727 8.64678C1.84102 8.45303 2.15977 8.45303 2.35352 8.64678L7.00039 13.2937L11.6473 8.64678C11.841 8.45303 12.1598 8.45303 12.3535 8.64678C12.5473 8.84053 12.5473 9.15928 12.3535 9.35303L7.35352 14.353ZM12.3535 3.35303L7.35352 8.35303C7.15977 8.54678 6.84102 8.54678 6.64727 8.35303L1.64727 3.35303C1.45352 3.15928 1.45352 2.84053 1.64727 2.64678C1.84102 2.45303 2.15977 2.45303 2.35352 2.64678L7.00039 7.29365L11.6473 2.64678C11.841 2.45303 12.1598 2.45303 12.3535 2.64678C12.5473 2.84053 12.5473 3.15928 12.3535 3.35303Z" fill="#262E30"/>
</svg>

After

Width:  |  Height:  |  Size: 768 B

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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