From 2af2f0f98bd51a58ea34a56f78af9d95dafd258b Mon Sep 17 00:00:00 2001 From: tome9111991 <57866234+tome9111991@users.noreply.github.com> Date: Fri, 24 Apr 2026 15:39:32 +0200 Subject: [PATCH] enh: flow rate pattern calibration menu (#11956) * feat: Add flow rate calibration pattern selector dialog * feat: Integrate PR #11881 and improve Flow Rate Calibration Wizard - Integrated PR #11881: Display layer duration in G-code viewer position window. - Enhanced Flow Rate Calibration: - Implemented a Wizard dialog (FlowRateCalibrationDialog) using DPIDialog for Dark Mode support. - Restricted pattern selection to 'Archimedean Chords' and 'Monotonic'. - Integrated logic to pass the selected pattern to the calibration generation. * fix(UI): Refactor FlowRateCalibrationDialog to calib_dlg for macOS build fix and UI consistency Moved FlowRateCalibrationDialog from MainFrame.cpp to calib_dlg.hpp/.cpp to resolve build errors on macOS. Updated UI to match Pressure Advance calibration dialog style (Dark Mode support, RadioGroups). Logic moved to dialog class. * Update Wiki link for flow rate calibration * ui: replace RadioGroup with BitmapComboBox for Flow Rate pattern selection * fix(ui): use custom ComboBox widget for Flow Rate Calibration Replaces wxBitmapComboBox with OrcaSlicer's custom ComboBox widget to fix rendering issues on Windows (empty selection) and compilation errors on Linux. * Refactor: Cleanup unused includes and members in FlowRate calibration dialog * Fix: Complete rename of Flow Rate to Flow ratio in calibration menus after merge * Fix: Update Flow Rate to Flow Ratio in Calibration Dialog and Wiki Link --------- Co-authored-by: yw4z Co-authored-by: SoftFever --- src/slic3r/GUI/CalibrationPanel.cpp | 2 +- src/slic3r/GUI/MainFrame.cpp | 48 ++++++--------- src/slic3r/GUI/MainFrame.hpp | 1 + src/slic3r/GUI/Plater.cpp | 12 ++-- src/slic3r/GUI/Plater.hpp | 3 +- src/slic3r/GUI/calib_dlg.cpp | 94 +++++++++++++++++++++++++++++ src/slic3r/GUI/calib_dlg.hpp | 16 +++++ 7 files changed, 139 insertions(+), 37 deletions(-) diff --git a/src/slic3r/GUI/CalibrationPanel.cpp b/src/slic3r/GUI/CalibrationPanel.cpp index 76c545f912..a0d52a228f 100644 --- a/src/slic3r/GUI/CalibrationPanel.cpp +++ b/src/slic3r/GUI/CalibrationPanel.cpp @@ -25,7 +25,7 @@ wxString get_calibration_type_name(CalibMode cali_mode) case CalibMode::Calib_PA_Line: return _L("Flow Dynamics"); case CalibMode::Calib_Flow_Rate: - return _L("Flow Rate"); + return _L("Flow ratio"); case CalibMode::Calib_Vol_speed_Tower: return _L("Max Volumetric Speed"); case CalibMode::Calib_Temp_Tower: diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 70c622ee6c..cbcbd0adaf 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -3278,23 +3278,15 @@ void MainFrame::init_menubar_as_editor() }, "", nullptr, [this]() {return m_plater->is_view3D_shown();; }, this); - // Flow rate (with submenu) - auto flowrate_menu = new wxMenu(); - append_menu_item( - flowrate_menu, wxID_ANY, _L("Pass 1"), _L("Flow ratio test - Pass 1"), - [this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(false, 1); }, "", nullptr, + // Flow rate (Wizard Dialog) + append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Flow ratio"), _L("Flow Rate Calibration"), + [this](wxCommandEvent&) { + if (!m_plater) return; + if (!m_flow_rate_calib_dlg) + m_flow_rate_calib_dlg = new FlowRateCalibrationDialog((wxWindow*)this, wxID_ANY, m_plater); + m_flow_rate_calib_dlg->ShowModal(); + }, "", nullptr, [this]() {return m_plater->is_view3D_shown();; }, this); - append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 2"), _L("Flow ratio test - Pass 2"), - [this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(false, 2); }, "", nullptr, - [this]() {return m_plater->is_view3D_shown();; }, this); - flowrate_menu->AppendSeparator(); - append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (Recommended)"), _L("Orca YOLO flowratio calibration, 0.01 step"), - [this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(true, 1); }, "", nullptr, - [this]() {return m_plater->is_view3D_shown();; }, this); - append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (perfectionist version)"), _L("Orca YOLO flowratio calibration, 0.005 step"), - [this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(true, 2); }, "", nullptr, - [this]() {return m_plater->is_view3D_shown();; }, this); - m_topbar->GetCalibMenu()->AppendSubMenu(flowrate_menu, _L("Flow ratio")); // Retraction append_menu_item(m_topbar->GetCalibMenu(), wxID_ANY, _L("Retraction"), _L("Retraction"), @@ -3390,21 +3382,14 @@ void MainFrame::init_menubar_as_editor() [this]() {return m_plater->is_view3D_shown();; }, this); // Flowrate (with submenu) - auto flowrate_menu = new wxMenu(); - append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 1"), _L("Flow ratio test - Pass 1"), - [this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(false, 1); }, "", nullptr, - [this]() {return m_plater->is_view3D_shown();; }, this); - append_menu_item(flowrate_menu, wxID_ANY, _L("Pass 2"), _L("Flow ratio test - Pass 2"), - [this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(false, 2); }, "", nullptr, - [this]() {return m_plater->is_view3D_shown();; }, this); - append_submenu(calib_menu,flowrate_menu,wxID_ANY,_L("Flow ratio"),_L("Flow ratio"),"", - [this]() {return m_plater->is_view3D_shown();; }); - flowrate_menu->AppendSeparator(); - append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (Recommended)"), _L("Orca YOLO flowratio calibration, 0.01 step"), - [this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(true, 1); }, "", nullptr, - [this]() {return m_plater->is_view3D_shown();; }, this); - append_menu_item(flowrate_menu, wxID_ANY, _L("YOLO (perfectionist version)"), _L("Orca YOLO flowratio calibration, 0.005 step"), - [this](wxCommandEvent&) { if (m_plater) m_plater->calib_flowrate(true, 2); }, "", nullptr, + // ORCA: Flow rate (Wizard Dialog) + append_menu_item(calib_menu, wxID_ANY, _L("Flow ratio"), _L("Flow Rate Calibration"), + [this](wxCommandEvent&) { + if (!m_plater) return; + if (!m_flow_rate_calib_dlg) + m_flow_rate_calib_dlg = new FlowRateCalibrationDialog((wxWindow*)this, wxID_ANY, m_plater); + m_flow_rate_calib_dlg->ShowModal(); + }, "", nullptr, [this]() {return m_plater->is_view3D_shown();; }, this); // Retraction @@ -4361,3 +4346,4 @@ void SettingsDialog::on_dpi_changed(const wxRect& suggested_rect) } // GUI } // Slic3r + diff --git a/src/slic3r/GUI/MainFrame.hpp b/src/slic3r/GUI/MainFrame.hpp index 5cbeb48f93..20229a611e 100644 --- a/src/slic3r/GUI/MainFrame.hpp +++ b/src/slic3r/GUI/MainFrame.hpp @@ -362,6 +362,7 @@ public: void fit_tab_labels(); // ORCA PA_Calibration_Dlg* m_pa_calib_dlg{ nullptr }; + FlowRateCalibrationDialog* m_flow_rate_calib_dlg{ nullptr }; Temp_Calibration_Dlg* m_temp_calib_dlg{ nullptr }; MaxVolumetricSpeed_Test_Dlg* m_vol_test_dlg { nullptr }; VFA_Test_Dlg* m_vfa_test_dlg { nullptr }; diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 234e37edf2..532540fa72 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -12769,7 +12769,8 @@ void Plater::_calib_pa_select_added_objects() { // Adjust settings for flowrate calibration // For linear mode, pass 1 means normal version while pass 2 mean "for perfectionists" version -void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, int pass) +// ORCA: Add pattern parameter +void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, int pass, InfillPattern pattern) { auto print_config = &wxGetApp().preset_bundle->prints.get_edited_preset().config; auto printerConfig = &wxGetApp().preset_bundle->printers.get_edited_preset().config; @@ -12832,7 +12833,8 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i _obj->config.set_key_value("sparse_infill_pattern", new ConfigOptionEnum(ipRectilinear)); _obj->config.set_key_value("top_surface_line_width", new ConfigOptionFloatOrPercent(nozzle_diameter * 1.2f, false)); _obj->config.set_key_value("internal_solid_infill_line_width", new ConfigOptionFloatOrPercent(nozzle_diameter * 1.2f, false)); - _obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum(ipArchimedeanChords)); + // ORCA: use the pattern parameter + _obj->config.set_key_value("top_surface_pattern", new ConfigOptionEnum(pattern)); _obj->config.set_key_value("top_solid_infill_flow_ratio", new ConfigOptionFloat(1.0f)); _obj->config.set_key_value("infill_direction", new ConfigOptionFloat(45)); _obj->config.set_key_value("solid_infill_direction", new ConfigOptionFloat(135)); @@ -12883,7 +12885,8 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i wxGetApp().get_tab(Preset::TYPE_PRINTER)->reload_config(); } -void Plater::calib_flowrate(bool is_linear, int pass) { +// ORCA: Add pattern parameter +void Plater::calib_flowrate(bool is_linear, int pass, InfillPattern pattern) { if (pass != 1 && pass != 2) return; wxString calib_name; @@ -12915,7 +12918,8 @@ void Plater::calib_flowrate(bool is_linear, int pass) { (boost::filesystem::path(Slic3r::resources_dir()) / "calib" / "filament_flow" / "flowrate-test-pass2.3mf").string()); } - adjust_settings_for_flowrate_calib(model().objects, is_linear, pass); + // ORCA: pass the pattern + adjust_settings_for_flowrate_calib(model().objects, is_linear, pass, pattern); wxGetApp().get_tab(Preset::TYPE_PRINTER)->reload_config(); auto printer_config = &wxGetApp().preset_bundle->printers.get_edited_preset().config; printer_config->set_key_value("resonance_avoidance", new ConfigOptionBool{false}); diff --git a/src/slic3r/GUI/Plater.hpp b/src/slic3r/GUI/Plater.hpp index 8fde64ead2..31e0e2f0e1 100644 --- a/src/slic3r/GUI/Plater.hpp +++ b/src/slic3r/GUI/Plater.hpp @@ -331,7 +331,8 @@ public: // SoftFever void calib_pa(const Calib_Params& params); - void calib_flowrate(bool is_linear, int pass); + //ORCA: Add pattern parameter to calib_flowrate + void calib_flowrate(bool is_linear, int pass, InfillPattern pattern = ipArchimedeanChords); void calib_temp(const Calib_Params& params); void calib_max_vol_speed(const Calib_Params& params); void calib_retraction(const Calib_Params& params); diff --git a/src/slic3r/GUI/calib_dlg.cpp b/src/slic3r/GUI/calib_dlg.cpp index ea7d1e02a5..50b69663e0 100644 --- a/src/slic3r/GUI/calib_dlg.cpp +++ b/src/slic3r/GUI/calib_dlg.cpp @@ -9,6 +9,7 @@ #include #include #include "libslic3r/PrintConfig.hpp" +#include "libslic3r/Utils.hpp" namespace Slic3r { namespace GUI { @@ -1436,4 +1437,97 @@ void Cornering_Test_Dlg::on_dpi_changed(const wxRect& suggested_rect) { Fit(); } +// FlowRateCalibrationDialog +// +FlowRateCalibrationDialog::FlowRateCalibrationDialog(wxWindow* parent, wxWindowID id, Plater* plater) + : DPIDialog(parent, id, _L("Flow Ratio Calibration"), wxDefaultPosition, parent->FromDIP(wxSize(-1, 280)), wxDEFAULT_DIALOG_STYLE), m_plater(plater) +{ + SetBackgroundColour(*wxWHITE); // make sure background color set for dialog + SetForegroundColour(wxColour("#363636")); + SetFont(Label::Body_14); + + wxBoxSizer* v_sizer = new wxBoxSizer(wxVERTICAL); + SetSizer(v_sizer); + + // Type selection + auto labeled_box_type = new LabeledStaticBox(this, _L("Calibration Test Type")); + auto type_box = new wxStaticBoxSizer(labeled_box_type, wxVERTICAL); + + m_rbType = new RadioGroup(this, { _L("Pass 1 (Coarse)"), _L("Pass 2 (Fine)"), _L("YOLO (Recommended)"), _L("YOLO (Perfectionist)") }, wxVERTICAL, 1); + m_rbType->SetSelection(2); // Default to YOLO Recommended + type_box->Add(m_rbType, 0, wxALL | wxEXPAND, FromDIP(4)); + v_sizer->Add(type_box, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10)); + + // Pattern selection + auto labeled_box_pattern = new LabeledStaticBox(this, _L("Top Surface Pattern")); + auto pattern_box = new wxStaticBoxSizer(labeled_box_pattern, wxVERTICAL); + + // ORCA: Use ComboBox with icons instead of RadioGroup + m_rbPattern = new ComboBox(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0, nullptr, wxCB_READONLY); + + boost::filesystem::path image_path(Slic3r::resources_dir()); + image_path /= "images"; + + auto add_pattern_item = [&](const std::string& name, const wxString& label) { + auto icon_name = "param_" + name; + if (boost::filesystem::exists(image_path / (icon_name + ".svg"))) { + // Using 24px icon size to match other settings (Field.cpp uses 24) + ScalableBitmap bm(this, icon_name, 24); + m_rbPattern->Append(label, bm.bmp()); + } else { + m_rbPattern->Append(label); + } + }; + + add_pattern_item("archimedeanchords", _L("Archimedean Chords")); + add_pattern_item("monotonic", _L("Monotonic")); + m_rbPattern->SetSelection(0); // Default to Archimedean Chords + // ORCA: explicit set value to ensure display on Windows + m_rbPattern->SetValue(m_rbPattern->GetString(0)); + + pattern_box->Add(m_rbPattern, 0, wxALL | wxEXPAND, FromDIP(4)); + v_sizer->Add(pattern_box, 0, wxTOP | wxRIGHT | wxLEFT | wxEXPAND, FromDIP(10)); + + v_sizer->AddSpacer(FromDIP(5)); + + auto dlg_btns = new DialogButtons(this, {"OK"}); + + auto bottom_sizer = new wxBoxSizer(wxHORIZONTAL); + auto wiki = new HyperLink(this, _L("Wiki Guide"), "https://www.orcaslicer.com/wiki/calibration/flow-ratio-calib"); + bottom_sizer->Add(wiki, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(20)); + bottom_sizer->AddStretchSpacer(); + bottom_sizer->Add(dlg_btns, 0, wxEXPAND); + v_sizer->Add(bottom_sizer, 0, wxEXPAND); + + dlg_btns->GetOK()->Bind(wxEVT_BUTTON, &FlowRateCalibrationDialog::on_start, this); + + wxGetApp().UpdateDlgDarkUI(this); + + Layout(); + Fit(); +} + +FlowRateCalibrationDialog::~FlowRateCalibrationDialog() { + // Disconnect Events +} + +void FlowRateCalibrationDialog::on_start(wxCommandEvent& event) { + int type = m_rbType->GetSelection(); + int patternIdx = m_rbPattern->GetSelection(); + + InfillPattern pattern = ipArchimedeanChords; + if (patternIdx == 1) pattern = ipMonotonic; + + bool is_linear = (type >= 2); + int pass = (type % 2) + 1; + + m_plater->calib_flowrate(is_linear, pass, pattern); + EndModal(wxID_OK); +} + +void FlowRateCalibrationDialog::on_dpi_changed(const wxRect& suggested_rect) { + this->Refresh(); + Fit(); +} + }} // namespace Slic3r::GUI diff --git a/src/slic3r/GUI/calib_dlg.hpp b/src/slic3r/GUI/calib_dlg.hpp index 759cde1d0d..5ff0fbf3e3 100644 --- a/src/slic3r/GUI/calib_dlg.hpp +++ b/src/slic3r/GUI/calib_dlg.hpp @@ -180,5 +180,21 @@ protected: TextInput* m_tiJDEnd; Plater* m_plater; }; + +class FlowRateCalibrationDialog : public DPIDialog +{ +public: + FlowRateCalibrationDialog(wxWindow* parent, wxWindowID id, Plater* plater); + ~FlowRateCalibrationDialog(); + void on_dpi_changed(const wxRect& suggested_rect) override; + +protected: + virtual void on_start(wxCommandEvent& event); + + RadioGroup* m_rbType; + // ORCA: use standard OrcaSlicer ComboBox instead of BitmapComboBox + ComboBox* m_rbPattern; + Plater* m_plater; +}; }} // namespace Slic3r::GUI #endif