mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-26 02:01:12 -06:00
Merge remote-tracking branch 'origin/master' into ys_ph_printers
This commit is contained in:
commit
a6dc3d37f5
78 changed files with 4309 additions and 2783 deletions
|
|
@ -163,6 +163,8 @@ set(SLIC3R_GUI_SOURCES
|
|||
GUI/InstanceCheck.hpp
|
||||
GUI/Search.cpp
|
||||
GUI/Search.hpp
|
||||
GUI/NotificationManager.cpp
|
||||
GUI/NotificationManager.hpp
|
||||
Utils/Http.cpp
|
||||
Utils/Http.hpp
|
||||
Utils/FixModelByWin10.cpp
|
||||
|
|
|
|||
|
|
@ -89,11 +89,13 @@ void BackgroundSlicingProcess::process_fff()
|
|||
{
|
||||
assert(m_print == m_fff_print);
|
||||
m_print->process();
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_slicing_completed_id));
|
||||
wxCommandEvent evt(m_event_slicing_completed_id);
|
||||
evt.SetInt((int)(m_fff_print->step_state_with_timestamp(PrintStep::psBrim).timestamp));
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt.Clone());
|
||||
m_fff_print->export_gcode(m_temp_output_path, m_gcode_preview_data, m_thumbnail_cb);
|
||||
|
||||
if (this->set_step_started(bspsGCodeFinalize)) {
|
||||
if (! m_export_path.empty()) {
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
||||
//FIXME localize the messages
|
||||
// Perform the final post-processing of the export path by applying the print statistics over the file name.
|
||||
std::string export_path = m_fff_print->print_statistics().finalize_output_path(m_export_path);
|
||||
|
|
@ -124,6 +126,7 @@ void BackgroundSlicingProcess::process_fff()
|
|||
run_post_process_scripts(export_path, m_fff_print->config());
|
||||
m_print->set_status(100, (boost::format(_utf8(L("G-code file exported to %1%"))) % export_path).str());
|
||||
} else if (! m_upload_job.empty()) {
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
||||
prepare_upload();
|
||||
} else {
|
||||
m_print->set_status(100, _utf8(L("Slicing complete")));
|
||||
|
|
@ -149,6 +152,8 @@ void BackgroundSlicingProcess::process_sla()
|
|||
m_print->process();
|
||||
if (this->set_step_started(bspsGCodeFinalize)) {
|
||||
if (! m_export_path.empty()) {
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
||||
|
||||
const std::string export_path = m_sla_print->print_statistics().finalize_output_path(m_export_path);
|
||||
|
||||
Zipper zipper(export_path);
|
||||
|
|
@ -170,6 +175,7 @@ void BackgroundSlicingProcess::process_sla()
|
|||
|
||||
m_print->set_status(100, (boost::format(_utf8(L("Masked SLA file exported to %1%"))) % export_path).str());
|
||||
} else if (! m_upload_job.empty()) {
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
||||
prepare_upload();
|
||||
} else {
|
||||
m_print->set_status(100, _utf8(L("Slicing complete")));
|
||||
|
|
|
|||
|
|
@ -60,6 +60,10 @@ public:
|
|||
// The following wxCommandEvent will be sent to the UI thread / Plater window, when the G-code export is finished.
|
||||
// The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed.
|
||||
void set_finished_event(int event_id) { m_event_finished_id = event_id; }
|
||||
// The following wxCommandEvent will be sent to the UI thread / Plater window, when the G-code is being exported to
|
||||
// specified path or uploaded.
|
||||
// The wxCommandEvent is sent to the UI thread asynchronously without waiting for the event to be processed.
|
||||
void set_export_began_event(int event_id) { m_event_export_began_id = event_id; }
|
||||
|
||||
// Activate either m_fff_print or m_sla_print.
|
||||
// Return true if changed.
|
||||
|
|
@ -190,6 +194,9 @@ private:
|
|||
int m_event_slicing_completed_id = 0;
|
||||
// wxWidgets command ID to be sent to the plater to inform that the task finished.
|
||||
int m_event_finished_id = 0;
|
||||
// wxWidgets command ID to be sent to the plater to inform that the G-code is being exported.
|
||||
int m_event_export_began_id = 0;
|
||||
|
||||
};
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
|
|
|||
|
|
@ -353,6 +353,7 @@ void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config)
|
|||
toggle_field("support_head_penetration", supports_en);
|
||||
toggle_field("support_head_width", supports_en);
|
||||
toggle_field("support_pillar_diameter", supports_en);
|
||||
toggle_field("support_small_pillar_diameter_percent", supports_en);
|
||||
toggle_field("support_max_bridges_on_pillar", supports_en);
|
||||
toggle_field("support_pillar_connection_mode", supports_en);
|
||||
toggle_field("support_buildplate_only", supports_en);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "GUI_ObjectManipulation.hpp"
|
||||
#include "Mouse3DController.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "NotificationManager.hpp"
|
||||
|
||||
#if ENABLE_RETINA_GL
|
||||
#include "slic3r/Utils/RetinaHelper.hpp"
|
||||
|
|
@ -225,56 +226,44 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
|
|||
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
|
||||
|
||||
const Size& cnv_size = canvas.get_canvas_size();
|
||||
float canvas_w = (float)cnv_size.get_width();
|
||||
float canvas_h = (float)cnv_size.get_height();
|
||||
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
imgui.set_next_window_pos(canvas_w - imgui.get_style_scaling() * THICKNESS_BAR_WIDTH, canvas_h, ImGuiCond_Always, 1.0f, 1.0f);
|
||||
imgui.set_next_window_pos(static_cast<float>(cnv_size.get_width()) - imgui.get_style_scaling() * THICKNESS_BAR_WIDTH,
|
||||
static_cast<float>(cnv_size.get_height()), ImGuiCond_Always, 1.0f, 1.0f);
|
||||
|
||||
imgui.begin(_(L("Variable layer height")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
|
||||
imgui.begin(_L("Variable layer height"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(_(L("Left mouse button:")));
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(ORANGE, _L("Left mouse button:"));
|
||||
ImGui::SameLine();
|
||||
imgui.text(_(L("Add detail")));
|
||||
imgui.text(_L("Add detail"));
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(_(L("Right mouse button:")));
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(ORANGE, _L("Right mouse button:"));
|
||||
ImGui::SameLine();
|
||||
imgui.text(_(L("Remove detail")));
|
||||
imgui.text(_L("Remove detail"));
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(_(L("Shift + Left mouse button:")));
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(ORANGE, _L("Shift + Left mouse button:"));
|
||||
ImGui::SameLine();
|
||||
imgui.text(_(L("Reset to base")));
|
||||
imgui.text(_L("Reset to base"));
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(_(L("Shift + Right mouse button:")));
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(ORANGE, _L("Shift + Right mouse button:"));
|
||||
ImGui::SameLine();
|
||||
imgui.text(_(L("Smoothing")));
|
||||
imgui.text(_L("Smoothing"));
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
imgui.text(_(L("Mouse wheel:")));
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(ORANGE, _L("Mouse wheel:"));
|
||||
ImGui::SameLine();
|
||||
imgui.text(_(L("Increase/decrease edit area")));
|
||||
imgui.text(_L("Increase/decrease edit area"));
|
||||
|
||||
ImGui::Separator();
|
||||
if (imgui.button(_(L("Adaptive"))))
|
||||
if (imgui.button(_L("Adaptive")))
|
||||
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), Event<float>(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, m_adaptive_quality));
|
||||
|
||||
ImGui::SameLine();
|
||||
float text_align = ImGui::GetCursorPosX();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
imgui.text(_(L("Quality / Speed")));
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
imgui.text(_L("Quality / Speed"));
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(_(L("Higher print quality versus higher print speed.")).ToUTF8());
|
||||
ImGui::TextUnformatted(_L("Higher print quality versus higher print speed.").ToUTF8());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
|
||||
|
|
@ -285,13 +274,13 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
|
|||
ImGui::SliderFloat("", &m_adaptive_quality, 0.0f, 1.f, "%.2f");
|
||||
|
||||
ImGui::Separator();
|
||||
if (imgui.button(_(L("Smooth"))))
|
||||
if (imgui.button(_L("Smooth")))
|
||||
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), HeightProfileSmoothEvent(EVT_GLCANVAS_SMOOTH_LAYER_HEIGHT_PROFILE, m_smooth_params));
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(text_align);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
imgui.text(_(L("Radius")));
|
||||
imgui.text(_L("Radius"));
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(widget_align);
|
||||
ImGui::PushItemWidth(imgui.get_style_scaling() * 120.0f);
|
||||
|
|
@ -301,7 +290,7 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
|
|||
|
||||
ImGui::SetCursorPosX(text_align);
|
||||
ImGui::AlignTextToFramePadding();
|
||||
imgui.text(_(L("Keep min")));
|
||||
imgui.text(_L("Keep min"));
|
||||
ImGui::SameLine();
|
||||
if (ImGui::GetCursorPosX() < widget_align) // because of line lenght after localization
|
||||
ImGui::SetCursorPosX(widget_align);
|
||||
|
|
@ -310,7 +299,7 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const
|
|||
imgui.checkbox("##2", m_smooth_params.keep_min);
|
||||
|
||||
ImGui::Separator();
|
||||
if (imgui.button(_(L("Reset"))))
|
||||
if (imgui.button(_L("Reset")))
|
||||
wxPostEvent((wxEvtHandler*)canvas.get_wxglcanvas(), SimpleEvent(EVT_GLCANVAS_RESET_LAYER_HEIGHT_PROFILE));
|
||||
|
||||
imgui.end();
|
||||
|
|
@ -663,19 +652,45 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool
|
|||
|
||||
m_warnings.emplace_back(warning);
|
||||
std::sort(m_warnings.begin(), m_warnings.end());
|
||||
|
||||
std::string text;
|
||||
switch (warning) {
|
||||
case ObjectOutside: text = L("An object outside the print area was detected."); break;
|
||||
case ToolpathOutside: text = L("A toolpath outside the print area was detected."); break;
|
||||
case SlaSupportsOutside: text = L("SLA supports outside the print area were detected."); break;
|
||||
case SomethingNotShown: text = L("Some objects are not visible."); break;
|
||||
case ObjectClashed: wxGetApp().plater()->get_notification_manager()->push_plater_error_notification(L("An object outside the print area was detected.\n"
|
||||
"Resolve the current problem to continue slicing."),
|
||||
*(wxGetApp().plater()->get_current_canvas3D()));
|
||||
break;
|
||||
}
|
||||
if (!text.empty())
|
||||
wxGetApp().plater()->get_notification_manager()->push_plater_warning_notification(text, *(wxGetApp().plater()->get_current_canvas3D()));
|
||||
}
|
||||
else {
|
||||
if (it == m_warnings.end()) // deactivating something that is not active is an easy task
|
||||
return;
|
||||
|
||||
m_warnings.erase(it);
|
||||
if (m_warnings.empty()) { // nothing remains to be shown
|
||||
|
||||
std::string text;
|
||||
switch (warning) {
|
||||
case ObjectOutside: text = L("An object outside the print area was detected."); break;
|
||||
case ToolpathOutside: text = L("A toolpath outside the print area was detected."); break;
|
||||
case SlaSupportsOutside: text = L("SLA supports outside the print area were detected."); break;
|
||||
case SomethingNotShown: text = L("Some objects are not visibl.e"); break;
|
||||
case ObjectClashed: wxGetApp().plater()->get_notification_manager()->close_plater_error_notification(); break;
|
||||
}
|
||||
if (!text.empty())
|
||||
wxGetApp().plater()->get_notification_manager()->close_plater_warning_notification(text);
|
||||
|
||||
/*if (m_warnings.empty()) { // nothing remains to be shown
|
||||
reset();
|
||||
m_msg_text = "";// save information for rescaling
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/*
|
||||
// Look at the end of our vector and generate proper texture.
|
||||
std::string text;
|
||||
bool red_colored = false;
|
||||
|
|
@ -697,6 +712,7 @@ void GLCanvas3D::WarningTexture::activate(WarningTexture::Warning warning, bool
|
|||
// save information for rescaling
|
||||
m_msg_text = text;
|
||||
m_is_colored_red = red_colored;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1430,8 +1446,7 @@ void GLCanvas3D::Tooltip::render(const Vec2d& mouse_position, GLCanvas3D& canvas
|
|||
#if ENABLE_SLOPE_RENDERING
|
||||
void GLCanvas3D::Slope::render() const
|
||||
{
|
||||
if (m_dialog_shown)
|
||||
{
|
||||
if (m_dialog_shown) {
|
||||
const std::array<float, 2>& z_range = m_volumes.get_slope_z_range();
|
||||
std::array<float, 2> angle_range = { Geometry::rad2deg(::acos(z_range[0])) - 90.0f, Geometry::rad2deg(::acos(z_range[1])) - 90.0f };
|
||||
bool modified = false;
|
||||
|
|
@ -1439,9 +1454,9 @@ void GLCanvas3D::Slope::render() const
|
|||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
const Size& cnv_size = m_canvas.get_canvas_size();
|
||||
imgui.set_next_window_pos((float)cnv_size.get_width(), (float)cnv_size.get_height(), ImGuiCond_Always, 1.0f, 1.0f);
|
||||
imgui.begin(_(L("Slope visualization")), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
imgui.begin(_L("Slope visualization"), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
imgui.text(_(L("Facets' slope range (degrees)")) + ":");
|
||||
imgui.text(_L("Facets' slope range (degrees)") + ":");
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.0f, 0.0f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 0.0f, 0.0f, 0.5f));
|
||||
|
|
@ -1453,8 +1468,7 @@ void GLCanvas3D::Slope::render() const
|
|||
float slope_bound = 90.f - angle_range[1];
|
||||
bool mod = ImGui::SliderFloat("##red", &slope_bound, 0.0f, 90.0f, "%.1f");
|
||||
angle_range[1] = 90.f - slope_bound;
|
||||
if (mod)
|
||||
{
|
||||
if (mod) {
|
||||
modified = true;
|
||||
if (angle_range[0] > angle_range[1])
|
||||
angle_range[0] = angle_range[1];
|
||||
|
|
@ -1462,15 +1476,14 @@ void GLCanvas3D::Slope::render() const
|
|||
|
||||
ImGui::PopStyleColor(4);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.75f, 0.75f, 0.0f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 1.0f, 0.0f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.85f, 0.0f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.25f, 0.0f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, ImVec4(1.0f, 1.0f, 0.0f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(0.85f, 0.85f, 0.0f, 0.5f));
|
||||
ImGui::PushStyleColor(ImGuiCol_SliderGrab, ImVec4(0.25f, 0.25f, 0.0f, 1.0f));
|
||||
|
||||
slope_bound = 90.f - angle_range[0];
|
||||
mod = ImGui::SliderFloat("##yellow", &slope_bound, 0.0f, 90.0f, "%.1f");
|
||||
angle_range[0] = 90.f - slope_bound;
|
||||
if (mod)
|
||||
{
|
||||
if (mod) {
|
||||
modified = true;
|
||||
if (angle_range[1] < angle_range[0])
|
||||
angle_range[1] = angle_range[0];
|
||||
|
|
@ -2089,6 +2102,8 @@ void GLCanvas3D::render()
|
|||
|
||||
std::string tooltip;
|
||||
|
||||
|
||||
|
||||
// Negative coordinate means out of the window, likely because the window was deactivated.
|
||||
// In that case the tooltip should be hidden.
|
||||
if (m_mouse.position.x() >= 0. && m_mouse.position.y() >= 0.)
|
||||
|
|
@ -2118,6 +2133,8 @@ void GLCanvas3D::render()
|
|||
m_tooltip.render(m_mouse.position, *this);
|
||||
|
||||
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this);
|
||||
|
||||
wxGetApp().plater()->get_notification_manager()->render_notifications(*this);
|
||||
|
||||
wxGetApp().imgui()->render();
|
||||
|
||||
|
|
@ -3433,6 +3450,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
#ifdef SLIC3R_DEBUG_MOUSE_EVENTS
|
||||
printf((format_mouse_event_debug_message(evt) + " - Consumed by ImGUI\n").c_str());
|
||||
#endif /* SLIC3R_DEBUG_MOUSE_EVENTS */
|
||||
m_dirty = true;
|
||||
// do not return if dragging or tooltip not empty to allow for tooltip update
|
||||
if (!m_mouse.dragging && m_tooltip.is_empty())
|
||||
return;
|
||||
|
|
@ -3826,7 +3844,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt)
|
|||
m_gizmos.reset_all_states();
|
||||
|
||||
// Only refresh if picking is enabled, in that case the objects may get highlighted if the mouse cursor hovers over.
|
||||
if (m_picking_enabled)
|
||||
//if (m_picking_enabled)
|
||||
m_dirty = true;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@
|
|||
#include "Mouse3DController.hpp"
|
||||
#include "RemovableDriveManager.hpp"
|
||||
#include "InstanceCheck.hpp"
|
||||
#include "NotificationManager.hpp"
|
||||
|
||||
#ifdef __WXMSW__
|
||||
#include <dbt.h>
|
||||
|
|
@ -387,7 +388,7 @@ bool GUI_App::on_init_inner()
|
|||
// supplied as argument to --datadir; in that case we should still run the wizard
|
||||
preset_bundle->setup_directories();
|
||||
|
||||
#ifdef __WXMSW__
|
||||
#ifdef __WXMSW__
|
||||
associate_3mf_files();
|
||||
#endif // __WXMSW__
|
||||
|
||||
|
|
@ -395,6 +396,11 @@ bool GUI_App::on_init_inner()
|
|||
Bind(EVT_SLIC3R_VERSION_ONLINE, [this](const wxCommandEvent &evt) {
|
||||
app_config->set("version_online", into_u8(evt.GetString()));
|
||||
app_config->save();
|
||||
if(this->plater_ != nullptr) {
|
||||
if (*Semver::parse(SLIC3R_VERSION) < * Semver::parse(into_u8(evt.GetString()))) {
|
||||
this->plater_->get_notification_manager()->push_notification(NotificationType::NewAppAviable, *(this->plater_->get_current_canvas3D()));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// initialize label colors and fonts
|
||||
|
|
@ -1085,34 +1091,21 @@ void GUI_App::add_config_menu(wxMenuBar *menu)
|
|||
break;
|
||||
case ConfigMenuPreferences:
|
||||
{
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
bool app_layout_changed = false;
|
||||
#else
|
||||
bool recreate_app = false;
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
{
|
||||
// the dialog needs to be destroyed before the call to recreate_GUI()
|
||||
// or sometimes the application crashes into wxDialogBase() destructor
|
||||
// so we put it into an inner scope
|
||||
PreferencesDialog dlg(mainframe);
|
||||
dlg.ShowModal();
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
app_layout_changed = dlg.settings_layout_changed();
|
||||
#else
|
||||
recreate_app = dlg.settings_layout_changed();
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
}
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
if (app_layout_changed) {
|
||||
mainframe->GetSizer()->Hide((size_t)0);
|
||||
mainframe->update_layout();
|
||||
mainframe->select_tab(0);
|
||||
mainframe->GetSizer()->Show((size_t)0);
|
||||
}
|
||||
#else
|
||||
if (recreate_app)
|
||||
recreate_GUI(_L("Changing of the settings layout") + dots);
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
break;
|
||||
}
|
||||
case ConfigMenuLanguage:
|
||||
|
|
@ -1480,7 +1473,7 @@ void GUI_App::check_updates(const bool verbose)
|
|||
|
||||
PresetUpdater::UpdateResult updater_result;
|
||||
try {
|
||||
updater_result = preset_updater->config_update(app_config->orig_version());
|
||||
updater_result = preset_updater->config_update(app_config->orig_version(), verbose);
|
||||
if (updater_result == PresetUpdater::R_INCOMPAT_EXIT) {
|
||||
mainframe->Close();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -195,12 +195,15 @@ public:
|
|||
Plater* plater();
|
||||
Model& model();
|
||||
|
||||
|
||||
AppConfig* app_config{ nullptr };
|
||||
PresetBundle* preset_bundle{ nullptr };
|
||||
PresetUpdater* preset_updater{ nullptr };
|
||||
MainFrame* mainframe{ nullptr };
|
||||
Plater* plater_{ nullptr };
|
||||
|
||||
PresetUpdater* get_preset_updater() { return preset_updater; }
|
||||
|
||||
wxNotebook* tab_panel() const ;
|
||||
int extruders_cnt() const;
|
||||
int extruders_edited_cnt() const;
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ ObjectList::ObjectList(wxWindow* parent) :
|
|||
// ptFFF
|
||||
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap("layers");
|
||||
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill");
|
||||
CATEGORY_ICON[L("Ironing")] = create_scaled_bitmap("infill"); // FIXME when the ironing icon is available
|
||||
CATEGORY_ICON[L("Ironing")] = create_scaled_bitmap("ironing");
|
||||
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap("support");
|
||||
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap("time");
|
||||
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap("funnel");
|
||||
|
|
@ -642,7 +642,7 @@ void ObjectList::msw_rescale_icons()
|
|||
// ptFFF
|
||||
CATEGORY_ICON[L("Layers and Perimeters")] = create_scaled_bitmap("layers");
|
||||
CATEGORY_ICON[L("Infill")] = create_scaled_bitmap("infill");
|
||||
CATEGORY_ICON[L("Ironing")] = create_scaled_bitmap("infill"); // FIXME when the ironing icon is available
|
||||
CATEGORY_ICON[L("Ironing")] = create_scaled_bitmap("ironing");
|
||||
CATEGORY_ICON[L("Support material")] = create_scaled_bitmap("support");
|
||||
CATEGORY_ICON[L("Speed")] = create_scaled_bitmap("time");
|
||||
CATEGORY_ICON[L("Extruders")] = create_scaled_bitmap("funnel");
|
||||
|
|
|
|||
|
|
@ -110,13 +110,8 @@ public:
|
|||
if (!m_can_rescale)
|
||||
return;
|
||||
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
if (m_force_rescale || is_new_scale_factor())
|
||||
rescale(wxRect());
|
||||
#else
|
||||
if (is_new_scale_factor())
|
||||
rescale(wxRect());
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
});
|
||||
#else
|
||||
this->Bind(EVT_DPI_CHANGED_SLICER, [this](const DpiChangedEvent& evt) {
|
||||
|
|
@ -127,13 +122,8 @@ public:
|
|||
if (!m_can_rescale)
|
||||
return;
|
||||
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
if (m_force_rescale || is_new_scale_factor())
|
||||
rescale(evt.rect);
|
||||
#else
|
||||
if (is_new_scale_factor())
|
||||
rescale(evt.rect);
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
});
|
||||
#endif // wxVERSION_EQUAL_OR_GREATER_THAN
|
||||
|
||||
|
|
@ -175,9 +165,7 @@ public:
|
|||
int em_unit() const { return m_em_unit; }
|
||||
// int font_size() const { return m_font_size; }
|
||||
const wxFont& normal_font() const { return m_normal_font; }
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
void enable_force_rescale() { m_force_rescale = true; }
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
protected:
|
||||
virtual void on_dpi_changed(const wxRect &suggested_rect) = 0;
|
||||
|
|
@ -191,9 +179,7 @@ private:
|
|||
wxFont m_normal_font;
|
||||
float m_prev_scale_factor;
|
||||
bool m_can_rescale{ true };
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
bool m_force_rescale{ false };
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
int m_new_font_point_size;
|
||||
|
||||
|
|
@ -233,17 +219,17 @@ private:
|
|||
{
|
||||
this->Freeze();
|
||||
|
||||
#if ENABLE_LAYOUT_NO_RESTART && wxVERSION_EQUAL_OR_GREATER_THAN(3,1,3)
|
||||
#if wxVERSION_EQUAL_OR_GREATER_THAN(3,1,3)
|
||||
if (m_force_rescale) {
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
#endif // wxVERSION_EQUAL_OR_GREATER_THAN
|
||||
// rescale fonts of all controls
|
||||
scale_controls_fonts(this, m_new_font_point_size);
|
||||
// rescale current window font
|
||||
scale_win_font(this, m_new_font_point_size);
|
||||
#if ENABLE_LAYOUT_NO_RESTART && wxVERSION_EQUAL_OR_GREATER_THAN(3,1,3)
|
||||
#if wxVERSION_EQUAL_OR_GREATER_THAN(3,1,3)
|
||||
m_force_rescale = false;
|
||||
}
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
#endif // wxVERSION_EQUAL_OR_GREATER_THAN
|
||||
|
||||
// set normal application font as a current window font
|
||||
m_normal_font = this->GetFont();
|
||||
|
|
|
|||
|
|
@ -513,9 +513,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
|||
|
||||
auto draw_text_with_caption = [this, &caption_max](const wxString& caption, const wxString& text) {
|
||||
static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ORANGE);
|
||||
m_imgui->text(caption);
|
||||
ImGui::PopStyleColor();
|
||||
m_imgui->text_colored(ORANGE, caption);
|
||||
ImGui::SameLine(caption_max);
|
||||
m_imgui->text(text);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -37,11 +37,17 @@ namespace GUI {
|
|||
|
||||
|
||||
static const std::map<const char, std::string> font_icons = {
|
||||
{ImGui::PrintIconMarker , "cog" },
|
||||
{ImGui::PrinterIconMarker , "printer" },
|
||||
{ImGui::PrinterSlaIconMarker, "sla_printer"},
|
||||
{ImGui::FilamentIconMarker , "spool" },
|
||||
{ImGui::MaterialIconMarker , "resin" }
|
||||
{ImGui::PrintIconMarker , "cog" },
|
||||
{ImGui::PrinterIconMarker , "printer" },
|
||||
{ImGui::PrinterSlaIconMarker, "sla_printer" },
|
||||
{ImGui::FilamentIconMarker , "spool" },
|
||||
{ImGui::MaterialIconMarker , "resin" },
|
||||
{ImGui::CloseIconMarker , "cross" },
|
||||
{ImGui::CloseIconHoverMarker, "cross_focus_large" },
|
||||
{ImGui::TimerDotMarker , "timer_dot" },
|
||||
{ImGui::TimerDotEmptyMarker , "timer_dot_empty" },
|
||||
{ImGui::WarningMarker , "flag_green" },
|
||||
{ImGui::ErrorMarker , "flag_red" }
|
||||
};
|
||||
|
||||
ImGuiWrapper::ImGuiWrapper()
|
||||
|
|
@ -265,6 +271,11 @@ void ImGuiWrapper::set_next_window_bg_alpha(float alpha)
|
|||
ImGui::SetNextWindowBgAlpha(alpha);
|
||||
}
|
||||
|
||||
void ImGuiWrapper::set_next_window_size(float x, float y, ImGuiCond cond)
|
||||
{
|
||||
ImGui::SetNextWindowSize(ImVec2(x, y), cond);
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::begin(const std::string &name, int flags)
|
||||
{
|
||||
return ImGui::Begin(name.c_str(), nullptr, (ImGuiWindowFlags)flags);
|
||||
|
|
@ -296,12 +307,23 @@ bool ImGuiWrapper::button(const wxString &label)
|
|||
return ImGui::Button(label_utf8.c_str());
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::button(const wxString& label, float width, float height)
|
||||
{
|
||||
auto label_utf8 = into_u8(label);
|
||||
return ImGui::Button(label_utf8.c_str(), ImVec2(width, height));
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::radio_button(const wxString &label, bool active)
|
||||
{
|
||||
auto label_utf8 = into_u8(label);
|
||||
return ImGui::RadioButton(label_utf8.c_str(), active);
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::image_button()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::input_double(const std::string &label, const double &value, const std::string &format)
|
||||
{
|
||||
return ImGui::InputDouble(label.c_str(), const_cast<double*>(&value), 0.0f, 0.0f, format.c_str());
|
||||
|
|
@ -354,6 +376,22 @@ void ImGuiWrapper::text(const wxString &label)
|
|||
this->text(label_utf8.c_str());
|
||||
}
|
||||
|
||||
void ImGuiWrapper::text_colored(const ImVec4& color, const char* label)
|
||||
{
|
||||
ImGui::TextColored(color, label);
|
||||
}
|
||||
|
||||
void ImGuiWrapper::text_colored(const ImVec4& color, const std::string& label)
|
||||
{
|
||||
this->text_colored(color, label.c_str());
|
||||
}
|
||||
|
||||
void ImGuiWrapper::text_colored(const ImVec4& color, const wxString& label)
|
||||
{
|
||||
auto label_utf8 = into_u8(label);
|
||||
this->text_colored(color, label_utf8.c_str());
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::slider_float(const char* label, float* v, float v_min, float v_max, const char* format/* = "%.3f"*/, float power/* = 1.0f*/)
|
||||
{
|
||||
return ImGui::SliderFloat(label, v, v_min, v_max, format, power);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ public:
|
|||
|
||||
void set_next_window_pos(float x, float y, int flag, float pivot_x = 0.0f, float pivot_y = 0.0f);
|
||||
void set_next_window_bg_alpha(float alpha);
|
||||
void set_next_window_size(float x, float y, ImGuiCond cond);
|
||||
|
||||
bool begin(const std::string &name, int flags = 0);
|
||||
bool begin(const wxString &name, int flags = 0);
|
||||
|
|
@ -65,7 +66,9 @@ public:
|
|||
void end();
|
||||
|
||||
bool button(const wxString &label);
|
||||
bool button(const wxString& label, float width, float height);
|
||||
bool radio_button(const wxString &label, bool active);
|
||||
bool image_button();
|
||||
bool input_double(const std::string &label, const double &value, const std::string &format = "%.3f");
|
||||
bool input_double(const wxString &label, const double &value, const std::string &format = "%.3f");
|
||||
bool input_vec3(const std::string &label, const Vec3d &value, float width, const std::string &format = "%.3f");
|
||||
|
|
@ -73,6 +76,9 @@ public:
|
|||
void text(const char *label);
|
||||
void text(const std::string &label);
|
||||
void text(const wxString &label);
|
||||
void text_colored(const ImVec4& color, const char* label);
|
||||
void text_colored(const ImVec4& color, const std::string& label);
|
||||
void text_colored(const ImVec4& color, const wxString& label);
|
||||
bool slider_float(const char* label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
|
||||
bool slider_float(const std::string& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
|
||||
bool slider_float(const wxString& label, float* v, float v_min, float v_max, const char* format = "%.3f", float power = 1.0f);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
enum class ERescaleTarget
|
||||
{
|
||||
Mainframe,
|
||||
|
|
@ -71,15 +70,12 @@ static void rescale_dialog_after_dpi_change(MainFrame& mainframe, SettingsDialog
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
MainFrame::MainFrame() :
|
||||
DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "mainframe"),
|
||||
m_printhost_queue_dlg(new PrintHostQueueDialog(this))
|
||||
, m_recent_projects(9)
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
, m_settings_dialog(this)
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
{
|
||||
// Fonts were created by the DPIFrame constructor for the monitor, on which the window opened.
|
||||
wxGetApp().update_fonts(this);
|
||||
|
|
@ -119,43 +115,15 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
|||
|
||||
m_loaded = true;
|
||||
|
||||
#if !ENABLE_LAYOUT_NO_RESTART
|
||||
#ifdef __APPLE__
|
||||
// Using SetMinSize() on Mac messes up the window position in some cases
|
||||
// cf. https://groups.google.com/forum/#!topic/wx-users/yUKPBBfXWO0
|
||||
// So, if we haven't possibility to set MinSize() for the MainFrame,
|
||||
// set the MinSize() as a half of regular for the m_plater and m_tabpanel, when settings layout is in slNew mode
|
||||
// Otherwise, MainFrame will be maximized by height
|
||||
if (slNew) {
|
||||
wxSize size = wxGetApp().get_min_size();
|
||||
size.SetHeight(int(0.5*size.GetHeight()));
|
||||
m_plater->SetMinSize(size);
|
||||
m_tabpanel->SetMinSize(size);
|
||||
}
|
||||
#endif
|
||||
#endif // !ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
// initialize layout
|
||||
m_main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(m_main_sizer, 1, wxEXPAND);
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
SetSizer(sizer);
|
||||
// initialize layout from config
|
||||
update_layout();
|
||||
sizer->SetSizeHints(this);
|
||||
Fit();
|
||||
#else
|
||||
if (m_plater && m_layout != slOld)
|
||||
sizer->Add(m_plater, 1, wxEXPAND);
|
||||
|
||||
if (m_tabpanel && m_layout != slDlg)
|
||||
sizer->Add(m_tabpanel, 1, wxEXPAND);
|
||||
|
||||
sizer->SetSizeHints(this);
|
||||
SetSizer(sizer);
|
||||
Fit();
|
||||
#endif // !ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
const wxSize min_size = wxGetApp().get_min_size(); //wxSize(76*wxGetApp().em_unit(), 49*wxGetApp().em_unit());
|
||||
#ifdef __APPLE__
|
||||
|
|
@ -247,12 +215,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
|||
});
|
||||
|
||||
wxGetApp().persist_window_geometry(this, true);
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
wxGetApp().persist_window_geometry(&m_settings_dialog, true);
|
||||
#else
|
||||
if (m_settings_dialog != nullptr)
|
||||
wxGetApp().persist_window_geometry(m_settings_dialog, true);
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
update_ui_from_settings(); // FIXME (?)
|
||||
|
||||
|
|
@ -260,7 +223,6 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
|||
m_plater->show_action_buttons(true);
|
||||
}
|
||||
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
void MainFrame::update_layout()
|
||||
{
|
||||
auto restore_to_creation = [this]() {
|
||||
|
|
@ -375,7 +337,6 @@ void MainFrame::update_layout()
|
|||
Layout();
|
||||
Thaw();
|
||||
}
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
// Called when closing the application and when switching the application language.
|
||||
void MainFrame::shutdown()
|
||||
|
|
@ -409,20 +370,9 @@ void MainFrame::shutdown()
|
|||
// In addition, there were some crashes due to the Paint events sent to already destructed windows.
|
||||
this->Show(false);
|
||||
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
if (m_settings_dialog.IsShown())
|
||||
// call Close() to trigger call to lambda defined into GUI_App::persist_window_geometry()
|
||||
m_settings_dialog.Close();
|
||||
#else
|
||||
if (m_settings_dialog != nullptr)
|
||||
{
|
||||
if (m_settings_dialog->IsShown())
|
||||
// call Close() to trigger call to lambda defined into GUI_App::persist_window_geometry()
|
||||
m_settings_dialog->Close();
|
||||
|
||||
m_settings_dialog->Destroy();
|
||||
}
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
// Stop the background thread (Windows and Linux).
|
||||
// Disconnect from a 3DConnextion driver (OSX).
|
||||
|
|
@ -481,7 +431,6 @@ void MainFrame::update_title()
|
|||
|
||||
void MainFrame::init_tabpanel()
|
||||
{
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
// wxNB_NOPAGETHEME: Disable Windows Vista theme for the Notebook background. The theme performance is terrible on Windows 10
|
||||
// with multiple high resolution displays connected.
|
||||
m_tabpanel = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
|
||||
|
|
@ -490,27 +439,6 @@ void MainFrame::init_tabpanel()
|
|||
#endif
|
||||
m_tabpanel->Hide();
|
||||
m_settings_dialog.set_tabpanel(m_tabpanel);
|
||||
#else
|
||||
m_layout = wxGetApp().app_config->get("old_settings_layout_mode") == "1" ? slOld :
|
||||
wxGetApp().app_config->get("new_settings_layout_mode") == "1" ? slNew :
|
||||
wxGetApp().app_config->get("dlg_settings_layout_mode") == "1" ? slDlg : slOld;
|
||||
|
||||
// From the very beginning the Print settings should be selected
|
||||
m_last_selected_tab = m_layout == slDlg ? 0 : 1;
|
||||
|
||||
if (m_layout == slDlg) {
|
||||
m_settings_dialog = new SettingsDialog(this);
|
||||
m_tabpanel = m_settings_dialog->get_tabpanel();
|
||||
}
|
||||
else {
|
||||
// wxNB_NOPAGETHEME: Disable Windows Vista theme for the Notebook background. The theme performance is terrible on Windows 10
|
||||
// with multiple high resolution displays connected.
|
||||
m_tabpanel = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
|
||||
#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
|
||||
m_tabpanel->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||
#endif
|
||||
}
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
m_tabpanel->Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, [this](wxEvent&) {
|
||||
wxWindow* panel = m_tabpanel->GetCurrentPage();
|
||||
|
|
@ -531,20 +459,9 @@ void MainFrame::init_tabpanel()
|
|||
select_tab(0); // select Plater
|
||||
});
|
||||
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
m_plater = new Plater(this, this);
|
||||
m_plater->Hide();
|
||||
#else
|
||||
if (m_layout == slOld) {
|
||||
m_plater = new Plater(m_tabpanel, this);
|
||||
m_tabpanel->AddPage(m_plater, _L("Plater"));
|
||||
}
|
||||
else {
|
||||
m_plater = new Plater(this, this);
|
||||
if (m_layout == slNew)
|
||||
m_tabpanel->AddPage(new wxPanel(m_tabpanel), _L("Plater")); // empty panel just for Plater tab
|
||||
}
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
wxGetApp().plater_ = m_plater;
|
||||
|
||||
wxGetApp().obj_list()->create_popup_menus();
|
||||
|
|
@ -686,7 +603,6 @@ bool MainFrame::can_slice() const
|
|||
|
||||
bool MainFrame::can_change_view() const
|
||||
{
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
switch (m_layout)
|
||||
{
|
||||
default: { return false; }
|
||||
|
|
@ -697,15 +613,6 @@ bool MainFrame::can_change_view() const
|
|||
return page_id != wxNOT_FOUND && dynamic_cast<const Slic3r::GUI::Plater*>(m_tabpanel->GetPage((size_t)page_id)) != nullptr;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (m_layout == slNew)
|
||||
return m_plater->IsShown();
|
||||
if (m_layout == slDlg)
|
||||
return true;
|
||||
// slOld layout mode
|
||||
int page_id = m_tabpanel->GetSelection();
|
||||
return page_id != wxNOT_FOUND && dynamic_cast<const Slic3r::GUI::Plater*>(m_tabpanel->GetPage((size_t)page_id)) != nullptr;
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
}
|
||||
|
||||
bool MainFrame::can_select() const
|
||||
|
|
@ -746,11 +653,7 @@ void MainFrame::on_dpi_changed(const wxRect& suggested_rect)
|
|||
wxGetApp().plater()->msw_rescale();
|
||||
|
||||
// update Tabs
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
if (m_layout != ESettingsLayout::Dlg) // Do not update tabs if the Settings are in the separated dialog
|
||||
#else
|
||||
if (m_layout != slDlg) // Update tabs later, from the SettingsDialog, when the Settings are in the separated dialog
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
for (auto tab : wxGetApp().tabs_list)
|
||||
tab->msw_rescale();
|
||||
|
||||
|
|
@ -779,10 +682,8 @@ void MainFrame::on_dpi_changed(const wxRect& suggested_rect)
|
|||
|
||||
this->Maximize(is_maximized);
|
||||
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
if (m_layout == ESettingsLayout::Dlg)
|
||||
rescale_dialog_after_dpi_change(*this, m_settings_dialog, ERescaleTarget::SettingsDialog);
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
}
|
||||
|
||||
void MainFrame::on_sys_color_changed()
|
||||
|
|
@ -1516,25 +1417,15 @@ void MainFrame::load_config(const DynamicPrintConfig& config)
|
|||
void MainFrame::select_tab(size_t tab/* = size_t(-1)*/)
|
||||
{
|
||||
bool tabpanel_was_hidden = false;
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
if (m_layout == ESettingsLayout::Dlg) {
|
||||
#else
|
||||
if (m_layout == slDlg) {
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
if (tab==0) {
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
if (m_settings_dialog.IsShown())
|
||||
this->SetFocus();
|
||||
#else
|
||||
if (m_settings_dialog->IsShown())
|
||||
this->SetFocus();
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
// plater should be focused for correct navigation inside search window
|
||||
if (m_plater->canvas3D()->is_search_pressed())
|
||||
m_plater->SetFocus();
|
||||
return;
|
||||
}
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
// Show/Activate Settings Dialog
|
||||
#ifdef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
|
||||
if (m_settings_dialog.IsShown())
|
||||
|
|
@ -1551,28 +1442,11 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/)
|
|||
m_settings_dialog.Show();
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
// Show/Activate Settings Dialog
|
||||
if (m_settings_dialog->IsShown())
|
||||
#ifdef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
|
||||
m_settings_dialog->Hide();
|
||||
#else
|
||||
m_settings_dialog->SetFocus();
|
||||
else
|
||||
#endif
|
||||
m_settings_dialog->Show();
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
}
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
else if (m_layout == ESettingsLayout::New) {
|
||||
m_main_sizer->Show(m_plater, tab == 0);
|
||||
tabpanel_was_hidden = !m_main_sizer->IsShown(m_tabpanel);
|
||||
m_main_sizer->Show(m_tabpanel, tab != 0);
|
||||
#else
|
||||
else if (m_layout == slNew) {
|
||||
m_plater->Show(tab == 0);
|
||||
m_tabpanel->Show(tab != 0);
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
// plater should be focused for correct navigation inside search window
|
||||
if (tab == 0 && m_plater->canvas3D()->is_search_pressed())
|
||||
|
|
@ -1589,11 +1463,7 @@ void MainFrame::select_tab(size_t tab/* = size_t(-1)*/)
|
|||
tab->update_changed_tree_ui();
|
||||
|
||||
// when tab == -1, it means we should show the last selected tab
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
m_tabpanel->SetSelection(tab == (size_t)(-1) ? m_last_selected_tab : (m_layout == ESettingsLayout::Dlg && tab != 0) ? tab - 1 : tab);
|
||||
#else
|
||||
m_tabpanel->SetSelection(tab == (size_t)(-1) ? m_last_selected_tab : (m_layout == slDlg && tab != 0) ? tab-1 : tab);
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
}
|
||||
|
||||
// Set a camera direction, zoom to all objects.
|
||||
|
|
@ -1722,34 +1592,6 @@ SettingsDialog::SettingsDialog(MainFrame* mainframe)
|
|||
SetIcon(wxIcon(var("PrusaSlicer_128px.png"), wxBITMAP_TYPE_PNG));
|
||||
#endif // _WIN32
|
||||
|
||||
#if !ENABLE_LAYOUT_NO_RESTART
|
||||
// wxNB_NOPAGETHEME: Disable Windows Vista theme for the Notebook background. The theme performance is terrible on Windows 10
|
||||
// with multiple high resolution displays connected.
|
||||
m_tabpanel = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxGetApp().get_min_size(), wxNB_TOP | wxTAB_TRAVERSAL | wxNB_NOPAGETHEME);
|
||||
#ifndef __WXOSX__ // Don't call SetFont under OSX to avoid name cutting in ObjectList
|
||||
m_tabpanel->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||
#endif
|
||||
|
||||
m_tabpanel->Bind(wxEVT_KEY_UP, [this](wxKeyEvent& evt) {
|
||||
if ((evt.GetModifiers() & wxMOD_CONTROL) != 0) {
|
||||
switch (evt.GetKeyCode()) {
|
||||
case '1': { m_main_frame->select_tab(0); break; }
|
||||
case '2': { m_main_frame->select_tab(1); break; }
|
||||
case '3': { m_main_frame->select_tab(2); break; }
|
||||
case '4': { m_main_frame->select_tab(3); break; }
|
||||
#ifdef __APPLE__
|
||||
case 'f':
|
||||
#else /* __APPLE__ */
|
||||
case WXK_CONTROL_F:
|
||||
#endif /* __APPLE__ */
|
||||
case 'F': { m_main_frame->plater()->search(false); break; }
|
||||
default:break;
|
||||
}
|
||||
}
|
||||
});
|
||||
#endif // !ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
this->Bind(wxEVT_SHOW, [this](wxShowEvent& evt) {
|
||||
|
||||
auto key_up_handker = [this](wxKeyEvent& evt) {
|
||||
|
|
@ -1779,13 +1621,9 @@ SettingsDialog::SettingsDialog(MainFrame* mainframe)
|
|||
m_tabpanel->Unbind(wxEVT_KEY_UP, key_up_handker);
|
||||
}
|
||||
});
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
// initialize layout
|
||||
auto sizer = new wxBoxSizer(wxVERTICAL);
|
||||
#if !ENABLE_LAYOUT_NO_RESTART
|
||||
sizer->Add(m_tabpanel, 1, wxEXPAND);
|
||||
#endif // !ENABLE_LAYOUT_NO_RESTART
|
||||
sizer->SetSizeHints(this);
|
||||
SetSizer(sizer);
|
||||
Fit();
|
||||
|
|
|
|||
|
|
@ -55,11 +55,7 @@ class SettingsDialog : public DPIDialog
|
|||
public:
|
||||
SettingsDialog(MainFrame* mainframe);
|
||||
~SettingsDialog() {}
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
void set_tabpanel(wxNotebook* tabpanel) { m_tabpanel = tabpanel; }
|
||||
#else
|
||||
wxNotebook* get_tabpanel() { return m_tabpanel; }
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
|
|
@ -119,7 +115,6 @@ class MainFrame : public DPIFrame
|
|||
|
||||
wxFileHistory m_recent_projects;
|
||||
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
enum class ESettingsLayout
|
||||
{
|
||||
Unknown,
|
||||
|
|
@ -129,13 +124,6 @@ class MainFrame : public DPIFrame
|
|||
};
|
||||
|
||||
ESettingsLayout m_layout{ ESettingsLayout::Unknown };
|
||||
#else
|
||||
enum SettingsLayout {
|
||||
slOld = 0,
|
||||
slNew,
|
||||
slDlg,
|
||||
} m_layout;
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
protected:
|
||||
virtual void on_dpi_changed(const wxRect &suggested_rect);
|
||||
|
|
@ -145,9 +133,7 @@ public:
|
|||
MainFrame();
|
||||
~MainFrame() = default;
|
||||
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
void update_layout();
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
// Called when closing the application and when switching the application language.
|
||||
void shutdown();
|
||||
|
|
@ -190,12 +176,8 @@ public:
|
|||
|
||||
Plater* m_plater { nullptr };
|
||||
wxNotebook* m_tabpanel { nullptr };
|
||||
#if ENABLE_LAYOUT_NO_RESTART
|
||||
SettingsDialog m_settings_dialog;
|
||||
wxWindow* m_plater_page{ nullptr };
|
||||
#else
|
||||
SettingsDialog* m_settings_dialog { nullptr };
|
||||
#endif // ENABLE_LAYOUT_NO_RESTART
|
||||
wxProgressDialog* m_progress_dialog { nullptr };
|
||||
std::shared_ptr<ProgressStatusBar> m_statusbar;
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ bool MeshRaycaster::unproject_on_mesh(const Vec2d& mouse_pos, const Transform3d&
|
|||
Vec3d direction;
|
||||
line_from_mouse_pos(mouse_pos, trafo, camera, point, direction);
|
||||
|
||||
std::vector<sla::EigenMesh3D::hit_result> hits = m_emesh.query_ray_hits(point, direction);
|
||||
std::vector<sla::IndexedMesh::hit_result> hits = m_emesh.query_ray_hits(point, direction);
|
||||
|
||||
if (hits.empty())
|
||||
return false; // no intersection found
|
||||
|
|
@ -184,7 +184,7 @@ std::vector<unsigned> MeshRaycaster::get_unobscured_idxs(const Geometry::Transfo
|
|||
|
||||
bool is_obscured = false;
|
||||
// Cast a ray in the direction of the camera and look for intersection with the mesh:
|
||||
std::vector<sla::EigenMesh3D::hit_result> hits;
|
||||
std::vector<sla::IndexedMesh::hit_result> hits;
|
||||
// Offset the start of the ray by EPSILON to account for numerical inaccuracies.
|
||||
hits = m_emesh.query_ray_hits((inverse_trafo * pt + direction_to_camera_mesh * EPSILON).cast<double>(),
|
||||
direction_to_camera.cast<double>());
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/Geometry.hpp"
|
||||
#include "libslic3r/SLA/EigenMesh3D.hpp"
|
||||
#include "libslic3r/SLA/IndexedMesh.hpp"
|
||||
#include "admesh/stl.h"
|
||||
|
||||
#include "slic3r/GUI/3DScene.hpp"
|
||||
|
|
@ -147,7 +147,7 @@ public:
|
|||
Vec3f get_triangle_normal(size_t facet_idx) const;
|
||||
|
||||
private:
|
||||
sla::EigenMesh3D m_emesh;
|
||||
sla::IndexedMesh m_emesh;
|
||||
std::vector<stl_normal> m_normals;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "AppConfig.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
#include "Plater.hpp"
|
||||
#include "NotificationManager.hpp"
|
||||
|
||||
#include <wx/glcanvas.h>
|
||||
|
||||
|
|
@ -239,8 +240,7 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
|
|||
|
||||
// when the user clicks on [X] or [Close] button we need to trigger
|
||||
// an extra frame to let the dialog disappear
|
||||
if (m_settings_dialog_closed_by_user)
|
||||
{
|
||||
if (m_settings_dialog_closed_by_user) {
|
||||
m_show_settings_dialog = false;
|
||||
m_settings_dialog_closed_by_user = false;
|
||||
canvas.request_extra_frame();
|
||||
|
|
@ -261,13 +261,10 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
|
|||
|
||||
static ImVec2 last_win_size(0.0f, 0.0f);
|
||||
bool shown = true;
|
||||
if (imgui.begin(_(L("3Dconnexion settings")), &shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse))
|
||||
{
|
||||
if (shown)
|
||||
{
|
||||
if (imgui.begin(_L("3Dconnexion settings"), &shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse)) {
|
||||
if (shown) {
|
||||
ImVec2 win_size = ImGui::GetWindowSize();
|
||||
if ((last_win_size.x != win_size.x) || (last_win_size.y != win_size.y))
|
||||
{
|
||||
if (last_win_size.x != win_size.x || last_win_size.y != win_size.y) {
|
||||
// when the user clicks on [X] button, the next time the dialog is shown
|
||||
// has a dummy size, so we trigger an extra frame to let it have the correct size
|
||||
last_win_size = win_size;
|
||||
|
|
@ -275,59 +272,51 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
|
|||
}
|
||||
|
||||
const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text(_(L("Device:")));
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(color, _L("Device:"));
|
||||
ImGui::SameLine();
|
||||
imgui.text(m_device_str);
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text(_(L("Speed:")));
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(color, _L("Speed:"));
|
||||
|
||||
float translation_scale = (float)params_copy.translation.scale / Params::DefaultTranslationScale;
|
||||
if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.1f, 10.0f, "%.1f")) {
|
||||
if (imgui.slider_float(_L("Translation") + "##1", &translation_scale, 0.1f, 10.0f, "%.1f")) {
|
||||
params_copy.translation.scale = Params::DefaultTranslationScale * (double)translation_scale;
|
||||
params_changed = true;
|
||||
}
|
||||
|
||||
float rotation_scale = params_copy.rotation.scale / Params::DefaultRotationScale;
|
||||
if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.1f, 10.0f, "%.1f")) {
|
||||
if (imgui.slider_float(_L("Rotation") + "##1", &rotation_scale, 0.1f, 10.0f, "%.1f")) {
|
||||
params_copy.rotation.scale = Params::DefaultRotationScale * rotation_scale;
|
||||
params_changed = true;
|
||||
}
|
||||
|
||||
float zoom_scale = params_copy.zoom.scale / Params::DefaultZoomScale;
|
||||
if (imgui.slider_float(_(L("Zoom")), &zoom_scale, 0.1f, 10.0f, "%.1f")) {
|
||||
if (imgui.slider_float(_L("Zoom"), &zoom_scale, 0.1f, 10.0f, "%.1f")) {
|
||||
params_copy.zoom.scale = Params::DefaultZoomScale * zoom_scale;
|
||||
params_changed = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text(_(L("Deadzone:")));
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(color, _L("Deadzone:"));
|
||||
|
||||
float translation_deadzone = (float)params_copy.translation.deadzone;
|
||||
if (imgui.slider_float(_(L("Translation")) + "/" + _(L("Zoom")), &translation_deadzone, 0.0f, (float)Params::MaxTranslationDeadzone, "%.2f")) {
|
||||
if (imgui.slider_float(_L("Translation") + "/" + _L("Zoom"), &translation_deadzone, 0.0f, (float)Params::MaxTranslationDeadzone, "%.2f")) {
|
||||
params_copy.translation.deadzone = (double)translation_deadzone;
|
||||
params_changed = true;
|
||||
}
|
||||
|
||||
float rotation_deadzone = params_copy.rotation.deadzone;
|
||||
if (imgui.slider_float(_(L("Rotation")) + "##2", &rotation_deadzone, 0.0f, Params::MaxRotationDeadzone, "%.2f")) {
|
||||
if (imgui.slider_float(_L("Rotation") + "##2", &rotation_deadzone, 0.0f, Params::MaxRotationDeadzone, "%.2f")) {
|
||||
params_copy.rotation.deadzone = rotation_deadzone;
|
||||
params_changed = true;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text(_(L("Options:")));
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(color, _L("Options:"));
|
||||
|
||||
bool swap_yz = params_copy.swap_yz;
|
||||
if (imgui.checkbox("Swap Y/Z axes", swap_yz)) {
|
||||
if (imgui.checkbox(_L("Swap Y/Z axes"), swap_yz)) {
|
||||
params_copy.swap_yz = swap_yz;
|
||||
params_changed = true;
|
||||
}
|
||||
|
|
@ -335,25 +324,20 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
|
|||
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
ImGui::Separator();
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text("DEBUG:");
|
||||
imgui.text("Vectors:");
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(color, "DEBUG:");
|
||||
imgui.text_colored(color, "Vectors:");
|
||||
Vec3f translation = m_state.get_first_vector_of_type(State::QueueItem::TranslationType).cast<float>();
|
||||
Vec3f rotation = m_state.get_first_vector_of_type(State::QueueItem::RotationType).cast<float>();
|
||||
ImGui::InputFloat3("Translation##3", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text("Queue size:");
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(color, "Queue size:");
|
||||
|
||||
int input_queue_size_current[2] = { int(m_state.input_queue_size_current()), int(m_state.input_queue_max_size_achieved) };
|
||||
ImGui::InputInt2("Current##4", input_queue_size_current, ImGuiInputTextFlags_ReadOnly);
|
||||
|
||||
int input_queue_size_param = int(params_copy.input_queue_max_size);
|
||||
if (ImGui::InputInt("Max size", &input_queue_size_param, 1, 1, ImGuiInputTextFlags_ReadOnly))
|
||||
{
|
||||
if (ImGui::InputInt("Max size", &input_queue_size_param, 1, 1, ImGuiInputTextFlags_ReadOnly)) {
|
||||
if (input_queue_size_param > 0) {
|
||||
params_copy.input_queue_max_size = input_queue_size_param;
|
||||
params_changed = true;
|
||||
|
|
@ -361,23 +345,19 @@ void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
|
|||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text("Camera:");
|
||||
ImGui::PopStyleColor();
|
||||
imgui.text_colored(color, "Camera:");
|
||||
Vec3f target = wxGetApp().plater()->get_camera().get_target().cast<float>();
|
||||
ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
|
||||
ImGui::Separator();
|
||||
if (imgui.button(_(L("Close"))))
|
||||
{
|
||||
if (imgui.button(_L("Close"))) {
|
||||
// the user clicked on the [Close] button
|
||||
m_settings_dialog_closed_by_user = true;
|
||||
canvas.set_as_dirty();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// the user clicked on the [X] button
|
||||
m_settings_dialog_closed_by_user = true;
|
||||
canvas.set_as_dirty();
|
||||
|
|
@ -424,6 +404,8 @@ void Mouse3DController::disconnected()
|
|||
m_params_by_device[m_device_str] = m_params_ui;
|
||||
m_device_str.clear();
|
||||
m_connected = false;
|
||||
wxGetApp().plater()->get_notification_manager()->push_notification(NotificationType::Mouse3dDisconnected, *(wxGetApp().plater()->get_current_canvas3D()));
|
||||
|
||||
wxGetApp().plater()->CallAfter([]() {
|
||||
Plater *plater = wxGetApp().plater();
|
||||
if (plater != nullptr) {
|
||||
|
|
|
|||
918
src/slic3r/GUI/NotificationManager.cpp
Normal file
918
src/slic3r/GUI/NotificationManager.cpp
Normal file
|
|
@ -0,0 +1,918 @@
|
|||
#include "NotificationManager.hpp"
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
#include "Plater.hpp"
|
||||
#include "GLCanvas3D.hpp"
|
||||
#include "ImGuiWrapper.hpp"
|
||||
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <wx/glcanvas.h>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
|
||||
|
||||
#define NOTIFICATION_MAX_MOVE 3.0f
|
||||
|
||||
#define GAP_WIDTH 10.0f
|
||||
#define SPACE_RIGHT_PANEL 10.0f
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
wxDEFINE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent);
|
||||
wxDEFINE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClickedEvent);
|
||||
wxDEFINE_EVENT(EVT_PRESET_UPDATE_AVIABLE_CLICKED, PresetUpdateAviableClickedEvent);
|
||||
|
||||
namespace Notifications_Internal{
|
||||
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);
|
||||
}
|
||||
}
|
||||
//ScalableBitmap bmp_icon;
|
||||
//------PopNotification--------
|
||||
NotificationManager::PopNotification::PopNotification(const NotificationData &n, const int id, wxEvtHandler* evt_handler) :
|
||||
m_data (n)
|
||||
, m_id (id)
|
||||
, m_remaining_time (n.duration)
|
||||
, m_last_remaining_time (n.duration)
|
||||
, m_counting_down (n.duration != 0)
|
||||
, m_text1 (n.text1)
|
||||
, m_hypertext (n.hypertext)
|
||||
, m_text2 (n.text2)
|
||||
, m_evt_handler (evt_handler)
|
||||
{
|
||||
init();
|
||||
}
|
||||
NotificationManager::PopNotification::~PopNotification()
|
||||
{
|
||||
}
|
||||
NotificationManager::PopNotification::RenderResult NotificationManager::PopNotification::render(GLCanvas3D& canvas, const float& initial_y)
|
||||
{
|
||||
if (m_finished)
|
||||
return RenderResult::Finished;
|
||||
if (m_close_pending) {
|
||||
// request of extra frame will be done in caller function by ret val ClosePending
|
||||
m_finished = true;
|
||||
return RenderResult::ClosePending;
|
||||
}
|
||||
if (m_hidden) {
|
||||
m_top_y = initial_y - GAP_WIDTH;
|
||||
return RenderResult::Static;
|
||||
}
|
||||
RenderResult ret_val = m_counting_down ? RenderResult::Countdown : RenderResult::Static;
|
||||
Size cnv_size = canvas.get_canvas_size();
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
bool shown = true;
|
||||
std::string name;
|
||||
ImVec2 mouse_pos = ImGui::GetMousePos();
|
||||
|
||||
if (m_line_height != ImGui::CalcTextSize("A").y)
|
||||
init();
|
||||
|
||||
set_next_window_size(imgui);
|
||||
|
||||
//top y of window
|
||||
m_top_y = initial_y + m_window_height;
|
||||
//top right position
|
||||
ImVec2 win_pos(1.0f * (float)cnv_size.get_width() - SPACE_RIGHT_PANEL, 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
|
||||
if (mouse_pos.x < win_pos.x && mouse_pos.x > win_pos.x - m_window_width && mouse_pos.y > win_pos.y&& mouse_pos.y < win_pos.y + m_window_height)
|
||||
{
|
||||
ImGui::SetNextWindowFocus();
|
||||
ret_val = RenderResult::Hovered;
|
||||
//reset fading
|
||||
m_fading_out = false;
|
||||
m_current_fade_opacity = 1.f;
|
||||
m_remaining_time = m_data.duration;
|
||||
m_countdown_frame = 0;
|
||||
}
|
||||
|
||||
if (m_counting_down && m_remaining_time < 0)
|
||||
m_close_pending = true;
|
||||
|
||||
if (m_close_pending) {
|
||||
// request of extra frame will be done in caller function by ret val ClosePending
|
||||
m_finished = true;
|
||||
return RenderResult::ClosePending;
|
||||
}
|
||||
|
||||
// color change based on fading out
|
||||
bool fading_pop = false;
|
||||
if (m_fading_out) {
|
||||
if (!m_paused)
|
||||
m_current_fade_opacity -= 1.f / ((m_fading_time + 1.f) * 60.f);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_Text), m_fading_out, m_current_fade_opacity);
|
||||
fading_pop = true;
|
||||
}
|
||||
// background color
|
||||
if (m_is_gray) {
|
||||
ImVec4 backcolor(0.7f, 0.7f, 0.7f, 0.5f);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
|
||||
} else if (m_data.level == NotificationLevel::ErrorNotification) {
|
||||
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
|
||||
backcolor.x += 0.3f;
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
|
||||
} else if (m_data.level == NotificationLevel::WarningNotification) {
|
||||
ImVec4 backcolor = ImGui::GetStyleColorVec4(ImGuiCol_WindowBg);
|
||||
backcolor.x += 0.3f;
|
||||
backcolor.y += 0.15f;
|
||||
Notifications_Internal::push_style_color(ImGuiCol_WindowBg, backcolor, m_fading_out, m_current_fade_opacity);
|
||||
}
|
||||
|
||||
//name of window - probably indentifies window and is shown so last_end add whitespaces according to id
|
||||
for (size_t i = 0; i < m_id; i++)
|
||||
name += " ";
|
||||
if (imgui.begin(name, &shown, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar )) {
|
||||
if (shown) {
|
||||
|
||||
ImVec2 win_size = ImGui::GetWindowSize();
|
||||
|
||||
|
||||
//FIXME: dont forget to us this for texts
|
||||
//GUI::format(_utf8(L()));
|
||||
|
||||
/*
|
||||
//countdown numbers
|
||||
ImGui::SetCursorPosX(15);
|
||||
ImGui::SetCursorPosY(15);
|
||||
imgui.text(std::to_string(m_remaining_time).c_str());
|
||||
*/
|
||||
if(m_counting_down)
|
||||
render_countdown(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);
|
||||
if (m_multiline && m_lines_count > 3)
|
||||
render_minimize_button(imgui, win_pos.x, win_pos.y);
|
||||
} else {
|
||||
// the user clicked on the [X] button ( ImGuiWindowFlags_NoTitleBar means theres no [X] button)
|
||||
m_close_pending = true;
|
||||
canvas.set_as_dirty();
|
||||
}
|
||||
}
|
||||
imgui.end();
|
||||
|
||||
if (fading_pop) {
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
if (m_is_gray)
|
||||
ImGui::PopStyleColor();
|
||||
else if (m_data.level == NotificationLevel::ErrorNotification)
|
||||
ImGui::PopStyleColor();
|
||||
else if (m_data.level == NotificationLevel::WarningNotification)
|
||||
ImGui::PopStyleColor();
|
||||
return ret_val;
|
||||
}
|
||||
void NotificationManager::PopNotification::init()
|
||||
{
|
||||
std::string text = m_text1 + " " + m_hypertext;
|
||||
int last_end = 0;
|
||||
m_lines_count = 0;
|
||||
|
||||
//determine line width
|
||||
m_line_height = ImGui::CalcTextSize("A").y;
|
||||
|
||||
m_left_indentation = m_line_height;
|
||||
if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) {
|
||||
std::string text;
|
||||
text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker);
|
||||
float picture_width = ImGui::CalcTextSize(text.c_str()).x;
|
||||
m_left_indentation = picture_width + m_line_height / 2;
|
||||
}
|
||||
m_window_width_offset = m_left_indentation + m_line_height * 2;
|
||||
m_window_width = m_line_height * 25;
|
||||
|
||||
// count lines
|
||||
m_endlines.clear();
|
||||
while (last_end < text.length() - 1)
|
||||
{
|
||||
int next_hard_end = text.find_first_of('\n', last_end);
|
||||
if (next_hard_end > 0 && ImGui::CalcTextSize(text.substr(last_end, next_hard_end - last_end).c_str()).x < m_window_width - m_window_width_offset) {
|
||||
//next line is ended by '/n'
|
||||
m_endlines.push_back(next_hard_end);
|
||||
last_end = next_hard_end + 1;
|
||||
}
|
||||
else {
|
||||
// find next suitable endline
|
||||
if (ImGui::CalcTextSize(text.substr(last_end).c_str()).x >= m_window_width - 3.5f * m_line_height) {// m_window_width_offset) {
|
||||
// more than one line till end
|
||||
int next_space = text.find_first_of(' ', last_end);
|
||||
if (next_space > 0) {
|
||||
int next_space_candidate = text.find_first_of(' ', next_space + 1);
|
||||
while (next_space_candidate > 0 && ImGui::CalcTextSize(text.substr(last_end, next_space_candidate - last_end).c_str()).x < m_window_width - m_window_width_offset) {
|
||||
next_space = next_space_candidate;
|
||||
next_space_candidate = text.find_first_of(' ', next_space + 1);
|
||||
}
|
||||
m_endlines.push_back(next_space);
|
||||
last_end = next_space + 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
m_endlines.push_back(text.length());
|
||||
last_end = text.length();
|
||||
}
|
||||
|
||||
}
|
||||
m_lines_count++;
|
||||
}
|
||||
}
|
||||
void NotificationManager::PopNotification::set_next_window_size(ImGuiWrapper& imgui)
|
||||
{
|
||||
if (m_multiline) {
|
||||
m_window_height = m_lines_count * m_line_height;
|
||||
}else
|
||||
{
|
||||
m_window_height = 2 * m_line_height;
|
||||
}
|
||||
m_window_height += 1 * m_line_height; // top and bottom
|
||||
}
|
||||
|
||||
void NotificationManager::PopNotification::render_text(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);
|
||||
float x_offset = m_left_indentation;
|
||||
std::string fulltext = m_text1 + m_hypertext; //+ m_text2;
|
||||
ImVec2 text_size = ImGui::CalcTextSize(fulltext.c_str());
|
||||
// text posistions are calculated by lines count
|
||||
// large texts has "more" button or are displayed whole
|
||||
// smaller texts are divided as one liners and two liners
|
||||
if (m_lines_count > 2) {
|
||||
if (m_multiline) {
|
||||
|
||||
int last_end = 0;
|
||||
float starting_y = m_line_height/2;//10;
|
||||
float shift_y = m_line_height;// -m_line_height / 20;
|
||||
for (size_t i = 0; i < m_lines_count; i++) {
|
||||
std::string line = m_text1.substr(last_end , m_endlines[i] - last_end);
|
||||
last_end = m_endlines[i] + 1;
|
||||
ImGui::SetCursorPosX(x_offset);
|
||||
ImGui::SetCursorPosY(starting_y + i * shift_y);
|
||||
imgui.text(line.c_str());
|
||||
}
|
||||
//hyperlink text
|
||||
if (!m_hypertext.empty())
|
||||
{
|
||||
render_hypertext(imgui, x_offset + ImGui::CalcTextSize(m_text1.substr(m_endlines[m_lines_count - 2] + 1, m_endlines[m_lines_count - 1] - m_endlines[m_lines_count - 2] - 1).c_str()).x, starting_y + (m_lines_count - 1) * shift_y, m_hypertext);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
// line1
|
||||
ImGui::SetCursorPosX(x_offset);
|
||||
ImGui::SetCursorPosY(win_size.y / 2 - win_size.y / 6 - m_line_height / 2);
|
||||
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
|
||||
// line2
|
||||
std::string line = m_text1.substr(m_endlines[0] + 1, m_endlines[1] - m_endlines[0] - 1);
|
||||
if (ImGui::CalcTextSize(line.c_str()).x > m_window_width - m_window_width_offset - ImGui::CalcTextSize((".." + _u8L("More")).c_str()).x)
|
||||
{
|
||||
line = line.substr(0, line.length() - 6);
|
||||
line += "..";
|
||||
}else
|
||||
line += " ";
|
||||
ImGui::SetCursorPosX(x_offset);
|
||||
ImGui::SetCursorPosY(win_size.y / 2 + win_size.y / 6 - m_line_height / 2);
|
||||
imgui.text(line.c_str());
|
||||
// "More" hypertext
|
||||
render_hypertext(imgui, x_offset + ImGui::CalcTextSize(line.c_str()).x, win_size.y / 2 + win_size.y / 6 - m_line_height / 2, _u8L("More"), true);
|
||||
}
|
||||
} else {
|
||||
//text 1
|
||||
float cursor_y = win_size.y / 2 - text_size.y / 2;
|
||||
float cursor_x = x_offset;
|
||||
if(m_lines_count > 1) {
|
||||
// line1
|
||||
ImGui::SetCursorPosX(x_offset);
|
||||
ImGui::SetCursorPosY(win_size.y / 2 - win_size.y / 6 - m_line_height / 2);
|
||||
imgui.text(m_text1.substr(0, m_endlines[0]).c_str());
|
||||
// line2
|
||||
std::string line = m_text1.substr(m_endlines[0] + 1);
|
||||
cursor_y = win_size.y / 2 + win_size.y / 6 - m_line_height / 2;
|
||||
ImGui::SetCursorPosX(x_offset);
|
||||
ImGui::SetCursorPosY(cursor_y);
|
||||
imgui.text(line.c_str());
|
||||
cursor_x = x_offset + ImGui::CalcTextSize(line.c_str()).x;
|
||||
} else {
|
||||
ImGui::SetCursorPosX(x_offset);
|
||||
ImGui::SetCursorPosY(cursor_y);
|
||||
imgui.text(m_text1.c_str());
|
||||
cursor_x = x_offset + ImGui::CalcTextSize(m_text1.c_str()).x;
|
||||
}
|
||||
//hyperlink text
|
||||
if (!m_hypertext.empty())
|
||||
{
|
||||
render_hypertext(imgui, cursor_x + 4, cursor_y, m_hypertext);
|
||||
}
|
||||
|
||||
//notification text 2
|
||||
//text 2 is suposed to be after the hyperlink - currently it is not used
|
||||
/*
|
||||
if (!m_text2.empty())
|
||||
{
|
||||
ImVec2 part_size = ImGui::CalcTextSize(m_hypertext.c_str());
|
||||
ImGui::SetCursorPosX(win_size.x / 2 + text_size.x / 2 - part_size.x + 8 - x_offset);
|
||||
ImGui::SetCursorPosY(cursor_y);
|
||||
imgui.text(m_text2.c_str());
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
void NotificationManager::PopNotification::render_hypertext(ImGuiWrapper& imgui, const float text_x, const float text_y, const std::string text, bool more)
|
||||
{
|
||||
//invisible button
|
||||
ImVec2 part_size = ImGui::CalcTextSize(text.c_str());
|
||||
ImGui::SetCursorPosX(text_x -4);
|
||||
ImGui::SetCursorPosY(text_y -5);
|
||||
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));
|
||||
if (imgui.button(" ", part_size.x + 6, part_size.y + 10))
|
||||
{
|
||||
if (more)
|
||||
{
|
||||
m_multiline = true;
|
||||
set_next_window_size(imgui);
|
||||
}
|
||||
else {
|
||||
on_text_click();
|
||||
m_close_pending = true;
|
||||
}
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
//hover color
|
||||
ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_RectOnly))
|
||||
orange_color.y += 0.2f;
|
||||
|
||||
//text
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, orange_color, m_fading_out, m_current_fade_opacity);
|
||||
ImGui::SetCursorPosX(text_x);
|
||||
ImGui::SetCursorPosY(text_y);
|
||||
imgui.text(text.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
//underline
|
||||
ImVec2 lineEnd = ImGui::GetItemRectMax();
|
||||
lineEnd.y -= 2;
|
||||
ImVec2 lineStart = lineEnd;
|
||||
lineStart.x = ImGui::GetItemRectMin().x;
|
||||
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.w * 255.f * (m_fading_out ? m_current_fade_opacity : 1.f))));
|
||||
|
||||
}
|
||||
|
||||
void NotificationManager::PopNotification::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)
|
||||
{
|
||||
ImVec2 win_size(win_size_x, win_size_y);
|
||||
ImVec2 win_pos(win_pos_x, win_pos_y);
|
||||
ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
|
||||
orange_color.w = 0.8f;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity);
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(.0f, .0f, .0f, .0f));
|
||||
|
||||
|
||||
//button - if part if treggered
|
||||
std::string button_text;
|
||||
button_text = ImGui::CloseIconMarker;
|
||||
|
||||
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_multiline? 2 * m_line_height : 0)),
|
||||
true))
|
||||
{
|
||||
button_text = ImGui::CloseIconHoverMarker;
|
||||
}
|
||||
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.25f);
|
||||
ImGui::SetCursorPosY(win_size.y / 2 - button_size.y/2);
|
||||
if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
|
||||
{
|
||||
m_close_pending = true;
|
||||
}
|
||||
|
||||
//invisible large button
|
||||
ImGui::SetCursorPosX(win_size.x - win_size.x / 10.f);
|
||||
ImGui::SetCursorPosY(0);
|
||||
if (imgui.button(" ", win_size.x / 10.f, win_size.y - (m_multiline ? 2 * m_line_height : 0)))
|
||||
{
|
||||
m_close_pending = true;
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
void NotificationManager::PopNotification::render_countdown(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);
|
||||
|
||||
//countdown dots
|
||||
std::string dot_text;
|
||||
dot_text = m_remaining_time <= (float)m_data.duration / 4 * 3 ? ImGui::TimerDotEmptyMarker : ImGui::TimerDotMarker;
|
||||
ImGui::SetCursorPosX(win_size.x - m_line_height);
|
||||
//ImGui::SetCursorPosY(win_size.y / 2 - 24);
|
||||
ImGui::SetCursorPosY(0);
|
||||
imgui.text(dot_text.c_str());
|
||||
|
||||
dot_text = m_remaining_time < m_data.duration / 2 ? ImGui::TimerDotEmptyMarker : ImGui::TimerDotMarker;
|
||||
ImGui::SetCursorPosX(win_size.x - m_line_height);
|
||||
//ImGui::SetCursorPosY(win_size.y / 2 - 9);
|
||||
ImGui::SetCursorPosY(win_size.y / 2 - m_line_height / 2);
|
||||
imgui.text(dot_text.c_str());
|
||||
|
||||
dot_text = m_remaining_time <= m_data.duration / 4 ? ImGui::TimerDotEmptyMarker : ImGui::TimerDotMarker;
|
||||
ImGui::SetCursorPosX(win_size.x - m_line_height);
|
||||
//ImGui::SetCursorPosY(win_size.y / 2 + 6);
|
||||
ImGui::SetCursorPosY(win_size.y - m_line_height);
|
||||
imgui.text(dot_text.c_str());
|
||||
*/
|
||||
if (!m_fading_out && m_remaining_time <= m_data.duration / 4) {
|
||||
m_fading_out = true;
|
||||
m_fading_time = m_remaining_time;
|
||||
}
|
||||
|
||||
if (m_last_remaining_time != m_remaining_time) {
|
||||
m_last_remaining_time = m_remaining_time;
|
||||
m_countdown_frame = 0;
|
||||
}
|
||||
/*
|
||||
//countdown line
|
||||
ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
|
||||
float invisible_length = ((float)(m_data.duration - m_remaining_time) / (float)m_data.duration * win_size_x);
|
||||
invisible_length -= win_size_x / ((float)m_data.duration * 60.f) * (60 - m_countdown_frame);
|
||||
ImVec2 lineEnd = ImVec2(win_pos_x - invisible_length, win_pos_y + win_size_y - 5);
|
||||
ImVec2 lineStart = ImVec2(win_pos_x - win_size_x, win_pos_y + win_size_y - 5);
|
||||
ImGui::GetWindowDrawList()->AddLine(lineStart, lineEnd, IM_COL32((int)(orange_color.x * 255), (int)(orange_color.y * 255), (int)(orange_color.z * 255), (int)(orange_color.picture_width * 255.f * (m_fading_out ? m_current_fade_opacity : 1.f))), 2.f);
|
||||
if (!m_paused)
|
||||
m_countdown_frame++;
|
||||
*/
|
||||
}
|
||||
void NotificationManager::PopNotification::render_left_sign(ImGuiWrapper& imgui)
|
||||
{
|
||||
if (m_data.level == NotificationLevel::ErrorNotification || m_data.level == NotificationLevel::WarningNotification) {
|
||||
std::string text;
|
||||
text = (m_data.level == NotificationLevel::ErrorNotification ? ImGui::ErrorMarker : ImGui::WarningMarker);
|
||||
ImGui::SetCursorPosX(m_line_height / 3);
|
||||
ImGui::SetCursorPosY(m_window_height / 2 - m_line_height / 2);
|
||||
imgui.text(text.c_str());
|
||||
}
|
||||
}
|
||||
void NotificationManager::PopNotification::render_minimize_button(ImGuiWrapper& imgui, const float win_pos_x, const float win_pos_y)
|
||||
{
|
||||
ImVec4 orange_color = ImGui::GetStyleColorVec4(ImGuiCol_Button);
|
||||
orange_color.w = 0.8f;
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(.0f, .0f, .0f, .0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(.0f, .0f, .0f, .0f));
|
||||
Notifications_Internal::push_style_color(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_WindowBg), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f), m_fading_out, m_current_fade_opacity);
|
||||
Notifications_Internal::push_style_color(ImGuiCol_TextSelectedBg, ImVec4(0, .75f, .75f, 1.f), m_fading_out, m_current_fade_opacity);
|
||||
|
||||
|
||||
//button - if part if treggered
|
||||
std::string button_text;
|
||||
button_text = ImGui::CloseIconMarker;
|
||||
if (ImGui::IsMouseHoveringRect(ImVec2(win_pos_x - m_window_width / 10.f, win_pos_y + m_window_height - 2 * m_line_height + 1),
|
||||
ImVec2(win_pos_x, win_pos_y + m_window_height),
|
||||
true))
|
||||
{
|
||||
button_text = ImGui::CloseIconHoverMarker;
|
||||
}
|
||||
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(m_window_width - m_line_height * 2.25f);
|
||||
ImGui::SetCursorPosY(m_window_height - button_size.y - 5);
|
||||
if (imgui.button(button_text.c_str(), button_size.x, button_size.y))
|
||||
{
|
||||
m_multiline = false;
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
void NotificationManager::PopNotification::on_text_click()
|
||||
{
|
||||
switch (m_data.type) {
|
||||
case NotificationType::ExportToRemovableFinished :
|
||||
assert(m_evt_handler != nullptr);
|
||||
if (m_evt_handler != nullptr)
|
||||
wxPostEvent(m_evt_handler, EjectDriveNotificationClickedEvent(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED));
|
||||
break;
|
||||
case NotificationType::SlicingComplete :
|
||||
//wxGetApp().plater()->export_gcode(false);
|
||||
assert(m_evt_handler != nullptr);
|
||||
if (m_evt_handler != nullptr)
|
||||
wxPostEvent(m_evt_handler, ExportGcodeNotificationClickedEvent(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED));
|
||||
break;
|
||||
case NotificationType::PresetUpdateAviable :
|
||||
//wxGetApp().plater()->export_gcode(false);
|
||||
assert(m_evt_handler != nullptr);
|
||||
if (m_evt_handler != nullptr)
|
||||
wxPostEvent(m_evt_handler, PresetUpdateAviableClickedEvent(EVT_PRESET_UPDATE_AVIABLE_CLICKED));
|
||||
break;
|
||||
case NotificationType::NewAppAviable:
|
||||
wxLaunchDefaultBrowser("https://github.com/prusa3d/PrusaSlicer/releases");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void NotificationManager::PopNotification::update(const NotificationData& n)
|
||||
{
|
||||
m_text1 = n.text1;
|
||||
m_hypertext = n.hypertext;
|
||||
m_text2 = n.text2;
|
||||
init();
|
||||
}
|
||||
bool NotificationManager::PopNotification::compare_text(const std::string& text)
|
||||
{
|
||||
std::string t1(m_text1);
|
||||
std::string t2(text);
|
||||
t1.erase(std::remove_if(t1.begin(), t1.end(), ::isspace), t1.end());
|
||||
t2.erase(std::remove_if(t2.begin(), t2.end(), ::isspace), t2.end());
|
||||
if (t1.compare(t2) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
NotificationManager::SlicingCompleteLargeNotification::SlicingCompleteLargeNotification(const NotificationData& n, const int id, wxEvtHandler* evt_handler, bool large) :
|
||||
NotificationManager::PopNotification(n, id, evt_handler)
|
||||
{
|
||||
set_large(large);
|
||||
}
|
||||
void NotificationManager::SlicingCompleteLargeNotification::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_is_large)
|
||||
PopNotification::render_text(imgui, win_size_x, win_size_y, win_pos_x, win_pos_y);
|
||||
else {
|
||||
ImVec2 win_size(win_size_x, win_size_y);
|
||||
ImVec2 win_pos(win_pos_x, win_pos_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_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());
|
||||
|
||||
render_hypertext(imgui, x_offset + text1_size.x + 4, cursor_y, m_hypertext);
|
||||
|
||||
}
|
||||
}
|
||||
void NotificationManager::SlicingCompleteLargeNotification::set_print_info(std::string info)
|
||||
{
|
||||
m_print_info = info;
|
||||
m_has_print_info = true;
|
||||
if(m_is_large)
|
||||
m_lines_count = 2;
|
||||
}
|
||||
void NotificationManager::SlicingCompleteLargeNotification::set_large(bool l)
|
||||
{
|
||||
m_is_large = l;
|
||||
m_counting_down = !l;
|
||||
m_hypertext = l ? _u8L("Export G-Code.") : std::string();
|
||||
m_hidden = !l;
|
||||
}
|
||||
//------NotificationManager--------
|
||||
NotificationManager::NotificationManager(wxEvtHandler* evt_handler) :
|
||||
m_evt_handler(evt_handler)
|
||||
{
|
||||
}
|
||||
NotificationManager::~NotificationManager()
|
||||
{
|
||||
for (PopNotification* notification : m_pop_notifications)
|
||||
{
|
||||
delete notification;
|
||||
}
|
||||
}
|
||||
void NotificationManager::push_notification(const NotificationType type, GLCanvas3D& canvas, int timestamp)
|
||||
{
|
||||
auto it = std::find_if(basic_notifications.begin(), basic_notifications.end(),
|
||||
boost::bind(&NotificationData::type, _1) == type);
|
||||
if (it != basic_notifications.end())
|
||||
push_notification_data( *it, canvas, timestamp);
|
||||
}
|
||||
void NotificationManager::push_notification(const std::string& text, GLCanvas3D& canvas, int timestamp)
|
||||
{
|
||||
push_notification_data({ NotificationType::CustomNotification, NotificationLevel::RegularNotification, 10, text }, canvas, timestamp );
|
||||
}
|
||||
void NotificationManager::push_notification(const std::string& text, NotificationManager::NotificationLevel level, GLCanvas3D& canvas, int timestamp)
|
||||
{
|
||||
switch (level)
|
||||
{
|
||||
case Slic3r::GUI::NotificationManager::NotificationLevel::RegularNotification:
|
||||
push_notification_data({ NotificationType::CustomNotification, level, 10, text }, canvas, timestamp);
|
||||
break;
|
||||
case Slic3r::GUI::NotificationManager::NotificationLevel::ErrorNotification:
|
||||
push_notification_data({ NotificationType::CustomNotification, level, 0, text }, canvas, timestamp);
|
||||
|
||||
break;
|
||||
case Slic3r::GUI::NotificationManager::NotificationLevel::ImportantNotification:
|
||||
push_notification_data({ NotificationType::CustomNotification, level, 0, text }, canvas, timestamp);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
void NotificationManager::push_slicing_error_notification(const std::string& text, GLCanvas3D& canvas)
|
||||
{
|
||||
set_all_slicing_errors_gray(false);
|
||||
push_notification_data({ NotificationType::SlicingError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, canvas, 0);
|
||||
close_notification_of_type(NotificationType::SlicingComplete);
|
||||
}
|
||||
void NotificationManager::push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, size_t oid, int warning_step)
|
||||
{
|
||||
NotificationData data { NotificationType::SlicingWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text };
|
||||
|
||||
NotificationManager::SlicingWarningNotification* notification = new NotificationManager::SlicingWarningNotification(data, m_next_id++, m_evt_handler);
|
||||
notification->set_object_id(oid);
|
||||
notification->set_warning_step(warning_step);
|
||||
if
|
||||
(push_notification_data(notification, canvas, 0)) {
|
||||
notification->set_gray(gray);
|
||||
}
|
||||
else {
|
||||
delete notification;
|
||||
}
|
||||
|
||||
}
|
||||
void NotificationManager::push_plater_error_notification(const std::string& text, GLCanvas3D& canvas)
|
||||
{
|
||||
push_notification_data({ NotificationType::PlaterError, NotificationLevel::ErrorNotification, 0, _u8L("ERROR:") + "\n" + text }, canvas, 0);
|
||||
}
|
||||
void NotificationManager::push_plater_warning_notification(const std::string& text, GLCanvas3D& canvas)
|
||||
{
|
||||
push_notification_data({ NotificationType::PlaterWarning, NotificationLevel::WarningNotification, 0, _u8L("WARNING:") + "\n" + text }, canvas, 0);
|
||||
}
|
||||
void NotificationManager::close_plater_error_notification()
|
||||
{
|
||||
for (PopNotification* notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::PlaterError) {
|
||||
notification->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::close_plater_warning_notification(const std::string& text)
|
||||
{
|
||||
for (PopNotification* notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::PlaterWarning && notification->compare_text(_u8L("WARNING:") + "\n" + text)) {
|
||||
notification->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::set_all_slicing_errors_gray(bool g)
|
||||
{
|
||||
for (PopNotification* notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::SlicingError) {
|
||||
notification->set_gray(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::set_all_slicing_warnings_gray(bool g)
|
||||
{
|
||||
for (PopNotification* notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::SlicingWarning) {
|
||||
notification->set_gray(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::set_slicing_warning_gray(const std::string& text, bool g)
|
||||
{
|
||||
for (PopNotification* notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::SlicingWarning && notification->compare_text(text)) {
|
||||
notification->set_gray(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::close_slicing_errors_and_warnings()
|
||||
{
|
||||
for (PopNotification* notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::SlicingError || notification->get_type() == NotificationType::SlicingWarning) {
|
||||
notification->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::push_slicing_complete_notification(GLCanvas3D& canvas, int timestamp, bool large)
|
||||
{
|
||||
std::string hypertext;
|
||||
int time = 10;
|
||||
if(large)
|
||||
{
|
||||
hypertext = _u8L("Export G-Code.");
|
||||
time = 0;
|
||||
}
|
||||
NotificationData data{ NotificationType::SlicingComplete, NotificationLevel::RegularNotification, time, _u8L("Slicing finished."), hypertext };
|
||||
|
||||
NotificationManager::SlicingCompleteLargeNotification* notification = new NotificationManager::SlicingCompleteLargeNotification(data, m_next_id++, m_evt_handler, large);
|
||||
if (push_notification_data(notification, canvas, timestamp)) {
|
||||
} else {
|
||||
delete notification;
|
||||
}
|
||||
}
|
||||
void NotificationManager::set_slicing_complete_print_time(std::string info)
|
||||
{
|
||||
for (PopNotification* notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::SlicingComplete) {
|
||||
dynamic_cast<SlicingCompleteLargeNotification*>(notification)->set_print_info(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::set_slicing_complete_large(bool large)
|
||||
{
|
||||
for (PopNotification* notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::SlicingComplete) {
|
||||
dynamic_cast<SlicingCompleteLargeNotification*>(notification)->set_large(large);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::close_notification_of_type(const NotificationType type)
|
||||
{
|
||||
for (PopNotification* notification : m_pop_notifications) {
|
||||
if (notification->get_type() == type) {
|
||||
notification->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
void NotificationManager::compare_warning_oids(const std::vector<size_t>& living_oids)
|
||||
{
|
||||
for (PopNotification* notification : m_pop_notifications) {
|
||||
if (notification->get_type() == NotificationType::SlicingWarning) {
|
||||
auto w = dynamic_cast<SlicingWarningNotification*>(notification);
|
||||
bool found = false;
|
||||
for (size_t oid : living_oids) {
|
||||
if (w->get_object_id() == oid) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
notification->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
bool NotificationManager::push_notification_data(const NotificationData ¬ification_data, GLCanvas3D& canvas, int timestamp)
|
||||
{
|
||||
PopNotification* n = new PopNotification(notification_data, m_next_id++, m_evt_handler);
|
||||
bool r = push_notification_data(n, canvas, timestamp);
|
||||
if (!r)
|
||||
delete n;
|
||||
return r;
|
||||
}
|
||||
bool NotificationManager::push_notification_data(NotificationManager::PopNotification* notification, GLCanvas3D& canvas, int timestamp)
|
||||
{
|
||||
// if timestamped notif, push only new one
|
||||
if (timestamp != 0) {
|
||||
if (m_used_timestamps.find(timestamp) == m_used_timestamps.end()) {
|
||||
m_used_timestamps.insert(timestamp);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!this->find_older(notification)) {
|
||||
m_pop_notifications.emplace_back(notification);
|
||||
canvas.request_extra_frame();
|
||||
return true;
|
||||
} else {
|
||||
m_pop_notifications.back()->update(notification->get_data());
|
||||
canvas.request_extra_frame();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void NotificationManager::render_notifications(GLCanvas3D& canvas)
|
||||
{
|
||||
float last_x = 0.0f;
|
||||
float current_height = 0.0f;
|
||||
bool request_next_frame = false;
|
||||
bool render_main = false;
|
||||
bool hovered = false;
|
||||
sort_notifications();
|
||||
// iterate thru notifications and render them / erease them
|
||||
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end();) {
|
||||
if ((*it)->get_finished()) {
|
||||
delete (*it);
|
||||
it = m_pop_notifications.erase(it);
|
||||
} else {
|
||||
(*it)->set_paused(m_hovered);
|
||||
PopNotification::RenderResult res = (*it)->render(canvas, last_x);
|
||||
if (res != PopNotification::RenderResult::Finished) {
|
||||
last_x = (*it)->get_top() + GAP_WIDTH;
|
||||
current_height = std::max(current_height, (*it)->get_current_top());
|
||||
render_main = true;
|
||||
}
|
||||
if (res == PopNotification::RenderResult::Countdown || res == PopNotification::RenderResult::ClosePending || res == PopNotification::RenderResult::Finished)
|
||||
request_next_frame = true;
|
||||
if (res == PopNotification::RenderResult::Hovered)
|
||||
hovered = true;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
m_hovered = hovered;
|
||||
|
||||
//actualizate timers and request frame if needed
|
||||
wxWindow* p = dynamic_cast<wxWindow*> (wxGetApp().plater());
|
||||
while (p->GetParent())
|
||||
p = p->GetParent();
|
||||
wxTopLevelWindow* top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
|
||||
if (!top_level_wnd->IsActive())
|
||||
return;
|
||||
|
||||
if (!m_hovered && m_last_time < wxGetLocalTime())
|
||||
{
|
||||
if (wxGetLocalTime() - m_last_time == 1)
|
||||
{
|
||||
for(auto notification : m_pop_notifications)
|
||||
{
|
||||
notification->substract_remaining_time();
|
||||
}
|
||||
}
|
||||
m_last_time = wxGetLocalTime();
|
||||
}
|
||||
|
||||
if (request_next_frame)
|
||||
canvas.request_extra_frame();
|
||||
}
|
||||
|
||||
|
||||
void NotificationManager::sort_notifications()
|
||||
{
|
||||
std::sort(m_pop_notifications.begin(), m_pop_notifications.end(), [](PopNotification* n1, PopNotification* n2) {
|
||||
int n1l = (int)n1->get_data().level;
|
||||
int n2l = (int)n2->get_data().level;
|
||||
if (n1l == n2l && n1->get_is_gray() && !n2->get_is_gray())
|
||||
return true;
|
||||
return (n1l < n2l);
|
||||
});
|
||||
}
|
||||
|
||||
bool NotificationManager::find_older(NotificationManager::PopNotification* notification)
|
||||
{
|
||||
NotificationType type = notification->get_type();
|
||||
std::string text = notification->get_data().text1;
|
||||
for (auto it = m_pop_notifications.begin(); it != m_pop_notifications.end(); ++it) {
|
||||
if((*it)->get_type() == type && !(*it)->get_finished()) {
|
||||
if (type == NotificationType::CustomNotification || type == NotificationType::PlaterWarning) {
|
||||
if (!(*it)->compare_text(text))
|
||||
continue;
|
||||
}else if (type == NotificationType::SlicingWarning) {
|
||||
auto w1 = dynamic_cast<SlicingWarningNotification*>(notification);
|
||||
auto w2 = dynamic_cast<SlicingWarningNotification*>(*it);
|
||||
if (w1 != nullptr && w2 != nullptr) {
|
||||
if (!(*it)->compare_text(text) || w1->get_object_id() != w2->get_object_id()) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (it != m_pop_notifications.end() - 1)
|
||||
std::rotate(it, it + 1, m_pop_notifications.end());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NotificationManager::dpi_changed()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}//namespace GUI
|
||||
}//namespace Slic3r
|
||||
268
src/slic3r/GUI/NotificationManager.hpp
Normal file
268
src/slic3r/GUI/NotificationManager.hpp
Normal file
|
|
@ -0,0 +1,268 @@
|
|||
#ifndef slic3r_GUI_NotificationManager_hpp_
|
||||
#define slic3r_GUI_NotificationManager_hpp_
|
||||
|
||||
#include "Event.hpp"
|
||||
#include "I18N.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
using EjectDriveNotificationClickedEvent = SimpleEvent;
|
||||
wxDECLARE_EVENT(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, EjectDriveNotificationClickedEvent);
|
||||
using ExportGcodeNotificationClickedEvent = SimpleEvent;
|
||||
wxDECLARE_EVENT(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, ExportGcodeNotificationClickedEvent);
|
||||
using PresetUpdateAviableClickedEvent = SimpleEvent;
|
||||
wxDECLARE_EVENT(EVT_PRESET_UPDATE_AVIABLE_CLICKED, PresetUpdateAviableClickedEvent);
|
||||
|
||||
class GLCanvas3D;
|
||||
class ImGuiWrapper;
|
||||
|
||||
enum class NotificationType
|
||||
{
|
||||
CustomNotification,
|
||||
SlicingComplete,
|
||||
SlicingNotPossible,
|
||||
ExportToRemovableFinished,
|
||||
Mouse3dDisconnected,
|
||||
Mouse3dConnected,
|
||||
NewPresetsAviable,
|
||||
NewAppAviable,
|
||||
PresetUpdateAviable,
|
||||
LoadingFailed,
|
||||
ValidateError, // currently not used - instead Slicing error is used for both slicing and validate errors
|
||||
SlicingError,
|
||||
SlicingWarning,
|
||||
PlaterError,
|
||||
PlaterWarning,
|
||||
ApplyError
|
||||
|
||||
};
|
||||
class NotificationManager
|
||||
{
|
||||
public:
|
||||
enum class NotificationLevel : int
|
||||
{
|
||||
ErrorNotification = 4,
|
||||
WarningNotification = 3,
|
||||
ImportantNotification = 2,
|
||||
RegularNotification = 1,
|
||||
};
|
||||
// duration 0 means not disapearing
|
||||
struct NotificationData {
|
||||
NotificationType type;
|
||||
NotificationLevel level;
|
||||
const int duration;
|
||||
const std::string text1;
|
||||
const std::string hypertext = std::string();
|
||||
const std::string text2 = std::string();
|
||||
};
|
||||
|
||||
//Pop notification - shows only once to user.
|
||||
class PopNotification
|
||||
{
|
||||
public:
|
||||
enum class RenderResult
|
||||
{
|
||||
Finished,
|
||||
ClosePending,
|
||||
Static,
|
||||
Countdown,
|
||||
Hovered
|
||||
};
|
||||
PopNotification(const NotificationData &n, const int id, wxEvtHandler* evt_handler);
|
||||
virtual ~PopNotification();
|
||||
RenderResult render(GLCanvas3D& canvas, const float& initial_y);
|
||||
// close will dissapear notification on next render
|
||||
void close() { m_close_pending = true; }
|
||||
// data from newer notification of same type
|
||||
void update(const NotificationData& n);
|
||||
bool get_finished() const { return m_finished; }
|
||||
// returns top after movement
|
||||
float get_top() const { return m_top_y; }
|
||||
//returns top in actual frame
|
||||
float get_current_top() const { return m_top_y; }
|
||||
const NotificationType get_type() const { return m_data.type; }
|
||||
const NotificationData get_data() const { return m_data; }
|
||||
const bool get_is_gray() const { return m_is_gray; }
|
||||
// Call equals one second down
|
||||
void substract_remaining_time() { m_remaining_time--; }
|
||||
void set_gray(bool g) { m_is_gray = g; }
|
||||
void set_paused(bool p) { m_paused = p; }
|
||||
bool compare_text(const std::string& text);
|
||||
protected:
|
||||
// Call after every size change
|
||||
void init();
|
||||
// Calculetes correct size but not se it in imgui!
|
||||
virtual void set_next_window_size(ImGuiWrapper& imgui);
|
||||
virtual void render_text(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x , const float win_pos_y);
|
||||
void render_close_button(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x , const float win_pos_y);
|
||||
void render_countdown(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x , const float win_pos_y);
|
||||
void render_hypertext(ImGuiWrapper& imgui,
|
||||
const float text_x, const float text_y,
|
||||
const std::string text,
|
||||
bool more = false);
|
||||
void render_left_sign(ImGuiWrapper& imgui);
|
||||
void render_minimize_button(ImGuiWrapper& imgui,
|
||||
const float win_pos_x, const float win_pos_y);
|
||||
void on_text_click();
|
||||
|
||||
const NotificationData m_data;
|
||||
|
||||
int m_id;
|
||||
// Main text
|
||||
std::string m_text1;
|
||||
// Clickable text
|
||||
std::string m_hypertext;
|
||||
// Aditional text after hypertext - currently not used
|
||||
std::string m_text2;
|
||||
// Countdown variables
|
||||
long m_remaining_time;
|
||||
bool m_counting_down;
|
||||
long m_last_remaining_time;
|
||||
bool m_paused{ false };
|
||||
int m_countdown_frame{ 0 };
|
||||
bool m_fading_out{ false };
|
||||
// total time left when fading beggins
|
||||
float m_fading_time{ 0.0f };
|
||||
float m_current_fade_opacity{ 1.f };
|
||||
// If hidden the notif is alive but not visible to user
|
||||
bool m_hidden { false };
|
||||
// m_finished = true - does not render, marked to delete
|
||||
bool m_finished { false };
|
||||
// Will go to m_finished next render
|
||||
bool m_close_pending { false };
|
||||
// variables to count positions correctly
|
||||
float m_window_width_offset;
|
||||
float m_left_indentation;
|
||||
// Total size of notification window - varies based on monitor
|
||||
float m_window_height { 56.0f };
|
||||
float m_window_width { 450.0f };
|
||||
//Distance from bottom of notifications to top of this notification
|
||||
float m_top_y { 0.0f };
|
||||
|
||||
// Height of text
|
||||
// Used as basic scaling unit!
|
||||
float m_line_height;
|
||||
std::vector<int> m_endlines;
|
||||
// Gray are f.e. eorrors when its uknown if they are still valid
|
||||
bool m_is_gray { false };
|
||||
//if multiline = true, notification is showing all lines(>2)
|
||||
bool m_multiline { false };
|
||||
int m_lines_count{ 1 };
|
||||
wxEvtHandler* m_evt_handler;
|
||||
};
|
||||
|
||||
class SlicingCompleteLargeNotification : public PopNotification
|
||||
{
|
||||
public:
|
||||
SlicingCompleteLargeNotification(const NotificationData& n, const int id, wxEvtHandler* evt_handler, bool largeds);
|
||||
void set_large(bool l);
|
||||
bool get_large() { return m_is_large; }
|
||||
|
||||
void set_print_info(std::string info);
|
||||
protected:
|
||||
virtual void render_text(ImGuiWrapper& imgui,
|
||||
const float win_size_x, const float win_size_y,
|
||||
const float win_pos_x, const float win_pos_y)
|
||||
override;
|
||||
|
||||
bool m_is_large;
|
||||
bool m_has_print_info { false };
|
||||
std::string m_print_info { std::string() };
|
||||
};
|
||||
|
||||
class SlicingWarningNotification : public PopNotification
|
||||
{
|
||||
public:
|
||||
SlicingWarningNotification(const NotificationData& n, const int id, wxEvtHandler* evt_handler) : PopNotification(n, id, evt_handler) {}
|
||||
void set_object_id(size_t id) { object_id = id; }
|
||||
const size_t get_object_id() { return object_id; }
|
||||
void set_warning_step(int ws) { warning_step = ws; }
|
||||
const int get_warning_step() { return warning_step; }
|
||||
protected:
|
||||
size_t object_id;
|
||||
int warning_step;
|
||||
};
|
||||
|
||||
NotificationManager(wxEvtHandler* evt_handler);
|
||||
~NotificationManager();
|
||||
|
||||
|
||||
// only type means one of basic_notification (see below)
|
||||
void push_notification(const NotificationType type, GLCanvas3D& canvas, int timestamp = 0);
|
||||
// only text means Undefined type
|
||||
void push_notification(const std::string& text, GLCanvas3D& canvas, int timestamp = 0);
|
||||
void push_notification(const std::string& text, NotificationLevel level, GLCanvas3D& canvas, int timestamp = 0);
|
||||
// creates Slicing Error notification with custom text
|
||||
void push_slicing_error_notification(const std::string& text, GLCanvas3D& canvas);
|
||||
// creates Slicing Warning notification with custom text
|
||||
void push_slicing_warning_notification(const std::string& text, bool gray, GLCanvas3D& canvas, size_t oid, int warning_step);
|
||||
// marks slicing errors as gray
|
||||
void set_all_slicing_errors_gray(bool g);
|
||||
// marks slicing warings as gray
|
||||
void set_all_slicing_warnings_gray(bool g);
|
||||
void set_slicing_warning_gray(const std::string& text, bool g);
|
||||
// imidietly stops showing slicing errors
|
||||
void close_slicing_errors_and_warnings();
|
||||
void compare_warning_oids(const std::vector<size_t>& living_oids);
|
||||
void push_plater_error_notification(const std::string& text, GLCanvas3D& canvas);
|
||||
void push_plater_warning_notification(const std::string& text, GLCanvas3D& canvas);
|
||||
void close_plater_error_notification();
|
||||
void close_plater_warning_notification(const std::string& text);
|
||||
// creates special notification slicing complete
|
||||
// if large = true prints printing time and export button
|
||||
void push_slicing_complete_notification(GLCanvas3D& canvas, int timestamp, bool large);
|
||||
void set_slicing_complete_print_time(std::string info);
|
||||
void set_slicing_complete_large(bool large);
|
||||
// renders notifications in queue and deletes expired ones
|
||||
void render_notifications(GLCanvas3D& canvas);
|
||||
// finds and closes all notifications of given type
|
||||
void close_notification_of_type(const NotificationType type);
|
||||
void dpi_changed();
|
||||
private:
|
||||
//pushes notification into the queue of notifications that are rendered
|
||||
//can be used to create custom notification
|
||||
bool push_notification_data(const NotificationData& notification_data, GLCanvas3D& canvas, int timestamp);
|
||||
bool push_notification_data(NotificationManager::PopNotification* notification, GLCanvas3D& canvas, int timestamp);
|
||||
//finds older notification of same type and moves it to the end of queue. returns true if found
|
||||
bool find_older(NotificationManager::PopNotification* notification);
|
||||
void sort_notifications();
|
||||
|
||||
wxEvtHandler* m_evt_handler;
|
||||
std::deque<PopNotification*> m_pop_notifications;
|
||||
int m_next_id { 1 };
|
||||
long m_last_time { 0 };
|
||||
bool m_hovered { false };
|
||||
//timestamps used for slining finished - notification could be gone so it needs to be stored here
|
||||
std::unordered_set<int> m_used_timestamps;
|
||||
|
||||
//prepared (basic) notifications
|
||||
const std::vector<NotificationData> basic_notifications = {
|
||||
{NotificationType::SlicingNotPossible, NotificationLevel::RegularNotification, 10, _u8L("Slicing is not possible.")},
|
||||
{NotificationType::ExportToRemovableFinished, NotificationLevel::ImportantNotification, 0, _u8L("Exporting finished."), _u8L("Eject drive.") },
|
||||
{NotificationType::Mouse3dDisconnected, NotificationLevel::RegularNotification, 10, _u8L("3D Mouse disconnected.") },
|
||||
{NotificationType::Mouse3dConnected, NotificationLevel::RegularNotification, 5, _u8L("3D Mouse connected.") },
|
||||
{NotificationType::NewPresetsAviable, NotificationLevel::ImportantNotification, 20, _u8L("New Presets are available."), _u8L("See here.") },
|
||||
{NotificationType::PresetUpdateAviable, NotificationLevel::ImportantNotification, 20, _u8L("Configuration update is available."), _u8L("See more.")},
|
||||
{NotificationType::NewAppAviable, NotificationLevel::ImportantNotification, 20, _u8L("New version is available."), _u8L("See Releases page.")},
|
||||
//{NotificationType::NewAppAviable, NotificationLevel::ImportantNotification, 20, _u8L("New vesion of PrusaSlicer is available.", _u8L("Download page.") },
|
||||
//{NotificationType::LoadingFailed, NotificationLevel::RegularNotification, 20, _u8L("Loading of model has Failed") },
|
||||
//{NotificationType::DeviceEjected, NotificationLevel::RegularNotification, 10, _u8L("Removable device has been safely ejected")} // if we want changeble text (like here name of device), we need to do it as CustomNotification
|
||||
};
|
||||
};
|
||||
|
||||
}//namespace GUI
|
||||
}//namespace Slic3r
|
||||
|
||||
#endif //slic3r_GUI_NotificationManager_hpp_
|
||||
|
|
@ -74,8 +74,10 @@
|
|||
#include "../Utils/PrintHost.hpp"
|
||||
#include "../Utils/FixModelByWin10.hpp"
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
#include "../Utils/PresetUpdater.hpp"
|
||||
#include "RemovableDriveManager.hpp"
|
||||
#include "InstanceCheck.hpp"
|
||||
#include "NotificationManager.hpp"
|
||||
#include "PresetComboBoxes.hpp"
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
|
@ -102,6 +104,7 @@ wxDEFINE_EVENT(EVT_SCHEDULE_BACKGROUND_PROCESS, SimpleEvent);
|
|||
wxDEFINE_EVENT(EVT_SLICING_UPDATE, SlicingStatusEvent);
|
||||
wxDEFINE_EVENT(EVT_SLICING_COMPLETED, wxCommandEvent);
|
||||
wxDEFINE_EVENT(EVT_PROCESS_COMPLETED, wxCommandEvent);
|
||||
wxDEFINE_EVENT(EVT_EXPORT_BEGAN, wxCommandEvent);
|
||||
|
||||
// Sidebar widgets
|
||||
|
||||
|
|
@ -569,7 +572,7 @@ struct Sidebar::priv
|
|||
wxButton *btn_export_gcode;
|
||||
wxButton *btn_reslice;
|
||||
ScalableButton *btn_send_gcode;
|
||||
ScalableButton *btn_remove_device;
|
||||
ScalableButton *btn_eject_device;
|
||||
ScalableButton* btn_export_gcode_removable; //exports to removable drives (appears only if removable drive is connected)
|
||||
|
||||
bool is_collapsed {false};
|
||||
|
|
@ -742,12 +745,12 @@ Sidebar::Sidebar(Plater *parent)
|
|||
};
|
||||
|
||||
init_scalable_btn(&p->btn_send_gcode , "export_gcode", _L("Send to printer") + "\tCtrl+Shift+G");
|
||||
init_scalable_btn(&p->btn_remove_device, "eject_sd" , _L("Remove device") + "\tCtrl+T");
|
||||
init_scalable_btn(&p->btn_eject_device, "eject_sd" , _L("Remove device") + "\tCtrl+T");
|
||||
init_scalable_btn(&p->btn_export_gcode_removable, "export_to_sd", _L("Export to SD card / Flash drive") + "\tCtrl+U");
|
||||
|
||||
// regular buttons "Slice now" and "Export G-code"
|
||||
|
||||
const int scaled_height = p->btn_remove_device->GetBitmapHeight() + 4;
|
||||
const int scaled_height = p->btn_eject_device->GetBitmapHeight() + 4;
|
||||
auto init_btn = [this](wxButton **btn, wxString label, const int button_height) {
|
||||
*btn = new wxButton(this, wxID_ANY, label, wxDefaultPosition,
|
||||
wxSize(-1, button_height), wxBU_EXACTFIT);
|
||||
|
|
@ -765,7 +768,7 @@ Sidebar::Sidebar(Plater *parent)
|
|||
complect_btns_sizer->Add(p->btn_export_gcode, 1, wxEXPAND);
|
||||
complect_btns_sizer->Add(p->btn_send_gcode);
|
||||
complect_btns_sizer->Add(p->btn_export_gcode_removable);
|
||||
complect_btns_sizer->Add(p->btn_remove_device);
|
||||
complect_btns_sizer->Add(p->btn_eject_device);
|
||||
|
||||
|
||||
btns_sizer->Add(p->btn_reslice, 0, wxEXPAND | wxTOP, margin_5);
|
||||
|
|
@ -788,7 +791,7 @@ Sidebar::Sidebar(Plater *parent)
|
|||
p->plater->select_view_3D("Preview");
|
||||
});
|
||||
p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); });
|
||||
p->btn_remove_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); });
|
||||
p->btn_eject_device->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->eject_drive(); });
|
||||
p->btn_export_gcode_removable->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->export_gcode(true); });
|
||||
}
|
||||
|
||||
|
|
@ -931,9 +934,9 @@ void Sidebar::msw_rescale()
|
|||
p->object_info->msw_rescale();
|
||||
|
||||
p->btn_send_gcode->msw_rescale();
|
||||
p->btn_remove_device->msw_rescale();
|
||||
p->btn_eject_device->msw_rescale();
|
||||
p->btn_export_gcode_removable->msw_rescale();
|
||||
const int scaled_height = p->btn_remove_device->GetBitmap().GetHeight() + 4;
|
||||
const int scaled_height = p->btn_eject_device->GetBitmap().GetHeight() + 4;
|
||||
p->btn_export_gcode->SetMinSize(wxSize(-1, scaled_height));
|
||||
p->btn_reslice ->SetMinSize(wxSize(-1, scaled_height));
|
||||
|
||||
|
|
@ -956,7 +959,7 @@ void Sidebar::sys_color_changed()
|
|||
|
||||
// btn...->msw_rescale() updates icon on button, so use it
|
||||
p->btn_send_gcode->msw_rescale();
|
||||
p->btn_remove_device->msw_rescale();
|
||||
p->btn_eject_device->msw_rescale();
|
||||
p->btn_export_gcode_removable->msw_rescale();
|
||||
|
||||
p->scrolled->Layout();
|
||||
|
|
@ -1192,6 +1195,12 @@ void Sidebar::update_sliced_info_sizer()
|
|||
new_label += format_wxstr("\n - %1%", _L("normal mode"));
|
||||
info_text += format_wxstr("\n%1%", ps.estimated_normal_print_time);
|
||||
fill_labels(ps.estimated_normal_custom_gcode_print_times, new_label, info_text);
|
||||
|
||||
// uncomment next line to not disappear slicing finished notif when colapsing sidebar before time estimate
|
||||
//if (p->plater->is_sidebar_collapsed())
|
||||
p->plater->get_notification_manager()->set_slicing_complete_large(p->plater->is_sidebar_collapsed());
|
||||
p->plater->get_notification_manager()->set_slicing_complete_print_time("Estimated printing time: " + ps.estimated_normal_print_time);
|
||||
|
||||
}
|
||||
if (ps.estimated_silent_print_time != "N/A") {
|
||||
new_label += format_wxstr("\n - %1%", _L("stealth mode"));
|
||||
|
|
@ -1227,15 +1236,16 @@ void Sidebar::enable_buttons(bool enable)
|
|||
p->btn_reslice->Enable(enable);
|
||||
p->btn_export_gcode->Enable(enable);
|
||||
p->btn_send_gcode->Enable(enable);
|
||||
p->btn_remove_device->Enable(enable);
|
||||
p->btn_eject_device->Enable(enable);
|
||||
p->btn_export_gcode_removable->Enable(enable);
|
||||
}
|
||||
|
||||
bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Show(show); }
|
||||
bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); }
|
||||
bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); }
|
||||
bool Sidebar::show_disconnect(bool show) const { return p->btn_remove_device->Show(show); }
|
||||
bool Sidebar::show_export_removable(bool show)const { return p->btn_export_gcode_removable->Show(show); }
|
||||
bool Sidebar::show_reslice(bool show) const { return p->btn_reslice->Show(show); }
|
||||
bool Sidebar::show_export(bool show) const { return p->btn_export_gcode->Show(show); }
|
||||
bool Sidebar::show_send(bool show) const { return p->btn_send_gcode->Show(show); }
|
||||
bool Sidebar::show_export_removable(bool show) const { return p->btn_export_gcode_removable->Show(show); }
|
||||
bool Sidebar::show_eject(bool show) const { return p->btn_eject_device->Show(show); }
|
||||
bool Sidebar::get_eject_shown() const { return p->btn_eject_device->IsShown(); }
|
||||
|
||||
bool Sidebar::is_multifilament()
|
||||
{
|
||||
|
|
@ -1433,6 +1443,7 @@ struct Plater::priv
|
|||
GLToolbar view_toolbar;
|
||||
GLToolbar collapse_toolbar;
|
||||
Preview *preview;
|
||||
NotificationManager* notification_manager;
|
||||
|
||||
BackgroundSlicingProcess background_process;
|
||||
bool suppressed_backround_processing_update { false };
|
||||
|
|
@ -1617,7 +1628,17 @@ struct Plater::priv
|
|||
void on_slicing_update(SlicingStatusEvent&);
|
||||
void on_slicing_completed(wxCommandEvent&);
|
||||
void on_process_completed(wxCommandEvent&);
|
||||
void on_export_began(wxCommandEvent&);
|
||||
void on_layer_editing_toggled(bool enable);
|
||||
void on_slicing_began();
|
||||
|
||||
void clear_warnings();
|
||||
void add_warning(const Slic3r::PrintStateBase::Warning &warning, size_t oid);
|
||||
void actualizate_warnings(const Model& model, size_t print_oid);
|
||||
// Displays dialog window with list of warnings.
|
||||
// Returns true if user clicks OK.
|
||||
// Returns true if current_warnings vector is empty without showning the dialog
|
||||
bool warnings_dialog();
|
||||
|
||||
void on_action_add(SimpleEvent&);
|
||||
void on_action_split_objects(SimpleEvent&);
|
||||
|
|
@ -1668,7 +1689,7 @@ struct Plater::priv
|
|||
// Flag indicating that the G-code export targets a removable device, therefore the show_action_buttons() needs to be called at any case when the background processing finishes.
|
||||
bool writing_to_removable_device = { false };
|
||||
bool inside_snapshot_capture() { return m_prevent_snapshots != 0; }
|
||||
|
||||
bool process_completed_with_error { false };
|
||||
private:
|
||||
bool init_object_menu();
|
||||
bool init_common_menu(wxMenu* menu, const bool is_part = false);
|
||||
|
|
@ -1696,6 +1717,11 @@ private:
|
|||
* */
|
||||
std::string m_last_fff_printer_profile_name;
|
||||
std::string m_last_sla_printer_profile_name;
|
||||
|
||||
// vector of all warnings generated by last slicing
|
||||
std::vector<std::pair<Slic3r::PrintStateBase::Warning, size_t>> current_warnings;
|
||||
bool show_warning_dialog { false };
|
||||
|
||||
};
|
||||
|
||||
const std::regex Plater::priv::pattern_bundle(".*[.](amf|amf[.]xml|zip[.]amf|3mf|prusa)", std::regex::icase);
|
||||
|
|
@ -1741,6 +1767,7 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
});
|
||||
background_process.set_slicing_completed_event(EVT_SLICING_COMPLETED);
|
||||
background_process.set_finished_event(EVT_PROCESS_COMPLETED);
|
||||
background_process.set_export_began_event(EVT_EXPORT_BEGAN);
|
||||
// Default printer technology for default config.
|
||||
background_process.select_technology(this->printer_technology);
|
||||
// Register progress callback from the Print class to the Plater.
|
||||
|
|
@ -1852,8 +1879,9 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_MOVE_DOUBLE_SLIDER, [this](wxKeyEvent& evt) { preview->move_double_slider(evt); });
|
||||
preview->get_wxglcanvas()->Bind(EVT_GLCANVAS_EDIT_COLOR_CHANGE, [this](wxKeyEvent& evt) { preview->edit_double_slider(evt); });
|
||||
|
||||
q->Bind(EVT_SLICING_COMPLETED, &priv::on_slicing_completed, this);
|
||||
q->Bind(EVT_SLICING_COMPLETED, &priv::on_slicing_completed, this);
|
||||
q->Bind(EVT_PROCESS_COMPLETED, &priv::on_process_completed, this);
|
||||
q->Bind(EVT_EXPORT_BEGAN, &priv::on_export_began, this);
|
||||
q->Bind(EVT_GLVIEWTOOLBAR_3D, [q](SimpleEvent&) { q->select_view_3D("3D"); });
|
||||
q->Bind(EVT_GLVIEWTOOLBAR_PREVIEW, [q](SimpleEvent&) { q->select_view_3D("Preview"); });
|
||||
|
||||
|
|
@ -1880,16 +1908,27 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame)
|
|||
});
|
||||
#endif /* _WIN32 */
|
||||
|
||||
this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this](RemovableDriveEjectEvent &evt) {
|
||||
notification_manager = new NotificationManager(this->q);
|
||||
this->q->Bind(EVT_EJECT_DRIVE_NOTIFICAION_CLICKED, [this](EjectDriveNotificationClickedEvent&) { this->q->eject_drive(); });
|
||||
this->q->Bind(EVT_EXPORT_GCODE_NOTIFICAION_CLICKED, [this](ExportGcodeNotificationClickedEvent&) { this->q->export_gcode(true); });
|
||||
this->q->Bind(EVT_PRESET_UPDATE_AVIABLE_CLICKED, [this](PresetUpdateAviableClickedEvent&) { wxGetApp().get_preset_updater()->on_update_notification_confirm(); });
|
||||
|
||||
this->q->Bind(EVT_REMOVABLE_DRIVE_EJECTED, [this, q](RemovableDriveEjectEvent &evt) {
|
||||
if (evt.data.second) {
|
||||
this->show_action_buttons(this->ready_to_slice);
|
||||
Slic3r::GUI::show_info(this->q, format_wxstr(_L("Unmounting successful. The device %s(%s) can now be safely removed from the computer."),
|
||||
evt.data.first.name, evt.data.first.path));
|
||||
} else
|
||||
Slic3r::GUI::show_info(this->q, format_wxstr(_L("Ejecting of device %s(%s) has failed."),
|
||||
evt.data.first.name, evt.data.first.path));
|
||||
notification_manager->push_notification(format(_L("Unmounting successful. The device %s(%s) can now be safely removed from the computer."),evt.data.first.name, evt.data.first.path),
|
||||
NotificationManager::NotificationLevel::RegularNotification, *q->get_current_canvas3D());
|
||||
} else {
|
||||
notification_manager->push_notification(format(_L("Ejecting of device %s(%s) has failed."), evt.data.first.name, evt.data.first.path),
|
||||
NotificationManager::NotificationLevel::ErrorNotification, *q->get_current_canvas3D());
|
||||
}
|
||||
});
|
||||
this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this, q](RemovableDrivesChangedEvent &) {
|
||||
this->show_action_buttons(this->ready_to_slice);
|
||||
if (!this->sidebar->get_eject_shown()) {
|
||||
notification_manager->close_notification_of_type(NotificationType::ExportToRemovableFinished);
|
||||
}
|
||||
});
|
||||
this->q->Bind(EVT_REMOVABLE_DRIVES_CHANGED, [this](RemovableDrivesChangedEvent &) { this->show_action_buttons(this->ready_to_slice); });
|
||||
// Start the background thread and register this window as a target for update events.
|
||||
wxGetApp().removable_drive_manager()->init(this->q);
|
||||
#ifdef _WIN32
|
||||
|
|
@ -2519,6 +2558,8 @@ void Plater::priv::reset()
|
|||
{
|
||||
Plater::TakeSnapshot snapshot(q, _L("Reset Project"));
|
||||
|
||||
clear_warnings();
|
||||
|
||||
set_project_filename(wxEmptyString);
|
||||
|
||||
// Prevent toolpaths preview from rendering while we modify the Print object
|
||||
|
|
@ -2688,22 +2729,13 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
|
|||
// The state of the Print changed, and it is non-zero. Let's validate it and give the user feedback on errors.
|
||||
std::string err = this->background_process.validate();
|
||||
if (err.empty()) {
|
||||
notification_manager->set_all_slicing_errors_gray(true);
|
||||
if (invalidated != Print::APPLY_STATUS_UNCHANGED && this->background_processing_enabled())
|
||||
return_state |= UPDATE_BACKGROUND_PROCESS_RESTART;
|
||||
} else {
|
||||
// The print is not valid.
|
||||
// Only show the error message immediately, if the top level parent of this window is active.
|
||||
auto p = dynamic_cast<wxWindow*>(this->q);
|
||||
while (p->GetParent())
|
||||
p = p->GetParent();
|
||||
auto *top_level_wnd = dynamic_cast<wxTopLevelWindow*>(p);
|
||||
if (! postpone_error_messages && top_level_wnd && top_level_wnd->IsActive()) {
|
||||
// The error returned from the Print needs to be translated into the local language.
|
||||
GUI::show_error(this->q, err);
|
||||
} else {
|
||||
// Show the error message once the main window gets activated.
|
||||
this->delayed_error_message = err;
|
||||
}
|
||||
// The print is not valid.
|
||||
// Show error as notification.
|
||||
notification_manager->push_slicing_error_notification(err, *q->get_current_canvas3D());
|
||||
return_state |= UPDATE_BACKGROUND_PROCESS_INVALID;
|
||||
}
|
||||
} else if (! this->delayed_error_message.empty()) {
|
||||
|
|
@ -2711,6 +2743,14 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool
|
|||
return_state |= UPDATE_BACKGROUND_PROCESS_INVALID;
|
||||
}
|
||||
|
||||
//actualizate warnings
|
||||
if (invalidated != Print::APPLY_STATUS_UNCHANGED) {
|
||||
actualizate_warnings(this->q->model(), this->background_process.current_print()->id().id);
|
||||
notification_manager->set_all_slicing_warnings_gray(true);
|
||||
show_warning_dialog = false;
|
||||
process_completed_with_error = false;
|
||||
}
|
||||
|
||||
if (invalidated != Print::APPLY_STATUS_UNCHANGED && was_running && ! this->background_process.running() &&
|
||||
(return_state & UPDATE_BACKGROUND_PROCESS_RESTART) == 0) {
|
||||
// The background processing was killed and it will not be restarted.
|
||||
|
|
@ -2773,6 +2813,8 @@ bool Plater::priv::restart_background_process(unsigned int state)
|
|||
this->statusbar()->set_status_text(_L("Cancelling"));
|
||||
this->background_process.stop();
|
||||
});
|
||||
if (!show_warning_dialog)
|
||||
on_slicing_began();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -2799,6 +2841,7 @@ void Plater::priv::export_gcode(fs::path output_path, bool output_path_on_remova
|
|||
if ((state & priv::UPDATE_BACKGROUND_PROCESS_INVALID) != 0)
|
||||
return;
|
||||
|
||||
show_warning_dialog = true;
|
||||
if (! output_path.empty()) {
|
||||
background_process.schedule_export(output_path.string(), output_path_on_removable_media);
|
||||
} else {
|
||||
|
|
@ -3285,11 +3328,20 @@ void Plater::priv::on_slicing_update(SlicingStatusEvent &evt)
|
|||
state = print_object->step_state_with_warnings(static_cast<SLAPrintObjectStep>(warning_step));
|
||||
}
|
||||
// Now process state.warnings.
|
||||
for (auto const& warning : state.warnings) {
|
||||
if (warning.current) {
|
||||
notification_manager->push_slicing_warning_notification(warning.message, false, *q->get_current_canvas3D(), object_id.id, warning_step);
|
||||
add_warning(warning, object_id.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::priv::on_slicing_completed(wxCommandEvent &)
|
||||
void Plater::priv::on_slicing_completed(wxCommandEvent & evt)
|
||||
{
|
||||
//notification_manager->push_notification(NotificationType::SlicingComplete, *q->get_current_canvas3D(), evt.GetInt());
|
||||
notification_manager->push_slicing_complete_notification(*q->get_current_canvas3D(), evt.GetInt(), is_sidebar_collapsed());
|
||||
|
||||
switch (this->printer_technology) {
|
||||
case ptFFF:
|
||||
this->update_fff_scene();
|
||||
|
|
@ -3302,8 +3354,63 @@ void Plater::priv::on_slicing_completed(wxCommandEvent &)
|
|||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
void Plater::priv::on_export_began(wxCommandEvent& evt)
|
||||
{
|
||||
if (show_warning_dialog)
|
||||
warnings_dialog();
|
||||
}
|
||||
void Plater::priv::on_slicing_began()
|
||||
{
|
||||
clear_warnings();
|
||||
notification_manager->close_notification_of_type(NotificationType::SlicingComplete);
|
||||
}
|
||||
void Plater::priv::add_warning(const Slic3r::PrintStateBase::Warning& warning, size_t oid)
|
||||
{
|
||||
for (auto const& it : current_warnings) {
|
||||
if (warning.message_id == it.first.message_id) {
|
||||
if (warning.message_id != 0 || (warning.message_id == 0 && warning.message == it.first.message))
|
||||
return;
|
||||
}
|
||||
}
|
||||
current_warnings.emplace_back(std::pair<Slic3r::PrintStateBase::Warning, size_t>(warning, oid));
|
||||
}
|
||||
void Plater::priv::actualizate_warnings(const Model& model, size_t print_oid)
|
||||
{
|
||||
std::vector<size_t> living_oids;
|
||||
living_oids.push_back(model.id().id);
|
||||
living_oids.push_back(print_oid);
|
||||
for (auto it = model.objects.begin(); it != model.objects.end(); ++it) {
|
||||
living_oids.push_back((*it)->id().id);
|
||||
}
|
||||
notification_manager->compare_warning_oids(living_oids);
|
||||
}
|
||||
void Plater::priv::clear_warnings()
|
||||
{
|
||||
notification_manager->close_slicing_errors_and_warnings();
|
||||
this->current_warnings.clear();
|
||||
}
|
||||
bool Plater::priv::warnings_dialog()
|
||||
{
|
||||
if (current_warnings.empty())
|
||||
return true;
|
||||
std::string text = _u8L("There are active warnings concerning sliced models:\n");
|
||||
bool empt = true;
|
||||
for (auto const& it : current_warnings) {
|
||||
int next_n = it.first.message.find_first_of('\n', 0);
|
||||
text += "\n";
|
||||
if (next_n != std::string::npos)
|
||||
text += it.first.message.substr(0, next_n);
|
||||
else
|
||||
text += it.first.message;
|
||||
}
|
||||
//text += "\n\nDo you still wish to export?";
|
||||
wxMessageDialog msg_wingow(this->q, text, wxString(SLIC3R_APP_NAME " ") + _L("generated warnings"), wxOK);
|
||||
const auto res = msg_wingow.ShowModal();
|
||||
return res == wxID_OK;
|
||||
|
||||
}
|
||||
void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
||||
{
|
||||
// Stop the background task, wait until the thread goes into the "Idle" state.
|
||||
|
|
@ -3322,14 +3429,13 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
|||
if (error) {
|
||||
wxString message = evt.GetString();
|
||||
if (message.IsEmpty())
|
||||
message = _L("Export failed");
|
||||
if (q->m_tracking_popup_menu)
|
||||
// We don't want to pop-up a message box when tracking a pop-up menu.
|
||||
// We postpone the error message instead.
|
||||
q->m_tracking_popup_menu_error_message = message;
|
||||
else
|
||||
show_error(q, message);
|
||||
message = _L("Export failed.");
|
||||
notification_manager->push_slicing_error_notification(boost::nowide::narrow(message), *q->get_current_canvas3D());
|
||||
this->statusbar()->set_status_text(message);
|
||||
const wxString invalid_str = _L("Invalid data");
|
||||
for (auto btn : { ActionButtonType::abReslice, ActionButtonType::abSendGCode, ActionButtonType::abExport })
|
||||
sidebar->set_btn_label(btn, invalid_str);
|
||||
process_completed_with_error = true;
|
||||
}
|
||||
if (canceled)
|
||||
this->statusbar()->set_status_text(_L("Cancelled"));
|
||||
|
|
@ -3355,18 +3461,21 @@ void Plater::priv::on_process_completed(wxCommandEvent &evt)
|
|||
default: break;
|
||||
}
|
||||
|
||||
|
||||
if (canceled) {
|
||||
if (wxGetApp().get_mode() == comSimple)
|
||||
sidebar->set_btn_label(ActionButtonType::abReslice, "Slice now");
|
||||
show_action_buttons(true);
|
||||
}
|
||||
else if (this->writing_to_removable_device || wxGetApp().get_mode() == comSimple)
|
||||
else if (wxGetApp().get_mode() == comSimple)
|
||||
{
|
||||
wxGetApp().removable_drive_manager()->set_exporting_finished(true);
|
||||
show_action_buttons(false);
|
||||
}
|
||||
this->writing_to_removable_device = false;
|
||||
else if (this->writing_to_removable_device)
|
||||
{
|
||||
show_action_buttons(false);
|
||||
notification_manager->push_notification(NotificationType::ExportToRemovableFinished, *q->get_current_canvas3D());
|
||||
}
|
||||
this->writing_to_removable_device = false;
|
||||
}
|
||||
|
||||
void Plater::priv::on_layer_editing_toggled(bool enable)
|
||||
|
|
@ -4013,7 +4122,7 @@ void Plater::priv::show_action_buttons(const bool ready_to_slice) const
|
|||
sidebar->show_export(true) |
|
||||
sidebar->show_send(send_gcode_shown) |
|
||||
sidebar->show_export_removable(removable_media_status.has_removable_drives) |
|
||||
sidebar->show_disconnect(removable_media_status.has_eject))
|
||||
sidebar->show_eject(removable_media_status.has_eject))
|
||||
sidebar->Layout();
|
||||
}
|
||||
else
|
||||
|
|
@ -4025,7 +4134,7 @@ void Plater::priv::show_action_buttons(const bool ready_to_slice) const
|
|||
sidebar->show_export(!ready_to_slice) |
|
||||
sidebar->show_send(send_gcode_shown && !ready_to_slice) |
|
||||
sidebar->show_export_removable(!ready_to_slice && removable_media_status.has_removable_drives) |
|
||||
sidebar->show_disconnect(!ready_to_slice && removable_media_status.has_eject))
|
||||
sidebar->show_eject(!ready_to_slice && removable_media_status.has_eject))
|
||||
sidebar->Layout();
|
||||
}
|
||||
}
|
||||
|
|
@ -4588,6 +4697,9 @@ void Plater::export_gcode(bool prefer_removable)
|
|||
if (p->model.objects.empty())
|
||||
return;
|
||||
|
||||
if (p->process_completed_with_error)//here
|
||||
return;
|
||||
|
||||
// If possible, remove accents from accented latin characters.
|
||||
// This function is useful for generating file names to be processed by legacy firmwares.
|
||||
fs::path default_output_file;
|
||||
|
|
@ -4847,7 +4959,6 @@ void Plater::export_toolpaths_to_obj() const
|
|||
p->preview->get_canvas3d()->export_toolpaths_to_obj(into_u8(path).c_str());
|
||||
}
|
||||
|
||||
|
||||
void Plater::reslice()
|
||||
{
|
||||
// Stop arrange and (or) optimize rotation tasks.
|
||||
|
|
@ -5535,6 +5646,16 @@ Mouse3DController& Plater::get_mouse3d_controller()
|
|||
return p->mouse3d_controller;
|
||||
}
|
||||
|
||||
const NotificationManager* Plater::get_notification_manager() const
|
||||
{
|
||||
return p->notification_manager;
|
||||
}
|
||||
|
||||
NotificationManager* Plater::get_notification_manager()
|
||||
{
|
||||
return p->notification_manager;
|
||||
}
|
||||
|
||||
bool Plater::can_delete() const { return p->can_delete(); }
|
||||
bool Plater::can_delete_all() const { return p->can_delete_all(); }
|
||||
bool Plater::can_increase_instances() const { return p->can_increase_instances(); }
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ class ObjectLayers;
|
|||
class ObjectList;
|
||||
class GLCanvas3D;
|
||||
class Mouse3DController;
|
||||
class NotificationManager;
|
||||
struct Camera;
|
||||
class Bed3D;
|
||||
class GLToolbar;
|
||||
|
|
@ -95,8 +96,9 @@ public:
|
|||
bool show_reslice(bool show) const;
|
||||
bool show_export(bool show) const;
|
||||
bool show_send(bool show) const;
|
||||
bool show_disconnect(bool show)const;
|
||||
bool show_eject(bool show)const;
|
||||
bool show_export_removable(bool show) const;
|
||||
bool get_eject_shown() const;
|
||||
bool is_multifilament();
|
||||
void update_mode();
|
||||
bool is_collapsed();
|
||||
|
|
@ -303,6 +305,9 @@ public:
|
|||
Mouse3DController& get_mouse3d_controller();
|
||||
|
||||
void set_bed_shape() const;
|
||||
|
||||
const NotificationManager* get_notification_manager() const;
|
||||
NotificationManager* get_notification_manager();
|
||||
|
||||
// ROII wrapper for suppressing the Undo / Redo snapshot to be taken.
|
||||
class SuppressSnapshots
|
||||
|
|
|
|||
|
|
@ -234,30 +234,6 @@ void PreferencesDialog::accept()
|
|||
}
|
||||
}
|
||||
|
||||
#if !ENABLE_LAYOUT_NO_RESTART
|
||||
if (m_settings_layout_changed) {
|
||||
// the dialog needs to be destroyed before the call to recreate_gui()
|
||||
// or sometimes the application crashes into wxDialogBase() destructor
|
||||
// so we put it into an inner scope
|
||||
wxMessageDialog dialog(nullptr,
|
||||
_L("Switching the settings layout mode will trigger application restart.\n"
|
||||
"You will lose content of the plater.") + "\n\n" +
|
||||
_L("Do you want to proceed?"),
|
||||
wxString(SLIC3R_APP_NAME) + " - " + _L("Switching the settings layout mode"),
|
||||
wxICON_QUESTION | wxOK | wxCANCEL);
|
||||
|
||||
if (dialog.ShowModal() == wxID_CANCEL)
|
||||
{
|
||||
int selection = app_config->get("old_settings_layout_mode") == "1" ? 0 :
|
||||
app_config->get("new_settings_layout_mode") == "1" ? 1 :
|
||||
app_config->get("dlg_settings_layout_mode") == "1" ? 2 : 0;
|
||||
|
||||
m_layout_mode_box->SetSelection(selection);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // !ENABLE_LAYOUT_NO_RESTART
|
||||
|
||||
for (std::map<std::string, std::string>::iterator it = m_values.begin(); it != m_values.end(); ++it)
|
||||
app_config->set(it->first, it->second);
|
||||
|
||||
|
|
|
|||
|
|
@ -3959,6 +3959,7 @@ void TabSLAPrint::build()
|
|||
|
||||
optgroup = page->new_optgroup(L("Support pillar"));
|
||||
optgroup->append_single_option_line("support_pillar_diameter");
|
||||
optgroup->append_single_option_line("support_small_pillar_diameter_percent");
|
||||
optgroup->append_single_option_line("support_max_bridges_on_pillar");
|
||||
|
||||
optgroup->append_single_option_line("support_pillar_connection_mode");
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/GUI/NotificationManager.hpp"
|
||||
#include "slic3r/Utils/Http.hpp"
|
||||
#include "slic3r/Config/Version.hpp"
|
||||
#include "slic3r/Config/Snapshot.hpp"
|
||||
|
|
@ -154,6 +155,9 @@ struct PresetUpdater::priv
|
|||
bool cancel;
|
||||
std::thread thread;
|
||||
|
||||
bool has_waiting_updates { false };
|
||||
Updates waiting_updates;
|
||||
|
||||
priv();
|
||||
|
||||
void set_download_prefs(AppConfig *app_config);
|
||||
|
|
@ -165,6 +169,7 @@ struct PresetUpdater::priv
|
|||
void check_install_indices() const;
|
||||
Updates get_config_updates(const Semver& old_slic3r_version) const;
|
||||
void perform_updates(Updates &&updates, bool snapshot = true) const;
|
||||
void set_waiting_updates(Updates u);
|
||||
};
|
||||
|
||||
PresetUpdater::priv::priv()
|
||||
|
|
@ -326,7 +331,15 @@ void PresetUpdater::priv::sync_config(const VendorMap vendors)
|
|||
continue;
|
||||
}
|
||||
Slic3r::rename_file(idx_path_temp, idx_path);
|
||||
index = std::move(new_index);
|
||||
//if we rename path we need to change it in Index object too or create the object again
|
||||
//index = std::move(new_index);
|
||||
try {
|
||||
index.load(idx_path);
|
||||
}
|
||||
catch (const std::exception& /* err */) {
|
||||
BOOST_LOG_TRIVIAL(error) << format("Could not load downloaded index %1% for vendor %2%: invalid index?", idx_path, vendor.name);
|
||||
continue;
|
||||
}
|
||||
if (cancel)
|
||||
return;
|
||||
}
|
||||
|
|
@ -632,6 +645,12 @@ void PresetUpdater::priv::perform_updates(Updates &&updates, bool snapshot) cons
|
|||
}
|
||||
}
|
||||
|
||||
void PresetUpdater::priv::set_waiting_updates(Updates u)
|
||||
{
|
||||
waiting_updates = u;
|
||||
has_waiting_updates = true;
|
||||
}
|
||||
|
||||
PresetUpdater::PresetUpdater() :
|
||||
p(new priv())
|
||||
{}
|
||||
|
|
@ -690,9 +709,9 @@ void PresetUpdater::slic3r_update_notify()
|
|||
}
|
||||
}
|
||||
|
||||
PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver &old_slic3r_version) const
|
||||
PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver& old_slic3r_version, bool no_notification) const
|
||||
{
|
||||
if (! p->enabled_config_update) { return R_NOOP; }
|
||||
if (! p->enabled_config_update) { return R_NOOP; }
|
||||
|
||||
auto updates = p->get_config_updates(old_slic3r_version);
|
||||
if (updates.incompats.size() > 0) {
|
||||
|
|
@ -779,30 +798,38 @@ PresetUpdater::UpdateResult PresetUpdater::config_update(const Semver &old_slic3
|
|||
}
|
||||
|
||||
// regular update
|
||||
BOOST_LOG_TRIVIAL(info) << format("Update of %1% bundles available. Asking for confirmation ...", updates.updates.size());
|
||||
if (no_notification) {
|
||||
BOOST_LOG_TRIVIAL(info) << format("Update of %1% bundles available. Asking for confirmation ...", p->waiting_updates.updates.size());
|
||||
|
||||
std::vector<GUI::MsgUpdateConfig::Update> updates_msg;
|
||||
for (const auto &update : updates.updates) {
|
||||
std::string changelog_url = update.version.config_version.prerelease() == nullptr ? update.changelog_url : std::string();
|
||||
updates_msg.emplace_back(update.vendor, update.version.config_version, update.version.comment, std::move(changelog_url));
|
||||
}
|
||||
std::vector<GUI::MsgUpdateConfig::Update> updates_msg;
|
||||
for (const auto& update : updates.updates) {
|
||||
std::string changelog_url = update.version.config_version.prerelease() == nullptr ? update.changelog_url : std::string();
|
||||
updates_msg.emplace_back(update.vendor, update.version.config_version, update.version.comment, std::move(changelog_url));
|
||||
}
|
||||
|
||||
GUI::MsgUpdateConfig dlg(updates_msg);
|
||||
GUI::MsgUpdateConfig dlg(updates_msg);
|
||||
|
||||
const auto res = dlg.ShowModal();
|
||||
if (res == wxID_OK) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "User agreed to perform the update";
|
||||
p->perform_updates(std::move(updates));
|
||||
const auto res = dlg.ShowModal();
|
||||
if (res == wxID_OK) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "User agreed to perform the update";
|
||||
p->perform_updates(std::move(updates));
|
||||
|
||||
// Reload global configuration
|
||||
auto *app_config = GUI::wxGetApp().app_config;
|
||||
GUI::wxGetApp().preset_bundle->load_presets(*app_config);
|
||||
GUI::wxGetApp().load_current_presets();
|
||||
return R_UPDATE_INSTALLED;
|
||||
// Reload global configuration
|
||||
auto* app_config = GUI::wxGetApp().app_config;
|
||||
GUI::wxGetApp().preset_bundle->load_presets(*app_config);
|
||||
GUI::wxGetApp().load_current_presets();
|
||||
return R_UPDATE_INSTALLED;
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(info) << "User refused the update";
|
||||
return R_UPDATE_REJECT;
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << "User refused the update";
|
||||
return R_UPDATE_REJECT;
|
||||
p->set_waiting_updates(updates);
|
||||
GUI::wxGetApp().plater()->get_notification_manager()->push_notification(GUI::NotificationType::PresetUpdateAviable, *(GUI::wxGetApp().plater()->get_current_canvas3D()));
|
||||
}
|
||||
|
||||
// MsgUpdateConfig will show after the notificaation is clicked
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << "No configuration updates available.";
|
||||
}
|
||||
|
|
@ -825,5 +852,37 @@ void PresetUpdater::install_bundles_rsrc(std::vector<std::string> bundles, bool
|
|||
p->perform_updates(std::move(updates), snapshot);
|
||||
}
|
||||
|
||||
void PresetUpdater::on_update_notification_confirm()
|
||||
{
|
||||
if (!p->has_waiting_updates)
|
||||
return;
|
||||
BOOST_LOG_TRIVIAL(info) << format("Update of %1% bundles available. Asking for confirmation ...", p->waiting_updates.updates.size());
|
||||
|
||||
std::vector<GUI::MsgUpdateConfig::Update> updates_msg;
|
||||
for (const auto& update : p->waiting_updates.updates) {
|
||||
std::string changelog_url = update.version.config_version.prerelease() == nullptr ? update.changelog_url : std::string();
|
||||
updates_msg.emplace_back(update.vendor, update.version.config_version, update.version.comment, std::move(changelog_url));
|
||||
}
|
||||
|
||||
GUI::MsgUpdateConfig dlg(updates_msg);
|
||||
|
||||
const auto res = dlg.ShowModal();
|
||||
if (res == wxID_OK) {
|
||||
BOOST_LOG_TRIVIAL(debug) << "User agreed to perform the update";
|
||||
p->perform_updates(std::move(p->waiting_updates));
|
||||
|
||||
// Reload global configuration
|
||||
auto* app_config = GUI::wxGetApp().app_config;
|
||||
GUI::wxGetApp().preset_bundle->load_presets(*app_config);
|
||||
GUI::wxGetApp().load_current_presets();
|
||||
p->has_waiting_updates = false;
|
||||
//return R_UPDATE_INSTALLED;
|
||||
}
|
||||
else {
|
||||
BOOST_LOG_TRIVIAL(info) << "User refused the update";
|
||||
//return R_UPDATE_REJECT;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,16 +35,20 @@ public:
|
|||
R_INCOMPAT_CONFIGURED,
|
||||
R_UPDATE_INSTALLED,
|
||||
R_UPDATE_REJECT,
|
||||
R_UPDATE_NOTIFICATION
|
||||
};
|
||||
|
||||
// If updating is enabled, check if updates are available in cache, if so, ask about installation.
|
||||
// A false return value implies Slic3r should exit due to incompatibility of configuration.
|
||||
// Providing old slic3r version upgrade profiles on upgrade of an application even in case
|
||||
// that the config index installed from the Internet is equal to the index contained in the installation package.
|
||||
UpdateResult config_update(const Semver &old_slic3r_version) const;
|
||||
// no_notification = force modal textbox, otherwise some cases only shows notification
|
||||
UpdateResult config_update(const Semver &old_slic3r_version, bool no_notification) const;
|
||||
|
||||
// "Update" a list of bundles from resources (behaves like an online update).
|
||||
void install_bundles_rsrc(std::vector<std::string> bundles, bool snapshot = true) const;
|
||||
|
||||
void on_update_notification_confirm();
|
||||
private:
|
||||
struct priv;
|
||||
std::unique_ptr<priv> p;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue