NEW: gcode viewer add recommended colour filament widget

Change-Id: I37f38a175bb3f4a574a4855f8fef04e704da259c
(cherry picked from commit 4014c61f889f5cf0b7830123fb0a72690ff4e1e5)
This commit is contained in:
Mack
2024-07-04 21:00:39 +08:00
committed by Noisyfox
parent f33f2fbc7d
commit fb2226208a
8 changed files with 232 additions and 15 deletions

View File

@@ -13,11 +13,12 @@
#include <wx/mstream.h>
#include <wx/rawbmp.h>
#endif /* __WXGTK2__ */
#include <GL/glew.h>
#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<unsigned char> 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

View File

@@ -8,6 +8,7 @@
#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif
#include <imgui/imgui.h>
#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<std::string, wxBitmap*> 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

View File

@@ -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<int> filament_maps = print.get_filament_maps();
std::vector<std::string> color_opt = print.config().option<ConfigOptionStrings>("filament_colour")->values;
std::vector<std::string> type_opt = print.config().option<ConfigOptionStrings>("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::vector<const GCodeProcessor
return;
}
void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
{
ImGuiWrapper &imgui = *wxGetApp().imgui();
auto link_text = [&](std::string &label) {
ImVec2 wiki_part_size = ImGui::CalcTextSize(label.c_str());
ImColor HyperColor = ImColor(48, 221, 114, 255).Value;
ImGui::PushStyleColor(ImGuiCol_Text, HyperColor.Value);
imgui.text(label.c_str());
ImGui::PopStyleColor();
// click behavior
if (ImGui::IsMouseHoveringRect(ImGui::GetItemRectMin(), ImGui::GetItemRectMax(), true)) {
// underline
ImVec2 lineEnd = ImGui::GetItemRectMax();
lineEnd.y -= 2.0f;
ImVec2 lineStart = lineEnd;
lineStart.x = ImGui::GetItemRectMin().x;
ImGui::GetWindowDrawList()->AddLine(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<float> offsets;
std::vector<std::string> labels;

View File

@@ -739,6 +739,11 @@ private:
bool m_only_gcode_in_preview {false};
std::vector<size_t> m_ssid_to_moveid_map;
//BBS: extruder dispensing filament
//std::pair<TYPE, CLOUR>
std::vector<std::pair<std::string, std::string>> m_left_extruder_filament;
std::vector<std::pair<std::string, std::string>> m_right_extruder_filament;
std::vector<TBuffer> m_buffers{ static_cast<size_t>(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

View File

@@ -134,6 +134,7 @@ static const std::map<const wchar_t, std::string> 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);

View File

@@ -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);
};