mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-19 11:23:42 +00:00
NEW: gcode viewer add recommended colour filament widget
Change-Id: I37f38a175bb3f4a574a4855f8fef04e704da259c (cherry picked from commit 4014c61f889f5cf0b7830123fb0a72690ff4e1e5)
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user