From fb2226208a1747204b747d65915837a63923ee53 Mon Sep 17 00:00:00 2001 From: Mack Date: Thu, 4 Jul 2024 21:00:39 +0800 Subject: [PATCH] NEW: gcode viewer add recommended colour filament widget Change-Id: I37f38a175bb3f4a574a4855f8fef04e704da259c (cherry picked from commit 4014c61f889f5cf0b7830123fb0a72690ff4e1e5) --- deps_src/imgui/imconfig.h | 2 + resources/images/filament_green.svg | 8 ++ src/slic3r/GUI/BitmapCache.cpp | 62 +++++++++++++- src/slic3r/GUI/BitmapCache.hpp | 6 +- src/slic3r/GUI/GCodeViewer.cpp | 126 +++++++++++++++++++++++++--- src/slic3r/GUI/GCodeViewer.hpp | 6 ++ src/slic3r/GUI/ImGuiWrapper.cpp | 34 ++++++++ src/slic3r/GUI/ImGuiWrapper.hpp | 3 +- 8 files changed, 232 insertions(+), 15 deletions(-) create mode 100644 resources/images/filament_green.svg diff --git a/deps_src/imgui/imconfig.h b/deps_src/imgui/imconfig.h index bd83a3c44e..9f38c09797 100644 --- a/deps_src/imgui/imconfig.h +++ b/deps_src/imgui/imconfig.h @@ -228,5 +228,7 @@ namespace ImGui const wchar_t OpenHoverDarkButton = 0x085B; // void MyFunction(const char* name, const MyMatrix44& v); + + const wchar_t FilamentGreen = 0x0850; } diff --git a/resources/images/filament_green.svg b/resources/images/filament_green.svg new file mode 100644 index 0000000000..1a417fbb9f --- /dev/null +++ b/resources/images/filament_green.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index db334cd998..73dbdb7e5f 100644 --- a/src/slic3r/GUI/BitmapCache.cpp +++ b/src/slic3r/GUI/BitmapCache.cpp @@ -13,11 +13,12 @@ #include #include #endif /* __WXGTK2__ */ - +#include #define NANOSVG_IMPLEMENTATION #include "nanosvg/nanosvg.h" #define NANOSVGRAST_IMPLEMENTATION #include "nanosvg/nanosvgrast.h" +#include "3DScene.hpp" namespace Slic3r { namespace GUI { @@ -553,6 +554,65 @@ bool BitmapCache::parse_color4(const std::string& scolor, unsigned char* rgba_ou } return true; } +//BBS Replace svg green with the specified colour +bool BitmapCache::load_from_svg_file_change_color(const std::string &filename, unsigned width, unsigned height, ImTextureID &texture_id, const char *hexColor) +{ + NSVGimage* image = nsvgParseFromFile(filename.c_str(), "px", 96.0f); + if (image == nullptr) { + return false; + } + + unsigned int change_color = nsvg__parseColorHex(hexColor); + change_color |= (unsigned int) (1.0f * 255) << 24; // opacity + unsigned int green_color = 4282560000; + for (NSVGshape* shape = image->shapes; shape != nullptr; shape = shape->next) { + // find green color + if (shape->fill.color == green_color) { + shape->fill.color = change_color; + } + } + + float scale = (float)width / image->width; + + int n_pixels = width * height; + + if (n_pixels <= 0) { + nsvgDelete(image); + return false; + } + + NSVGrasterizer* rast = nsvgCreateRasterizer(); + if (rast == nullptr) { + nsvgDelete(image); + return false; + } + std::vector data(n_pixels * 4, 0); + nsvgRasterize(rast, image, 0, 0, scale, data.data(), width, height, width * 4); + + bool compress = false; + GLint last_texture; + unsigned m_image_texture{ 0 }; + unsigned char* pixels = (unsigned char*)(&data[0]); + + glsafe(::glGetIntegerv(GL_TEXTURE_BINDING_2D, &last_texture)); + glsafe(::glGenTextures(1, &m_image_texture)); + glsafe(::glBindTexture(GL_TEXTURE_2D, m_image_texture)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + glsafe(::glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + glsafe(::glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)); + glsafe(::glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels)); + + // Store our identifier + texture_id = (ImTextureID)(intptr_t)m_image_texture; + + // Restore state + glsafe(::glBindTexture(GL_TEXTURE_2D, last_texture)); + + nsvgDeleteRasterizer(rast); + nsvgDelete(image); + + return true; +} } // namespace GUI } // namespace Slic3r diff --git a/src/slic3r/GUI/BitmapCache.hpp b/src/slic3r/GUI/BitmapCache.hpp index dd8ef5a450..e2ebe75314 100644 --- a/src/slic3r/GUI/BitmapCache.hpp +++ b/src/slic3r/GUI/BitmapCache.hpp @@ -8,6 +8,7 @@ #ifndef WX_PRECOMP #include #endif +#include #include "libslic3r/Color.hpp" struct NSVGimage; @@ -54,6 +55,9 @@ public: static bool parse_color(const std::string& scolor, unsigned char* rgb_out); static bool parse_color4(const std::string& scolor, unsigned char* rgba_out); + static bool load_from_svg_file_change_color(const std::string &filename, unsigned width, unsigned height, ImTextureID &texture_id, const char *hexColor); + + private: std::map m_map; double m_gs = 0.2; // value, used for image.ConvertToGreyscale(m_gs, m_gs, m_gs) @@ -63,4 +67,4 @@ private: } // GUI } // Slic3r -#endif /* SLIC3R_GUI_BITMAP_CACHE_HPP */ +#endif // SLIC3R_GUI_BITMAP_CACHE_HPP diff --git a/src/slic3r/GUI/GCodeViewer.cpp b/src/slic3r/GUI/GCodeViewer.cpp index cc0ff7f8b8..aae3d7beb7 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -960,6 +960,16 @@ void GCodeViewer::load(const GCodeProcessorResult& gcode_result, const Print& pr m_gcode_result = &gcode_result; m_only_gcode_in_preview = only_gcode; + std::vector filament_maps = print.get_filament_maps(); + std::vector color_opt = print.config().option("filament_colour")->values; + std::vector type_opt = print.config().option("filament_type")->values; + for (int i = 0; i < filament_maps.size(); ++i) { + if (filament_maps[i] == 1) { + m_left_extruder_filament.emplace_back(type_opt[i], color_opt[i]); + } else { + m_right_extruder_filament.emplace_back(type_opt[i], color_opt[i]); + } + } m_sequential_view.gcode_window.load_gcode(gcode_result.filename, gcode_result.lines_ends); //BBS: add only gcode mode @@ -4359,6 +4369,91 @@ void GCodeViewer::render_all_plates_stats(const std::vectorAddLine(lineStart, lineEnd, HyperColor); + + if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)); + } + }; + + ////BBS Color Arrangement Recommendation + ImGui::Dummy({ window_padding, window_padding }); + ImGui::Dummy({ window_padding, window_padding }); + ImGui::SameLine(); + imgui.title(_u8L("Color Arrangement Recommendation")); + //BBS AMS containers + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(window_padding * 3, 0)); + ImGui::BeginChild("#AMS", ImVec2(0, 230.0f), false, ImGuiWindowFlags_AlwaysUseWindowPadding); + { + // BBS save time; + imgui.text(_u8L("Since you set 1 AMS")); + ImGui::SameLine(); + // BBS change button + link_text(_u8L("(change)")); + ImGui::SameLine(); + imgui.text(_u8L(",this arrangement would be optimal.")); + imgui.text(_u8L("It will save 738g filament and 23 minutes")); + + float available_width = ImGui::GetContentRegionAvail().x; + float available_height = ImGui::GetContentRegionAvail().y; + float half_width = available_width * 0.5f; + float spacing = 12.0f * m_scale; + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.00f, 0.00f, 0.00f, 0.3f)); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(window_padding * 2, window_padding)); + ImDrawList *child_begin_draw_list = ImGui::GetWindowDrawList(); + ImVec2 cursor_pos = ImGui::GetCursorScreenPos(); + child_begin_draw_list->AddRectFilled(cursor_pos, ImVec2(cursor_pos.x + half_width, cursor_pos.y + 24.0f * m_scale), IM_COL32(0, 0, 0, 64)); + ImGui::BeginChild("#LeftAMS", ImVec2(half_width, available_height - 20 * m_scale), false, ImGuiWindowFlags_AlwaysUseWindowPadding); + { + imgui.bold_text(_u8L("Left")); + ImGui::Dummy({window_padding, window_padding}); + int index = 1; + for (const auto &extruder_filament : m_left_extruder_filament) { + imgui.filament_group(extruder_filament.first, extruder_filament.second.c_str()); + if (index % 4 != 0) { ImGui::SameLine(0, spacing); } + } + ImGui::EndChild(); + } + ImGui::SameLine(); + cursor_pos = ImGui::GetCursorScreenPos(); + child_begin_draw_list->AddRectFilled(cursor_pos, ImVec2(cursor_pos.x + half_width, cursor_pos.y + 24.0f * m_scale), IM_COL32(0, 0, 0, 64)); + ImGui::BeginChild("#RightAMS", ImVec2(half_width, available_height - 20 * m_scale), false, ImGuiWindowFlags_AlwaysUseWindowPadding); + { + imgui.bold_text(_u8L("Right")); + ImGui::Dummy({window_padding, window_padding}); + int index = 1; + for (const auto &extruder_filament : m_right_extruder_filament) { + imgui.filament_group(extruder_filament.first, extruder_filament.second.c_str()); + if (index % 4 != 0) { ImGui::SameLine(0, spacing); } + } + ImGui::EndChild(); + } + ImGui::PopStyleColor(1); + ImGui::PopStyleVar(1); + link_text(_u8L("Customize Arrangement")); + ImGui::EndChild(); + } + ImGui::PopStyleVar(1); +} + void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canvas_height, int right_margin) { if (!m_legend_enabled) @@ -4651,10 +4746,15 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv return ret; }; - //BBS display Color Scheme + //BBS Slicing Result title ImGui::Dummy({ window_padding, window_padding }); ImGui::Dummy({ window_padding, window_padding }); ImGui::SameLine(window_padding * 2); // ORCA Ignores item spacing to get perfect window margins since since this part uses dummies for window padding + std::string title = _u8L("Slicing Result"); + imgui.bold_text(title); + ImVec2 longest_text_size = imgui.calc_text_size(_u8L("Since you set 1 AMS (change) ,this arrangement would be optimal.")); + ImVec2 title_text_size = imgui.calc_text_size(title); + ImGui::SameLine(0, longest_text_size.x - title_text_size.x); std::wstring btn_name; if (m_fold) btn_name = ImGui::UnfoldButtonIcon; @@ -4666,7 +4766,6 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv float calc_padding = (ImGui::GetFrameHeight() - 16 * m_scale) / 2; // ORCA calculated padding for 16x16 icon ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(calc_padding, calc_padding)); // ORCA Center icon with frame padding ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f * m_scale); // ORCA Match button style with combo box - float button_width = 16 * m_scale + calc_padding * 2; // ORCA match buttons height with combo box if (ImGui::Button(into_u8(btn_name).c_str(), ImVec2(button_width, button_width))) { m_fold = !m_fold; @@ -4681,6 +4780,19 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ImGui::PopStyleColor(3); ImGui::PopStyleVar(2); + if (m_fold) { + legend_height = ImGui::GetStyle().WindowPadding.y + ImGui::GetFrameHeight() + window_padding * 2.5; + imgui.end(); + ImGui::PopStyleColor(6); + ImGui::PopStyleVar(2); + return; + } + + render_legend_color_arr_recommen(window_padding); + + //BBS display Color Scheme + ImGui::Dummy({ window_padding, window_padding }); + //imgui.bold_text(_u8L("Color Scheme")); push_combo_style(); @@ -4714,16 +4826,6 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ImGui::Dummy({ window_padding, window_padding }); // ORCA Matches top-bottom window paddings float window_width = ImGui::GetWindowWidth(); // ORCA Store window width - if (m_fold) { - legend_height = ImGui::GetFrameHeight() + window_padding * 4; // ORCA using 4 instead 2 gives correct toolbar margins while its folded - ImGui::SameLine(window_width); // ORCA use stored window width while folded. This prevents annoying position change on fold/expand button - ImGui::Dummy({ 0, 0 }); - imgui.end(); - ImGui::PopStyleColor(6); - ImGui::PopStyleVar(2); - return; - } - // data used to properly align items in columns when showing time std::vector offsets; std::vector labels; diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index 94a7b0bc43..216afd150a 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -739,6 +739,11 @@ private: bool m_only_gcode_in_preview {false}; std::vector m_ssid_to_moveid_map; + //BBS: extruder dispensing filament + //std::pair + std::vector> m_left_extruder_filament; + std::vector> m_right_extruder_filament; + std::vector m_buffers{ static_cast(EMoveType::Extrude) }; // bounding box of toolpaths BoundingBoxf3 m_paths_bounding_box; @@ -898,6 +903,7 @@ private: //BBS: GUI refactor: add canvas size void render_legend(float &legend_height, int canvas_width, int canvas_height, int right_margin); + void render_legend_color_arr_recommen(float window_padding); void render_slider(int canvas_width, int canvas_height); #if ENABLE_GCODE_VIEWER_STATISTICS diff --git a/src/slic3r/GUI/ImGuiWrapper.cpp b/src/slic3r/GUI/ImGuiWrapper.cpp index 6b93098aa2..36c6863d96 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -134,6 +134,7 @@ static const std::map font_icons_large = { {ImGui::PrevArrowBtnIcon, "notification_arrow_left" }, {ImGui::NextArrowBtnIcon, "notification_arrow_right" }, {ImGui::CompleteIcon, "notification_slicing_complete" }, + {ImGui::FilamentGreen, "filament_green" }, {ImGui::PlayButton, "notification_play" }, {ImGui::PlayDarkButton, "notification_play_dark" }, @@ -3159,6 +3160,39 @@ void ImGuiWrapper::clipboard_set(void* /* user_data */, const char* text) } } +void ImGuiWrapper::filament_group(const std::string &filament_type, const char *hex_color) +{ + //ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + ImDrawList *draw_list = ImGui::GetWindowDrawList(); + static ImTextureID transparent; + ImVec2 img_size = {30.0f, 45.0f}; + ImVec2 text_size = ImGui::CalcTextSize(filament_type.c_str()); + BitmapCache::load_from_svg_file_change_color(Slic3r::resources_dir() + "/images/filament_green.svg", img_size.x, img_size.y, transparent, hex_color); + ImGui::BeginGroup(); + { + ImVec2 cursor_pos = ImGui::GetCursorScreenPos(); + draw_list->AddImage(transparent, cursor_pos, {cursor_pos.x + img_size.x, cursor_pos.y + img_size.y}, {0, 0}, {1, 1}, ImGui::GetColorU32(ImVec4(1.f, 1.f, 1.f, 1.f))); + // image border test + // draw_list->AddRect(cursor_pos, {cursor_pos.x + img_size.x, cursor_pos.y + img_size.y}, IM_COL32(0, 0, 0, 255)); + ImVec2 current_cursor = ImGui::GetCursorPos(); + ImGui::SetCursorPos({current_cursor.x + (img_size.x - text_size.x) * 0.5f, current_cursor.y + 40}); + this->text(filament_type); + ImGui::EndGroup(); + } + //ImGui::PopStyleVar(1); +} + +void ImGuiWrapper::sub_title(const std::string &label) +{ + ImDrawList *draw_list = ImGui::GetWindowDrawList(); + text_colored(ImVec4(1.0f, 1.0f, 1.0f, 0.5f), label); + ImGui::SameLine(); + ImVec2 cursor_pos = ImGui::GetCursorScreenPos(); + float available_width = ImGui::GetContentRegionAvail().x; + draw_list->AddLine(ImVec2(cursor_pos.x, cursor_pos.y + 8.0f), ImVec2(cursor_pos.x + available_width, cursor_pos.y + 8.0f), IM_COL32(255, 255, 255, 100)); + ImGui::NewLine(); +} + bool IMTexture::load_from_svg_file(const std::string& filename, unsigned width, unsigned height, ImTextureID& texture_id) { NSVGimage* image = nsvgParseFromFile(filename.c_str(), "px", 96.0f); diff --git a/src/slic3r/GUI/ImGuiWrapper.hpp b/src/slic3r/GUI/ImGuiWrapper.hpp index 65c8225120..5cb60d010b 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -155,6 +155,8 @@ public: void text_wrapped(const wxString &label, float wrap_width); void tooltip(const char *label, float wrap_width); void tooltip(const wxString &label, float wrap_width); + void filament_group(const std::string &filament_type, const char *hex_color); + void sub_title(const std::string &label); // Float sliders: Manually inserted values aren't clamped by ImGui.Using this wrapper function does (when clamp==true). @@ -388,7 +390,6 @@ class IMTexture public: // load svg file to thumbnail data, specific width, height is thumbnailData width, height static bool load_from_svg_file(const std::string& filename, unsigned width, unsigned height, ImTextureID &texture_id); - };