feat(gui): add purge mode selector dialog

The engine already implements prime_volume_mode (Default/Saving/Fast)
but nothing in the UI could set it, leaving prime-saving unreachable on
multi-sub-nozzle extruders and fast purge unreachable on printers that
support it.

- new PurgeModeDialog with selectable Standard/Fast or
  Standard/Prime Saving cards depending on printer capability
- "Purge mode" sidebar button next to Flushing volumes; opens the
  dialog and stores the choice in the project config
- printer preset-load gating: button shown only when the printer has
  multiple sub-nozzles per extruder or sets support_fast_purge_mode;
  stale project values the printer cannot honor reset to Default
- enable fast purge on A2L 0.4 (support_fast_purge_mode), explicit
  default 0 in the common machine base
- new dialog strings added to OrcaSlicer.pot

Printers without these capabilities never show the button and their
projects keep prime_volume_mode at Default, so slicing output is
unchanged.
This commit is contained in:
SoftFever
2026-07-10 15:41:57 +08:00
parent b2eeed2622
commit 93a81179a1
13 changed files with 432 additions and 3 deletions
+18
View File
@@ -18475,6 +18475,24 @@ msgstr ""
msgid "Whether this printer supports fast purge mode with optimized temperature and multiplier."
msgstr ""
msgid "Purge mode"
msgstr ""
msgid "Purge Mode Settings"
msgstr ""
msgid "Prime Saving"
msgstr ""
msgid "Perform full purging with speed and temperature transition for the best print quality."
msgstr ""
msgid "Uses optimized purge temperature, multiplier and stronger extrusion for faster purging. May cause slight color mixing in some extreme cases."
msgstr ""
msgid "Reduces prime waste and prints faster. May cause slight color mixing or small surface defects."
msgstr ""
msgid "Deretraction speed (extruder change)"
msgstr ""
+4
View File
@@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="20" height="20" rx="10" fill="#00AF42" fill-opacity="0.2"/>
<path d="M14.0828 8.14395L9.08284 13.144C9.0393 13.1877 8.98755 13.2223 8.93057 13.246C8.87359 13.2696 8.81251 13.2818 8.75081 13.2818C8.68912 13.2818 8.62803 13.2696 8.57105 13.246C8.51408 13.2223 8.46233 13.1877 8.41878 13.144L6.23128 10.9565C6.18768 10.9129 6.15309 10.8611 6.12949 10.8041C6.1059 10.7471 6.09375 10.6861 6.09375 10.6244C6.09375 10.5628 6.1059 10.5017 6.12949 10.4447C6.15309 10.3878 6.18768 10.336 6.23128 10.2924C6.27488 10.2488 6.32665 10.2142 6.38362 10.1906C6.44059 10.167 6.50165 10.1549 6.56331 10.1549C6.62498 10.1549 6.68604 10.167 6.74301 10.1906C6.79998 10.2142 6.85174 10.2488 6.89534 10.2924L8.7512 12.1482L13.4196 7.48067C13.5076 7.39261 13.6271 7.34314 13.7516 7.34314C13.8761 7.34314 13.9956 7.39261 14.0836 7.48067C14.1717 7.56873 14.2212 7.68817 14.2212 7.8127C14.2212 7.93724 14.1717 8.05667 14.0836 8.14473L14.0828 8.14395Z" fill="#00AF42" stroke="#00AF42" stroke-width="0.833333"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

+4
View File
@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.2" d="M5.98183 18.0178C1.49214 10.5356 7.48183 3.05343 20.1981 3.80156C20.9462 16.5216 13.464 22.5075 5.98183 18.0178Z" fill="#00AF42"/>
<path d="M20.9489 3.75655C20.9381 3.57307 20.8604 3.39991 20.7305 3.26994C20.6005 3.13998 20.4273 3.06226 20.2439 3.05155C13.1067 2.63249 7.38979 4.78124 4.95229 8.81249C4.10738 10.1915 3.69103 11.7903 3.75604 13.4062C3.80948 14.8987 4.24448 16.4062 5.04885 17.8922L3.21979 19.7203C3.07906 19.861 3 20.0519 3 20.2509C3 20.4499 3.07906 20.6408 3.21979 20.7815C3.36052 20.9223 3.55139 21.0013 3.75042 21.0013C3.94944 21.0013 4.14031 20.9223 4.28104 20.7815L6.10917 18.9525C7.59417 19.7559 9.1026 20.1909 10.5942 20.2444C10.6985 20.2481 10.8026 20.25 10.9064 20.25C12.4174 20.254 13.8997 19.8379 15.1879 19.0481C19.2192 16.6106 21.3689 10.8947 20.9489 3.75655ZM14.4145 17.7656C12.2817 19.0575 9.75698 19.0781 7.22292 17.8378L15.532 9.52967C15.6017 9.45999 15.6569 9.37727 15.6947 9.28622C15.7324 9.19518 15.7518 9.0976 15.7518 8.99905C15.7518 8.9005 15.7324 8.80292 15.6947 8.71188C15.6569 8.62083 15.6017 8.53811 15.532 8.46842C15.4623 8.39874 15.3796 8.34347 15.2885 8.30575C15.1975 8.26804 15.0999 8.24863 15.0014 8.24863C14.9028 8.24863 14.8052 8.26804 14.7142 8.30575C14.6231 8.34347 14.5404 8.39874 14.4707 8.46842L6.1626 16.7812C4.92604 14.25 4.94385 11.7187 6.23479 9.58967C8.30573 6.17061 13.2285 4.29842 19.4826 4.52155C19.7067 10.7709 17.8335 15.6947 14.4145 17.7656Z" fill="#00AF42"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

+4
View File
@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.2" d="M20.25 5.25V10.5C20.25 19.5 12 21.75 12 21.75C12 21.75 3.75 19.5 3.75 10.5V5.25C3.75 5.05109 3.82902 4.86032 3.96967 4.71967C4.11032 4.57902 4.30109 4.5 4.5 4.5H19.5C19.6989 4.5 19.8897 4.57902 20.0303 4.71967C20.171 4.86032 20.25 5.05109 20.25 5.25Z" fill="#00AF42"/>
<path d="M19.5 3.75H4.5C4.10218 3.75 3.72064 3.90804 3.43934 4.18934C3.15804 4.47064 3 4.85218 3 5.25V10.5C3 15.4425 5.3925 18.4378 7.39969 20.0803C9.56156 21.8484 11.7122 22.4494 11.8059 22.4738C11.9348 22.5088 12.0708 22.5088 12.1997 22.4738C12.2934 22.4494 14.4413 21.8484 16.6059 20.0803C18.6075 18.4378 21 15.4425 21 10.5V5.25C21 4.85218 20.842 4.47064 20.5607 4.18934C20.2794 3.90804 19.8978 3.75 19.5 3.75ZM19.5 10.5C19.5 13.9753 18.2194 16.7962 15.6937 18.8831C14.5943 19.7885 13.344 20.493 12 20.9644C10.6736 20.5012 9.4387 19.8092 8.35125 18.9197C5.79563 16.8291 4.5 13.9969 4.5 10.5V5.25H19.5V10.5Z" fill="#00AF42"/>
</svg>

After

Width:  |  Height:  |  Size: 1023 B

@@ -87,6 +87,7 @@
"retract_lift_below": [
"326"
],
"support_fast_purge_mode": "1",
"support_object_skip_flush": "1",
"upward_compatible_machine": [
"Bambu Lab H2S 0.4 nozzle"
@@ -141,6 +141,7 @@
"single_extruder_multi_material": "1",
"support_air_filtration": "0",
"support_chamber_temp_control": "0",
"support_fast_purge_mode": "0",
"support_object_skip_flush": "0",
"wipe": [
"1"
+2 -1
View File
@@ -7882,7 +7882,8 @@ void PrintConfigDef::init_fff_params()
def->set_default_value(new ConfigOptionIntsNullable{ 1 });
// Printer flag gating the fast-purge mode selector in the Multi-Filament
// UI. comDevelop, default false; no shipping profile sets it, so the UI stays hidden.
// UI. comDevelop, default false; profiles of printers that support fast purge
// enable it, which shows the purge-mode selector for those printers.
def = this->add("support_fast_purge_mode", coBool);
def->label = L("Support fast purge mode");
def->tooltip = L("Whether this printer supports fast purge mode with optimized temperature and multiplier.");
+2
View File
@@ -411,6 +411,8 @@ set(SLIC3R_GUI_SOURCES
GUI/Project.hpp
GUI/PublishDialog.cpp
GUI/PublishDialog.hpp
GUI/PurgeModeDialog.cpp
GUI/PurgeModeDialog.hpp
GUI/RammingChart.cpp
GUI/RammingChart.hpp
GUI/RecenterDialog.cpp
+36 -2
View File
@@ -170,6 +170,7 @@
#include "StepMeshDialog.hpp"
#include "FilamentMapDialog.hpp"
#include "CloneDialog.hpp"
#include "PurgeModeDialog.hpp"
#include "DeviceCore/DevFilaSystem.h"
#include "DeviceCore/DevManager.h"
@@ -551,6 +552,7 @@ struct Sidebar::priv
wxStaticLine* m_staticline2;
wxPanel* m_panel_project_title;
ScalableButton* m_filament_icon = nullptr;
Button * m_purge_mode_btn = nullptr;
Button * m_flushing_volume_btn = nullptr;
TextInput* m_search_item = nullptr;
StaticBox* m_search_bar = nullptr;
@@ -2663,12 +2665,13 @@ Sidebar::Sidebar(Plater *parent)
p->m_panel_filament_title->SetBackgroundColor(title_bg);
p->m_panel_filament_title->SetBackgroundColor2(0xF1F1F1);
p->m_panel_filament_title->Bind(wxEVT_LEFT_UP, [this](wxMouseEvent &e) {
if (!p || !p->m_panel_filament_content || !m_scrolled_sizer || !p->m_bpButton_set_filament || !p->m_flushing_volume_btn || !p->m_bpButton_add_filament || !ams_btn)
if (!p || !p->m_panel_filament_content || !m_scrolled_sizer || !p->m_bpButton_set_filament || !p->m_purge_mode_btn || !p->m_flushing_volume_btn || !p->m_bpButton_add_filament || !ams_btn)
return;
// ORCA exclude area of del button from titlebar collapse/expand feature to fix undesired collapse when user spams del filament button
// also block fold/unfold feature when user clicks to spacing between icons
int exclude_pt = p->m_bpButton_set_filament->GetPosition().x; // maximum fixed item
if (p->m_flushing_volume_btn->IsShown()) exclude_pt = p->m_flushing_volume_btn->GetPosition().x;
if (p->m_purge_mode_btn->IsShown()) exclude_pt = p->m_purge_mode_btn->GetPosition().x;
else if (p->m_flushing_volume_btn->IsShown()) exclude_pt = p->m_flushing_volume_btn->GetPosition().x;
else if (p->m_bpButton_add_filament->IsShown()) exclude_pt = p->m_bpButton_add_filament->GetPosition().x - FromDIP(30); // reserve spacing for delete button
else if (ams_btn->IsShown()) exclude_pt = ams_btn->GetPosition().x;
if (e.GetPosition().x > exclude_pt)
@@ -2703,6 +2706,24 @@ Sidebar::Sidebar(Plater *parent)
bSizer39->AddStretchSpacer(1);
p->m_purge_mode_btn = new Button(p->m_panel_filament_title, _L("Purge mode"));
p->m_purge_mode_btn->SetStyle(ButtonStyle::Confirm, ButtonType::Compact);
p->m_purge_mode_btn->Bind(wxEVT_BUTTON, [](wxCommandEvent &e) {
auto &preset_bundle = *wxGetApp().preset_bundle;
auto support_fast_purge_opt = preset_bundle.printers.get_edited_preset().config.option<ConfigOptionBool>("support_fast_purge_mode");
bool support_fast_purge = support_fast_purge_opt ? support_fast_purge_opt->value : false;
auto dlg_type = support_fast_purge ? PurgeModeDialogType::FastMode : PurgeModeDialogType::MultiNozzle;
PurgeModeDialog dlg(static_cast<wxWindow *>(wxGetApp().mainframe), dlg_type);
if (dlg.ShowModal() == wxID_OK) {
preset_bundle.project_config.set_key_value("prime_volume_mode", new ConfigOptionEnum<PrimeVolumeMode>(dlg.get_selected_mode()));
wxGetApp().plater()->update();
}
});
bSizer39->Add(p->m_purge_mode_btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, FromDIP(4));
bSizer39->Hide(p->m_purge_mode_btn); // hidden on launch; shown only for printers that support purge mode selection
// BBS
// add wiping dialog
//wiping_dialog_button->SetFont(wxGetApp().normal_font());
@@ -3572,6 +3593,7 @@ void Sidebar::msw_rescale()
p->m_bpButton_del_filament->msw_rescale();
p->m_bpButton_ams_filament->msw_rescale();
p->m_bpButton_set_filament->msw_rescale();
p->m_purge_mode_btn->Rescale();
p->m_flushing_volume_btn->Rescale();
set_flushing_volume_warning(is_flush_config_modified()); // ORCA reapply appearance
@@ -3657,6 +3679,7 @@ void Sidebar::sys_color_changed()
p->m_bpButton_del_filament->msw_rescale();
p->m_bpButton_ams_filament->msw_rescale();
p->m_bpButton_set_filament->msw_rescale();
p->m_purge_mode_btn->Rescale();
p->m_flushing_volume_btn->Rescale();
set_flushing_volume_warning(is_flush_config_modified()); // ORCA reapply appearance
@@ -4426,6 +4449,17 @@ void Sidebar::show_SEMM_buttons()
Layout();
}
void Sidebar::enable_purge_mode_btn(bool enable)
{
if (!p || !p->m_purge_mode_btn)
return;
p->m_purge_mode_btn->Show(enable);
wxGetApp().CallAfter([this]() {
p->m_panel_filament_title->Layout();
this->Layout();
});
}
void Sidebar::update_dynamic_filament_list()
{
dynamic_filament_list.update();
+1
View File
@@ -208,6 +208,7 @@ public:
// Orca
static bool should_show_SEMM_buttons();
void show_SEMM_buttons();
void enable_purge_mode_btn(bool enable);
void update_dynamic_filament_list();
PlaterPresetComboBox * printer_combox();
+269
View File
@@ -0,0 +1,269 @@
#include "PurgeModeDialog.hpp"
#include <wx/sizer.h>
#include <wx/stattext.h>
#include <wx/statbmp.h>
#include <wx/dcbuffer.h>
#include <wx/graphics.h>
#include "I18N.hpp"
#include "GUI_App.hpp"
#include "wxExtensions.hpp"
#include "Widgets/Button.hpp"
#include "libslic3r/Utils.hpp"
namespace Slic3r { namespace GUI {
static const wxColour BgNormalColor = wxColour("#FFFFFF");
static const wxColour BgSelectColor = wxColour("#EBF9F0");
static const wxColour BorderNormalColor = wxColour("#CECECE");
static const wxColour BorderSelectedColor = wxColour("#00AE42");
static const wxColour TextNormalBlackColor = wxColour("#262E30");
static const wxColour TextNormalGreyColor = wxColour("#6B6B6B");
PurgeModeDialog::PurgeModeDialog(wxWindow *parent, PurgeModeDialogType dialog_type)
: DPIDialog(parent, wxID_ANY, _L("Purge Mode Settings"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE), m_dialog_type(dialog_type)
{
SetBackgroundColour(*wxWHITE);
SetMinSize(wxSize(FromDIP(520), FromDIP(320)));
SetMaxSize(wxSize(FromDIP(520), FromDIP(320)));
std::string icon_path = (boost::format("%1%/images/OrcaSlicerTitle.ico") % resources_dir()).str();
SetIcon(wxIcon(encode_path(icon_path.c_str()), wxBITMAP_TYPE_ICO));
auto main_sizer = new wxBoxSizer(wxVERTICAL);
auto options_panel = new wxPanel(this);
auto options_sizer = new wxBoxSizer(wxVERTICAL);
auto panels_sizer = new wxBoxSizer(wxHORIZONTAL);
auto &preset_bundle = *wxGetApp().preset_bundle;
auto current_mode = preset_bundle.project_config.option<ConfigOptionEnum<PrimeVolumeMode>>("prime_volume_mode");
PrimeVolumeMode mode = current_mode ? current_mode->value : pvmDefault;
m_selected_mode = mode;
bool is_fast_mode = (m_dialog_type == PurgeModeDialogType::FastMode);
m_standard_panel = new PurgeModeBtnPanel(options_panel, _L("Standard"), _L("Perform full purging with speed and temperature transition for the best print quality."),
"shield");
m_standard_panel->SetMinSize(wxSize(FromDIP(200), FromDIP(150)));
m_standard_panel->Select(mode == pvmDefault);
m_standard_panel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &) { select_option(pvmDefault); });
panels_sizer->Add(m_standard_panel, 1, wxEXPAND | wxRIGHT, FromDIP(12));
if (is_fast_mode) {
m_saving_panel = new PurgeModeBtnPanel(options_panel, _L("Fast"),
_L("Uses optimized purge temperature, multiplier and stronger extrusion for faster purging. May cause slight color mixing in some extreme cases."), "leaf");
m_saving_panel->SetMinSize(wxSize(FromDIP(200), FromDIP(150)));
m_saving_panel->Select(mode == pvmFast);
m_saving_panel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &) { select_option(pvmFast); });
} else {
m_saving_panel = new PurgeModeBtnPanel(options_panel, _L("Prime Saving"),
_L("Reduces prime waste and prints faster. May cause slight color mixing or small surface defects."), "leaf");
m_saving_panel->SetMinSize(wxSize(FromDIP(200), FromDIP(150)));
m_saving_panel->Select(mode == pvmSaving);
m_saving_panel->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &) { select_option(pvmSaving); });
}
panels_sizer->Add(m_saving_panel, 1, wxEXPAND | wxLEFT, FromDIP(12));
options_sizer->Add(panels_sizer, 0, wxEXPAND | wxALL, FromDIP(20));
options_panel->SetSizer(options_sizer);
main_sizer->Add(options_panel, 1, wxEXPAND);
auto btn_sizer = new wxBoxSizer(wxHORIZONTAL);
btn_sizer->AddStretchSpacer();
auto ok_btn = new Button(this, _L("Confirm"));
ok_btn->SetStyle(ButtonStyle::Confirm, ButtonType::Compact);
ok_btn->SetId(wxID_OK);
auto cancel_btn = new Button(this, _L("Cancel"));
cancel_btn->SetStyle(ButtonStyle::Regular, ButtonType::Compact);
cancel_btn->SetId(wxID_CANCEL);
btn_sizer->Add(ok_btn, 0, wxRIGHT, FromDIP(12));
btn_sizer->Add(cancel_btn, 0);
main_sizer->Add(btn_sizer, 0, wxEXPAND | wxALL, FromDIP(20));
SetSizer(main_sizer);
Fit();
CenterOnParent();
wxGetApp().UpdateDlgDarkUI(this);
}
void PurgeModeDialog::select_option(PrimeVolumeMode mode)
{
m_selected_mode = mode;
update_panel_selection();
}
void PurgeModeDialog::update_panel_selection()
{
if (m_selected_mode == pvmDefault) {
m_standard_panel->Select(true);
m_saving_panel->Select(false);
} else {
m_standard_panel->Select(false);
m_saving_panel->Select(true);
}
}
void PurgeModeDialog::on_dpi_changed(const wxRect &suggested_rect)
{
const int &em = em_unit();
msw_buttons_rescale(this, em, {wxID_OK, wxID_CANCEL});
const wxSize &size = wxSize(70 * em, 32 * em);
SetMinSize(size);
Fit();
Refresh();
}
PurgeModeBtnPanel::PurgeModeBtnPanel(wxWindow *parent, const wxString &label, const wxString &detail, const std::string &icon_path) : wxPanel(parent)
{
SetBackgroundColour(*wxWHITE);
SetBackgroundStyle(wxBG_STYLE_PAINT);
const int horizontal_margin = FromDIP(12);
auto sizer = new wxBoxSizer(wxVERTICAL);
icon = create_scaled_bitmap(icon_path, nullptr, 20);
m_btn = new wxStaticBitmap(this, wxID_ANY, icon, wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
check_icon = create_scaled_bitmap("completed_2", nullptr, 20);
m_check_btn = new wxStaticBitmap(this, wxID_ANY, check_icon, wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
m_check_btn->Hide();
auto icon_sizer = new wxBoxSizer(wxHORIZONTAL);
icon_sizer->Add(m_btn, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, horizontal_margin);
icon_sizer->AddStretchSpacer();
icon_sizer->Add(m_check_btn, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, horizontal_margin);
m_label = new wxStaticText(this, wxID_ANY, label);
m_label->SetFont(Label::Head_14);
m_label->SetForegroundColour(TextNormalBlackColor);
auto label_sizer = new wxBoxSizer(wxHORIZONTAL);
label_sizer->Add(m_label, 0, wxALIGN_CENTER_VERTICAL | wxLEFT, horizontal_margin);
auto detail_sizer = new wxBoxSizer(wxHORIZONTAL);
m_detail = new Label(this, detail);
m_detail->SetFont(Label::Body_12);
m_detail->SetForegroundColour(TextNormalGreyColor);
m_detail->Wrap(FromDIP(200));
detail_sizer->Add(m_detail, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, horizontal_margin);
sizer->AddSpacer(FromDIP(15));
sizer->Add(icon_sizer, 0, wxEXPAND);
sizer->AddSpacer(FromDIP(10));
sizer->Add(label_sizer, 0, wxEXPAND);
sizer->AddSpacer(FromDIP(6));
sizer->Add(detail_sizer, 0, wxEXPAND);
sizer->AddSpacer(FromDIP(10));
SetSizer(sizer);
Layout();
Fit();
wxGetApp().UpdateDarkUIWin(this);
// Clicks on child widgets must select the whole card, so re-dispatch them on the panel.
auto forward_click_to_parent = [this](wxMouseEvent &) {
wxCommandEvent click_event(wxEVT_LEFT_DOWN, GetId());
click_event.SetEventObject(this);
this->ProcessEvent(click_event);
};
m_btn->Bind(wxEVT_LEFT_DOWN, forward_click_to_parent);
m_label->Bind(wxEVT_LEFT_DOWN, forward_click_to_parent);
m_detail->Bind(wxEVT_LEFT_DOWN, forward_click_to_parent);
Bind(wxEVT_PAINT, &PurgeModeBtnPanel::OnPaint, this);
Bind(wxEVT_ENTER_WINDOW, &PurgeModeBtnPanel::OnEnterWindow, this);
Bind(wxEVT_LEAVE_WINDOW, &PurgeModeBtnPanel::OnLeaveWindow, this);
}
void PurgeModeBtnPanel::OnPaint(wxPaintEvent &event)
{
wxAutoBufferedPaintDC dc(this);
wxGraphicsContext *gc = wxGraphicsContext::Create(dc);
if (gc) {
dc.Clear();
wxRect rect = GetClientRect();
gc->SetBrush(wxTransparentColour);
gc->DrawRoundedRectangle(0, 0, rect.width, rect.height, 0);
wxColour bg_color = m_selected ? BgSelectColor : BgNormalColor;
wxColour border_color = m_hover || m_selected ? BorderSelectedColor : BorderNormalColor;
bg_color = StateColor::darkModeColorFor(bg_color);
border_color = StateColor::darkModeColorFor(border_color);
gc->SetBrush(wxBrush(bg_color));
gc->SetPen(wxPen(border_color, 1));
gc->DrawRoundedRectangle(1, 1, rect.width - 2, rect.height - 2, 8);
delete gc;
}
}
void PurgeModeBtnPanel::UpdateStatus()
{
if (m_selected) {
m_btn->SetBackgroundColour(BgSelectColor);
m_label->SetBackgroundColour(BgSelectColor);
m_detail->SetBackgroundColour(BgSelectColor);
if (m_check_btn) {
m_check_btn->SetBackgroundColour(BgSelectColor);
m_check_btn->Show();
}
} else {
m_btn->SetBackgroundColour(BgNormalColor);
m_label->SetBackgroundColour(BgNormalColor);
m_detail->SetBackgroundColour(BgNormalColor);
if (m_check_btn) {
m_check_btn->SetBackgroundColour(BgNormalColor);
m_check_btn->Hide();
}
}
Layout();
Refresh();
wxGetApp().UpdateDarkUIWin(this);
}
void PurgeModeBtnPanel::OnEnterWindow(wxMouseEvent &event)
{
if (!m_hover) {
m_hover = true;
UpdateStatus();
Refresh();
event.Skip();
}
}
void PurgeModeBtnPanel::OnLeaveWindow(wxMouseEvent &event)
{
if (m_hover) {
wxPoint pos = this->ScreenToClient(wxGetMousePosition());
if (this->GetClientRect().Contains(pos)) return;
m_hover = false;
UpdateStatus();
Refresh();
event.Skip();
}
}
void PurgeModeBtnPanel::Select(bool selected)
{
m_selected = selected;
UpdateStatus();
Refresh();
}
}} // namespace Slic3r::GUI
+69
View File
@@ -0,0 +1,69 @@
#pragma once
#include <wx/dialog.h>
#include <wx/panel.h>
#include "GUI_Utils.hpp"
#include "libslic3r/PrintConfig.hpp"
#include "Widgets/Label.hpp"
class wxStaticText;
class wxStaticBitmap;
namespace Slic3r {
namespace GUI {
class PurgeModeBtnPanel : public wxPanel
{
public:
PurgeModeBtnPanel(wxWindow *parent, const wxString &label, const wxString &detail, const std::string &icon_path);
void Select(bool selected);
protected:
void OnPaint(wxPaintEvent &event);
private:
void OnEnterWindow(wxMouseEvent &event);
void OnLeaveWindow(wxMouseEvent &event);
void UpdateStatus();
wxBitmap icon;
wxBitmap check_icon;
wxStaticBitmap *m_btn;
wxStaticBitmap *m_check_btn;
wxStaticText *m_label;
Label *m_detail;
bool m_hover{false};
bool m_selected{false};
};
enum class PurgeModeDialogType {
MultiNozzle,
FastMode
};
class PurgeModeDialog : public DPIDialog
{
public:
PurgeModeDialog(wxWindow *parent, PurgeModeDialogType dialog_type = PurgeModeDialogType::MultiNozzle);
PrimeVolumeMode get_selected_mode() const { return m_selected_mode; }
protected:
void on_dpi_changed(const wxRect &suggested_rect) override;
private:
void select_option(PrimeVolumeMode mode);
void update_panel_selection();
PurgeModeBtnPanel *m_standard_panel;
PurgeModeBtnPanel *m_saving_panel;
PrimeVolumeMode m_selected_mode;
PurgeModeDialogType m_dialog_type;
};
} // namespace GUI
} // namespace Slic3r
+21
View File
@@ -5656,6 +5656,27 @@ void TabPrinter::on_preset_loaded()
if (wxGetApp().plater())
wxGetApp().plater()->sidebar().reset_fila_switch();
}
// Purge mode selection is only meaningful for printers with multiple sub-nozzles per
// extruder (prime saving) or fast-purge support; reset stale project values that the
// current printer cannot honor and toggle the sidebar button accordingly.
auto extruder_max_nozzle_count = current_printer.config.option<ConfigOptionIntsNullable>("extruder_max_nozzle_count");
bool has_multiple_nozzle = extruder_max_nozzle_count &&
std::any_of(extruder_max_nozzle_count->values.begin(), extruder_max_nozzle_count->values.end(),
[](int v) { return v > 1 && v != ConfigOptionIntsNullable::nil_value(); });
auto support_fast_purge_opt = current_printer.config.option<ConfigOptionBool>("support_fast_purge_mode");
bool support_fast_purge = support_fast_purge_opt ? support_fast_purge_opt->value : false;
bool show_purge_mode = has_multiple_nozzle || support_fast_purge;
if (auto *prime_volume_mode = m_preset_bundle->project_config.option<ConfigOptionEnum<PrimeVolumeMode>>("prime_volume_mode")) {
if (!show_purge_mode)
prime_volume_mode->value = PrimeVolumeMode::pvmDefault;
else if (!has_multiple_nozzle && prime_volume_mode->value == PrimeVolumeMode::pvmSaving)
prime_volume_mode->value = PrimeVolumeMode::pvmDefault;
else if (!support_fast_purge && prime_volume_mode->value == PrimeVolumeMode::pvmFast)
prime_volume_mode->value = PrimeVolumeMode::pvmDefault;
}
if (wxGetApp().plater())
wxGetApp().plater()->sidebar().enable_purge_mode_btn(show_purge_mode);
}
void TabPrinter::update_pages()