From 50abe02f182b3ca2d4b01fbac7a42d41b9acff58 Mon Sep 17 00:00:00 2001 From: SoftFever Date: Fri, 17 Jul 2026 05:06:09 +0800 Subject: [PATCH] Make AMS trays read-only in laser mode and add the gradient fill helper --- src/slic3r/GUI/AMSDryControl.cpp | 4 ++-- src/slic3r/GUI/AMSDryControl.hpp | 2 +- src/slic3r/GUI/FilamentBitmapUtils.cpp | 20 ++++++++++++++++++++ src/slic3r/GUI/FilamentBitmapUtils.hpp | 7 +++++++ src/slic3r/GUI/StatusPanel.cpp | 2 +- src/slic3r/GUI/Widgets/AMSControl.cpp | 13 +++++++++++++ src/slic3r/GUI/Widgets/AMSControl.hpp | 2 ++ src/slic3r/GUI/Widgets/AMSItem.cpp | 19 +++++++++++++++---- src/slic3r/GUI/Widgets/AMSItem.hpp | 4 ++++ 9 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/AMSDryControl.cpp b/src/slic3r/GUI/AMSDryControl.cpp index 56a4f5e739..943fad3230 100644 --- a/src/slic3r/GUI/AMSDryControl.cpp +++ b/src/slic3r/GUI/AMSDryControl.cpp @@ -86,7 +86,7 @@ FilamentItemPanel::FilamentItemPanel(wxWindow* parent, const wxString& text, con : wxPanel(parent, id) , m_icon_name(icon_name) { - SetBackgroundColour(wxColour("#F0F0F1")); // Light gray background + SetBackgroundColour(wxColour("#F0F0F1")); // Orca: light-gray panel scheme (#F0F0F1 replaces REF #F7F7F7) SetMinSize(wxSize(FromDIP(64), FromDIP(106))); // Width: 64, Height: 106 SetSize(wxSize(FromDIP(64), FromDIP(106))); // Fixed size @@ -977,7 +977,7 @@ void AMSDryCtrWin::create() // set title icon SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE)); this->SetDoubleBuffered(true); - std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); + std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str(); // Orca: app title icon SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO)); SetSize(wxSize(FromDIP(700), FromDIP(500))); diff --git a/src/slic3r/GUI/AMSDryControl.hpp b/src/slic3r/GUI/AMSDryControl.hpp index 43e177eeb1..a7500b5b03 100644 --- a/src/slic3r/GUI/AMSDryControl.hpp +++ b/src/slic3r/GUI/AMSDryControl.hpp @@ -6,7 +6,7 @@ #include "slic3r/GUI/wxExtensions.hpp" #include "slic3r/GUI/DeviceCore/DevFilaSystem.h" -#include "slic3r/GUI/I18N.hpp" +#include "slic3r/GUI/I18N.hpp" // Orca: explicit _L() catalog include #include #include diff --git a/src/slic3r/GUI/FilamentBitmapUtils.cpp b/src/slic3r/GUI/FilamentBitmapUtils.cpp index 3308c722cc..9b43647ac0 100644 --- a/src/slic3r/GUI/FilamentBitmapUtils.cpp +++ b/src/slic3r/GUI/FilamentBitmapUtils.cpp @@ -8,6 +8,26 @@ namespace Slic3r { namespace GUI { +void fill_gradient_rect_east(wxDC& dc, const wxRect& rect, const wxColour& from, const wxColour& to) +{ + if (rect.width <= 0 || rect.height <= 0) return; + + auto mix_channel = [](unsigned char a, unsigned char b, double t) { + return static_cast(a + (b - a) * t + 0.5); + }; + + dc.SetPen(*wxTRANSPARENT_PEN); + for (int x = 0; x < rect.width; ++x) { + const double t = rect.width > 1 ? static_cast(x) / (rect.width - 1) : 0.0; + const wxColour col(mix_channel(from.Red(), to.Red(), t), + mix_channel(from.Green(), to.Green(), t), + mix_channel(from.Blue(), to.Blue(), t), + mix_channel(from.Alpha(), to.Alpha(), t)); + dc.SetBrush(wxBrush(col)); + dc.DrawRectangle(rect.x + x, rect.y, 1, rect.height); + } +} + // Helper struct to hold bitmap and DC struct BitmapDC { wxBitmap bitmap; diff --git a/src/slic3r/GUI/FilamentBitmapUtils.hpp b/src/slic3r/GUI/FilamentBitmapUtils.hpp index b949522353..87d5b275cc 100644 --- a/src/slic3r/GUI/FilamentBitmapUtils.hpp +++ b/src/slic3r/GUI/FilamentBitmapUtils.hpp @@ -3,10 +3,17 @@ #include #include +#include +#include #include namespace Slic3r { namespace GUI { +// Fills a rect with a west->east linear gradient by drawing solid 1px columns. +// Use instead of wxDC::GradientFillLinear, whose CoreGraphics (CGShading) backend +// fails to render on some macOS builds; solid fills are unaffected. +void fill_gradient_rect_east(wxDC& dc, const wxRect& rect, const wxColour& from, const wxColour& to); + enum class FilamentRenderMode { Single, Dual, diff --git a/src/slic3r/GUI/StatusPanel.cpp b/src/slic3r/GUI/StatusPanel.cpp index 1bd564b5e1..9617eb60cc 100644 --- a/src/slic3r/GUI/StatusPanel.cpp +++ b/src/slic3r/GUI/StatusPanel.cpp @@ -3391,7 +3391,7 @@ void StatusPanel::update_ams(MachineObject *obj) } // must select a current can - m_ams_control->UpdateAms(obj->get_printer_series_str(), obj->printer_type, ams_info, ext_info, *obj->GetExtderSystem(), obj->get_dev_id(), false); + m_ams_control->UpdateAms(obj->get_printer_series_str(), obj->printer_type, ams_info, ext_info, *obj->GetExtderSystem(), obj->get_dev_id(), obj, false); m_ams_control->UpdateAmsDryControl(obj); last_tray_exist_bits = obj->tray_exist_bits; diff --git a/src/slic3r/GUI/Widgets/AMSControl.cpp b/src/slic3r/GUI/Widgets/AMSControl.cpp index 07aa574430..66a8cdacdb 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.cpp +++ b/src/slic3r/GUI/Widgets/AMSControl.cpp @@ -927,6 +927,7 @@ void AMSControl::UpdateAms(const std::string &series_name, std::vector ext_info, DevExtderSystem data, std::string dev_id, + MachineObject* obj, bool is_reset, bool test) { @@ -996,6 +997,18 @@ void AMSControl::UpdateAms(const std::string &series_name, } } + // 2D mode (laser/cut) makes every spool view-only: show the read-only (eye) icon while the spool + // stays clickable to open the read-only filament dialog. + // Orca: gated on the device mode via MachineObject::is_fdm_type(); obj is null for callers that do + // not supply it, leaving spools editable. + const bool view_only = obj && !obj->is_fdm_type(); + for (auto ams_item : m_ams_item_list) { + if (ams_item.second == nullptr) { continue; } + for (auto lib_it : ams_item.second->get_can_lib_list()) { + if (lib_it.second) { lib_it.second->set_view_only(view_only); } + } + } + for (auto ams_prv : m_ams_preview_list) { std::string id = ams_prv.second->get_ams_id(); auto item = m_ams_item_list.find(id); diff --git a/src/slic3r/GUI/Widgets/AMSControl.hpp b/src/slic3r/GUI/Widgets/AMSControl.hpp index 1fe8876eba..39421f1275 100644 --- a/src/slic3r/GUI/Widgets/AMSControl.hpp +++ b/src/slic3r/GUI/Widgets/AMSControl.hpp @@ -179,8 +179,10 @@ public: std::vector ext_info, DevExtderSystem data, std::string dev_id, + MachineObject* obj = nullptr, bool is_reset = true, bool test = false); + // Orca: simulation-data generator for local AMS-layout testing (no device required) std::vector GenerateSimulateData(); void AddAms(AMSinfo info, AMSPanelPos pos = AMSPanelPos::LEFT_PANEL); diff --git a/src/slic3r/GUI/Widgets/AMSItem.cpp b/src/slic3r/GUI/Widgets/AMSItem.cpp index 2fe49ccaa3..b6f335b580 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.cpp +++ b/src/slic3r/GUI/Widgets/AMSItem.cpp @@ -3,6 +3,7 @@ #include "../BitmapCache.hpp" #include "../I18N.hpp" #include "../GUI_App.hpp" +#include "../FilamentBitmapUtils.hpp" #include "../Utils/WxFontUtils.hpp" #include "slic3r/GUI/DeviceTab/uiAmsHumidityPopup.h" @@ -1374,6 +1375,11 @@ void AMSLib::render_lite_lib(wxDC& dc) } } + // View-only mode forces the read-only (eye) icon even for third-party spools. + if (m_view_only) { + temp_bitmap_third = temp_bitmap_brand; + } + dc.SetPen(wxPen(*wxTRANSPARENT_PEN)); if (m_info.material_cols.size() > 1) { int left = FromDIP(10); @@ -1382,7 +1388,7 @@ void AMSLib::render_lite_lib(wxDC& dc) if (m_info.ctype == 0) { for (int i = 0; i < m_info.material_cols.size() - 1; i++) { auto rect = wxRect(left, FromDIP(10), libsize.x - FromDIP(18), libsize.y - FromDIP(18)); - dc.GradientFillLinear(rect, m_info.material_cols[i], m_info.material_cols[i + 1], wxEAST); + fill_gradient_rect_east(dc, rect, m_info.material_cols[i], m_info.material_cols[i + 1]); left += gwidth; } } @@ -1465,6 +1471,11 @@ void AMSLib::render_generic_lib(wxDC &dc) temp_bitmap_brand = m_bitmap_readonly; } + // View-only mode forces the read-only (eye) icon even for third-party spools. + if (m_view_only) { + temp_bitmap_third = temp_bitmap_brand; + } + dc.SetPen(wxPen(tmp_lib_colour, 1, wxPENSTYLE_SOLID)); dc.SetBrush(wxBrush(tmp_lib_colour)); @@ -1575,7 +1586,7 @@ void AMSLib::render_generic_lib(wxDC &dc) } auto rect = wxRect(left, height - curr_height, gwidth, curr_height); - dc.GradientFillLinear(rect, m_info.material_cols[i], m_info.material_cols[i + 1], wxEAST); + fill_gradient_rect_east(dc, rect, m_info.material_cols[i], m_info.material_cols[i + 1]); left += gwidth; } } @@ -2749,7 +2760,7 @@ void AMSPreview::doRender(wxDC &dc) } auto rect = wxRect(fleft, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, gwidth, AMS_ITEM_CUBE_SIZE.y); - dc.GradientFillLinear(rect, iter->material_cols[i], iter->material_cols[i + 1], wxEAST); + fill_gradient_rect_east(dc, rect, iter->material_cols[i], iter->material_cols[i + 1]); fleft += gwidth; } } @@ -2821,7 +2832,7 @@ void AMSPreview::doRender(wxDC &dc) } auto rect = wxRect(fleft, (size.y - AMS_ITEM_CUBE_SIZE.y) / 2, gwidth, AMS_ITEM_CUBE_SIZE.y); - dc.GradientFillLinear(rect, iter.material_cols[i], iter.material_cols[i + 1], wxEAST); + fill_gradient_rect_east(dc, rect, iter.material_cols[i], iter.material_cols[i + 1]); fleft += gwidth; } } diff --git a/src/slic3r/GUI/Widgets/AMSItem.hpp b/src/slic3r/GUI/Widgets/AMSItem.hpp index 18a9ee53ef..bed57e7d39 100644 --- a/src/slic3r/GUI/Widgets/AMSItem.hpp +++ b/src/slic3r/GUI/Widgets/AMSItem.hpp @@ -503,6 +503,9 @@ public: void support_cali(bool sup) { m_support_cali = sup; Refresh(); }; virtual bool Enable(bool enable = true); void set_disable_mode(bool disable) { m_disable_mode = disable; } + // View-only mode (2D laser/cut): show the read-only (eye) icon for every editable spool + // while keeping it clickable to open the read-only filament dialog. + void set_view_only(bool view_only) { if (m_view_only != view_only) { m_view_only = view_only; Refresh(); } } void msw_rescale(); void on_pass_road(bool pass); @@ -542,6 +545,7 @@ protected: wxColour m_road_def_color; wxColour m_lib_color; bool m_disable_mode{ false }; + bool m_view_only{ false }; bool m_pass_road{false}; void on_enter_window(wxMouseEvent &evt);