diff --git a/resources/images/filament_green.svg b/resources/images/filament_green.svg new file mode 100644 index 000000000..1a417fbb9 --- /dev/null +++ b/resources/images/filament_green.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/imgui/imconfig.h b/src/imgui/imconfig.h index 358912148..13f542bbe 100644 --- a/src/imgui/imconfig.h +++ b/src/imgui/imconfig.h @@ -215,5 +215,7 @@ namespace ImGui const wchar_t ClipboardBtnIcon = 0x0848; const wchar_t ClipboardBtnDarkIcon = 0x0849; // void MyFunction(const char* name, const MyMatrix44& v); + + const wchar_t FilamentGreen = 0x0850; } diff --git a/src/slic3r/GUI/BitmapCache.cpp b/src/slic3r/GUI/BitmapCache.cpp index 8e5990c89..5582ece23 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 { @@ -541,6 +542,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 bbfecd715..e321d3e56 100644 --- a/src/slic3r/GUI/BitmapCache.hpp +++ b/src/slic3r/GUI/BitmapCache.hpp @@ -8,6 +8,7 @@ #ifndef WX_PRECOMP #include #endif +#include struct NSVGimage; @@ -52,6 +53,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) @@ -61,4 +65,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 389b7d7e2..6bcae6e08 100644 --- a/src/slic3r/GUI/GCodeViewer.cpp +++ b/src/slic3r/GUI/GCodeViewer.cpp @@ -1012,6 +1012,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 @@ -4576,6 +4586,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) @@ -4868,10 +4963,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(); + 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 + boost::nowide::widen(std::string("")); @@ -4881,13 +4981,25 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.0f, 0.68f, 0.26f, 1.00f)); ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.0f, 0.68f, 0.26f, 0.78f)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f)); - //ImGui::PushItemWidth( float button_width = ImGui::CalcTextSize(into_u8(btn_name).c_str()).x; if (ImGui::Button(into_u8(btn_name).c_str(), ImVec2(button_width, 0))) { m_fold = !m_fold; } ImGui::PopStyleColor(3); ImGui::PopStyleVar(1); + + 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::SameLine(); imgui.bold_text(_u8L("Color Scheme")); push_combo_style(); @@ -4920,14 +5032,6 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv ImGui::SameLine(); ImGui::Dummy({ window_padding, window_padding }); - if (m_fold) { - legend_height = ImGui::GetStyle().WindowPadding.y + ImGui::GetFrameHeight() + window_padding * 2.5; - 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 ae0c1ca38..2887c4961 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -751,6 +751,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; @@ -911,6 +916,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 ec50a49fc..79a92cb16 100644 --- a/src/slic3r/GUI/ImGuiWrapper.cpp +++ b/src/slic3r/GUI/ImGuiWrapper.cpp @@ -133,6 +133,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" } }; static const std::map font_icons_extra_large = { @@ -2840,6 +2841,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 ca4259714..f5d89f8a7 100644 --- a/src/slic3r/GUI/ImGuiWrapper.hpp +++ b/src/slic3r/GUI/ImGuiWrapper.hpp @@ -153,6 +153,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). @@ -335,7 +337,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); - };