From 6114a415cf3faef78ab50a1c79562bbbd980d2a3 Mon Sep 17 00:00:00 2001 From: "liz.li" Date: Thu, 5 Jan 2023 09:06:18 +0800 Subject: [PATCH] NEW:add statistics of all plates in preview Change-Id: Ia93ca5a31d07ae5d52a37bb7b6fb0e3b26cfd012 --- resources/images/im_all_plates_stats.svg | 7 + .../im_all_plates_stats_transparent.svg | 7 + src/slic3r/GUI/GCodeViewer.cpp | 243 ++++++++++++++++-- src/slic3r/GUI/GCodeViewer.hpp | 2 + src/slic3r/GUI/GLCanvas3D.cpp | 171 +++++++++++- src/slic3r/GUI/GLCanvas3D.hpp | 5 +- src/slic3r/GUI/IMToolbar.cpp | 5 + src/slic3r/GUI/IMToolbar.hpp | 6 +- src/slic3r/GUI/PartPlate.cpp | 19 ++ src/slic3r/GUI/PartPlate.hpp | 4 + src/slic3r/GUI/Plater.cpp | 30 ++- 11 files changed, 466 insertions(+), 33 deletions(-) create mode 100644 resources/images/im_all_plates_stats.svg create mode 100644 resources/images/im_all_plates_stats_transparent.svg diff --git a/resources/images/im_all_plates_stats.svg b/resources/images/im_all_plates_stats.svg new file mode 100644 index 0000000000..e0ac402c38 --- /dev/null +++ b/resources/images/im_all_plates_stats.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/resources/images/im_all_plates_stats_transparent.svg b/resources/images/im_all_plates_stats_transparent.svg new file mode 100644 index 0000000000..b60c5d3627 --- /dev/null +++ b/resources/images/im_all_plates_stats_transparent.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index c7c4f1480c..f1f1c8ad1a 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -4118,6 +4118,210 @@ void GCodeViewer::render_shells() // glsafe(::glDepthMask(GL_TRUE)); } +//BBS +void GCodeViewer::render_all_plates_stats(const std::vector& gcode_result_list, bool show /*= true*/) const { + if (!show) + return; + ImGuiWrapper& imgui = *wxGetApp().imgui(); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0, 10.0 * m_scale)); + ImGui::PushStyleColor(ImGuiCol_Separator, ImVec4(1.0f, 1.0f, 1.0f, 0.6f)); + ImGui::PushStyleColor(ImGuiCol_Header, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, ImVec4(0.00f, 0.68f, 0.26f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, ImVec4(0.42f, 0.42f, 0.42f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImVec4(0.93f, 0.93f, 0.93f, 1.00f)); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImVec4(0.93f, 0.93f, 0.93f, 1.00f)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(340.f * m_scale * imgui.scaled(1.0f / 15.0f), 0)); + + ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), 0, ImVec2(0.5f, 0.5f)); + ImGui::Begin(_L("Statistics of All Plates").c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + + std::vector filament_diameters = gcode_result_list.front()->filament_diameters; + std::vector filament_densities = gcode_result_list.front()->filament_densities; + std::vector filament_colors = decode_colors(wxGetApp().plater()->get_extruder_colors_from_plater_config(gcode_result_list.back())); + + bool imperial_units = wxGetApp().app_config->get("use_inches") == "1"; + float window_padding = 4.0f * m_scale; + const float icon_size = ImGui::GetTextLineHeight() * 0.7; + std::vector offsets; + std::map volume_of_extruders_all_plates; // map + std::map flushed_volume_of_extruders_all_plates; // map + std::vector model_used_filaments_m_all_plates; + std::vector model_used_filaments_g_all_plates; + std::vector flushed_filaments_m_all_plates; + std::vector flushed_filaments_g_all_plates; + float total_time_all_plates = 0.0f; + bool show_detailed_statistics_page = false; + + auto max_width = [](const std::vector& items, const std::string& title, float extra_size = 0.0f) { + float ret = ImGui::CalcTextSize(title.c_str()).x; + for (const std::string& item : items) { + ret = std::max(ret, extra_size + ImGui::CalcTextSize(item.c_str()).x); + } + return ret; + }; + auto calculate_offsets = [max_width, window_padding](const std::vector>>& title_columns, float extra_size = 0.0f) { + const ImGuiStyle& style = ImGui::GetStyle(); + std::vector offsets; + offsets.push_back(max_width(title_columns[0].second, title_columns[0].first, extra_size) + 3.0f * style.ItemSpacing.x + style.WindowPadding.x); + for (size_t i = 1; i < title_columns.size() - 1; i++) + offsets.push_back(offsets.back() + max_width(title_columns[i].second, title_columns[i].first) + style.ItemSpacing.x); + if (title_columns.back().first == _u8L("Display")) + offsets.back() = ImGui::GetWindowWidth() - ImGui::CalcTextSize(_u8L("Display").c_str()).x - ImGui::GetFrameHeight() / 2 - 2 * window_padding; + + float average_col_width = ImGui::GetWindowWidth() / static_cast(title_columns.size()); + std::vector ret; + ret.push_back(0); + for (size_t i = 1; i < title_columns.size(); i++) { + ret.push_back(std::max(offsets[i - 1], i * average_col_width)); + } + + return ret; + }; + auto append_item = [icon_size, &imgui, imperial_units, &window_padding, &draw_list, this](const Color& color, const std::vector>& columns_offsets) + { + // render icon + ImVec2 pos = ImVec2(ImGui::GetCursorScreenPos().x + window_padding * 3, ImGui::GetCursorScreenPos().y); + + draw_list->AddRectFilled({ pos.x + 1.0f * m_scale, pos.y + 3.0f * m_scale }, { pos.x + icon_size - 1.0f * m_scale, pos.y + icon_size + 1.0f * m_scale }, + ImGui::GetColorU32({ color[0], color[1], color[2], 1.0f })); + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(20.0 * m_scale, 6.0 * m_scale)); + + // render selectable + ImGui::Dummy({ 0.0, 0.0 }); + ImGui::SameLine(); + + // render column item + { + float dummy_size = ImGui::GetStyle().ItemSpacing.x + icon_size; + ImGui::SameLine(dummy_size); + imgui.text(columns_offsets[0].first); + + for (auto i = 1; i < columns_offsets.size(); i++) { + ImGui::SameLine(columns_offsets[i].second); + imgui.text(columns_offsets[i].first); + } + } + + ImGui::PopStyleVar(1); + }; + auto append_headers = [&imgui](const std::vector>& title_offsets) { + for (size_t i = 0; i < title_offsets.size(); i++) { + ImGui::SameLine(title_offsets[i].second); + imgui.bold_text(title_offsets[i].first); + } + ImGui::Separator(); + }; + auto get_used_filament_from_volume = [this, imperial_units, &filament_diameters, &filament_densities](double volume, int extruder_id) { + double koef = imperial_units ? 1.0 / GizmoObjectManipulation::in_to_mm : 0.001; + std::pair ret = { koef * volume / (PI * sqr(0.5 * filament_diameters[extruder_id])), + volume * filament_densities[extruder_id] * 0.001 }; + return ret; + }; + + ImGui::Dummy({ window_padding, window_padding }); + ImGui::SameLine(); + // title and item data + { + PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list(); + for (auto plate : plate_list.get_nonempty_plate_list()) + { + auto plate_print_statistics = plate->get_slice_result()->print_statistics; + auto plate_extruders = plate->get_extruders(true); + for (size_t extruder_id : plate_extruders) { + extruder_id -= 1; + if (plate_print_statistics.volumes_per_extruder.find(extruder_id) == plate_print_statistics.volumes_per_extruder.end()) + continue; + double volume = plate_print_statistics.volumes_per_extruder.at(extruder_id); + volume_of_extruders_all_plates[extruder_id] += volume; + if (plate_print_statistics.flush_per_filament.find(extruder_id) == plate_print_statistics.flush_per_filament.end()) + flushed_volume_of_extruders_all_plates[extruder_id] = 0; + else { + double flushed_volume = plate_print_statistics.flush_per_filament.at(extruder_id); + flushed_volume_of_extruders_all_plates[extruder_id] += flushed_volume; + } + } + const PrintEstimatedStatistics::Mode& plate_time_mode = plate_print_statistics.modes[static_cast(m_time_estimate_mode)]; + total_time_all_plates += plate_time_mode.time; + } + + for (auto it = volume_of_extruders_all_plates.begin(); it != volume_of_extruders_all_plates.end(); it++) { + auto [model_used_filament_m, model_used_filament_g] = get_used_filament_from_volume(it->second, it->first); + model_used_filaments_m_all_plates.push_back(model_used_filament_m); + model_used_filaments_g_all_plates.push_back(model_used_filament_g); + } + for (auto it = flushed_volume_of_extruders_all_plates.begin(); it != flushed_volume_of_extruders_all_plates.end(); it++) { + auto [flushed_filament_m, flushed_filament_g] = get_used_filament_from_volume(it->second, it->first); + if (flushed_filament_m != 0.0 || flushed_filament_g != 0.0) + show_detailed_statistics_page = true; + flushed_filaments_m_all_plates.push_back(flushed_filament_m); + flushed_filaments_g_all_plates.push_back(flushed_filament_g); + } + + char buff[64]; + double longest_str = 0.0; + for (auto i : model_used_filaments_g_all_plates) { + if (i > longest_str) + longest_str = i; + } + ::sprintf(buff, "%.2f", longest_str); + offsets = calculate_offsets({ {_u8L("Filament"), {""}}, {_u8L("Model"), {buff}}, {_u8L("Flushed"), {buff}}, /*{_u8L("Tower"), total_filaments},*/ {_u8L("Total"), {buff}} }, icon_size); + + if (!show_detailed_statistics_page) + append_headers({ {_u8L("Filament"), offsets[0]}, {_u8L("Model"), offsets[2]} }); + else + append_headers({ {_u8L("Filament"), offsets[0]}, {_u8L("Model"), offsets[1]}, {_u8L("Flushed"), offsets[2]}, /*{_u8L("Tower"), offsets[3]},*/ {_u8L("Total"), offsets[3]} });// to add Tower + } + + // item + { + size_t i = 0; + for (auto it = volume_of_extruders_all_plates.begin(); it != volume_of_extruders_all_plates.end(); it++) { + if (i < model_used_filaments_m_all_plates.size() && i < model_used_filaments_g_all_plates.size()) { + std::vector> columns_offsets; + columns_offsets.push_back({ std::to_string(it->first + 1), offsets[0] }); + + char buf[64]; + if (show_detailed_statistics_page) { + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", model_used_filaments_m_all_plates[i], model_used_filaments_g_all_plates[i]); + columns_offsets.push_back({ buf, offsets[1] }); + + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", flushed_filaments_m_all_plates[i], flushed_filaments_g_all_plates[i]); + columns_offsets.push_back({ buf, offsets[2] }); + + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", model_used_filaments_m_all_plates[i] + flushed_filaments_m_all_plates[i], model_used_filaments_g_all_plates[i] + flushed_filaments_g_all_plates[i]); + columns_offsets.push_back({ buf, offsets[3] }); + } + else { + ::sprintf(buf, imperial_units ? "%.2f in %.2f oz" : "%.2f m %.2f g", model_used_filaments_m_all_plates[i], model_used_filaments_g_all_plates[i]); + columns_offsets.push_back({ buf, offsets[2] }); + } + + append_item(filament_colors[it->first], columns_offsets); + } + i++; + } + + ImGui::Dummy(ImVec2(0.0f, ImGui::GetFontSize() * 0.1)); + ImGui::Dummy({ window_padding, window_padding }); + ImGui::SameLine(); + imgui.title(_u8L("Total Time Estimation")); + + ImGui::Dummy({ window_padding, window_padding }); + ImGui::SameLine(); + imgui.text(_u8L("Total time") + ":"); + ImGui::SameLine(); + imgui.text(short_time(get_time_dhms(total_time_all_plates))); + } + ImGui::End(); + ImGui::PopStyleColor(6); + ImGui::PopStyleVar(3); + return; +} + void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canvas_height, int right_margin) { if (!m_legend_enabled) @@ -4381,6 +4585,14 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv return std::make_pair(it->second.first * koef, it->second.second); }; + // get used filament (meters and grams) from used volume in respect to the active extruder + auto get_used_filament_from_volume = [this, imperial_units](double volume, int extruder_id) { + double koef = imperial_units ? 1.0 / GizmoObjectManipulation::in_to_mm : 0.001; + std::pair ret = { koef * volume / (PI * sqr(0.5 * m_filament_diameters[extruder_id])), + volume * m_filament_densities[extruder_id] * 0.001 }; + return ret; + }; + //BBS display Color Scheme ImGui::Dummy({ window_padding, window_padding }); ImGui::Dummy({ window_padding, window_padding }); @@ -4460,13 +4672,6 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv double koef = imperial_units ? GizmoObjectManipulation::in_to_mm : 1000.0; double unit_conver = imperial_units ? GizmoObjectManipulation::oz_to_g : 1; - // get used filament (meters and grams) from used volume in respect to the active extruder - auto get_used_filament_from_volume = [this, imperial_units](double volume, int extruder_id) { - double koef = imperial_units ? 1.0 / GizmoObjectManipulation::in_to_mm : 0.001; - std::pair ret = { koef * volume / (PI * sqr(0.5 * m_filament_diameters[extruder_id])), - volume * m_filament_densities[extruder_id] * 0.001 }; - return ret; - }; // extrusion paths section -> title ImGui::Dummy({ window_padding, window_padding }); @@ -4746,13 +4951,13 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv char buf[64]; if (show_flushed_filaments) { - ::sprintf(buf, imperial_units ? "%.2f in\n%.2f g" : "%.2f m\n%.2f g", model_used_filaments_m[i], model_used_filaments_g[i]); + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", model_used_filaments_m[i], model_used_filaments_g[i]); columns_offsets.push_back({ buf, offsets[1] }); - ::sprintf(buf, imperial_units ? "%.2f in\n%.2f g" : "%.2f m\n%.2f g", flushed_filaments_m[i], flushed_filaments_g[i]); + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", flushed_filaments_m[i], flushed_filaments_g[i]); columns_offsets.push_back({ buf, offsets[2] }); - ::sprintf(buf, imperial_units ? "%.2f in\n%.2f g" : "%.2f m\n%.2f g", model_used_filaments_m[i] + flushed_filaments_m[i], model_used_filaments_g[i] + flushed_filaments_g[i]); + ::sprintf(buf, imperial_units ? "%.2f in\n%.2f oz" : "%.2f m\n%.2f g", model_used_filaments_m[i] + flushed_filaments_m[i], model_used_filaments_g[i] + flushed_filaments_g[i]); columns_offsets.push_back({ buf, offsets[3] }); } else { @@ -5289,16 +5494,16 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv } default : { assert(false); break; } } + } - if (m_view_type == EViewType::ColorPrint) { - ImGui::Spacing(); - ImGui::Dummy({ window_padding, window_padding }); - ImGui::SameLine(); - offsets = calculate_offsets({ { _u8L("Options"), { ""}}, { _u8L("Display"), {""}} }, icon_size); - append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} }); - for (auto item : options_items) - append_option_item(item, offsets); - } + if (m_view_type == EViewType::ColorPrint) { + ImGui::Spacing(); + ImGui::Dummy({ window_padding, window_padding }); + ImGui::SameLine(); + offsets = calculate_offsets({ { _u8L("Options"), { ""}}, { _u8L("Display"), {""}} }, icon_size); + append_headers({ {_u8L("Options"), offsets[0] }, { _u8L("Display"), offsets[1]} }); + for (auto item : options_items) + append_option_item(item, offsets); } legend_height = ImGui::GetCurrentWindow()->Size.y; diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 465b3a6ec0..05cca2039c 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -805,6 +805,8 @@ public: void reset_shell(); void load_shells(const Print& print, bool initialized, bool force_previewing = false); void set_shells_on_preview(bool is_previewing) { m_shells.previewing = is_previewing; } + //BBS: add all plates filament statistics + void render_all_plates_stats(const std::vector& gcode_result_list, bool show = true) const; //BBS: GUI refactor: add canvas width and height void render(int canvas_width, int canvas_height, int right_margin); //BBS diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c3aaed90cd..8d09ef48b9 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1145,6 +1145,7 @@ GLCanvas3D::~GLCanvas3D() reset_volumes(); m_sel_plate_toolbar.del_all_item(); + m_sel_plate_toolbar.del_stats_item(); } void GLCanvas3D::post_event(wxEvent &&event) @@ -1593,6 +1594,11 @@ void GLCanvas3D::enable_main_toolbar(bool enable) m_main_toolbar.set_enabled(enable); } +void GLCanvas3D::reset_select_plate_toolbar_selection() { + if (m_sel_plate_toolbar.m_all_plates_stats_item) + m_sel_plate_toolbar.m_all_plates_stats_item->selected = false; +} + void GLCanvas3D::enable_select_plate_toolbar(bool enable) { m_sel_plate_toolbar.set_enabled(enable); @@ -1832,7 +1838,7 @@ void GLCanvas3D::render(bool only_init) _render_platelist(!camera.is_looking_downward(), only_current, only_body, hover_id); } /* preview render */ - else if (m_canvas_type == ECanvasType::CanvasPreview) { + else if (m_canvas_type == ECanvasType::CanvasPreview && m_render_preview) { //BBS: add outline logic _render_objects(GLVolumeCollection::ERenderType::Opaque, !m_gizmos.is_running()); //BBS: GUI refactor: add canvas size as parameters @@ -5802,6 +5808,9 @@ bool GLCanvas3D::_init_toolbars() if (!_init_separator_toolbar()) return false; + if (!_init_select_plate_toolbar()) + return false; + #if 0 if (!_init_view_toolbar()) return false; @@ -5967,7 +5976,24 @@ bool GLCanvas3D::_init_main_toolbar() //BBS: GUI refactor: GLToolbar bool GLCanvas3D::_init_select_plate_toolbar() { - return true; + std::string path = resources_dir() + "/images/"; + IMToolbarItem* item = new IMToolbarItem(); + bool result = item->image_texture.load_from_svg_file(path + "im_all_plates_stats.svg", false, false, false, 128); + result = result && item->image_texture_transparent.load_from_svg_file(path + "im_all_plates_stats_transparent.svg", false, false, false, 128); + m_sel_plate_toolbar.m_all_plates_stats_item = item; + + return result; +} + +void GLCanvas3D::_update_select_plate_toolbar_stats_item(bool force_selected) { + PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list(); + if (plate_list.get_nonempty_plate_list().size() > 1) + m_sel_plate_toolbar.show_stats_item = true; + else + m_sel_plate_toolbar.show_stats_item = false; + + if (force_selected && m_sel_plate_toolbar.show_stats_item) + m_sel_plate_toolbar.m_all_plates_stats_item->selected = true; } bool GLCanvas3D::_update_imgui_select_plate_toolbar() @@ -5975,6 +6001,8 @@ bool GLCanvas3D::_update_imgui_select_plate_toolbar() bool result = true; if (!m_sel_plate_toolbar.is_enabled()) return false; + _update_select_plate_toolbar_stats_item(); + m_sel_plate_toolbar.del_all_item(); PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list(); @@ -5990,6 +6018,7 @@ bool GLCanvas3D::_update_imgui_select_plate_toolbar() } m_sel_plate_toolbar.m_items.push_back(item); } + m_sel_plate_toolbar.is_display_scrollbar = false; return result; } @@ -7080,20 +7109,23 @@ void GLCanvas3D::_render_main_toolbar() //BBS: GUI refactor: GLToolbar adjust //when rendering, {0, 0} is at the center, {-0.5, 0.5} at the left-up -void GLCanvas3D::_render_imgui_select_plate_toolbar() const +void GLCanvas3D::_render_imgui_select_plate_toolbar() { if (!m_sel_plate_toolbar.is_enabled()) return; + IMToolbarItem* all_plates_stats_item = m_sel_plate_toolbar.m_all_plates_stats_item; + PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list(); for (int i = 0; i < plate_list.get_plate_count(); i++) { if (i < m_sel_plate_toolbar.m_items.size()) { - if (i == plate_list.get_curr_plate_index()) + if (i == plate_list.get_curr_plate_index() && !all_plates_stats_item->selected) m_sel_plate_toolbar.m_items[i]->selected = true; else m_sel_plate_toolbar.m_items[i]->selected = false; m_sel_plate_toolbar.m_items[i]->percent = plate_list.get_plate(i)->get_slicing_percent(); + if (plate_list.get_plate(i)->is_slice_result_valid()) { if (plate_list.get_plate(i)->is_slice_result_ready_for_print()) m_sel_plate_toolbar.m_items[i]->slice_state = IMToolbarItem::SliceState::SLICED; @@ -7107,6 +7139,39 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar() const m_sel_plate_toolbar.m_items[i]->slice_state = IMToolbarItem::SliceState::SLICING; } } + if (m_sel_plate_toolbar.show_stats_item) { + all_plates_stats_item->percent = 0.0f; + + size_t sliced_plates_cnt = 0; + bool slice_failed = false; + for (auto plate : plate_list.get_nonempty_plate_list()) { + if (plate->is_slice_result_valid() && plate->is_slice_result_ready_for_print()) + sliced_plates_cnt++; + if (plate->is_slice_result_valid() && !plate->is_slice_result_ready_for_print()) + slice_failed = true; + } + all_plates_stats_item->percent = (float)(sliced_plates_cnt) / (float)(plate_list.get_nonempty_plate_list().size()) * 100.0f; + + if (all_plates_stats_item->percent == 0.0f) + all_plates_stats_item->slice_state = IMToolbarItem::SliceState::UNSLICED; + else if (sliced_plates_cnt == plate_list.get_nonempty_plate_list().size()) + all_plates_stats_item->slice_state = IMToolbarItem::SliceState::SLICED; + else if (all_plates_stats_item->percent < 100.0f) + all_plates_stats_item->slice_state = IMToolbarItem::SliceState::SLICING; + + if (slice_failed) + all_plates_stats_item->slice_state = IMToolbarItem::SliceState::SLICE_FAILED; + + if (all_plates_stats_item->selected && all_plates_stats_item->slice_state == IMToolbarItem::SliceState::SLICED) { + m_gcode_viewer.render_all_plates_stats(plate_list.get_nonempty_plates_slice_results()); + m_render_preview = false; + } + else{ + m_gcode_viewer.render_all_plates_stats(plate_list.get_nonempty_plates_slice_results(), false); + m_render_preview = true; + } + }else + m_render_preview = true; // places the toolbar on the top_left corner of the 3d scene #if ENABLE_RETINA_GL @@ -7130,7 +7195,7 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar() const float button_margin = frame_padding; ImGuiWrapper& imgui = *wxGetApp().imgui(); - int item_count = m_sel_plate_toolbar.m_items.size(); + int item_count = m_sel_plate_toolbar.m_items.size() + (m_sel_plate_toolbar.show_stats_item ? 1 : 0); bool show_scroll = item_count * (button_height + frame_padding * 2.0f + button_margin) - button_margin + 22.0f * f_scale > canvas_h ? true: false; show_scroll = m_sel_plate_toolbar.is_display_scrollbar && show_scroll; float window_height = std::min(item_count * (button_height + (frame_padding + margin_size) * 2.0f + button_margin) - button_margin + 28.0f * f_scale, canvas_h); @@ -7171,7 +7236,89 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar() const ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint ImVec2 margin = ImVec2(margin_size, margin_size); - for (int i = 0; i < item_count; i++) { + if(m_sel_plate_toolbar.show_stats_item) + { + // draw image + ImVec2 button_start_pos = ImGui::GetCursorScreenPos(); + + if (all_plates_stats_item->selected) { + ImGui::PushStyleColor(ImGuiCol_Button, button_active); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, button_active); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, button_active); + } + else { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(128.0f, 128.0f, 128.0f, 0.0f)); + if (all_plates_stats_item->slice_state == IMToolbarItem::SliceState::SLICE_FAILED) { + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImGui::GetStyleColorVec4(ImGuiCol_Button)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImGui::GetStyleColorVec4(ImGuiCol_Button)); + } + else { + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, button_hover); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.42f, 0.42f, 0.42f, 1.0f)); + } + } + + ImVec4 text_clr; + ImTextureID btn_texture_id; + if (all_plates_stats_item->slice_state == IMToolbarItem::SliceState::UNSLICED || all_plates_stats_item->slice_state == IMToolbarItem::SliceState::SLICING || all_plates_stats_item->slice_state == IMToolbarItem::SliceState::SLICE_FAILED) + { + text_clr = ImVec4(0, 174.0f / 255.0f, 66.0f / 255.0f, 0.2f); + btn_texture_id = (ImTextureID)(intptr_t)(all_plates_stats_item->image_texture_transparent.get_id()); + } + else + { + text_clr = ImVec4(0, 174.0f / 255.0f, 66.0f / 255.0f, 1); + btn_texture_id = (ImTextureID)(intptr_t)(all_plates_stats_item->image_texture.get_id()); + } + + if (ImGui::ImageButton2(btn_texture_id, size, {0,0}, {1,1}, frame_padding, bg_col, tint_col, margin)) { + if (all_plates_stats_item->slice_state != IMToolbarItem::SliceState::SLICE_FAILED) { + if (m_process && !m_process->running()) { + for (int i = 0; i < m_sel_plate_toolbar.m_items.size(); i++) { + m_sel_plate_toolbar.m_items[i]->selected = false; + } + all_plates_stats_item->selected = true; + wxCommandEvent evt = wxCommandEvent(EVT_GLTOOLBAR_SLICE_ALL); + wxPostEvent(wxGetApp().plater(), evt); + } + } + } + + ImGui::PopStyleColor(3); + + ImVec2 start_pos = ImVec2(button_start_pos.x + frame_padding + margin.x, button_start_pos.y + frame_padding + margin.y); + if (all_plates_stats_item->slice_state == IMToolbarItem::SliceState::UNSLICED) { + ImVec2 size = ImVec2(button_width, button_height); + ImVec2 end_pos = ImVec2(start_pos.x + size.x, start_pos.y + size.y); + ImGui::GetForegroundDrawList()->AddRectFilled(start_pos, end_pos, IM_COL32(0, 0, 0, 80)); + } + else if (all_plates_stats_item->slice_state == IMToolbarItem::SliceState::SLICING) { + ImVec2 size = ImVec2(button_width, button_height * all_plates_stats_item->percent / 100.0f); + ImVec2 rect_start_pos = ImVec2(start_pos.x, start_pos.y + size.y); + ImVec2 rect_end_pos = ImVec2(start_pos.x + button_width, start_pos.y + button_height); + ImGui::GetForegroundDrawList()->AddRectFilled(rect_start_pos, rect_end_pos, IM_COL32(0, 0, 0, 80)); + } + else if (all_plates_stats_item->slice_state == IMToolbarItem::SliceState::SLICE_FAILED) { + ImVec2 size = ImVec2(button_width, button_height); + ImVec2 end_pos = ImVec2(start_pos.x + size.x, start_pos.y + size.y); + ImGui::GetForegroundDrawList()->AddRectFilled(start_pos, end_pos, IM_COL32(40, 1, 1, 64)); + ImGui::GetForegroundDrawList()->AddRect(start_pos, end_pos, IM_COL32(208, 27, 27, 255), 0.0f, 0, 1.0f); + } + + // draw text + GImGui->FontSize = 15.0f; + ImGui::PushStyleColor(ImGuiCol_Text, text_clr); + ImVec2 text_size = ImGui::CalcTextSize(_L("All Plates").c_str()); + ImVec2 text_start_pos = ImVec2(start_pos.x + (button_width - text_size.x) / 2, start_pos.y + 3.0f * button_height / 5.0f); + ImGui::RenderText(text_start_pos, _L("All Plates").c_str()); + text_size = ImGui::CalcTextSize(_L("Stats").c_str()); + text_start_pos = ImVec2(start_pos.x + (button_width - text_size.x) / 2, text_start_pos.y + ImGui::GetTextLineHeight()); + ImGui::RenderText(text_start_pos, _L("Stats").c_str()); + ImGui::PopStyleColor(); + ImGui::SetWindowFontScale(1.2f); + } + + for (int i = 0; i < m_sel_plate_toolbar.m_items.size(); i++) { IMToolbarItem* item = m_sel_plate_toolbar.m_items[i]; // draw image @@ -7183,11 +7330,16 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar() const if (item->selected) { ImGui::PushStyleColor(ImGuiCol_Button, button_active); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, button_active); - } else + } + else { + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(128.0f, 128.0f, 128.0f, 0.0f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.42f, 0.42f, 0.42f, 1.0f)); + } if (ImGui::ImageButton2(item->texture_id, size, uv0, uv1, frame_padding, bg_col, tint_col, margin)) { if (m_process && !m_process->running()) { + all_plates_stats_item->selected = false; + item->selected = true; // begin to slicing plate wxCommandEvent* evt = new wxCommandEvent(EVT_GLTOOLBAR_SELECT_SLICED_PLATE); evt->SetInt(i); @@ -7195,10 +7347,7 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar() const } } - if (item->selected) - ImGui::PopStyleColor(2); - else - ImGui::PopStyleColor(1); + ImGui::PopStyleColor(2); ImVec2 start_pos = ImVec2(button_start_pos.x + frame_padding + margin.x, button_start_pos.y + frame_padding + margin.y); if (item->slice_state == IMToolbarItem::SliceState::UNSLICED) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 82a20b2d19..e1b0787e3d 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -543,6 +543,7 @@ private: bool m_dirty; bool m_initialized; //BBS: add flag to controll rendering + bool m_render_preview{ true }; bool m_enable_render { true }; bool m_apply_zoom_to_volumes_filter; bool m_picking_enabled; @@ -785,6 +786,8 @@ public: void enable_selection(bool enable); void enable_main_toolbar(bool enable); //BBS: GUI refactor: GLToolbar + void _update_select_plate_toolbar_stats_item(bool force_selected = false); + void reset_select_plate_toolbar_selection(); void enable_select_plate_toolbar(bool enable); void enable_assemble_view_toolbar(bool enable); void enable_return_toolbar(bool enable); @@ -1097,7 +1100,7 @@ private: void _render_current_gizmo() const; void _render_gizmos_overlay(); void _render_main_toolbar(); - void _render_imgui_select_plate_toolbar() const; + void _render_imgui_select_plate_toolbar(); void _render_assemble_view_toolbar() const; void _render_return_toolbar() const; void _render_separator_toolbar_right() const; diff --git a/src/slic3r/GUI/IMToolbar.cpp b/src/slic3r/GUI/IMToolbar.cpp index f1d3481f3d..e14cdb2ffc 100644 --- a/src/slic3r/GUI/IMToolbar.cpp +++ b/src/slic3r/GUI/IMToolbar.cpp @@ -52,6 +52,11 @@ void IMToolbar::del_all_item() m_items.clear(); } +void IMToolbar::del_stats_item() +{ + delete m_all_plates_stats_item; + m_all_plates_stats_item = nullptr; +} bool IMReturnToolbar::init() { diff --git a/src/slic3r/GUI/IMToolbar.hpp b/src/slic3r/GUI/IMToolbar.hpp index c30b2e6ef0..681045fdb8 100644 --- a/src/slic3r/GUI/IMToolbar.hpp +++ b/src/slic3r/GUI/IMToolbar.hpp @@ -27,10 +27,11 @@ public: bool selected{ false }; float percent; - ImTextureID texture_id { 0 }; GLTexture image_texture; + GLTexture image_texture_transparent; SliceState slice_state; + ImTextureID texture_id { 0 }; std::vector image_data; unsigned int image_width; unsigned int image_height; @@ -47,6 +48,7 @@ public: float icon_width; float icon_height; bool is_display_scrollbar; + bool show_stats_item{ false }; IMToolbar() { icon_width = DEFAULT_TOOLBAR_BUTTON_WIDTH; @@ -54,7 +56,9 @@ public: } void del_all_item(); + void del_stats_item(); + IMToolbarItem* m_all_plates_stats_item = nullptr; std::vector m_items; float fontScale; diff --git a/src/slic3r/GUI/PartPlate.cpp b/src/slic3r/GUI/PartPlate.cpp index c2b18f3e98..cf86833ec1 100644 --- a/src/slic3r/GUI/PartPlate.cpp +++ b/src/slic3r/GUI/PartPlate.cpp @@ -3105,6 +3105,25 @@ PartPlate* PartPlateList::get_selected_plate() return m_plate_list[m_current_plate]; } +std::vector PartPlateList::get_nonempty_plate_list() +{ + std::vector nonempty_plate_list; + for (auto plate : m_plate_list){ + if (plate->get_extruders().size() != 0) { + nonempty_plate_list.push_back(plate); + } + } + return nonempty_plate_list; +} + +std::vector PartPlateList::get_nonempty_plates_slice_results() { + std::vector nonempty_plates_slice_result; + for (auto plate : get_nonempty_plate_list()) { + nonempty_plates_slice_result.push_back(plate->get_slice_result()); + } + return nonempty_plates_slice_result; +} + //select plate int PartPlateList::select_plate(int index) { diff --git a/src/slic3r/GUI/PartPlate.hpp b/src/slic3r/GUI/PartPlate.hpp index f2d76262c7..78305e2993 100644 --- a/src/slic3r/GUI/PartPlate.hpp +++ b/src/slic3r/GUI/PartPlate.hpp @@ -626,6 +626,10 @@ public: PartPlate* get_selected_plate(); + std::vector get_nonempty_plate_list(); + + std::vector get_nonempty_plates_slice_results(); + Vec3d get_current_plate_origin() { return compute_origin(m_current_plate, m_plate_cols); } Vec2d get_current_shape_position() { return compute_shape_position(m_current_plate, m_plate_cols); } Pointfs get_exclude_area() { return m_exclude_areas; } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 38d744680a..e14f031c85 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1688,6 +1688,8 @@ struct Plater::priv bool m_is_slicing {false}; bool m_is_publishing {false}; int m_cur_slice_plate; + //BBS: m_slice_all in .gcode.3mf file case, set true when slice all + bool m_slice_all_only_has_gcode{ false }; bool m_need_update{false}; //BBS: add popup object table logic @@ -5310,6 +5312,9 @@ void Plater::priv::set_current_panel(wxPanel* panel, bool no_slice) return; } + //BBS: wish to reset all plates stats item selected state when back to View3D Tab + preview->get_canvas3d()->reset_select_plate_toolbar_selection(); + wxPanel* old_panel = current_panel; //#if BBL_HAS_FIRST_PAGE if (!old_panel) { @@ -5810,6 +5815,20 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt) //BBS: add project slice logic bool is_finished = !m_slice_all || (m_cur_slice_plate == (partplate_list.get_plate_count() - 1)); + //BBS: slice .gcode.3mf file related logic, assign is_finished again + bool only_has_gcode_need_preview = false; + auto plate_list = this->partplate_list.get_plate_list(); + bool has_print_instances = false; + for (auto plate : plate_list) + has_print_instances = has_print_instances || plate->has_printable_instances(); + if (this->model.objects.empty() && !has_print_instances) + only_has_gcode_need_preview = true; + if (only_has_gcode_need_preview && m_slice_all_only_has_gcode) { + is_finished = (m_cur_slice_plate == (partplate_list.get_plate_count() - 1)); + if (is_finished) + m_slice_all_only_has_gcode = false; + } + // Stop the background task, wait until the thread goes into the "Idle" state. // At this point of time the thread should be either finished or canceled, // so the following call just confirms, that the produced data were consumed. @@ -6058,12 +6077,15 @@ void Plater::priv::on_action_slice_all(SimpleEvent&) Plater::setExtruderParams(Slic3r::Model::extruderParamsMap); Plater::setPrintSpeedTable(Slic3r::Model::printSpeedMap); m_slice_all = true; + m_slice_all_only_has_gcode = true; m_cur_slice_plate = 0; //select plate q->select_plate(m_cur_slice_plate); q->reslice(); if (!m_is_publishing) q->select_view_3D("Preview"); + //BBS: wish to select all plates stats item + preview->get_canvas3d()->_update_select_plate_toolbar_stats_item(true); } } @@ -8090,7 +8112,13 @@ void Plater::force_update_all_plate_thumbnails() } // BBS: backup -std::vector Plater::load_files(const std::vector& input_files, LoadStrategy strategy, bool ask_multi) { return p->load_files(input_files, strategy, ask_multi); } +std::vector Plater::load_files(const std::vector& input_files, LoadStrategy strategy, bool ask_multi) { + //BBS: wish to reset state when load a new file + p->m_slice_all_only_has_gcode = false; + //BBS: wish to reset all plates stats item selected state when load a new file + p->preview->get_canvas3d()->reset_select_plate_toolbar_selection(); + return p->load_files(input_files, strategy, ask_multi); +} // To be called when providing a list of files to the GUI slic3r on command line. std::vector Plater::load_files(const std::vector& input_files, LoadStrategy strategy, bool ask_multi)