#include "AmsMappingPopup.hpp" #include "I18N.hpp" #include "libslic3r/Utils.hpp" #include "libslic3r/Thread.hpp" #include "slic3r/Utils/WxFontUtils.hpp" #include "GUI.hpp" #include "GUI_App.hpp" #include "DeviceCore/DevConfigUtil.h" #include "GUI_Preview.hpp" #include "MainFrame.hpp" #include "format.hpp" #include "Widgets/ProgressDialog.hpp" #include "Widgets/RoundedRectangle.hpp" #include "Widgets/StaticBox.hpp" #include #include #include #include #include #include #include #include #include "Plater.hpp" #include "BitmapCache.hpp" #include "BindDialog.hpp" #include "FilamentBitmapUtils.hpp" #include "DeviceCore/DevFilaSystem.h" #include "DeviceCore/DevFilaSwitch.h" #include "DeviceCore/DevMappingNozzle.h" #include "DeviceCore/DevNozzleRack.h" // Orca: full type for m_rack.lock()->GetNozzleSystem()->GetOwner() #include "DeviceTab/wgtDeviceNozzleSelect.h" #include "DeviceTab/wgtMsgPanel.h" namespace Slic3r { namespace GUI { #define MATERIAL_ITEM_SIZE wxSize(FromDIP(65), FromDIP(50)) #define MATERIAL_REC_WHEEL_SIZE wxSize(FromDIP(17), FromDIP(16)) #define MAPPING_ITEM_REAL_SIZE wxSize(FromDIP(48), FromDIP(60)) wxDEFINE_EVENT(EVT_SET_FINISH_MAPPING, wxCommandEvent); const int LEFT_OFFSET = 2; MaterialItem::MaterialItem(wxWindow *parent, wxColour mcolour, wxString mname, std::string filament_id) : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) { m_arraw_bitmap_gray = ScalableBitmap(this, "drop_down2", FromDIP(8)); m_arraw_bitmap_white = ScalableBitmap(this, "topbar_dropdown", 12); m_transparent_mitem = ScalableBitmap(this, "transparent_material_up", 20); m_filament_wheel_transparent = ScalableBitmap(this, "filament_transparent", 25);//wxGetApp().dark_mode() ? "filament_dark_transparent" //m_ams_wheel_mitem = ScalableBitmap(this, "ams_wheel", FromDIP(25)); m_ams_wheel_mitem = ScalableBitmap(this, "ams_wheel_narrow", 25); m_ams_not_match = ScalableBitmap(this, "filament_not_mactch", 25); m_rack_nozzle_bitmap = ScalableBitmap(this, "dev_rack_nozzle_print_job", 22); m_material_coloul = mcolour; m_material_name = mname; m_ams_coloul = wxColour(0xEE,0xEE,0xEE); m_filament_id = filament_id; #ifdef __WINDOWS__ SetDoubleBuffered(true); #endif //__WINDOWS__ messure_size(); SetBackgroundColour(*wxWHITE); Bind(wxEVT_PAINT, &MaterialItem::paintEvent, this); wxGetApp().UpdateDarkUI(this); } MaterialItem::~MaterialItem() {} void MaterialItem::msw_rescale() { m_arraw_bitmap_gray.msw_rescale(); m_arraw_bitmap_white.msw_rescale(); m_transparent_mitem.msw_rescale(); m_ams_wheel_mitem.msw_rescale(); } void MaterialItem::allow_paint_dropdown(bool flag) { if (m_dropdown_allow_painted != flag) { m_dropdown_allow_painted = flag; } } void MaterialItem::set_ams_text(const wxString& txt) { if (m_ams_name != txt) { m_ams_name = txt; messure_size(); Refresh(); } } void MaterialItem::set_ams_info(wxColour col, wxString txt, int ctype, std::vector cols, bool record_back_info) { auto need_refresh = false; if (record_back_info) { m_back_ams_cols = cols; m_back_ams_ctype = ctype; m_back_ams_coloul = col; m_back_ams_name = txt; } if (m_ams_cols != cols) { m_ams_cols = cols; need_refresh = true; } if (m_ams_ctype != ctype) { m_ams_ctype = ctype; need_refresh = true; } if (m_ams_coloul != col) { m_ams_coloul = col; need_refresh = true;} if (m_ams_name != txt) { m_ams_name = txt; need_refresh = true; } if (need_refresh) { messure_size(); Refresh(); } BOOST_LOG_TRIVIAL(info) << "set_ams_info " << m_ams_name; } void MaterialItem::set_nozzle_info(const wxString& mapped_nozzle_str) { if (m_mapped_nozzle_str != mapped_nozzle_str) { m_mapped_nozzle_str = mapped_nozzle_str; messure_size(); Refresh(); } } void MaterialItem::set_material_cols(int ctype, const std::vector& cols) { if (m_material_ctype != ctype || m_material_cols != cols) { m_material_ctype = ctype; m_material_cols = cols; Refresh(); } } void MaterialItem::reset_ams_info() { m_ams_name = "-"; m_ams_coloul = wxColour(0xCE, 0xCE, 0xCE); m_ams_cols.clear(); m_ams_ctype = 0; m_mapped_nozzle_str.Clear(); messure_size(); Refresh(); } void MaterialItem::disable() { if (IsEnabled()) { m_enable = false; } } void MaterialItem::enable() { if (!IsEnabled()) { m_enable = true; } } void MaterialItem::on_selected() { if (!m_selected) { m_selected = true; Refresh(); } } void MaterialItem::on_warning() { if (!m_warning) { m_warning = true; Refresh(); } } void MaterialItem::on_normal() { if (m_selected || m_warning) { m_selected = false; m_warning = false; Refresh(); } } void MaterialItem::paintEvent(wxPaintEvent &evt) { wxPaintDC dc(this); render(dc); } void MaterialItem::render(wxDC &dc) { if (m_ams_name.empty()) { m_mapping_text = "-"; } else { m_mapping_text = m_ams_name; } if (m_mapping_text == "-") { m_match = false;} else {m_match = true;} #ifdef __WXMSW__ wxSize size = GetSize(); wxMemoryDC memdc; wxBitmap bmp(size.x, size.y); memdc.SelectObject(bmp); memdc.Blit({0, 0}, size, &dc, {0, 0}); { wxGCDC dc2(memdc); doRender(dc2); } memdc.SelectObject(wxNullBitmap); dc.DrawBitmap(bmp, 0, 0); #else doRender(dc); #endif } void MaterialItem::match(bool mat) { m_match = mat; Refresh(); } static constexpr size_t MAPPED_NOZZLE_STR_MAX_CHARS_PER_LINE = 7; static wxString s_wrap_mapped_nozzle_str(const wxString& text) { if (text.length() <= MAPPED_NOZZLE_STR_MAX_CHARS_PER_LINE) { return text; } wxArrayString parts = wxSplit(text, ','); wxString wrapped; std::vector buffers; for (auto& part : parts) { if (!part.empty()) { buffers.push_back(part.Trim(false).Trim(true)); } if (buffers.size() > 2) { if (!wrapped.empty()) { wrapped += "\n"; } wrapped += buffers[0]; wrapped += " "; wrapped += buffers[1]; wrapped += " "; wrapped += buffers[2]; buffers.clear(); } } if (!wrapped.empty()) { wrapped += "\n"; } if (buffers.size() > 0) { wrapped += buffers[0]; } if (buffers.size() > 1) { wrapped += " "; wrapped += buffers[1]; } return wrapped; } static int s_get_mapped_nozzle_str_line_count(const wxString& text) { if (text.empty()) { return 0; } return std::max(1, static_cast(wxSplit(s_wrap_mapped_nozzle_str(text), '\n', '\0').size())); } void MaterialItem::doRender(wxDC& dc) { wxSize size = GetSize(); auto mcolor = m_material_coloul; auto acolor = m_ams_coloul; change_the_opacity(acolor); if (mcolor.Alpha() == 0) { dc.DrawBitmap(m_transparent_mitem.bmp(), FromDIP(1), FromDIP(1)); } if (!IsEnabled()) { mcolor = wxColour(0x90, 0x90, 0x90); acolor = wxColour(0x90, 0x90, 0x90); } //top dc.SetPen(*wxTRANSPARENT_PEN); if (m_material_cols.size() > 1 && IsEnabled()) { int top_h = FromDIP(20); bool drawn = false; wxGraphicsContext* gc = dc.GetGraphicsContext(); if (gc) { double r = FromDIP(5); auto make_path = [&](double x, double w, bool left_round, bool right_round) { wxGraphicsPath p = gc->CreatePath(); double rl = left_round ? std::min(r, std::min(w, top_h)) : 0.0; double rr = right_round ? std::min(r, std::min(w, top_h)) : 0.0; p.MoveToPoint(x, top_h); p.AddLineToPoint(x, rl); if (rl > 0) p.AddArc(x + rl, rl, rl, M_PI, -M_PI / 2, true); p.AddLineToPoint(x + w - rr, 0); if (rr > 0) p.AddArc(x + w - rr, rr, rr, -M_PI / 2, 0, true); p.AddLineToPoint(x + w, top_h); p.CloseSubpath(); return p; }; if (m_material_ctype == 0) { wxGraphicsPath path = make_path(0, size.x, true, true); wxGraphicsGradientStops stops(m_material_cols.front(), m_material_cols.back()); for (size_t i = 1; i + 1 < m_material_cols.size(); i++) { float pos = (float)i / (m_material_cols.size() - 1); stops.Add(m_material_cols[i], pos); } gc->SetBrush(gc->CreateLinearGradientBrush(0, 0, size.x, 0, stops)); gc->FillPath(path); } else { int cols_size = m_material_cols.size(); for (int i = 0; i < cols_size; i++) { double x0 = (double)size.x * i / cols_size; double w = (i == cols_size - 1) ? (size.x - x0) : ((double)size.x / cols_size); wxGraphicsPath seg = make_path(x0, w, i == 0, i == cols_size - 1); gc->SetBrush(gc->CreateBrush(wxBrush(m_material_cols[i]))); gc->FillPath(seg); } } drawn = true; } if (!drawn) { if (m_material_ctype == 0) { int seg = m_material_cols.size() - 1; int gw = std::round((double)size.x / seg); for (int i = 0; i < seg; i++) { int x0 = gw * i; int w = (i == seg - 1) ? (size.x - x0) : gw; fill_gradient_rect_east(dc, wxRect(x0, 0, w, top_h), m_material_cols[i], m_material_cols[i + 1]); } } else { int cols_size = m_material_cols.size(); int cw = std::round((double)size.x / cols_size); for (int i = 0; i < cols_size; i++) { dc.SetBrush(wxBrush(m_material_cols[i])); int x0 = cw * i; int w = (i == cols_size - 1) ? (size.x - x0) : cw; dc.DrawRectangle(x0, 0, w, top_h); } } } } else { dc.SetBrush(wxBrush(mcolor)); dc.DrawRoundedRectangle(0, 0, size.x, FromDIP(20), 5); dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(wxBrush(mcolor)); dc.DrawRectangle(0, FromDIP(10), size.x, FromDIP(10)); } // materials name auto up = 0; auto material_name_colour = mcolor.GetLuminance() < 0.6 ? *wxWHITE : wxColour(0x26, 0x2E, 0x30); if (mcolor.Alpha() == 0) { material_name_colour = wxColour(0x26, 0x2E, 0x30); } dc.SetTextForeground(material_name_colour); dc.SetFont(::Label::Body_12); if (dc.GetTextExtent(m_material_name).x > GetSize().x - 10) { dc.SetFont(::Label::Body_10); } auto material_txt_size = dc.GetTextExtent(m_material_name); dc.DrawText(m_material_name, wxPoint((GetSize().x - material_txt_size.x) / 2, (FromDIP(20) - material_txt_size.y) / 2)); dc.SetPen(wxColour(0xAC, 0xAC, 0xAC)); dc.DrawLine(FromDIP(1), FromDIP(20), FromDIP(size.x), FromDIP(20)); up += FromDIP(20); up += FromDIP(2); // spacing //bottom rectangle in wheel bitmap, size is MATERIAL_REC_WHEEL_SIZE(22) auto paint_recty = up + (m_ams_wheel_mitem.GetBmpSize().y - MATERIAL_REC_WHEEL_SIZE.y) / 2; auto left = (size.x / 2 - MATERIAL_REC_WHEEL_SIZE.x) / 2 + FromDIP(3); auto right = left + MATERIAL_REC_WHEEL_SIZE.x - FromDIP(3); dc.SetPen(*wxTRANSPARENT_PEN); //bottom if (m_ams_cols.size() > 1) { int gwidth = std::round(MATERIAL_REC_WHEEL_SIZE.x / (m_ams_cols.size() - 1)); //gradient if (m_ams_ctype == 0) { for (int i = 0; i < m_ams_cols.size() - 1; i++) { auto rect = wxRect(left, paint_recty, right - left, MATERIAL_REC_WHEEL_SIZE.y); fill_gradient_rect_east(dc, rect, m_ams_cols[i], m_ams_cols[i + 1]); left += gwidth; } } else { int cols_size = m_ams_cols.size(); for (int i = 0; i < cols_size; i++) { dc.SetBrush(wxBrush(m_ams_cols[i])); float x = left + ((float)MATERIAL_REC_WHEEL_SIZE.x) * i / cols_size; if (i != cols_size - 1) { dc.DrawRoundedRectangle(x - FromDIP(LEFT_OFFSET), paint_recty, ((float)MATERIAL_REC_WHEEL_SIZE.x) / cols_size + FromDIP(3), MATERIAL_REC_WHEEL_SIZE.y, 3); } else { dc.DrawRoundedRectangle(x - FromDIP(LEFT_OFFSET), paint_recty, ((float)MATERIAL_REC_WHEEL_SIZE.x) / cols_size - FromDIP(1), MATERIAL_REC_WHEEL_SIZE.y, 3); } } } } else { if (m_match) { dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(wxBrush(wxColour(acolor))); dc.DrawRectangle((size.x / 2 - MATERIAL_REC_WHEEL_SIZE.x) / 2 + FromDIP(3) - FromDIP(LEFT_OFFSET), paint_recty, MATERIAL_REC_WHEEL_SIZE.x - FromDIP(1), MATERIAL_REC_WHEEL_SIZE.y); } } if (m_match) { dc.SetPen(wxPen(wxGetApp().dark_mode() ? wxColour(107, 107, 107) : wxColour(0xAC, 0xAC, 0xAC), FromDIP(1))); } else { dc.SetPen(wxPen(wxColour(234, 31, 48), FromDIP(1))); } dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRoundedRectangle(FromDIP(0), FromDIP(0), size.x - FromDIP(0), size.y, 5); if (m_selected) { dc.SetPen(wxPen(wxColour("#009688"), FromDIP(2))); // ORCA selected item border color (Orca accent) dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRoundedRectangle(FromDIP(1), FromDIP(1), size.x - FromDIP(1), size.y - FromDIP(1), 5); } else if (m_warning) { dc.SetPen(wxPen(wxColour(0xFF, 0x6F, 0x00), FromDIP(2))); dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRoundedRectangle(FromDIP(1), FromDIP(1), size.x - FromDIP(1), size.y - FromDIP(1), 5); } //#endif auto wheel_left = (GetSize().x / 2 - m_ams_wheel_mitem.GetBmpSize().x) / 2 + FromDIP(2) - FromDIP(LEFT_OFFSET); auto wheel_top = up; if (!m_match) { wheel_left = (size.x - m_ams_not_match.GetBmpWidth()) / 2 - FromDIP(LEFT_OFFSET); dc.DrawBitmap(m_ams_not_match.bmp(), wheel_left, wheel_top); } else { if (acolor.Alpha() == 0) { dc.DrawBitmap(m_filament_wheel_transparent.bmp(), wheel_left, wheel_top); } else { dc.DrawBitmap(m_ams_wheel_mitem.bmp(), wheel_left, wheel_top); } } // text and arrow dc.SetTextForeground(StateColor::darkModeColorFor(wxColour(0x26, 0x2E, 0x30))); int text_pos_x = 0; int text_pos_y = 0; auto mapping_txt_size = wxSize(0, 0); if (m_mapping_text.size() >= 4) { m_mapping_text.insert(m_mapping_text.size() / 2, "\n"); WxFontUtils::get_suitable_font_size(FromDIP(13), dc); mapping_txt_size = dc.GetTextExtent(m_mapping_text); text_pos_y = up + (m_ams_wheel_mitem.GetBmpSize().y - mapping_txt_size.y) / 2; text_pos_x = mapping_txt_size.x / 4; } else { dc.SetFont(::Label::Head_12); mapping_txt_size = dc.GetTextExtent(m_mapping_text); text_pos_y = up + (m_ams_wheel_mitem.GetBmpSize().y - mapping_txt_size.y) / 2; text_pos_x = 0; } int arrow_left = size.x - m_arraw_bitmap_white.GetBmpSize().x - FromDIP(4) - FromDIP(LEFT_OFFSET); if (m_match) { dc.DrawText(m_mapping_text, wxPoint(GetSize().x / 2 + (GetSize().x / 2 - mapping_txt_size.x) / 2 - FromDIP(8) - FromDIP(LEFT_OFFSET) + text_pos_x, text_pos_y)); int arrow_y = text_pos_y + (mapping_txt_size.y - m_arraw_bitmap_white.GetBmpHeight()) / 2; if ((acolor.Red() > 160 && acolor.Green() > 160 && acolor.Blue() > 160) && (acolor.Red() < 180 && acolor.Green() < 180 && acolor.Blue() < 180)) { dc.DrawBitmap(m_arraw_bitmap_white.bmp(), arrow_left, arrow_y); } else { dc.DrawBitmap(m_arraw_bitmap_gray.bmp(), arrow_left, arrow_y); } } up += m_ams_wheel_mitem.GetBmpSize().y; if (!m_mapped_nozzle_str.IsEmpty()) { wxPen dashed_pen(wxColour("#CECECE"), 1, wxPENSTYLE_SHORT_DASH); // Orca: WXCOLOUR_GREY400 macro not in scope here dc.SetPen(dashed_pen); up += FromDIP(4); // spacing dc.DrawLine(FromDIP(1), up, FromDIP(size.x), up); int bitmap_y = up + (size.y - up - m_rack_nozzle_bitmap.GetBmpHeight()) / 2; int bitmap_l = wheel_left + (m_ams_wheel_mitem.GetBmpWidth() - m_rack_nozzle_bitmap.GetBmpWidth()) / 2 + FromDIP(2); dc.DrawBitmap(m_rack_nozzle_bitmap.bmp(), bitmap_l, bitmap_y); const wxString wrapped_nozzle_str = s_wrap_mapped_nozzle_str(m_mapped_nozzle_str); dc.SetFont(::Label::Head_12); // Orca: no box-fit get_suitable_font_size overload here; the wrapped slot string is short, so the // fixed Head_12 label font (set above) renders it cleanly. const auto& text_size = dc.GetTextExtent(wrapped_nozzle_str); int text_x = (size.x + bitmap_l + m_rack_nozzle_bitmap.GetBmpWidth() - text_size.x) / 2; int text_y = up + (size.y - up - text_size.y) / 2; dc.DrawText(wrapped_nozzle_str, text_x, text_y); } } void MaterialItem::reset_valid_info() { set_ams_info(m_back_ams_coloul, m_back_ams_name, m_back_ams_ctype, m_back_ams_cols); } void MaterialItem::messure_size() { if (m_mapped_nozzle_str.empty()) { SetSize(wxSize(FromDIP(65), FromDIP(50))); SetMinSize(wxSize(FromDIP(65), FromDIP(50))); SetMaxSize(wxSize(FromDIP(65), FromDIP(50))); } else { const int line_count = s_get_mapped_nozzle_str_line_count(m_mapped_nozzle_str); const int item_height = FromDIP(84 + std::max(0, line_count - 1) * 10); SetSize(wxSize(FromDIP(65), item_height)); SetMinSize(wxSize(FromDIP(65), item_height)); SetMaxSize(wxSize(FromDIP(65), item_height)); } } MaterialSyncItem::MaterialSyncItem(wxWindow *parent, wxColour mcolour, wxString mname, std::string filament_id) : MaterialItem(parent, mcolour, mname, filament_id) { } MaterialSyncItem::~MaterialSyncItem() {} int MaterialSyncItem::get_real_offset() { int real_left_offset = m_dropdown_allow_painted ? LEFT_OFFSET : -2; return real_left_offset; } void MaterialSyncItem::render(wxDC &dc) { wxString mapping_txt = wxEmptyString; if (m_ams_name.empty()) { mapping_txt = "-"; } else { mapping_txt = m_ams_name; } if (mapping_txt == "-") { m_match = false; mapping_txt = _L("Unmapped"); SetToolTip(_L("Upper half area: Original\nLower half area: The filament from original project will be used when unmapped.\nAnd you can click it to modify")); } else { m_match = true; if (m_dropdown_allow_painted) { SetToolTip(_L("Upper half area: Original\nLower half area: Filament in AMS\nAnd you can click it to modify")); } else { SetToolTip(_L("Upper half area: Original\nLower half area: Filament in AMS\nAnd you cannot click it to modify")); } } dc.SetFont(::Label::Body_12); if (dc.GetTextExtent(m_material_name).x > GetSize().x - 10) { dc.SetFont(::Label::Body_10); } auto mapping_txt_size = dc.GetTextExtent(mapping_txt); m_text_pos_y = ((float) GetSize().y * 3 / 5 - mapping_txt_size.y) / 2 + (float) GetSize().y * 2 / 5; #ifdef __WXMSW__ wxSize size = GetSize(); wxMemoryDC memdc; wxBitmap bmp(size.x, size.y); memdc.SelectObject(bmp); memdc.Blit({0, 0}, size, &dc, {0, 0}); { wxGCDC dc2(memdc); doRender(dc2); } memdc.SelectObject(wxNullBitmap); dc.DrawBitmap(bmp, 0, 0); #else doRender(dc); #endif auto mcolor = m_material_coloul; auto acolor = m_ams_coloul; change_the_opacity(acolor); if (!IsEnabled()) { mcolor = wxColour(0x90, 0x90, 0x90); acolor = wxColour(0x90, 0x90, 0x90); } // materials name dc.SetFont(::Label::Body_12); auto material_name_colour = mcolor.GetLuminance() < 0.6 ? *wxWHITE : wxColour(0x26, 0x2E, 0x30); if (mcolor.Alpha() == 0) { material_name_colour = wxColour(0x26, 0x2E, 0x30); } dc.SetTextForeground(material_name_colour); auto full_text = m_material_index + " " + m_material_name; if (dc.GetTextExtent(full_text).x > GetSize().x - 10) { dc.SetFont(::Label::Body_10); } auto material_txt_size = dc.GetTextExtent(full_text); dc.DrawText(full_text, wxPoint((GetSize().x - material_txt_size.x) / 2, ((float) GetSize().y * 2 / 5 - material_txt_size.y) / 2)); int real_left_offset = get_real_offset(); if (m_match) { dc.SetTextForeground(StateColor::darkModeColorFor(wxColour(0x26, 0x2E, 0x30))); dc.SetFont(::Label::Head_12); dc.DrawText(mapping_txt, wxPoint(GetSize().x / 2 + (GetSize().x / 2 - mapping_txt_size.x) / 2 - FromDIP(8) - FromDIP(real_left_offset), m_text_pos_y)); } else { if (mcolor.Alpha() == 0) {//Because there is no unknown background color material_name_colour = StateColor::darkModeColorFor(wxColour(0x26, 0x2E, 0x30)); } dc.SetTextForeground(material_name_colour); if (mapping_txt_size.x > GetSize().x - 10) { dc.SetFont(::Label::Body_10); mapping_txt_size = dc.GetTextExtent(mapping_txt); } dc.DrawText(mapping_txt, wxPoint(GetSize().x / 2 - mapping_txt_size.x / 2 , m_text_pos_y)); } } void MaterialSyncItem::doRender(wxDC &dc) { wxSize size = GetSize(); auto mcolor = m_material_coloul; auto acolor = m_ams_coloul; change_the_opacity(acolor); if (mcolor.Alpha() == 0) { dc.DrawBitmap(m_transparent_mitem.bmp(), FromDIP(0), FromDIP(0)); } if (!IsEnabled()) { mcolor = wxColour(0x90, 0x90, 0x90); acolor = wxColour(0x90, 0x90, 0x90); } // top dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(wxBrush(mcolor)); dc.DrawRoundedRectangle(0, 0, size.x, FromDIP(20), 5); dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(wxBrush(mcolor)); dc.DrawRectangle(0, FromDIP(10), size.x, FromDIP(10)); dc.SetPen(wxColour(0xAC, 0xAC, 0xAC)); dc.DrawLine(FromDIP(1), FromDIP(20), FromDIP(size.x), FromDIP(20)); // bottom rectangle in wheel bitmap, size is MATERIAL_REC_WHEEL_SIZE(22) auto left = (size.x / 2 - MATERIAL_REC_WHEEL_SIZE.x) / 2 + FromDIP(3); auto up = (size.y * 0.4 + (size.y * 0.6 - MATERIAL_REC_WHEEL_SIZE.y) / 2); auto right = left + MATERIAL_REC_WHEEL_SIZE.x - FromDIP(3); dc.SetPen(*wxTRANSPARENT_PEN); int real_left_offset = get_real_offset(); // bottom if (m_match) { if (m_ams_cols.size() > 1) { int gwidth = std::round(MATERIAL_REC_WHEEL_SIZE.x / (m_ams_cols.size() - 1)); // gradient if (m_ams_ctype == 0) { if (!m_dropdown_allow_painted) { left += FromDIP(5); right += FromDIP(5); } for (int i = 0; i < m_ams_cols.size() - 1; i++) { auto rect = wxRect(left, up, right - left, MATERIAL_REC_WHEEL_SIZE.y); fill_gradient_rect_east(dc, rect, m_ams_cols[i], m_ams_cols[i + 1]); left += gwidth; } } else { if (!m_dropdown_allow_painted) { left += FromDIP(5); } int cols_size = m_ams_cols.size(); for (int i = 0; i < cols_size; i++) { dc.SetBrush(wxBrush(m_ams_cols[i])); float x = left + ((float) MATERIAL_REC_WHEEL_SIZE.x) * i / cols_size; if (i != cols_size - 1) { dc.DrawRoundedRectangle(x - FromDIP(real_left_offset), up, ((float) MATERIAL_REC_WHEEL_SIZE.x) / cols_size + FromDIP(3), MATERIAL_REC_WHEEL_SIZE.y, 3); } else { dc.DrawRoundedRectangle(x - FromDIP(real_left_offset), up, ((float) MATERIAL_REC_WHEEL_SIZE.x) / cols_size - FromDIP(1), MATERIAL_REC_WHEEL_SIZE.y, 3); } } } } else { dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(wxBrush(wxColour(acolor))); dc.DrawRectangle((size.x / 2 - MATERIAL_REC_WHEEL_SIZE.x) / 2 + FromDIP(3) - FromDIP(real_left_offset), up, MATERIAL_REC_WHEEL_SIZE.x - FromDIP(1), MATERIAL_REC_WHEEL_SIZE.y); } } else { dc.SetPen(*wxTRANSPARENT_PEN); dc.SetBrush(wxBrush(mcolor)); dc.DrawRoundedRectangle(0, FromDIP(21), size.x, size.y - FromDIP(21), 5); dc.DrawRectangle(0, FromDIP(21), size.x, FromDIP(10)); } ////border #if __APPLE__ dc.SetPen(wxColour(0xAC, 0xAC, 0xAC)); dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRoundedRectangle(1, 1, size.x - 1, size.y - 1, 5); if (m_selected) { dc.SetPen(wxColour("#009688")); // ORCA selected item border color (Orca accent) dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRoundedRectangle(1, 1, size.x - 1, size.y - 1, 5); } #else dc.SetPen(wxPen(wxGetApp().dark_mode() ? wxColour(107, 107, 107) : wxColour(0xAC, 0xAC, 0xAC), FromDIP(1))); dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRoundedRectangle(0, 0, size.x, size.y, 5); if (m_selected) { dc.SetPen(wxPen(wxColour("#009688"), FromDIP(2))); // ORCA selected item border color (Orca accent) dc.SetBrush(*wxTRANSPARENT_BRUSH); dc.DrawRoundedRectangle(FromDIP(1), FromDIP(1), size.x - FromDIP(1), size.y - FromDIP(1), 5); } #endif if (m_text_pos_y > 0 && m_match && m_dropdown_allow_painted) { // arrow (remove arrow) if ((acolor.Red() > 160 && acolor.Green() > 160 && acolor.Blue() > 160) && (acolor.Red() < 180 && acolor.Green() < 180 && acolor.Blue() < 180)) { dc.DrawBitmap(m_arraw_bitmap_white.bmp(), size.x - m_arraw_bitmap_white.GetBmpSize().x - FromDIP(4) - FromDIP(real_left_offset), m_text_pos_y + FromDIP(3)); } else { dc.DrawBitmap(m_arraw_bitmap_gray.bmp(), size.x - m_arraw_bitmap_gray.GetBmpSize().x - FromDIP(4) - FromDIP(real_left_offset), m_text_pos_y + FromDIP(3)); } } auto wheel_left = (GetSize().x / 2 - m_ams_wheel_mitem.GetBmpSize().x) / 2 + FromDIP(2); auto wheel_top = ((float) GetSize().y * 0.6 - m_ams_wheel_mitem.GetBmpSize().y) / 2 + (float) GetSize().y * 0.4; if (m_match) {// different with parent if (acolor.Alpha() == 0) { dc.DrawBitmap(m_filament_wheel_transparent.bmp(), wheel_left - FromDIP(real_left_offset), wheel_top); } else { dc.DrawBitmap(m_ams_wheel_mitem.bmp(), wheel_left - FromDIP(real_left_offset), wheel_top); } } //not draw m_ams_not_match } void MaterialSyncItem::set_material_index_str(std::string str) { m_material_index = str; } AmsMapingPopup::AmsMapingPopup(wxWindow *parent, bool use_in_sync_dialog) : PopupWindow(parent, wxBORDER_NONE | wxPU_CONTAINS_CONTROLS), m_use_in_sync_dialog(use_in_sync_dialog) { Bind(wxEVT_PAINT, &AmsMapingPopup::paintEvent, this); #ifdef __APPLE__ Bind(wxEVT_LEFT_DOWN, &AmsMapingPopup::on_left_down, this); Bind(wxEVT_MOTION, &AmsMapingPopup::on_mouse_move, this); #endif SetBackgroundColour(*wxWHITE); m_sizer_main = new wxBoxSizer(wxVERTICAL); m_sizer_main_h = new wxBoxSizer(wxHORIZONTAL); m_sizer_ams = new wxBoxSizer(wxHORIZONTAL); m_sizer_ams_left = new wxBoxSizer(wxVERTICAL); m_sizer_ams_right = new wxBoxSizer(wxVERTICAL); m_sizer_ams_left_horizonal = new wxBoxSizer(wxHORIZONTAL); m_sizer_ams_right_horizonal = new wxBoxSizer(wxHORIZONTAL); m_sizer_ams_basket_left = new wxBoxSizer(wxVERTICAL); m_sizer_ams_basket_right = new wxBoxSizer(wxVERTICAL); auto title_panel = new wxPanel(this, wxID_ANY); title_panel->SetBackgroundColour(StateColor::darkModeColorFor("#F1F1F1")); title_panel->SetSize(wxSize(-1, FromDIP(30))); title_panel->SetMinSize(wxSize(-1, FromDIP(30))); m_scrolled_window = new wxScrolledWindow(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL | wxHSCROLL); m_scrolled_window->SetBackgroundColour(*wxWHITE); m_scrolled_window->SetScrollRate(0, FromDIP(10)); wxBoxSizer *title_sizer_h= new wxBoxSizer(wxHORIZONTAL); wxBoxSizer *title_sizer_v = new wxBoxSizer(wxVERTICAL); m_title_text = new wxStaticText(title_panel, wxID_ANY, _L("AMS Slots")); m_title_text->SetForegroundColour(wxColour("#262E30")); m_title_text->SetFont(::Label::Body_16); title_sizer_v->Add(m_title_text, 0, wxALIGN_LEFT | wxLEFT, FromDIP(15)); title_sizer_h->Add(title_sizer_v, 1, wxALIGN_CENTER, 5); title_panel->SetSizer(title_sizer_h); title_panel->Layout(); title_panel->Fit(); m_left_marea_panel = new wxPanel(m_scrolled_window); m_left_marea_panel->SetName("left"); m_right_marea_panel = new wxPanel(m_scrolled_window); m_right_marea_panel->SetName("right"); m_left_first_text_panel = new wxPanel(m_left_marea_panel); m_right_first_text_panel = new wxPanel(m_right_marea_panel); auto sizer_temp = new wxBoxSizer(wxHORIZONTAL); /*left ext*/ m_left_extra_slot = new MappingItem(m_left_marea_panel); m_left_extra_slot->m_ams_id = VIRTUAL_TRAY_DEPUTY_ID; m_left_extra_slot->m_slot_id = 0; m_left_extra_slot->SetSize(wxSize(FromDIP(48), FromDIP(60))); m_left_extra_slot->SetMinSize(wxSize(FromDIP(48), FromDIP(60))); m_left_extra_slot->SetMaxSize(wxSize(FromDIP(48), FromDIP(60))); auto left_panel = new wxPanel(m_left_marea_panel); left_panel->SetSize(wxSize(FromDIP(182), FromDIP(60))); left_panel->SetMinSize(wxSize(FromDIP(182), FromDIP(60))); left_panel->SetMaxSize(wxSize(FromDIP(182), FromDIP(60))); sizer_temp->Add(m_left_extra_slot); sizer_temp->Add(left_panel); /*right ext*/ m_right_extra_slot = new MappingItem(m_right_marea_panel); m_right_extra_slot->m_ams_id = VIRTUAL_TRAY_MAIN_ID; m_right_extra_slot->m_slot_id = 0; m_right_extra_slot->SetSize(wxSize(FromDIP(48), FromDIP(60))); m_right_extra_slot->SetMinSize(wxSize(FromDIP(48), FromDIP(60))); m_right_extra_slot->SetMaxSize(wxSize(FromDIP(48), FromDIP(60))); std::string amp_pt = wxGetApp().preset_bundle->printers.get_edited_preset().get_printer_type(wxGetApp().preset_bundle); m_single_tip_text = _L("Please select from the following filaments"); m_left_tip_text = wxString::Format(_L("Select filament that installed to the %s"), _L(DevPrinterConfigUtil::get_toolhead_display_name(amp_pt, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::LowerCase))); m_right_tip_text = wxString::Format(_L("Select filament that installed to the %s"), _L(DevPrinterConfigUtil::get_toolhead_display_name(amp_pt, MAIN_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::LowerCase))); m_left_tips = new Label(m_left_first_text_panel); m_left_tips->SetForegroundColour(StateColor::darkModeColorFor("0x262E30")); m_left_tips->SetBackgroundColour(StateColor::darkModeColorFor("0xFFFFFF")); m_left_tips->SetFont(::Label::Body_13); m_left_tips->SetLabel(m_left_tip_text); m_left_first_text_panel->SetSizer(m_sizer_ams_left_horizonal); m_sizer_ams_left->Add(m_left_first_text_panel, 0, wxEXPAND | wxBOTTOM | wxTOP , FromDIP(8)); m_left_split_ams_sizer = create_split_sizer(m_left_marea_panel, _L("Left AMS")); m_sizer_ams_left->Add(m_left_split_ams_sizer, 0, wxEXPAND, 0); m_sizer_ams_left->Add(m_sizer_ams_basket_left, 0, wxEXPAND|wxTOP, FromDIP(8)); m_sizer_ams_left->Add(create_split_sizer(m_left_marea_panel, _L("External")), 0, wxEXPAND|wxTOP, FromDIP(8)); //m_sizer_ams_left->Add(m_left_extra_slot, 0, wxEXPAND|wxTOP, FromDIP(8)); m_sizer_ams_left->Add(sizer_temp, 0, wxEXPAND | wxTOP, FromDIP(8)); m_right_tips = new Label(m_right_first_text_panel); m_right_tips->SetForegroundColour(StateColor::darkModeColorFor("0x262E30")); m_right_tips->SetBackgroundColour(StateColor::darkModeColorFor("0xFFFFFF")); m_right_tips->SetFont(::Label::Body_13); m_right_tips->SetLabel(m_right_tip_text); m_sizer_ams_right_horizonal->AddStretchSpacer(); m_reset_btn = new ScalableButton(m_scrolled_window, wxID_ANY, wxGetApp().dark_mode() ? "erase_dark" : "erase", wxEmptyString, wxDefaultSize, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER, true, 14); m_reset_btn->SetName(wxGetApp().dark_mode() ? "erase_dark" : "erase"); m_reset_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent &e) { reset_ams_info(); }); m_reset_btn->SetBackgroundColour(*wxWHITE); m_reset_btn->SetToolTip(_L("Reset current filament mapping")); m_sizer_ams_right_horizonal->AddStretchSpacer(); m_sizer_ams_right_horizonal->AddSpacer(FromDIP(5)); m_reset_btn->Hide(); m_right_first_text_panel->SetSizer(m_sizer_ams_right_horizonal); const int same_height = 20; m_left_first_text_panel->SetMaxSize(wxSize(-1, FromDIP(same_height))); m_right_first_text_panel->SetMaxSize(wxSize(-1, FromDIP(same_height))); // content_sizer wxSizer *content_ams_sizer = new wxBoxSizer(wxVERTICAL); m_right_split_ams_sizer = create_split_sizer(m_right_marea_panel, _L("Right AMS")); m_right_split_ext_sizer = create_split_sizer(m_right_marea_panel, _L("External")); content_ams_sizer->Add(m_right_split_ams_sizer, 0, wxEXPAND, 0); content_ams_sizer->Add(m_sizer_ams_basket_right, 0, wxEXPAND | wxTOP, FromDIP(8)); content_ams_sizer->Add(m_right_split_ext_sizer, 0, wxEXPAND | wxTOP, FromDIP(8)); content_ams_sizer->Add(m_right_extra_slot, 0, wxEXPAND | wxTOP, FromDIP(8)); wxSizer *content_sizer = new wxBoxSizer(wxHORIZONTAL); content_sizer->Add(content_ams_sizer, 1, wxEXPAND | wxLEFT); m_flush_warning_panel = new DevIconLabel(m_right_marea_panel, "warning", ""); // Orca: dev_warning icon absent; use the shipped generic warning glyph m_flush_warning_panel->SetAllBackgroundColor(StateColor::darkModeColorFor("#FFFFE0")); m_flush_warning_panel->GetLabelItem()->SetForegroundColour(StateColor::darkModeColorFor("#F09A17")); m_flush_warning_panel->Show(false); m_sizer_ams_right->Add(m_right_first_text_panel, 0, wxEXPAND | wxBOTTOM | wxTOP, FromDIP(8)); m_sizer_ams_right->Add(m_flush_warning_panel, 0, wxBOTTOM | wxALIGN_LEFT, FromDIP(8)); m_sizer_ams_right->Add(content_sizer, 0, wxEXPAND, 0); m_rack_nozzle_select = new wgtDeviceNozzleRackSelect(m_scrolled_window); m_rack_nozzle_select->Bind(EVT_NOZZLE_SELECT_CHANGED, &AmsMapingPopup::OnNozzleMappingSelected, this); m_rack_nozzle_select->Bind(EVT_NOZZLE_SELECT_CLICKED, [this](wxCommandEvent &e) { this->Dismiss(); }); m_rack_nozzle_select->Show(false); m_ams_tips_msg_panel = new wgtMsgPanel(m_scrolled_window); m_left_marea_panel->SetSizer(m_sizer_ams_left); m_right_marea_panel->SetSizer(m_sizer_ams_right); m_sizer_ams_v = new wxBoxSizer(wxVERTICAL); m_split_line_panel = new wxPanel(m_scrolled_window, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(1), -1)); m_split_line_panel->SetBackgroundColour(*wxWHITE); m_split_line_panel->Bind(wxEVT_PAINT, [this](wxPaintEvent& evt) { wxPaintDC dc(m_split_line_panel); dc.SetPen(wxPen(wxColour(0xAC, 0xAC, 0xAC), 1, wxPENSTYLE_SHORT_DASH)); dc.DrawLine(0, FromDIP(20), 0, m_sizer_ams->GetSize().GetHeight()); }); //m_sizer_ams->Add(m_left_marea_panel, 0, wxEXPAND, FromDIP(0)); m_sizer_ams->Add(m_left_marea_panel, 0, wxRIGHT, FromDIP(10)); m_sizer_ams->Add(m_split_line_panel, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(7)); m_sizer_ams->Add(m_right_marea_panel, 0, wxEXPAND | wxLEFT, FromDIP(10)); m_sizer_ams_v->Add(m_reset_btn, 0, wxALIGN_RIGHT); m_sizer_ams_v->Add(m_sizer_ams, 0, wxEXPAND | wxBOTTOM, FromDIP(30)); m_sizer_ams_v->AddStretchSpacer(); m_sizer_ams_v->Add(m_ams_tips_msg_panel, 0, wxEXPAND | wxBottom, FromDIP(10)); m_sizer_main_h->Add(m_sizer_ams_v, 0, wxEXPAND | wxRIGHT, FromDIP(10)); m_sizer_main_h->Add(m_rack_nozzle_select, 0, wxEXPAND | wxTOP | wxLEFT, FromDIP(15)); m_scrolled_window->SetSizer(m_sizer_main_h); m_sizer_main->Add(title_panel, 0, wxEXPAND | wxALL, FromDIP(2)); m_sizer_main->Add(m_scrolled_window, 1, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(14)); m_sizer_main->Add( 0, 0, 0, wxTOP, FromDIP(14)); SetSizer(m_sizer_main); Layout(); Fit(); Bind(wxEVT_SHOW, [this](wxShowEvent& e) { if (e.IsShown() && m_parent_item) { auto show_pos = m_parent_item->ClientToScreen(wxPoint(0, 0)); int display_idx = wxDisplay::GetFromWindow(m_parent_item); if (display_idx == wxNOT_FOUND) display_idx = 0; wxRect screen_size = wxDisplay(display_idx).GetClientArea(); auto parent_size = m_parent_item->GetRect(); auto content_size = m_sizer_main_h->GetMinSize(); int popup_width = content_size.x + FromDIP(28); int popup_height = content_size.y; wxSize popup_size(popup_width, popup_height); // Horizontal Direction Processing if (show_pos.x + popup_size.x > screen_size.GetRight()) { show_pos.x = screen_size.GetRight() - popup_size.x; } //if popup size bigger than screen if (show_pos.x < screen_size.GetLeft()) { show_pos.x = screen_size.GetLeft(); m_scrolled_window->SetMaxSize(wxSize(screen_size.GetWidth(), popup_height)); m_scrolled_window->SetMinSize(wxSize(screen_size.GetWidth(), popup_height)); m_scrolled_window->SetScrollRate(FromDIP(10), FromDIP(10)); } else { m_scrolled_window->SetMaxSize(wxSize(popup_width, popup_height)); m_scrolled_window->SetMinSize(wxSize(popup_width, popup_height)); m_scrolled_window->SetScrollRate(0, FromDIP(10)); } //Vertical Direction Processing int available_height_below = screen_size.GetBottom() - (show_pos.y + parent_size.height); int available_height_above = show_pos.y - screen_size.GetTop(); if (popup_size.y <= available_height_below) { show_pos.y = show_pos.y + parent_size.height; } else if (popup_size.y <= available_height_above) { show_pos.y = show_pos.y - popup_size.y - FromDIP(34) - FromDIP(14);// title_height = FromDIP(30) + FromDIP(4) padding = FromDIP(14) } else { int max_available_height; if (available_height_below >= available_height_above) { show_pos.y = show_pos.y + parent_size.height; max_available_height = available_height_below; } else { show_pos.y = screen_size.GetTop(); max_available_height = available_height_above; } int title_and_padding = FromDIP(30) + FromDIP(4) + FromDIP(14); int max_scroll_height = max_available_height - title_and_padding; m_scrolled_window->SetMaxSize(wxSize(m_scrolled_window->GetMaxSize().x,max_scroll_height)); } Layout(); Fit(); this->Move(show_pos); } }); } void AmsMapingPopup::reset_ams_info() { if (m_reset_callback) { m_reset_callback(m_material_index); } } void AmsMapingPopup::set_reset_callback(ResetCallback callback) { m_reset_callback = callback; } void AmsMapingPopup::show_reset_button() { m_reset_btn->Show(); } // Orca: kept surface for the reverse-direction SelectMachine — this helper (dropped by the reference) // is still consumed by SelectMachine, so it stays as a permanent compatibility surface. std::vector AmsMapingPopup::parse_ams_mapping(const std::map& amsList) { std::vector m_tray_data; for (auto ams_iter = amsList.begin(); ams_iter != amsList.end(); ams_iter++) { BOOST_LOG_TRIVIAL(trace) << "ams_mapping ams id " << ams_iter->first.c_str(); auto ams_indx = atoi(ams_iter->first.c_str()); DevAms* ams_group = ams_iter->second; std::map::const_iterator tray_iter; for (tray_iter = ams_group->GetTrays().cbegin(); tray_iter != ams_group->GetTrays().cend(); tray_iter++) { DevAmsTray* tray_data = tray_iter->second; TrayData td; td.id = ams_indx * AMS_TOTAL_COUNT + atoi(tray_data->id.c_str()); if (!tray_data->is_exists) { td.type = EMPTY; } else { if (!tray_data->is_tray_info_ready()) { td.type = THIRD; } else { td.type = NORMAL; td.remain = tray_data->remain; td.colour = DevAmsTray::decode_color(tray_data->color); td.name = tray_data->get_display_filament_type(); td.filament_type = tray_data->get_filament_type(); } } m_tray_data.push_back(td); } } return m_tray_data; } void AmsMapingPopup::msw_rescale() { m_left_extra_slot->msw_rescale(); m_right_extra_slot->msw_rescale(); for (auto item : m_mapping_item_list) { item->msw_rescale(); } for (auto container : m_amsmapping_container_list) { container->msw_rescale(); } m_flush_warning_panel->Rescale(); m_rack_nozzle_select->Rescale(); Fit(); Refresh(); }; void AmsMapingPopup::set_sizer_title(wxBoxSizer *sizer, wxString text) { if (!sizer) { return; } wxSizerItemList items = sizer->GetChildren(); for (wxSizerItemList::iterator it = items.begin(); it != items.end(); ++it) { wxSizerItem *item = *it; auto temp_label = dynamic_cast