From 73b885fc3711e82ae4c2fabf2464a06714dda435 Mon Sep 17 00:00:00 2001 From: enricoturri1966 Date: Wed, 8 Jul 2020 13:33:50 +0200 Subject: [PATCH] GCodeViewer -> Added imgui dialog for estimated printing times --- src/libslic3r/GCode.cpp | 17 +- src/libslic3r/GCodeTimeEstimator.cpp | 33 ++ src/libslic3r/GCodeTimeEstimator.hpp | 8 + src/libslic3r/Print.hpp | 14 + src/libslic3r/Technologies.hpp | 4 +- src/slic3r/GUI/GCodeViewer.cpp | 379 +++++++++++++------ src/slic3r/GUI/GCodeViewer.hpp | 7 +- src/slic3r/GUI/GLCanvas3D.cpp | 68 ++-- src/slic3r/GUI/GLShadersManager.cpp | 2 +- src/slic3r/GUI/GUI_Preview.cpp | 5 +- src/slic3r/GUI/GUI_Preview.hpp | 3 +- src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp | 3 +- src/slic3r/GUI/ImGuiWrapper.cpp | 36 +- src/slic3r/GUI/ImGuiWrapper.hpp | 7 + src/slic3r/GUI/KBShortcutsDialog.cpp | 5 +- src/slic3r/GUI/MainFrame.cpp | 4 + src/slic3r/GUI/Plater.cpp | 26 +- 17 files changed, 438 insertions(+), 183 deletions(-) diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 8de64544c8..7bfb73aa37 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -1050,10 +1050,19 @@ namespace DoExport { print_statistics.clear(); print_statistics.estimated_normal_print_time = normal_time_estimator.get_time_dhm/*s*/(); print_statistics.estimated_silent_print_time = silent_time_estimator_enabled ? silent_time_estimator.get_time_dhm/*s*/() : "N/A"; - print_statistics.estimated_normal_custom_gcode_print_times = normal_time_estimator.get_custom_gcode_times_dhm(true); - if (silent_time_estimator_enabled) - print_statistics.estimated_silent_custom_gcode_print_times = silent_time_estimator.get_custom_gcode_times_dhm(true); - print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges); +#if ENABLE_GCODE_VIEWER + print_statistics.estimated_normal_custom_gcode_print_times_str = normal_time_estimator.get_custom_gcode_times_dhm(true); + print_statistics.estimated_normal_custom_gcode_print_times = normal_time_estimator.get_custom_gcode_times(true); + if (silent_time_estimator_enabled) { + print_statistics.estimated_silent_custom_gcode_print_times_str = silent_time_estimator.get_custom_gcode_times_dhm(true); + print_statistics.estimated_silent_custom_gcode_print_times = silent_time_estimator.get_custom_gcode_times(true); + } +#else + print_statistics.estimated_normal_custom_gcode_print_times = normal_time_estimator.get_custom_gcode_times_dhm(true); + if (silent_time_estimator_enabled) + print_statistics.estimated_silent_custom_gcode_print_times = silent_time_estimator.get_custom_gcode_times_dhm(true); +#endif // ENABLE_GCODE_VIEWER + print_statistics.total_toolchanges = std::max(0, wipe_tower_data.number_of_toolchanges); if (! extruders.empty()) { std::pair out_filament_used_mm ("; filament used [mm] = ", 0); std::pair out_filament_used_cm3("; filament used [cm3] = ", 0); diff --git a/src/libslic3r/GCodeTimeEstimator.cpp b/src/libslic3r/GCodeTimeEstimator.cpp index 9e8137ef0e..d67db84819 100644 --- a/src/libslic3r/GCodeTimeEstimator.cpp +++ b/src/libslic3r/GCodeTimeEstimator.cpp @@ -678,6 +678,21 @@ namespace Slic3r { return _get_time_minutes(get_time()); } +#if ENABLE_GCODE_VIEWER + std::vector>> GCodeTimeEstimator::get_custom_gcode_times(bool include_remaining) const + { + std::vector>> ret; + + float total_time = 0.0f; + for (const auto& [type, time] : m_custom_gcode_times) { + float remaining = include_remaining ? m_time - total_time : 0.0f; + ret.push_back({ type, { time, remaining } }); + total_time += time; + } + + return ret; + } +#else std::vector> GCodeTimeEstimator::get_custom_gcode_times() const { return m_custom_gcode_times; @@ -721,7 +736,24 @@ namespace Slic3r { } return ret; } +#endif // ENABLE_GCODE_VIEWER +#if ENABLE_GCODE_VIEWER + std::vector>> GCodeTimeEstimator::get_custom_gcode_times_dhm(bool include_remaining) const + { + std::vector>> ret; + + float total_time = 0.0f; + for (const auto& [type, time] : m_custom_gcode_times) { + std::string duration = _get_time_dhm(time); + std::string remaining = include_remaining ? _get_time_dhm(m_time - total_time) : ""; + ret.push_back({ type, { duration, remaining } }); + total_time += time; + } + + return ret; + } +#else std::vector> GCodeTimeEstimator::get_custom_gcode_times_dhm(bool include_remaining) const { std::vector> ret; @@ -742,6 +774,7 @@ namespace Slic3r { return ret; } +#endif // ENABLE_GCODE_VIEWER // Return an estimate of the memory consumed by the time estimator. size_t GCodeTimeEstimator::memory_used() const diff --git a/src/libslic3r/GCodeTimeEstimator.hpp b/src/libslic3r/GCodeTimeEstimator.hpp index 63e11c4faa..cfa12b40be 100644 --- a/src/libslic3r/GCodeTimeEstimator.hpp +++ b/src/libslic3r/GCodeTimeEstimator.hpp @@ -358,6 +358,9 @@ namespace Slic3r { std::string get_time_minutes() const; // Returns the estimated time, in seconds, for each custom gcode +#if ENABLE_GCODE_VIEWER + std::vector>> get_custom_gcode_times(bool include_remaining) const; +#else std::vector> get_custom_gcode_times() const; // Returns the estimated time, in format DDd HHh MMm SSs, for each color @@ -367,10 +370,15 @@ namespace Slic3r { // Returns the estimated time, in minutes (integer), for each color // If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)" std::vector get_color_times_minutes(bool include_remaining) const; +#endif // ENABLE_GCODE_VIEWER // Returns the estimated time, in format DDd HHh MMm, for each custom_gcode // If include_remaining==true the strings will be formatted as: "time for custom_gcode (remaining time at color start)" +#if ENABLE_GCODE_VIEWER + std::vector>> get_custom_gcode_times_dhm(bool include_remaining) const; +#else std::vector> get_custom_gcode_times_dhm(bool include_remaining) const; +#endif // ENABLE_GCODE_VIEWER // Return an estimate of the memory consumed by the time estimator. size_t memory_used() const; diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index e4f4c60f57..eb9a4fb4b7 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -305,8 +305,15 @@ struct PrintStatistics PrintStatistics() { clear(); } std::string estimated_normal_print_time; std::string estimated_silent_print_time; +#if ENABLE_GCODE_VIEWER + std::vector>> estimated_normal_custom_gcode_print_times; + std::vector>> estimated_silent_custom_gcode_print_times; + std::vector>> estimated_normal_custom_gcode_print_times_str; + std::vector>> estimated_silent_custom_gcode_print_times_str; +#else std::vector> estimated_normal_custom_gcode_print_times; std::vector> estimated_silent_custom_gcode_print_times; +#endif // ENABLE_GCODE_VIEWER double total_used_filament; double total_extruded_volume; double total_cost; @@ -326,8 +333,15 @@ struct PrintStatistics void clear() { estimated_normal_print_time.clear(); estimated_silent_print_time.clear(); +#if ENABLE_GCODE_VIEWER + estimated_normal_custom_gcode_print_times_str.clear(); + estimated_silent_custom_gcode_print_times_str.clear(); estimated_normal_custom_gcode_print_times.clear(); estimated_silent_custom_gcode_print_times.clear(); +#else + estimated_normal_custom_gcode_print_times.clear(); + estimated_silent_custom_gcode_print_times.clear(); +#endif //ENABLE_GCODE_VIEWER total_used_filament = 0.; total_extruded_volume = 0.; total_cost = 0.; diff --git a/src/libslic3r/Technologies.hpp b/src/libslic3r/Technologies.hpp index fb84efe5ab..b04e78c4ed 100644 --- a/src/libslic3r/Technologies.hpp +++ b/src/libslic3r/Technologies.hpp @@ -59,8 +59,8 @@ // Enable G-Code viewer #define ENABLE_GCODE_VIEWER (1 && ENABLE_2_3_0_ALPHA1) -#define ENABLE_GCODE_VIEWER_STATISTICS (1 && ENABLE_GCODE_VIEWER) -#define ENABLE_GCODE_VIEWER_SHADERS_EDITOR (1 && ENABLE_GCODE_VIEWER) +#define ENABLE_GCODE_VIEWER_STATISTICS (0 && ENABLE_GCODE_VIEWER) +#define ENABLE_GCODE_VIEWER_SHADERS_EDITOR (0 && ENABLE_GCODE_VIEWER) #define ENABLE_GCODE_VIEWER_AS_STATE (1 && ENABLE_GCODE_VIEWER) diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index 688134f7c9..26dc765db4 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -4,6 +4,8 @@ #if ENABLE_GCODE_VIEWER #include "libslic3r/Print.hpp" #include "libslic3r/Geometry.hpp" +#include "libslic3r/Model.hpp" +#include "libslic3r/Utils.hpp" #include "GUI_App.hpp" #if ENABLE_GCODE_VIEWER_AS_STATE #include "MainFrame.hpp" @@ -17,10 +19,7 @@ #include "GLCanvas3D.hpp" #include "GLToolbar.hpp" #include "GUI_Preview.hpp" -#include "libslic3r/Model.hpp" -#if ENABLE_GCODE_VIEWER_STATISTICS #include -#endif // ENABLE_GCODE_VIEWER_STATISTICS #include #include @@ -187,15 +186,14 @@ void GCodeViewer::SequentialView::Marker::render() const static float last_window_width = 0.0f; static size_t last_text_length = 0; - static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); ImGuiWrapper& imgui = *wxGetApp().imgui(); Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size(); - imgui.set_next_window_pos(static_cast(cnv_size.get_width()), static_cast(cnv_size.get_height()), ImGuiCond_Always, 1.0f, 1.0f); + imgui.set_next_window_pos(0.5f * static_cast(cnv_size.get_width()), static_cast(cnv_size.get_height()), ImGuiCond_Always, 0.5f, 1.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::SetNextWindowBgAlpha(0.25f); imgui.begin(std::string("ToolPosition"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(_u8L("Tool position") + ":"); ImGui::PopStyleColor(); ImGui::SameLine(); @@ -270,6 +268,7 @@ bool GCodeViewer::init() { switch (buffer_type(i)) { + default: { break; } case GCodeProcessor::EMoveType::Tool_change: case GCodeProcessor::EMoveType::Color_change: case GCodeProcessor::EMoveType::Pause_Print: @@ -420,6 +419,7 @@ void GCodeViewer::render() const m_sequential_view.marker.render(); render_shells(); render_legend(); + render_time_estimate(); #if ENABLE_GCODE_VIEWER_STATISTICS render_statistics(); #endif // ENABLE_GCODE_VIEWER_STATISTICS @@ -458,6 +458,7 @@ unsigned int GCodeViewer::get_options_visibility_flags() const flags = set_flag(flags, static_cast(Preview::OptionType::Shells), m_shells.visible); flags = set_flag(flags, static_cast(Preview::OptionType::ToolMarker), m_sequential_view.marker.is_visible()); flags = set_flag(flags, static_cast(Preview::OptionType::Legend), is_legend_enabled()); + flags = set_flag(flags, static_cast(Preview::OptionType::TimeEstimate), is_time_estimate_enabled()); return flags; } @@ -477,6 +478,7 @@ void GCodeViewer::set_options_visibility_from_flags(unsigned int flags) m_shells.visible = is_flag_set(static_cast(Preview::OptionType::Shells)); m_sequential_view.marker.set_visible(is_flag_set(static_cast(Preview::OptionType::ToolMarker))); enable_legend(is_flag_set(static_cast(Preview::OptionType::Legend))); + enable_time_estimate(is_flag_set(static_cast(Preview::OptionType::TimeEstimate))); } void GCodeViewer::set_layers_z_range(const std::array& layers_z_range) @@ -591,8 +593,8 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const return ret; }; - Vec3f v1 = get_vertex(start_id); - Vec3f v2 = get_vertex(start_id + 1); + Vec3f v1 = get_vertex(start_id) - half_height * Vec3f::UnitZ(); + Vec3f v2 = get_vertex(start_id + 1) - half_height * Vec3f::UnitZ(); float length = (v2 - v1).norm(); const auto&& [dir, right, up] = local_basis(v2 - v1); return Segment({ v1, v2, dir, right, up, half_width * right, half_height * up, length }); @@ -605,7 +607,8 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const const RenderPath& render_path = buffer.render_paths[i]; const Path& path = buffer.paths[render_path.path_id]; float half_width = 0.5f * path.width; - float half_height = 0.5f * path.height; + // clamp height to avoid artifacts due to z-fighting when importing the obj file into blender and similar + float half_height = std::max(0.5f * path.height, 0.005f); // generates vertices/normals/triangles std::vector out_vertices; @@ -657,7 +660,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const out_triangles.push_back({ base_id + 5, base_id + 3, base_id + 2 }); // update right vertices - if (disp < prev.length) { + if (disp < prev.length && disp < curr.length) { base_id = out_vertices.size() - 6; out_vertices[base_id + 0] -= disp_vec; out_vertices[base_id + 4] = out_vertices[base_id + 0]; @@ -670,7 +673,7 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const out_triangles.push_back({ base_id + 0, base_id + 3, base_id + 4 }); // update left vertices - if (disp < prev.length) { + if (disp < prev.length && disp < curr.length) { base_id = out_vertices.size() - 6; out_vertices[base_id + 2] -= disp_vec; out_vertices[base_id + 5] = out_vertices[base_id + 2]; @@ -742,27 +745,25 @@ void GCodeViewer::export_toolpaths_to_obj(const char* filename) const } // save to file - fprintf(fp, "\n# vertices path %lld\n", i + 1); + fprintf(fp, "\n# vertices path %zu\n", i + 1); for (const Vec3f& v : out_vertices) { fprintf(fp, "v %g %g %g\n", v[0], v[1], v[2]); } - fprintf(fp, "\n# normals path %lld\n", i + 1); + fprintf(fp, "\n# normals path %zu\n", i + 1); for (const Vec3f& n : out_normals) { fprintf(fp, "vn %g %g %g\n", n[0], n[1], n[2]); } - fprintf(fp, "\n# material path %lld\n", i + 1); - fprintf(fp, "usemtl material_%lld\n", i + 1); + fprintf(fp, "\n# material path %zu\n", i + 1); + fprintf(fp, "usemtl material_%zu\n", i + 1); - fprintf(fp, "\n# triangles path %lld\n", i + 1); + fprintf(fp, "\n# triangles path %zu\n", i + 1); for (const Triangle& t : out_triangles) { - fprintf(fp, "f %lld//%lld %lld//%lld %lld//%lld\n", t[0], t[0], t[1], t[1], t[2], t[2]); + fprintf(fp, "f %zu//%zu %zu//%zu %zu//%zu\n", t[0], t[0], t[1], t[1], t[2], t[2]); } - } -// fprintf(fp, "\n#vertices count %lld\n", out_vertices_count); fclose(fp); } @@ -775,12 +776,12 @@ void GCodeViewer::init_shaders() for (unsigned char i = begin_id; i < end_id; ++i) { switch (buffer_type(i)) { - case GCodeProcessor::EMoveType::Tool_change: { m_buffers[i].shader = is_glsl_120 ? "options_120_solid" : "options_110"; break; } - case GCodeProcessor::EMoveType::Color_change: { m_buffers[i].shader = is_glsl_120 ? "options_120_solid" : "options_110"; break; } - case GCodeProcessor::EMoveType::Pause_Print: { m_buffers[i].shader = is_glsl_120 ? "options_120_solid" : "options_110"; break; } - case GCodeProcessor::EMoveType::Custom_GCode: { m_buffers[i].shader = is_glsl_120 ? "options_120_solid" : "options_110"; break; } - case GCodeProcessor::EMoveType::Retract: { m_buffers[i].shader = is_glsl_120 ? "options_120_solid" : "options_110"; break; } - case GCodeProcessor::EMoveType::Unretract: { m_buffers[i].shader = is_glsl_120 ? "options_120_solid" : "options_110"; break; } + case GCodeProcessor::EMoveType::Tool_change: { m_buffers[i].shader = is_glsl_120 ? "options_120_flat" : "options_110"; break; } + case GCodeProcessor::EMoveType::Color_change: { m_buffers[i].shader = is_glsl_120 ? "options_120_flat" : "options_110"; break; } + case GCodeProcessor::EMoveType::Pause_Print: { m_buffers[i].shader = is_glsl_120 ? "options_120_flat" : "options_110"; break; } + case GCodeProcessor::EMoveType::Custom_GCode: { m_buffers[i].shader = is_glsl_120 ? "options_120_flat" : "options_110"; break; } + case GCodeProcessor::EMoveType::Retract: { m_buffers[i].shader = is_glsl_120 ? "options_120_flat" : "options_110"; break; } + case GCodeProcessor::EMoveType::Unretract: { m_buffers[i].shader = is_glsl_120 ? "options_120_flat" : "options_110"; break; } case GCodeProcessor::EMoveType::Extrude: { m_buffers[i].shader = "toolpaths"; break; } case GCodeProcessor::EMoveType::Travel: { m_buffers[i].shader = "toolpaths"; break; } default: { break; } @@ -1137,7 +1138,7 @@ void GCodeViewer::refresh_render_paths(bool keep_sequential_current_first, bool } // second pass: filter paths by sequential data and collect them by color - for (auto&& [buffer, id] : paths) { + for (const auto& [buffer, id] : paths) { const Path& path = buffer->paths[id]; if (m_sequential_view.current.last <= path.first.s_id || path.last.s_id <= m_sequential_view.current.first) continue; @@ -1203,8 +1204,8 @@ void GCodeViewer::render_toolpaths() const shader.set_uniform("percent_outline_radius", 0.01f * static_cast(m_shaders_editor.points.percent_outline)); shader.set_uniform("percent_center_radius", 0.01f * static_cast(m_shaders_editor.points.percent_center)); #else - shader.set_uniform("percent_outline_radius", 0.15f); - shader.set_uniform("percent_center_radius", 0.15f); + shader.set_uniform("percent_outline_radius", 0.0f); + shader.set_uniform("percent_center_radius", 0.33f); #endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR shader.set_uniform("viewport", viewport); shader.set_uniform("inv_proj_matrix", inv_proj); @@ -1266,6 +1267,7 @@ void GCodeViewer::render_toolpaths() const switch (buffer_type(i)) { + default: { break; } case GCodeProcessor::EMoveType::Tool_change: { render_as_points(buffer, EOptionsColors::ToolChanges, *shader); break; } case GCodeProcessor::EMoveType::Color_change: { render_as_points(buffer, EOptionsColors::ColorChanges, *shader); break; } case GCodeProcessor::EMoveType::Pause_Print: { render_as_points(buffer, EOptionsColors::PausePrints, *shader); break; } @@ -1320,18 +1322,15 @@ void GCodeViewer::render_shells() const // glsafe(::glDepthMask(GL_TRUE)); } +#define USE_ICON_HEXAGON 1 + void GCodeViewer::render_legend() const { - static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); - static const ImU32 ICON_BORDER_COLOR = ImGui::GetColorU32(ImVec4(0.0f, 0.0f, 0.0f, 1.0f)); - if (!m_legend_enabled) return; ImGuiWrapper& imgui = *wxGetApp().imgui(); -#define USE_ICON_HEXAGON 1 - imgui.set_next_window_pos(0.0f, 0.0f, ImGuiCond_Always); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::SetNextWindowBgAlpha(0.6f); @@ -1347,19 +1346,14 @@ void GCodeViewer::render_legend() const Line }; -#if ENABLE_GCODE_VIEWER_SHADERS_EDITOR auto add_item = [this, draw_list, &imgui](EItemType type, const Color& color, const std::string& label, std::function callback = nullptr) { -#else - auto add_item = [draw_list, &imgui](EItemType type, const Color& color, const std::string& label, std::function callback = nullptr) { -#endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR float icon_size = ImGui::GetTextLineHeight(); - ImVec2 pos = ImGui::GetCursorPos(); + ImVec2 pos = ImGui::GetCursorScreenPos(); switch (type) { default: case EItemType::Rect: { - draw_list->AddRect({ pos.x, pos.y }, { pos.x + icon_size, pos.y + icon_size }, ICON_BORDER_COLOR, 0.0f, 0); draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f }, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f })); break; @@ -1380,37 +1374,26 @@ void GCodeViewer::render_legend() const } else draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); - -// ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size)); -// draw_list->AddCircle(center, 0.5f * icon_size, ICON_BORDER_COLOR, 16); -// if (m_shaders_editor.shader_version == 1) { -// draw_list->AddCircleFilled(center, (0.5f * icon_size) - 2.0f, -// ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16); -// float radius = ((0.5f * icon_size) - 2.0f) * (1.0f - 0.01f * static_cast(m_shaders_editor.percent_outline)); -// draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); -// if (m_shaders_editor.percent_center > 0) { -// radius = ((0.5f * icon_size) - 2.0f) * 0.01f * static_cast(m_shaders_editor.percent_center); -// draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16); -// } -// } else -// draw_list->AddCircleFilled(center, (0.5f * icon_size) - 2.0f, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); #else - draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, 0.5f * icon_size, - ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); - -// draw_list->AddCircle({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, 0.5f * icon_size, ICON_BORDER_COLOR, 16); -// draw_list->AddCircleFilled({ 0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size) }, (0.5f * icon_size) - 2.0f, -// ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); + ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size)); + if (m_buffers[buffer_id(GCodeProcessor::EMoveType::Retract)].shader == "options_120_flat") { + draw_list->AddCircleFilled(center, 0.5f * icon_size, + ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16); + float radius = 0.5f * icon_size; + draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); + radius = 0.5f * icon_size * 0.01f * 33.0f; + draw_list->AddCircleFilled(center, radius, ImGui::GetColorU32({ 0.5f * color[0], 0.5f * color[1], 0.5f * color[2], 1.0f }), 16); + } + else + draw_list->AddCircleFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 16); #endif // ENABLE_GCODE_VIEWER_SHADERS_EDITOR + break; } case EItemType::Hexagon: { ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size)); draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 6); -// draw_list->AddNgon(center, 0.5f * icon_size, ICON_BORDER_COLOR, 6); -// draw_list->AddNgonFilled(center, (0.5f * icon_size) - 2.0f, -// ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 6); break; } case EItemType::Line: @@ -1454,21 +1437,18 @@ void GCodeViewer::render_legend() const }; // extrusion paths -> title - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); switch (m_view_type) { - case EViewType::FeatureType: { imgui.text(_u8L("Feature type")); break; } - case EViewType::Height: { imgui.text(_u8L("Height (mm)")); break; } - case EViewType::Width: { imgui.text(_u8L("Width (mm)")); break; } - case EViewType::Feedrate: { imgui.text(_u8L("Speed (mm/s)")); break; } - case EViewType::FanSpeed: { imgui.text(_u8L("Fan Speed (%%)")); break; } - case EViewType::VolumetricRate: { imgui.text(_u8L("Volumetric flow rate (mm³/s)")); break; } - case EViewType::Tool: { imgui.text(_u8L("Tool")); break; } - case EViewType::ColorPrint: { imgui.text(_u8L("Color Print")); break; } - default: { break; } + case EViewType::FeatureType: { imgui.title(_u8L("Feature type")); break; } + case EViewType::Height: { imgui.title(_u8L("Height (mm)")); break; } + case EViewType::Width: { imgui.title(_u8L("Width (mm)")); break; } + case EViewType::Feedrate: { imgui.title(_u8L("Speed (mm/s)")); break; } + case EViewType::FanSpeed: { imgui.title(_u8L("Fan Speed (%%)")); break; } + case EViewType::VolumetricRate: { imgui.title(_u8L("Volumetric flow rate (mm³/s)")); break; } + case EViewType::Tool: { imgui.title(_u8L("Tool")); break; } + case EViewType::ColorPrint: { imgui.title(_u8L("Color Print")); break; } + default: { break; } } - ImGui::PopStyleColor(); - ImGui::Separator(); // extrusion paths -> items switch (m_view_type) @@ -1566,28 +1546,26 @@ void GCodeViewer::render_legend() const else { for (int i = items_cnt; i >= 0; --i) { // create label for color change item - std::string id_str = " (" + std::to_string(i + 1) + ")"; - if (i == 0) { #if USE_ICON_HEXAGON - add_item(EItemType::Hexagon, m_tool_colors[i], (boost::format(_u8L("up to %.2f mm")) % cp_values.front().first).str() + id_str); + add_item(EItemType::Hexagon, m_tool_colors[i], (boost::format(_u8L("up to %.2f mm")) % cp_values.front().first).str()); #else - add_item(EItemType::Rect, m_tool_colors[i], (boost::format(_u8L("up to %.2f mm")) % cp_values.front().first).str() + id_str); + add_item(EItemType::Rect, m_tool_colors[i], (boost::format(_u8L("up to %.2f mm")) % cp_values.front().first).str()); #endif // USE_ICON_HEXAGON break; } else if (i == items_cnt) { #if USE_ICON_HEXAGON - add_item(EItemType::Hexagon, m_tool_colors[i], (boost::format(_u8L("above %.2f mm")) % cp_values[i - 1].second).str() + id_str); + add_item(EItemType::Hexagon, m_tool_colors[i], (boost::format(_u8L("above %.2f mm")) % cp_values[i - 1].second).str()); #else - add_item(EItemType::Rect, m_tool_colors[i], (boost::format(_u8L("above %.2f mm")) % cp_values[i - 1].second).str() + id_str); + add_item(EItemType::Rect, m_tool_colors[i], (boost::format(_u8L("above %.2f mm")) % cp_values[i - 1].second).str()); #endif // USE_ICON_HEXAGON continue; } #if USE_ICON_HEXAGON - add_item(EItemType::Hexagon, m_tool_colors[i], (boost::format(_u8L("%.2f - %.2f mm")) % cp_values[i - 1].second% cp_values[i].first).str() + id_str); + add_item(EItemType::Hexagon, m_tool_colors[i], (boost::format(_u8L("%.2f - %.2f mm")) % cp_values[i - 1].second % cp_values[i].first).str()); #else - add_item(EItemType::Rect, m_tool_colors[i], (boost::format(_u8L("%.2f - %.2f mm")) % cp_values[i - 1].second% cp_values[i].first).str() + id_str); + add_item(EItemType::Rect, m_tool_colors[i], (boost::format(_u8L("%.2f - %.2f mm")) % cp_values[i - 1].second % cp_values[i].first).str()); #endif // USE_ICON_HEXAGON } } @@ -1609,15 +1587,12 @@ void GCodeViewer::render_legend() const size_t last_color_id = m_tool_colors.size() - 1; for (int i = static_cast(custom_gcode_per_print_z.size()) - 1; i >= 0; --i) { if (custom_gcode_per_print_z[i].type == ColorChange) { - // create label for color change item - std::string id_str = " (" + std::to_string(color_change_idx--) + ")"; - #if USE_ICON_HEXAGON add_item(EItemType::Hexagon, m_tool_colors[last_color_id--], #else add_item(EItemType::Rect, m_tool_colors[last_color_id--], #endif // USE_ICON_HEXAGON - (boost::format(_u8L("Color change for Extruder %d at %.2f mm")) % custom_gcode_per_print_z[i].extruder % custom_gcode_per_print_z[i].print_z).str() + id_str); + (boost::format(_u8L("Color change for Extruder %d at %.2f mm")) % custom_gcode_per_print_z[i].extruder % custom_gcode_per_print_z[i].print_z).str()); } } } @@ -1641,11 +1616,7 @@ void GCodeViewer::render_legend() const { // title ImGui::Spacing(); - ImGui::Spacing(); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); - imgui.text(_u8L("Travel")); - ImGui::PopStyleColor(); - ImGui::Separator(); + imgui.title(_u8L("Travel")); // items add_item(EItemType::Line, Travel_Colors[0], _u8L("Movement")); @@ -1657,13 +1628,18 @@ void GCodeViewer::render_legend() const } } - auto any_option_visible = [this]() { - return m_buffers[buffer_id(GCodeProcessor::EMoveType::Color_change)].visible || - m_buffers[buffer_id(GCodeProcessor::EMoveType::Custom_GCode)].visible || - m_buffers[buffer_id(GCodeProcessor::EMoveType::Pause_Print)].visible || - m_buffers[buffer_id(GCodeProcessor::EMoveType::Retract)].visible || - m_buffers[buffer_id(GCodeProcessor::EMoveType::Tool_change)].visible || - m_buffers[buffer_id(GCodeProcessor::EMoveType::Unretract)].visible; + auto any_option_available = [this]() { + auto available = [this](GCodeProcessor::EMoveType type) { + const TBuffer& buffer = m_buffers[buffer_id(type)]; + return buffer.visible && buffer.indices.count > 0; + }; + + return available(GCodeProcessor::EMoveType::Color_change) || + available(GCodeProcessor::EMoveType::Custom_GCode) || + available(GCodeProcessor::EMoveType::Pause_Print) || + available(GCodeProcessor::EMoveType::Retract) || + available(GCodeProcessor::EMoveType::Tool_change) || + available(GCodeProcessor::EMoveType::Unretract); }; auto add_option = [this, add_item](GCodeProcessor::EMoveType move_type, EOptionsColors color, const std::string& text) { @@ -1677,14 +1653,10 @@ void GCodeViewer::render_legend() const }; // options - if (any_option_visible()) { + if (any_option_available()) { // title ImGui::Spacing(); - ImGui::Spacing(); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); - imgui.text(_u8L("Options")); - ImGui::PopStyleColor(); - ImGui::Separator(); + imgui.title(_u8L("Options")); // items add_option(GCodeProcessor::EMoveType::Retract, EOptionsColors::Retractions, _u8L("Retractions")); @@ -1699,10 +1671,175 @@ void GCodeViewer::render_legend() const ImGui::PopStyleVar(); } +void GCodeViewer::render_time_estimate() const +{ + static const std::vector Columns_Headers = { + _u8L("Operation"), + _u8L("Remaining"), + _u8L("Duration") + }; + + if (!m_time_estimate_enabled) + return; + + const PrintStatistics& ps = wxGetApp().plater()->fff_print().print_statistics(); + if (ps.estimated_normal_print_time == "N/A" && ps.estimated_silent_print_time == "N/A") + return; + + int columns_count = 1; + if (ps.estimated_silent_print_time != "N/A") + ++columns_count; + + ImGuiWrapper& imgui = *wxGetApp().imgui(); + Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size(); + imgui.set_next_window_pos(static_cast(cnv_size.get_width()), static_cast(cnv_size.get_height()), ImGuiCond_Always, 1.0f, 1.0f); + ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, 0.0f), ImVec2(-1.0f, 0.5f * static_cast(cnv_size.get_height()))); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::SetNextWindowBgAlpha(0.6f); + imgui.begin(std::string("Time_estimate"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove); + + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + float icon_size = ImGui::GetTextLineHeight(); + + using Time = std::pair; + using TimesList = std::vector>; + using Headers = std::vector; + using Offsets = std::array; + + auto add_mode = [this, &imgui, icon_size, draw_list](const std::string& mode, const std::string& time, const TimesList& times, const Headers& headers) { + auto add_partial_times = [this, &imgui, icon_size, draw_list](const TimesList& times, const Headers& headers) { + auto add_color = [this, &imgui, icon_size, draw_list](int id, Offsets& offsets, const Time& time) { + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); + std::string text = _u8L("Color"); + if (m_view_type != EViewType::ColorPrint) + text += " " + std::to_string(id); + imgui.text(text); + ImGui::PopStyleColor(); + ImGui::SameLine(); + + if (m_view_type == EViewType::ColorPrint) { + const Color& color = m_tool_colors[id - 1]; + ImVec2 pos = ImGui::GetCursorScreenPos(); +#if USE_ICON_HEXAGON + ImVec2 center(0.5f * (pos.x + pos.x + icon_size), 0.5f * (pos.y + pos.y + icon_size)); + draw_list->AddNgonFilled(center, 0.5f * icon_size, ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f }), 6); +#else + draw_list->AddRectFilled({ pos.x + 1.0f, pos.y + 1.0f }, { pos.x + icon_size - 1.0f, pos.y + icon_size - 1.0f }, + ImGui::GetColorU32({ m_tool_colors[i][0], m_tool_colors[i][1], m_tool_colors[i][2], 1.0f })); +#endif // USE_ICON_HEXAGON + } + ImGui::SameLine(offsets[0]); + imgui.text(short_time(get_time_dhms(time.second))); + ImGui::SameLine(offsets[1]); + imgui.text(short_time(get_time_dhms(time.first))); + }; + auto calc_offsets = [this, icon_size](const TimesList& times, const Headers& headers, int color_change_count) { + Offsets ret = { ImGui::CalcTextSize(headers[0].c_str()).x, ImGui::CalcTextSize(headers[1].c_str()).x }; + for (const auto& [type, time] : times) { + std::string label; + switch (type) + { + case CustomGCode::PausePrint: + { + label = _u8L("Pause"); + break; + } + case CustomGCode::ColorChange: + { + label = _u8L("Color"); + if (m_view_type != EViewType::ColorPrint) + label += " " + std::to_string(color_change_count); + break; + } + default: { break; } + } + + ret[0] = std::max(ret[0], ImGui::CalcTextSize(label.c_str()).x); + ret[1] = std::max(ret[1], ImGui::CalcTextSize(short_time(get_time_dhms(time.second)).c_str()).x); + } + + const ImGuiStyle& style = ImGui::GetStyle(); + ret[0] += icon_size + style.ItemSpacing.x; + ret[1] += ret[0] + style.ItemSpacing.x; + return ret; + }; + + if (times.empty()) + return; + + int color_change_count = 0; + for (auto time : times) { + if (time.first == CustomGCode::ColorChange) + ++color_change_count; + } + + Offsets offsets = calc_offsets(times, headers, color_change_count); + + ImGui::Spacing(); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); + imgui.text(headers[0]); + ImGui::SameLine(offsets[0]); + imgui.text(headers[1]); + ImGui::SameLine(offsets[1]); + imgui.text(headers[2]); + ImGui::PopStyleColor(); + + int last_color_id = color_change_count; + + for (int i = static_cast(times.size()) - 1; i >= 0; --i) { + const auto& [type, time] = times[i]; + + switch (type) + { + case CustomGCode::PausePrint: + { + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); + imgui.text(_u8L("Pause")); + ImGui::PopStyleColor(); + ImGui::SameLine(offsets[0]); + imgui.text(short_time(get_time_dhms(time.second - time.first))); + + add_color(last_color_id, offsets, time); + break; + } + case CustomGCode::ColorChange: + { + add_color(color_change_count, offsets, time); + last_color_id = color_change_count--; + break; + } + default: { break; } + } + } + }; + + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); + imgui.text(mode + ":"); + ImGui::PopStyleColor(); + ImGui::SameLine(); + imgui.text(time); + add_partial_times(times, headers); + }; + + // title + imgui.title(_u8L("Estimated printing time")); + + // times + if (ps.estimated_normal_print_time != "N/A") + add_mode(_u8L("Normal mode"), ps.estimated_normal_print_time, ps.estimated_normal_custom_gcode_print_times, Columns_Headers); + + if (ps.estimated_silent_print_time != "N/A") { + ImGui::Separator(); + add_mode(_u8L("Stealth mode"), ps.estimated_silent_print_time, ps.estimated_silent_custom_gcode_print_times, Columns_Headers); + } + + imgui.end(); + ImGui::PopStyleVar(); +} + #if ENABLE_GCODE_VIEWER_STATISTICS void GCodeViewer::render_statistics() const { - static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); static const float offset = 230.0f; ImGuiWrapper& imgui = *wxGetApp().imgui(); @@ -1711,7 +1848,7 @@ void GCodeViewer::render_statistics() const imgui.begin(std::string("GCodeViewer Statistics"), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow()); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("GCodeProcessor time:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); @@ -1719,19 +1856,19 @@ void GCodeViewer::render_statistics() const ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("Load time:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); imgui.text(std::to_string(m_statistics.load_time) + " ms"); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("Resfresh time:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); imgui.text(std::to_string(m_statistics.refresh_time) + " ms"); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("Resfresh paths time:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); @@ -1739,13 +1876,13 @@ void GCodeViewer::render_statistics() const ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("Multi GL_POINTS calls:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); imgui.text(std::to_string(m_statistics.gl_multi_points_calls_count)); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("Multi GL_LINE_STRIP calls:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); @@ -1753,7 +1890,7 @@ void GCodeViewer::render_statistics() const ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("GCodeProcessor results:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); @@ -1761,13 +1898,13 @@ void GCodeViewer::render_statistics() const ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("Paths CPU:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); imgui.text(std::to_string(m_statistics.paths_size) + " bytes"); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("Render paths CPU:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); @@ -1775,13 +1912,13 @@ void GCodeViewer::render_statistics() const ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("Vertices GPU:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); imgui.text(std::to_string(m_statistics.vertices_gpu_size) + " bytes"); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("Indices GPU:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); @@ -1789,13 +1926,13 @@ void GCodeViewer::render_statistics() const ImGui::Separator(); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("Travel segments:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); imgui.text(std::to_string(m_statistics.travel_segments_count)); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); imgui.text(std::string("Extrude segments:")); ImGui::PopStyleColor(); ImGui::SameLine(offset); @@ -1816,8 +1953,6 @@ void GCodeViewer::render_shaders_editor() const } }; - static const ImVec4 ORANGE(1.0f, 0.49f, 0.22f, 1.0f); - ImGuiWrapper& imgui = *wxGetApp().imgui(); Size cnv_size = wxGetApp().plater()->get_current_canvas3D()->get_canvas_size(); @@ -1828,8 +1963,8 @@ void GCodeViewer::render_shaders_editor() const if (ImGui::CollapsingHeader("Points", ImGuiTreeNodeFlags_DefaultOpen)) { if (ImGui::TreeNode("GLSL version")) { ImGui::RadioButton("1.10 (low end PCs)", &m_shaders_editor.points.shader_version, 0); - ImGui::RadioButton("1.20 flat (billboards)", &m_shaders_editor.points.shader_version, 1); - ImGui::RadioButton("1.20 solid (spheres default)", &m_shaders_editor.points.shader_version, 2); + ImGui::RadioButton("1.20 flat (billboards) [default]", &m_shaders_editor.points.shader_version, 1); + ImGui::RadioButton("1.20 solid (spheres)", &m_shaders_editor.points.shader_version, 2); ImGui::TreePop(); } diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 137ae89af7..90155c7281 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -248,7 +248,7 @@ class GCodeViewer { struct Points { - int shader_version{ 2 }; + int shader_version{ 1 }; float point_size{ 0.8f }; int percent_outline{ 0 }; int percent_center{ 33 }; @@ -341,6 +341,7 @@ private: Shells m_shells; EViewType m_view_type{ EViewType::FeatureType }; bool m_legend_enabled{ true }; + bool m_time_estimate_enabled{ true }; #if ENABLE_GCODE_VIEWER_STATISTICS mutable Statistics m_statistics; #endif // ENABLE_GCODE_VIEWER_STATISTICS @@ -396,6 +397,9 @@ public: bool is_legend_enabled() const { return m_legend_enabled; } void enable_legend(bool enable) { m_legend_enabled = enable; } + bool is_time_estimate_enabled() const { return m_time_estimate_enabled; } + void enable_time_estimate(bool enable) { m_time_estimate_enabled = enable; } + void export_toolpaths_to_obj(const char* filename) const; private: @@ -406,6 +410,7 @@ private: void render_toolpaths() const; void render_shells() const; void render_legend() const; + void render_time_estimate() const; #if ENABLE_GCODE_VIEWER_STATISTICS void render_statistics() const; #endif // ENABLE_GCODE_VIEWER_STATISTICS diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f8ff9406f3..8c69142485 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -219,8 +219,6 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const if (!m_enabled) return; - 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(); @@ -228,50 +226,50 @@ void GLCanvas3D::LayersEditing::render_overlay(const GLCanvas3D& canvas) const 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.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::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); + imgui.text(_L("Left mouse button:")); ImGui::PopStyleColor(); ImGui::SameLine(); - imgui.text(_(L("Add detail"))); + imgui.text(_L("Add detail")); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); - imgui.text(_(L("Right mouse button:"))); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); + imgui.text(_L("Right mouse button:")); ImGui::PopStyleColor(); 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::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); + imgui.text(_L("Shift + Left mouse button:")); ImGui::PopStyleColor(); 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::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); + imgui.text(_L("Shift + Right mouse button:")); ImGui::PopStyleColor(); ImGui::SameLine(); - imgui.text(_(L("Smoothing"))); + imgui.text(_L("Smoothing")); - ImGui::PushStyleColor(ImGuiCol_Text, ORANGE); - imgui.text(_(L("Mouse wheel:"))); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); + imgui.text(_L("Mouse wheel:")); ImGui::PopStyleColor(); 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(EVT_GLCANVAS_ADAPTIVE_LAYER_HEIGHT_PROFILE, m_adaptive_quality)); ImGui::SameLine(); float text_align = ImGui::GetCursorPosX(); ImGui::AlignTextToFramePadding(); - imgui.text(_(L("Quality / Speed"))); + 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(); } @@ -282,13 +280,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); @@ -298,7 +296,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); @@ -307,7 +305,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(); @@ -3078,8 +3076,7 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) #if ENABLE_GCODE_VIEWER case 'L': case 'l': { - if (!m_main_toolbar.is_enabled()) - { + if (!m_main_toolbar.is_enabled()) { m_gcode_viewer.enable_legend(!m_gcode_viewer.is_legend_enabled()); m_dirty = true; wxGetApp().plater()->update_preview_bottom_toolbar(); @@ -3090,13 +3087,24 @@ void GLCanvas3D::on_char(wxKeyEvent& evt) case 'O': case 'o': { _update_camera_zoom(-1.0); break; } #if ENABLE_RENDER_PICKING_PASS - case 'T': - case 't': { + case 'P': + case 'p': { m_show_picking_texture = !m_show_picking_texture; - m_dirty = true; + m_dirty = true; break; } #endif // ENABLE_RENDER_PICKING_PASS +#if ENABLE_GCODE_VIEWER + case 'T': + case 't': { + if (!m_main_toolbar.is_enabled()) { + m_gcode_viewer.enable_time_estimate(!m_gcode_viewer.is_time_estimate_enabled()); + m_dirty = true; + wxGetApp().plater()->update_preview_bottom_toolbar(); + } + break; + } +#endif // ENABLE_GCODE_VIEWER case 'Z': #if ENABLE_GCODE_VIEWER case 'z': diff --git a/src/slic3r/GUI/GLShadersManager.cpp b/src/slic3r/GUI/GLShadersManager.cpp index cb47d79618..e62a81d39b 100644 --- a/src/slic3r/GUI/GLShadersManager.cpp +++ b/src/slic3r/GUI/GLShadersManager.cpp @@ -69,7 +69,7 @@ GLShaderProgram* GLShadersManager::get_current_shader() if (id == 0) return nullptr; - auto it = std::find_if(m_shaders.begin(), m_shaders.end(), [id](std::unique_ptr& p) { return p->get_id() == id; }); + auto it = std::find_if(m_shaders.begin(), m_shaders.end(), [id](std::unique_ptr& p) { return static_cast(p->get_id()) == id; }); return (it != m_shaders.end()) ? it->get() : nullptr; } diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 530165001f..50a820cfaa 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -323,7 +323,8 @@ bool Preview::init(wxWindow* parent, Model* model) get_option_type_string(OptionType::CustomGCodes) + "|0|" + get_option_type_string(OptionType::Shells) + "|0|" + get_option_type_string(OptionType::ToolMarker) + "|0|" + - get_option_type_string(OptionType::Legend) + "|1" + get_option_type_string(OptionType::Legend) + "|1|" + + get_option_type_string(OptionType::TimeEstimate) + "|1" ); Slic3r::GUI::create_combochecklist(m_combochecklist_options, GUI::into_u8(_L("Options")), options_items); #else @@ -1458,10 +1459,10 @@ wxString Preview::get_option_type_string(OptionType type) const case OptionType::Shells: { return _L("Shells"); } case OptionType::ToolMarker: { return _L("Tool marker"); } case OptionType::Legend: { return _L("Legend"); } + case OptionType::TimeEstimate: { return _L("Estimated printing time"); } default: { return ""; } } } - #endif // ENABLE_GCODE_VIEWER } // namespace GUI diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index bf174c2e09..ff3bf41371 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -149,7 +149,8 @@ public: CustomGCodes, Shells, ToolMarker, - Legend + Legend, + TimeEstimate }; Preview(wxWindow* parent, Model* model, DynamicPrintConfig* config, BackgroundSlicingProcess* process, diff --git a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp index cd42857247..9aaded6e3c 100644 --- a/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp +++ b/src/slic3r/GUI/Gizmos/GLGizmoFdmSupports.cpp @@ -650,8 +650,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l window_width = std::max(window_width, button_width); 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); + ImGui::PushStyleColor(ImGuiCol_Text, ImGuiWrapper::COL_ORANGE_LIGHT); m_imgui->text(caption); ImGui::PopStyleColor(); ImGui::SameLine(caption_max); diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 51a9a6d4eb..2c463dc2a5 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -44,6 +44,12 @@ static const std::map font_icons = { {ImGui::MaterialIconMarker , "resin" } }; +const ImVec4 ImGuiWrapper::COL_WINDOW_BACKGROND = { 0.133f, 0.133f, 0.133f, 0.8f }; +const ImVec4 ImGuiWrapper::COL_GREY_DARK = { 0.333f, 0.333f, 0.333f, 1.0f }; +const ImVec4 ImGuiWrapper::COL_GREY_LIGHT = { 0.4f, 0.4f, 0.4f, 1.0f }; +const ImVec4 ImGuiWrapper::COL_ORANGE_DARK = { 0.757f, 0.404f, 0.216f, 1.0f }; +const ImVec4 ImGuiWrapper::COL_ORANGE_LIGHT = { 1.0f, 0.49f, 0.216f, 1.0f }; + ImGuiWrapper::ImGuiWrapper() : m_glyph_ranges(nullptr) , m_font_cjk(false) @@ -751,6 +757,22 @@ void ImGuiWrapper::search_list(const ImVec2& size_, bool (*items_getter)(int, co check_box(_L("Search in English"), view_params.english); } +void ImGuiWrapper::title(const std::string& str) +{ + ImGuiWindow* window = ImGui::GetCurrentWindow(); + const float frame_height = ImGui::CalcTextSize(str.c_str(), nullptr, false).y; + + ImRect frame_bb; + frame_bb.Min = { window->WorkRect.Min.x, window->DC.CursorPos.y }; + frame_bb.Max = { window->WorkRect.Max.x, window->DC.CursorPos.y + frame_height }; + + frame_bb.Min.x -= IM_FLOOR(window->WindowPadding.x * 0.5f - 1.0f); + frame_bb.Max.x += IM_FLOOR(window->WindowPadding.x * 0.5f); + + window->DrawList->AddRectFilled(frame_bb.Min, frame_bb.Max, ImGui::GetColorU32(COL_ORANGE_DARK), 0.0f, 0); + text(str); +} + void ImGuiWrapper::disabled_begin(bool disabled) { wxCHECK_RET(!m_disabled, "ImGUI: Unbalanced disabled_begin() call"); @@ -970,20 +992,10 @@ void ImGuiWrapper::init_style() { ImGuiStyle &style = ImGui::GetStyle(); - auto set_color = [&](ImGuiCol_ col, unsigned hex_color) { - style.Colors[col] = ImVec4( - ((hex_color >> 24) & 0xff) / 255.0f, - ((hex_color >> 16) & 0xff) / 255.0f, - ((hex_color >> 8) & 0xff) / 255.0f, - (hex_color & 0xff) / 255.0f); + auto set_color = [&](ImGuiCol_ entity, ImVec4 color) { + style.Colors[entity] = color; }; - static const unsigned COL_WINDOW_BACKGROND = 0x222222cc; - static const unsigned COL_GREY_DARK = 0x555555ff; - static const unsigned COL_GREY_LIGHT = 0x666666ff; - static const unsigned COL_ORANGE_DARK = 0xc16737ff; - static const unsigned COL_ORANGE_LIGHT = 0xff7d38ff; - // Window style.WindowRounding = 4.0f; set_color(ImGuiCol_WindowBg, COL_WINDOW_BACKGROND); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index bf542e1381..f79bd3fbc8 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -80,6 +80,7 @@ public: bool undo_redo_list(const ImVec2& size, const bool is_undo, bool (*items_getter)(const bool, int, const char**), int& hovered, int& selected, int& mouse_wheel); void search_list(const ImVec2& size, bool (*items_getter)(int, const char** label, const char** tooltip), char* search_str, Search::OptionViewParameters& view_params, int& selected, bool& edited, int& mouse_wheel, bool is_localized); + void title(const std::string& str); void disabled_begin(bool disabled); void disabled_end(); @@ -89,6 +90,12 @@ public: bool want_text_input() const; bool want_any_input() const; + static const ImVec4 COL_WINDOW_BACKGROND; + static const ImVec4 COL_GREY_DARK; + static const ImVec4 COL_GREY_LIGHT; + static const ImVec4 COL_ORANGE_DARK; + static const ImVec4 COL_ORANGE_LIGHT; + private: void init_font(bool compress); void init_input(); diff --git a/src/slic3r/GUI/KBShortcutsDialog.cpp b/src/slic3r/GUI/KBShortcutsDialog.cpp index 51ba06ba45..66e5ac4878 100644 --- a/src/slic3r/GUI/KBShortcutsDialog.cpp +++ b/src/slic3r/GUI/KBShortcutsDialog.cpp @@ -183,7 +183,7 @@ void KBShortcutsDialog::fill_shortcuts() #endif // __linux__ #if ENABLE_RENDER_PICKING_PASS // Don't localize debugging texts. - { "T", "Toggle picking pass texture rendering on/off" }, + { "P", "Toggle picking pass texture rendering on/off" }, #endif // ENABLE_RENDER_PICKING_PASS }; @@ -203,7 +203,8 @@ void KBShortcutsDialog::fill_shortcuts() { L("Arrow Down"), L("Lower Layer") }, { "U", L("Upper Layer") }, { "D", L("Lower Layer") }, - { "L", L("Show/Hide Legend") } + { "L", L("Show/Hide Legend") }, + { "T", L("Show/Hide Estimated printing time") } }; m_full_shortcuts.push_back(std::make_pair(_L("Preview"), preview_shortcuts)); diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index eba169dc96..59b8e56f34 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -355,6 +355,10 @@ void MainFrame::update_layout() // Set new settings switch (m_layout) { + case ESettingsLayout::Unknown: + { + break; + } case ESettingsLayout::Old: { m_plater->Reparent(m_tabpanel); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 36fa83470a..d0b52426c2 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1330,8 +1330,12 @@ void Sidebar::update_sliced_info_sizer() wxString str_color = _L("Color"); wxString str_pause = _L("Pause"); - auto fill_labels = [str_color, str_pause](const std::vector>& times, - wxString& new_label, wxString& info_text) +#if ENABLE_GCODE_VIEWER + auto fill_labels = [str_color, str_pause](const std::vector>>& times, +#else + auto fill_labels = [str_color, str_pause](const std::vector>& times, +#endif // ENABLE_GCODE_VIEWER + wxString& new_label, wxString& info_text) { int color_change_count = 0; for (auto time : times) @@ -1348,19 +1352,31 @@ void Sidebar::update_sliced_info_sizer() if (i != (int)times.size() - 1 && times[i].first == CustomGCode::PausePrint) new_label += format_wxstr(" -> %1%", str_pause); +#if ENABLE_GCODE_VIEWER + info_text += format_wxstr("\n%1% (%2%)", times[i].second.first, times[i].second.second); +#else info_text += format_wxstr("\n%1%", times[i].second); +#endif // ENABLE_GCODE_VIEWER } }; if (ps.estimated_normal_print_time != "N/A") { new_label += format_wxstr("\n - %1%", _L("normal mode")); info_text += format_wxstr("\n%1%", ps.estimated_normal_print_time); +#if ENABLE_GCODE_VIEWER + fill_labels(ps.estimated_normal_custom_gcode_print_times_str, new_label, info_text); +#else fill_labels(ps.estimated_normal_custom_gcode_print_times, new_label, info_text); +#endif // ENABLE_GCODE_VIEWER } if (ps.estimated_silent_print_time != "N/A") { new_label += format_wxstr("\n - %1%", _L("stealth mode")); info_text += format_wxstr("\n%1%", ps.estimated_silent_print_time); +#if ENABLE_GCODE_VIEWER + fill_labels(ps.estimated_silent_custom_gcode_print_times_str, new_label, info_text); +#else fill_labels(ps.estimated_silent_custom_gcode_print_times, new_label, info_text); +#endif // ENABLE_GCODE_VIEWER } p->sliced_info->SetTextAndShow(siEstimatedTime, info_text, new_label); } @@ -2709,6 +2725,9 @@ void Plater::priv::reset() if (view3D->is_layers_editing_enabled()) view3D->enable_layers_editing(false); +#if ENABLE_GCODE_VIEWER + reset_gcode_toolpaths(); +#endif // ENABLE_GCODE_VIEWER #if ENABLE_GCODE_VIEWER_AS_STATE gcode_result.reset(); #endif // ENABLE_GCODE_VIEWER_AS_STATE @@ -2859,8 +2878,7 @@ unsigned int Plater::priv::update_background_process(bool force_validation, bool // Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared. // Otherwise they will be just refreshed. #if ENABLE_GCODE_VIEWER - if (this->preview != nullptr) - { + if (this->preview != nullptr) { // If the preview is not visible, the following line just invalidates the preview, // but the G-code paths or SLA preview are calculated first once the preview is made visible. this->preview->get_canvas3d()->reset_gcode_toolpaths();