ENH: refine ui logic with filament group

1. Add filament group pop up when slice
2. Add more filament modes in filament dialog
3. Add capsule button

jira:NONE

Signed-off-by: xun.zhang <xun.zhang@bambulab.com>
Change-Id: I8bc3a2e08696e406b89e550a0335a1a36728ee65
This commit is contained in:
xun.zhang 2024-11-29 17:37:07 +08:00 committed by lane.wei
parent 414a2105c9
commit f1702a5c36
27 changed files with 1255 additions and 258 deletions

View File

@ -172,4 +172,6 @@ src/slic3r/GUI/SendMultiMachinePage.cpp
src/slic3r/GUI/MultiMachinePage.cpp
src/slic3r/GUI/MultiMachineManagerPage.cpp
src/slic3r/GUI/MultiTaskManagerPage.cpp
src/slic3r/GUI/MultiMachine.cpp
src/slic3r/GUI/MultiMachine.cpp
src/slic3r/GUI/FilamentMapDialog.cpp
src/slic3r/GUI/FilamentGroupPopup.cpp

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="7.5" stroke="#C2C2C2"/>
</svg>

After

Width:  |  Height:  |  Size: 152 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="16" height="16" rx="8" fill="#00AE42"/>
<path d="M6.83 11.37L4 8.54L5.41 7.13L6.82 8.54L10.36 5L11.77 6.41L6.83 11.37Z" fill="#F7F7F7"/>
</svg>

After

Width:  |  Height:  |  Size: 253 B

View File

@ -0,0 +1,7 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.07262 4.61082C3.35049 5.95191 2.88086 7.8561 2.88086 10.0005C2.88086 12.1449 3.35049 14.0491 4.07262 15.3902C4.8112 16.7618 5.70585 17.3755 6.50586 17.3755C7.30587 17.3755 8.20052 16.7618 8.9391 15.3902C9.66123 14.0491 10.1309 12.1449 10.1309 10.0005C10.1309 7.8561 9.66123 5.95191 8.9391 4.61082C8.20052 3.23918 7.30587 2.62549 6.50586 2.62549C5.70585 2.62549 4.8112 3.23918 4.07262 4.61082ZM2.75191 3.89967C3.59678 2.33064 4.88962 1.12549 6.50586 1.12549C8.1221 1.12549 9.41494 2.33064 10.2598 3.89967C11.1211 5.49925 11.6309 7.65756 11.6309 10.0005C11.6309 12.3434 11.1211 14.5017 10.2598 16.1013C9.41494 17.6703 8.1221 18.8755 6.50586 18.8755C4.88962 18.8755 3.59678 17.6703 2.75191 16.1013C1.8906 14.5017 1.38086 12.3434 1.38086 10.0005C1.38086 7.65756 1.8906 5.49925 2.75191 3.89967Z" fill="#262E30"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.8071 5H7.13086C6.09533 5 5.25586 6.84409 5.25586 10C5.25586 13.1559 6.09533 15 7.13086 15H11.8071C11.2267 13.6213 10.8809 11.8857 10.8809 10C10.8809 8.11434 11.2267 6.37871 11.8071 5Z" fill="#D9D9D9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.0988 4.375H7.13086C6.19757 4.375 5.58064 5.18705 5.22406 6.08611C4.84543 7.04076 4.63086 8.37669 4.63086 10C4.63086 11.6233 4.84543 12.9592 5.22406 13.9139C5.58064 14.813 6.19757 15.625 7.13086 15.625H12.0988C11.9011 15.2423 11.7233 14.8237 11.5686 14.375H7.13086C7.02862 14.375 6.70804 14.265 6.38601 13.453C6.08602 12.6967 5.88086 11.5326 5.88086 10C5.88086 8.46739 6.08602 7.30333 6.38601 6.54696C6.70804 5.73499 7.02862 5.625 7.13086 5.625H11.5686C11.7233 5.1763 11.9011 4.75771 12.0988 4.375Z" fill="#262E30"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.8226 4.61082C12.1005 5.95191 11.6309 7.8561 11.6309 10.0005C11.6309 12.1449 12.1005 14.0491 12.8226 15.3902C13.5612 16.7618 14.4558 17.3755 15.2559 17.3755C16.0559 17.3755 16.9505 16.7618 17.6891 15.3902C18.4112 14.0491 18.8809 12.1449 18.8809 10.0005C18.8809 7.8561 18.4112 5.95191 17.6891 4.61082C16.9505 3.23918 16.0559 2.62549 15.2559 2.62549C14.4558 2.62549 13.5612 3.23918 12.8226 4.61082ZM11.5019 3.89967C12.3468 2.33064 13.6396 1.12549 15.2559 1.12549C16.8721 1.12549 18.1649 2.33064 19.0098 3.89967C19.8711 5.49925 20.3809 7.65756 20.3809 10.0005C20.3809 12.3434 19.8711 14.5017 19.0098 16.1013C18.1649 17.6703 16.8721 18.8755 15.2559 18.8755C13.6396 18.8755 12.3468 17.6703 11.5019 16.1013C10.6406 14.5017 10.1309 12.3434 10.1309 10.0005C10.1309 7.65756 10.6406 5.49925 11.5019 3.89967Z" fill="#262E30"/>
<ellipse cx="15.2559" cy="10" rx="1.25" ry="2.5" fill="#D9D9D9" stroke="#262E30" stroke-width="0.6" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,3 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8.29004" cy="8.23108" r="7.5" stroke="#C2C2C2"/>
</svg>

After

Width:  |  Height:  |  Size: 164 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="7.5" fill="#00AE42" fill-opacity="0.16" stroke="#00AE42"/>
</svg>

After

Width:  |  Height:  |  Size: 187 B

View File

@ -0,0 +1,4 @@
<svg width="17" height="17" viewBox="0 0 17 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.290039" y="0.231079" width="16" height="16" rx="8" fill="#00AE42"/>
<circle cx="8.29004" cy="8.23108" r="3" fill="#F7F7F7"/>
</svg>

After

Width:  |  Height:  |  Size: 239 B

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="16" height="16" rx="8" fill="#00AE42"/>
<circle cx="8" cy="8" r="3" fill="#F7F7F7"/>
</svg>

After

Width:  |  Height:  |  Size: 201 B

View File

@ -0,0 +1,3 @@
<svg width="21" height="20" viewBox="0 0 21 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.8223 0.670677C18.5805 0.604357 18.3102 0.624806 18.0559 0.763978L1.22745 9.97419C0.29897 10.4823 0.417205 11.8517 1.41905 12.1932L5.9217 13.728C6.32217 13.8645 6.75749 13.6505 6.89399 13.25C7.0305 12.8495 6.81651 12.4142 6.41603 12.2777L2.59174 10.9742L15.6966 3.80188L8.1136 12.895C7.72855 13.3567 7.51766 13.9389 7.51766 14.5401V18.5996C7.51766 19.0227 7.86065 19.3657 8.28376 19.3657C8.70686 19.3657 9.04985 19.0227 9.04985 18.5996V14.5401C9.04985 14.2975 9.13495 14.0626 9.29032 13.8763L17.6718 3.82563L15.5515 15.8879L11.0451 14.228C10.6481 14.0818 10.2077 14.2851 10.0615 14.6821C9.91523 15.0791 10.1185 15.5195 10.5156 15.6658L15.3763 17.4562C16.0882 17.7184 16.8638 17.2723 16.9952 16.5251L19.5743 1.85264C19.6457 1.44649 19.4792 1.08673 19.2029 0.865349C19.1918 0.854897 19.1803 0.844711 19.1684 0.834808C19.0651 0.748615 18.9457 0.694265 18.8223 0.670677Z" fill="#262E30"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -265,6 +265,18 @@ void AppConfig::set_defaults()
set_bool("auto_calculate_when_filament_change", true);
}
if (get("ignore_ext_filament_in_filament_map").empty()){
set_bool("ignore_ext_filament_in_filament_map", false);
}
if (get("pop_up_filament_map_mode").empty()){
set_bool("pop_up_filament_map_mode", true);
}
if (get("prefered_filament_map_mode").empty()){
set("prefered_filament_map_mode",ConfigOptionEnum<FilamentMapMode>::get_enum_names()[FilamentMapMode::fmmAutoForFlush]);
}
if (get("show_home_page").empty()) {
set_bool("show_home_page", true);
}

View File

@ -286,6 +286,10 @@ set(SLIC3R_GUI_SOURCES
GUI/Field.hpp
GUI/DragDropPanel.cpp
GUI/DragDropPanel.hpp
GUI/CapsuleButton.cpp
GUI/CapsuleButton.hpp
GUI/FilamentMapPanel.cpp
GUI/FilamentMapPanel.hpp
GUI/FilamentMapDialog.cpp
GUI/FilamentMapDialog.hpp
GUI/OptionsGroup.cpp
@ -406,6 +410,8 @@ set(SLIC3R_GUI_SOURCES
GUI/InstanceCheck.hpp
GUI/Search.cpp
GUI/Search.hpp
GUI/FilamentGroupPopup.hpp
GUI/FilamentGroupPopup.cpp
GUI/NotificationManager.cpp
GUI/NotificationManager.hpp
GUI/UnsavedChangesDialog.cpp

View File

@ -0,0 +1,117 @@
#include "GUI_App.hpp"
#include "CapsuleButton.hpp"
#include "wx/graphics.h"
#include "Widgets/Label.hpp"
#include "wx/dcgraph.h"
namespace Slic3r { namespace GUI {
CapsuleButton::CapsuleButton(wxWindow *parent, wxWindowID id, const wxString &label, bool selected) : wxPanel(parent, id)
{
SetBackgroundColour(*wxWHITE);
SetBackgroundStyle(wxBG_STYLE_PAINT);
m_hovered = false;
m_selected = selected;
auto sizer = new wxBoxSizer(wxHORIZONTAL);
std::string icon_name = selected ? "capsule_tag_on" : "capsule_tag_off";
auto bmp = create_scaled_bitmap(icon_name, nullptr, FromDIP(16));
m_btn = new wxBitmapButton(this, wxID_ANY, bmp, wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
m_btn->SetBackgroundColour(*wxWHITE);
m_label = new Label(this, label);
sizer->AddSpacer(FromDIP(8));
sizer->Add(m_btn, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, FromDIP(6));
sizer->AddSpacer(FromDIP(8));
sizer->Add(m_label, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, FromDIP(6));
sizer->AddSpacer(FromDIP(8));
SetSizer(sizer);
Layout();
Fit();
auto forward_click_to_parent = [this](auto &event) {
wxCommandEvent click_event(wxEVT_BUTTON, 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);
this->Bind(wxEVT_LEFT_DOWN, forward_click_to_parent);
Bind(wxEVT_PAINT, &CapsuleButton::OnPaint, this);
Bind(wxEVT_ENTER_WINDOW, &CapsuleButton::OnEnterWindow, this);
Bind(wxEVT_LEAVE_WINDOW, &CapsuleButton::OnLeaveWindow, this);
GUI::wxGetApp().UpdateDarkUIWin(this);
}
void CapsuleButton::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 ? wxColour("#EBF9F0") : wxColour("#FFFFFF");
wxColour border_color = m_hovered || m_selected ? wxColour("#00AE42") : wxColour("#CECECE");
int cornerRadius = 5;
gc->SetBrush(wxBrush(bg_color));
gc->SetPen(wxPen(border_color, 2));
gc->DrawRoundedRectangle(1, 1, rect.width - 2, rect.height - 2, cornerRadius);
delete gc;
}
}
void CapsuleButton::Select(bool selected)
{
m_selected = selected;
UpdateStatus();
Refresh();
}
void CapsuleButton::OnEnterWindow(wxMouseEvent &event)
{
if (!m_hovered) {
m_hovered = true;
UpdateStatus();
Refresh();
}
event.Skip();
}
void CapsuleButton::OnLeaveWindow(wxMouseEvent &event)
{
if (m_hovered) {
wxPoint pos = this->ScreenToClient(wxGetMousePosition());
if (this->GetClientRect().Contains(pos)) return;
m_hovered = false;
UpdateStatus();
Refresh();
}
event.Skip();
}
void CapsuleButton::UpdateStatus()
{
const wxColour selected_color = wxColour("#EBF9F0");
const wxColour normal_color = wxColour("#FFFFFF");
std::string icon_name = m_selected ? "capsule_tag_on" : "capsule_tag_off";
auto bmp = create_scaled_bitmap(icon_name, nullptr, FromDIP(16));
m_btn->SetBitmap(bmp);
if (m_selected) {
m_label->SetBackgroundColour(selected_color);
m_btn->SetBackgroundColour(selected_color);
} else {
m_label->SetBackgroundColour(normal_color);
m_btn->SetBackgroundColour(normal_color);
}
}
}} // namespace Slic3r::GUI

View File

@ -0,0 +1,28 @@
#ifndef CAPSULE_BUTTON_HPP
#define CAPSULE_BUTTON_HPP
#include "GUI.hpp"
#include "wxExtensions.hpp"
namespace Slic3r { namespace GUI {
class CapsuleButton : public wxPanel
{
public:
CapsuleButton(wxWindow *parent, wxWindowID id, const wxString &label, bool selected);
void Select(bool selected);
protected:
void OnPaint(wxPaintEvent &event);
private:
void OnEnterWindow(wxMouseEvent &event);
void OnLeaveWindow(wxMouseEvent &event);
void UpdateStatus();
wxBitmapButton *m_btn;
Label *m_label;
bool m_hovered;
bool m_selected;
};
}} // namespace Slic3r::GUI
#endif

View File

@ -1,4 +1,5 @@
#include "DragDropPanel.hpp"
#include "Widgets/Label.hpp"
#include <slic3r/GUI/wxExtensions.hpp>
namespace Slic3r { namespace GUI {
@ -9,6 +10,27 @@ struct CustomData
unsigned char r, g, b;
};
wxColor Hex2Color(const std::string& str)
{
if (str.empty() || (str.length() != 9 && str.length() != 7) || str[0] != '#')
throw std::invalid_argument("Invalid hex color format");
auto hexToByte = [](const std::string& hex)->unsigned char
{
unsigned int byte;
std::istringstream(hex) >> std::hex >> byte;
return static_cast<unsigned char>(byte);
};
auto r = hexToByte(str.substr(1, 2));
auto g = hexToByte(str.substr(3, 2));
auto b = hexToByte(str.substr(5, 2));
unsigned char a = 255;
if (str.size() == 9)
a = hexToByte(str.substr(7, 2));
return wxColor(r, g, b, a);
}
// Custom data object used to store information that needs to be backed up during drag and drop
class ColorDataObject : public wxCustomDataObject
{
@ -150,21 +172,24 @@ DragDropPanel::DragDropPanel(wxWindow *parent, const wxString &label, bool is_au
auto title_sizer = new wxBoxSizer(wxHORIZONTAL);
title_panel->SetSizer(title_sizer);
wxStaticText *staticText = new wxStaticText(this, wxID_ANY, label);
staticText->SetBackgroundColour(0xEEEEEE);
title_sizer->Add(staticText, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
Label* static_text = new Label(this, label);
static_text->SetFont(Label::Head_13);
static_text->SetBackgroundColour(0xEEEEEE);
title_sizer->Add(static_text, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
m_sizer->Add(title_panel, 0, wxEXPAND);
m_sizer->AddSpacer(20);
m_grid_item_sizer = new wxGridSizer(0, 5, FromDIP(10), 0); // row = 0, col = 3, 10 10 is space
m_sizer->Add(m_grid_item_sizer);
m_grid_item_sizer = new wxGridSizer(0, 6, FromDIP(5),FromDIP(5)); // row = 0, col = 3, 10 10 is space
m_sizer->Add(m_grid_item_sizer, 1, wxEXPAND);
// set droptarget
auto drop_target = new ColorDropTarget(this);
SetDropTarget(drop_target);
SetSizer(m_sizer);
Layout();
Fit();
}
@ -172,7 +197,7 @@ void DragDropPanel::AddColorBlock(const wxColour &color, int filament_id, bool u
{
ColorPanel *panel = new ColorPanel(this, color, filament_id);
panel->SetMinSize(wxSize(FromDIP(32), FromDIP(40)));
m_grid_item_sizer->Add(panel, 0, wxALIGN_CENTER | wxLEFT, FromDIP(10));
m_grid_item_sizer->Add(panel, 0, wxALIGN_CENTER);
m_filament_blocks.push_back(panel);
if (update_ui) {
m_filament_blocks.front()->Refresh(); // FIX BUG: STUDIO-8467

View File

@ -11,6 +11,9 @@
namespace Slic3r { namespace GUI {
wxColor Hex2Color(const std::string& str);
class ColorPanel;
class DragDropPanel : public wxPanel
{

View File

@ -0,0 +1,318 @@
#include "FilamentGroupPopup.hpp"
#include "FilamentMapDialog.hpp"
#include "GUI_App.hpp"
#include "MsgDialog.hpp"
#include "I18N.hpp"
#include "wx/dcgraph.h"
namespace Slic3r { namespace GUI {
static const wxString AutoForFlushLabel = _L("Filament-Saving Mode");
static const wxString AutoForMatchLabel = _L("Convenient Mode");
static const wxString ManualLabel = _L("Manual Mode");
static const wxString AutoForFlushDesp = _L("(Arrage after slicing)");
static const wxString AutoForMatchDesp = _L("(Arrange before slicing)");
static const wxString ManualDesp = "";
static const wxString AutoForFlushDetail = _L("Disregrad the filaments in AMS. Optimize filament usage "
"by calculating the best allocation for the left and right "
"nozzles. Arrange the filaments according on the printer according to "
"the slicing results.");
static const wxString AutoForMatchDetail = _L("Based on the current filaments in the AMS, allocate the "
"filaments to the left and right nozzles.");
static const wxString ManualDetail = _L("Mannully allocate the filaments for the left and right nozzles.");
static bool is_multi_extruder()
{
const auto &preset_bundle = wxGetApp().preset_bundle;
const auto &full_config = preset_bundle->full_config();
const auto nozzle_diameters = full_config.option<ConfigOptionFloatsNullable>("nozzle_diameter");
return nozzle_diameters->size() > 1;
}
FilamentMapMode get_prefered_map_mode()
{
const static std::map<std::string, int> enum_keys_map = ConfigOptionEnum<FilamentMapMode>::get_enum_values();
auto &app_config = wxGetApp().app_config;
std::string mode_str = app_config->get("prefered_filament_map_mode");
auto iter = enum_keys_map.find(mode_str);
if (iter == enum_keys_map.end()) {
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("Could not get prefered_filament_map_mode from app config, use AutoForFlsuh mode");
return FilamentMapMode::fmmAutoForFlush;
}
return FilamentMapMode(iter->second);
}
static void set_prefered_map_mode(FilamentMapMode mode)
{
const static std::vector<std::string> enum_values = ConfigOptionEnum<FilamentMapMode>::get_enum_names();
auto &app_config = wxGetApp().app_config;
std::string mode_str;
if (mode < enum_values.size()) mode_str = enum_values[mode];
if (mode_str.empty()) BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format("Set empty prefered_filament_map_mode to app config");
app_config->set("prefered_filament_map_mode", mode_str);
}
static bool get_pop_up_remind_flag()
{
auto &app_config = wxGetApp().app_config;
return app_config->get_bool("pop_up_filament_map_mode");
}
static void set_pop_up_remind_flag(bool remind)
{
auto &app_config = wxGetApp().app_config;
app_config->set_bool("pop_up_filament_map_mode", remind);
}
bool is_pop_up_required()
{
FilamentMapMode mode = get_prefered_map_mode();
bool is_manual_mode_ = FilamentMapMode::fmmManual == mode;
bool is_multi_extruder_ = is_multi_extruder();
return is_multi_extruder_ && is_manual_mode_;
}
FilamentGroupPopup::FilamentGroupPopup(wxWindow *parent) : PopupWindow(parent, wxBORDER_NONE)
{
wxBoxSizer *top_sizer = new wxBoxSizer(wxVERTICAL);
const int horizontal_margin = FromDIP(16);
const int vertical_margin = FromDIP(15);
const int vertical_padding = FromDIP(12);
const int ratio_spacing = FromDIP(4);
const wxColor background_color = wxColor(255, 255, 255);
SetBackgroundColour(background_color);
radio_btns.resize(ButtonType::btCount);
button_labels.resize(ButtonType::btCount);
button_desps.resize(ButtonType::btCount);
detail_infos.resize(ButtonType::btCount);
std::vector<wxString> btn_texts = {AutoForFlushLabel, AutoForMatchLabel, ManualLabel};
std::vector<wxString> btn_desps = {AutoForFlushDesp, AutoForMatchDesp, ManualDesp};
std::vector<wxString> mode_details = {AutoForFlushDetail, AutoForMatchDetail, ManualDetail};
top_sizer->AddSpacer(vertical_margin);
auto checked_bmp = create_scaled_bitmap("map_mode_on", nullptr, 16);
auto unchecked_bmp = create_scaled_bitmap("map_mode_off", nullptr, 16);
for (size_t idx = 0; idx < ButtonType::btCount; ++idx) {
wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
radio_btns[idx] = new wxBitmapButton(this, idx, unchecked_bmp, wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
radio_btns[idx]->SetBackgroundColour(background_color);
button_labels[idx] = new wxStaticText(this, wxID_ANY, btn_texts[idx]);
button_labels[idx]->SetBackgroundColour(background_color);
button_labels[idx]->SetForegroundColour(wxColor("#262E30"));
button_labels[idx]->SetFont(Label::Head_14);
button_desps[idx] = new wxStaticText(this, wxID_ANY, btn_desps[idx]);
button_desps[idx]->SetBackgroundColour(background_color);
button_desps[idx]->SetForegroundColour(wxColor("#262E30"));
button_desps[idx]->SetFont(Label::Body_14);
button_sizer->Add(radio_btns[idx], 0, wxALIGN_CENTER_VERTICAL);
button_sizer->AddSpacer(ratio_spacing);
button_sizer->Add(button_labels[idx], 0, wxALIGN_CENTER_VERTICAL);
button_sizer->Add(button_desps[idx], 0, wxALIGN_CENTER_VERTICAL);
wxBoxSizer *label_sizer = new wxBoxSizer(wxHORIZONTAL);
detail_infos[idx] = new wxStaticText(this, wxID_ANY, mode_details[idx]);
detail_infos[idx]->SetBackgroundColour(background_color);
detail_infos[idx]->SetForegroundColour(wxColor("#6B6B6B"));
detail_infos[idx]->SetFont(Label::Body_12);
detail_infos[idx]->Wrap(FromDIP(320));
label_sizer->AddSpacer(radio_btns[idx]->GetRect().width + ratio_spacing);
label_sizer->Add(detail_infos[idx], 1, wxEXPAND | wxALIGN_CENTER_VERTICAL);
top_sizer->Add(button_sizer, 0, wxLEFT | wxRIGHT, horizontal_margin);
top_sizer->Add(label_sizer, 0, wxLEFT | wxRIGHT, horizontal_margin);
top_sizer->AddSpacer(vertical_padding);
radio_btns[idx]->Bind(wxEVT_BUTTON, [this, idx](wxCommandEvent &event) {
event.SetInt(idx);
OnRadioBtn(event);
});
radio_btns[idx]->Bind(wxEVT_ENTER_WINDOW, [this, idx](wxMouseEvent &) { UpdateButtonStatus(idx); });
radio_btns[idx]->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent &) { UpdateButtonStatus(); });
button_labels[idx]->Bind(wxEVT_LEFT_UP, [this, idx](wxMouseEvent &) {
wxCommandEvent event;
event.SetInt(idx);
OnRadioBtn(event);
});
button_labels[idx]->Bind(wxEVT_ENTER_WINDOW, [this, idx](wxMouseEvent &) { UpdateButtonStatus(idx); });
button_labels[idx]->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent &) { UpdateButtonStatus(); });
}
{
wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
wiki_link = new wxStaticText(this, wxID_ANY, _L("More info on wiki"));
wiki_link->SetBackgroundColour(background_color);
wiki_link->SetForegroundColour(wxColor("#00AE42"));
wiki_link->SetFont(Label::Body_12.Underlined());
wiki_link->SetCursor(wxCursor(wxCURSOR_HAND));
wiki_link->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent &) { wxLaunchDefaultBrowser("http//:example.com"); });
remind_checkbox = new wxCheckBox(this, wxID_ANY, _L("Don't remind me again"));
remind_checkbox->SetBackgroundColour(background_color);
remind_checkbox->SetForegroundColour(wxColor("#6B6B6B"));
remind_checkbox->SetFont(Label::Body_12);
remind_checkbox->Bind(wxEVT_CHECKBOX, &FilamentGroupPopup::OnRemindBtn, this);
button_sizer->Add(wiki_link, 0, wxLEFT, horizontal_margin);
button_sizer->AddStretchSpacer();
button_sizer->Add(remind_checkbox, 0, wxRIGHT, horizontal_margin);
top_sizer->Add(button_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, horizontal_margin);
}
top_sizer->AddSpacer(vertical_margin);
SetSizerAndFit(top_sizer);
m_mode = get_prefered_map_mode();
m_timer = new wxTimer(this);
GUI::wxGetApp().UpdateDarkUIWin(this);
Bind(wxEVT_TIMER, &FilamentGroupPopup::OnTimer, this);
Bind(wxEVT_ENTER_WINDOW, &FilamentGroupPopup::OnEnterWindow, this);
Bind(wxEVT_LEAVE_WINDOW, &FilamentGroupPopup::OnLeaveWindow, this);
}
void FilamentGroupPopup::DrawRoundedCorner(int radius)
{
#ifdef __WIN32__
HWND hwnd = GetHWND();
if (hwnd) {
HRGN hrgn = CreateRoundRectRgn(0, 0, GetRect().GetWidth(), GetRect().GetHeight(), radius, radius);
SetWindowRgn(hwnd, hrgn, TRUE);
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hwnd, 0, 0, LWA_COLORKEY);
}
#else
wxClientDC dc(this);
wxGraphicsContext *gc = wxGraphicsContext::Create(dc);
if (gc) {
gc->SetBrush(*wxWHITE_BRUSH);
gc->SetPen(*wxTRANSPARENT_PEN);
wxRect rect(0, 0, GetSize().GetWidth(), GetSize().GetHeight());
wxGraphicsPath path = wxGraphicsRenderer::GetDefaultRenderer()->CreatePath();
path.AddRoundedRectangle(0, 0, rect.width, rect.height, radius);
gc->DrawPath(path);
delete gc;
}
#endif
}
void FilamentGroupPopup::Init(bool connect_status)
{
radio_btns[ButtonType::btForMatch]->Enable(connect_status);
button_labels[ButtonType::btForMatch]->Enable(connect_status);
m_mode = get_prefered_map_mode();
wxCheckBoxState check_state = get_pop_up_remind_flag() ? wxCheckBoxState::wxCHK_UNCHECKED : wxCheckBoxState::wxCHK_CHECKED;
remind_checkbox->Set3StateValue(check_state);
UpdateButtonStatus();
}
void FilamentGroupPopup::tryPopup(bool connect_status)
{
auto canPopup = [this]() {
bool is_multi_extruder_ = is_multi_extruder();
bool pop_up_flag = get_pop_up_remind_flag();
return is_multi_extruder_ && pop_up_flag;
};
if (canPopup()) {
DrawRoundedCorner(16);
Init(connect_status);
ResetTimer();
PopupWindow::Popup();
}
}
void FilamentGroupPopup::tryClose() { StartTimer(); }
void FilamentGroupPopup::StartTimer() { m_timer->StartOnce(300); }
void FilamentGroupPopup::ResetTimer()
{
if (m_timer->IsRunning()) { m_timer->Stop(); }
}
void FilamentGroupPopup::OnRadioBtn(wxCommandEvent &event)
{
m_mode = mode_list.at(event.GetInt());
set_prefered_map_mode(m_mode);
UpdateButtonStatus(m_mode);
}
void FilamentGroupPopup::OnRemindBtn(wxCommandEvent &event)
{
bool is_checked = remind_checkbox->IsChecked();
set_pop_up_remind_flag(!is_checked);
if (is_checked) {
MessageDialog dialog(nullptr, _L("No further pop up.You can go to \"Preferences\" to reopen the pop up."), _L("Tips"), wxICON_INFORMATION | wxOK);
dialog.ShowModal();
Dismiss();
}
}
void FilamentGroupPopup::OnTimer(wxTimerEvent &event) { Dismiss(); }
void FilamentGroupPopup::OnLeaveWindow(wxMouseEvent &)
{
wxPoint pos = this->ScreenToClient(wxGetMousePosition());
if (this->GetClientRect().Contains(pos)) return;
StartTimer();
}
void FilamentGroupPopup::OnEnterWindow(wxMouseEvent &) { ResetTimer(); }
void FilamentGroupPopup::UpdateButtonStatus(int hover_idx)
{
auto checked_bmp = create_scaled_bitmap("map_mode_on", nullptr, 16);
auto unchecked_bmp = create_scaled_bitmap("map_mode_off", nullptr, 16);
auto checked_hover_bmp = create_scaled_bitmap("map_mode_on_hovered", nullptr);
auto unchecked_hover_bmp = create_scaled_bitmap("map_mode_off_hovered", nullptr);
for (int i = 0; i < ButtonType::btCount; ++i) {
// process checked and unchecked status
if (mode_list.at(i) == m_mode) {
if (i == hover_idx)
radio_btns[i]->SetBitmap(checked_hover_bmp);
else
radio_btns[i]->SetBitmap(checked_bmp);
button_labels[i]->SetFont(Label::Head_14);
} else {
if (i == hover_idx)
radio_btns[i]->SetBitmap(unchecked_hover_bmp);
else
radio_btns[i]->SetBitmap(unchecked_bmp);
button_labels[i]->SetFont(Label::Body_14);
}
}
if (m_mode == FilamentMapMode::fmmAutoForMatch)
remind_checkbox->Enable(false);
else
remind_checkbox->Enable(true);
}
}} // namespace Slic3r::GUI

View File

@ -0,0 +1,54 @@
#ifndef FILAMENT_GROUP_HOVER_HPP
#define FILAMENT_GROUP_HOVER_HPP
#include <wx/graphics.h>
#include <wx/hyperlink.h>
#include "wxExtensions.hpp"
#include "Widgets/PopupWindow.hpp"
namespace Slic3r { namespace GUI {
bool is_pop_up_required();
FilamentMapMode get_prefered_map_mode();
class FilamentGroupPopup : public PopupWindow
{
public:
FilamentGroupPopup(wxWindow *parent);
void tryPopup(bool connect_status);
void tryClose();
FilamentMapMode GetSelectedMode() const { return m_mode; }
private:
void StartTimer();
void ResetTimer();
void OnRadioBtn(wxCommandEvent &event);
void OnLeaveWindow(wxMouseEvent &);
void OnEnterWindow(wxMouseEvent &);
void OnTimer(wxTimerEvent &event);
void OnRemindBtn(wxCommandEvent &event);
void Init(bool connect_status);
void UpdateButtonStatus(int hover_idx = -1);
void DrawRoundedCorner(int radius);
private:
enum ButtonType { btForFlush, btForMatch, btManual, btCount };
const std::vector<FilamentMapMode> mode_list = {fmmAutoForFlush, fmmAutoForMatch, fmmManual};
FilamentMapMode m_mode;
wxTimer *m_timer;
std::vector<wxBitmapButton *> radio_btns;
std::vector<wxStaticText *> button_labels;
std::vector<wxStaticText *> button_desps;
std::vector<wxStaticText *> detail_infos;
wxStaticText *wiki_link;
wxCheckBox *remind_checkbox;
};
}} // namespace Slic3r::GUI
#endif

View File

@ -3,210 +3,118 @@
#include "Widgets/Button.hpp"
#include "Widgets/SwitchButton.hpp"
#include "I18N.hpp"
#include "GUI_App.hpp"
#include "CapsuleButton.hpp"
#include "SelectMachine.hpp"
namespace Slic3r { namespace GUI {
const wxString manual_tips = _L("we will slice according to this grouping method:");
const wxString manual_below_tips = _L("Tips:\n"
"You can drag the filaments to change which extruder they are assigned to.\n"
"But your filament arrangement may not be the most filament-efficient.");
const wxString auto_tips = _L("Automatic filament grouping will be performed to reduce flushing consumption\n"
"and filament changes during the slicing process.\n"
"The recommended results will be displayed below after slicing:");
const wxString auto_tips_with_result = _L("Automatic filament grouping will be performed to reduce flushing consumption\n"
"and filament changes during the slicing process.\n"
"The recommended results are shown below:");
wxColour hex_to_color(const std::string &hex)
{
if ((hex.length() != 7 && hex.length() != 9) || hex[0] != '#') {
throw std::invalid_argument("Invalid hex color format");
}
unsigned int r, g, b, a = 255;
std::stringstream ss;
// r
ss << std::hex << hex.substr(1, 2);
ss >> r;
ss.clear();
ss.str("");
// g
ss << std::hex << hex.substr(3, 2);
ss >> g;
ss.clear();
ss.str("");
// b
ss << std::hex << hex.substr(5, 2);
ss >> b;
// a
if (hex.length() == 9) {
ss.clear();
ss.str("");
ss << std::hex << hex.substr(7, 2);
ss >> a;
}
return wxColour(r, g, b, a);
}
FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
const DynamicPrintConfig *config,
const std::vector<int> &filament_map,
const std::vector<int> &extruders,
bool is_auto,
bool has_auto_result
)
FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
const std::vector<std::string> &filament_color,
const std::vector<int> &filament_map,
const std::vector<int> &filaments,
const FilamentMapMode mode,
bool show_default)
: wxDialog(parent, wxID_ANY, _L("Filament arrangement method of plate"), wxDefaultPosition, wxSize(2000, 1500))
, m_config(config)
, m_filament_color(filament_color)
, m_filament_map(filament_map)
, m_has_auto_result(has_auto_result)
{
SetBackgroundColour(*wxWHITE);
SetMinSize(wxSize(FromDIP(550), -1));
SetMaxSize(wxSize(FromDIP(550), -1));
if (mode < fmmManual)
m_page_type = PageType::ptAuto;
else if (mode == fmmManual)
m_page_type = PageType::ptManual;
else
m_page_type = PageType::ptDefault;
wxBoxSizer *main_sizer = new wxBoxSizer(wxVERTICAL);
main_sizer->AddSpacer(FromDIP(22));
m_mode_switch_btn = new SwitchButton(this);
m_mode_switch_btn->SetMaxSize({em_unit(this) * 12, -1});
m_mode_switch_btn->SetLabels(_L("Customize"), _L("Auto"));
m_mode_switch_btn->Bind(wxEVT_TOGGLEBUTTON, &FilamentMapDialog::on_switch_mode, this);
m_mode_switch_btn->SetValue(is_auto);
main_sizer->Add(m_mode_switch_btn, 0, wxCENTER | wxALL, 10);
wxBoxSizer *mode_sizer = new wxBoxSizer(wxHORIZONTAL);
m_tip_text = new wxStaticText(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
main_sizer->Add(m_tip_text, 0, wxALIGN_LEFT | wxLEFT, 15);
m_auto_btn = new CapsuleButton(this, PageType::ptAuto, _L("Auto"), false);
m_manual_btn = new CapsuleButton(this, PageType::ptManual, _L("Custom"), false);
if (show_default)
m_default_btn = new CapsuleButton(this, PageType::ptDefault, _L("Default"), true);
else
m_default_btn = nullptr;
m_extruder_panel_sizer = new wxBoxSizer(wxHORIZONTAL);
const int button_padding = FromDIP(2);
mode_sizer->AddStretchSpacer();
mode_sizer->Add(m_auto_btn, 1, wxALIGN_CENTER | wxLEFT | wxRIGHT, button_padding);
mode_sizer->Add(m_manual_btn, 1, wxALIGN_CENTER | wxLEFT | wxRIGHT, button_padding);
if (show_default) mode_sizer->Add(m_default_btn, 1, wxALIGN_CENTER | wxLEFT | wxRIGHT, button_padding);
mode_sizer->AddStretchSpacer();
m_manual_left_panel = new DragDropPanel(this, wxT("Left nozzle:"), false);
m_manual_right_panel = new DragDropPanel(this, wxT("Right nozzle:"), false);
main_sizer->Add(mode_sizer, 0, wxEXPAND);
main_sizer->AddSpacer(FromDIP(24));
std::vector<std::string> filament_color = config->option<ConfigOptionStrings>("filament_colour")->values;
for (size_t i = 0; i < filament_map.size(); ++i) {
auto iter = std::find(extruders.begin(), extruders.end(), i + 1);
if (iter == extruders.end())
continue;
auto panel_sizer = new wxBoxSizer(wxHORIZONTAL);
FilamentMapMode default_auto_mode = (mode < FilamentMapMode::fmmManual ? mode : FilamentMapMode::fmmAutoForFlush);
m_manual_map_panel = new FilamentMapManualPanel(this, m_filament_color, filaments, filament_map);
m_auto_map_panel = new FilamentMapAutoPanel(this, default_auto_mode);
if (show_default)
m_default_map_panel = new FilamentMapDefaultPanel(this);
else
m_default_map_panel = nullptr;
if (filament_map[i] == 1) {
m_manual_left_panel->AddColorBlock(hex_to_color(filament_color[i]), i + 1);
}
else if (filament_map[i] == 2) {
m_manual_right_panel->AddColorBlock(hex_to_color(filament_color[i]), i + 1);
}
else {
assert(false);
}
}
panel_sizer->Add(m_manual_map_panel, 0, wxALIGN_CENTER | wxEXPAND);
panel_sizer->Add(m_auto_map_panel, 0, wxALIGN_CENTER | wxEXPAND);
if (show_default) panel_sizer->Add(m_default_map_panel, 0, wxALIGN_CENTER | wxEXPAND);
main_sizer->Add(panel_sizer, 0, wxEXPAND);
m_switch_filament_btn = new ScalableButton(this, wxID_ANY, "switch_filament_maps");
m_switch_filament_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_switch_filaments, this);
m_switch_filament_btn->SetCanFocus(false);
// just for placeholder for auto
m_switch_filament_btn_auto = new ScalableButton(this, wxID_ANY, "switch_filament_maps");
m_switch_filament_btn_auto->Enable(false);
m_extruder_panel_sizer->Add(m_manual_left_panel, 1, wxEXPAND | wxALL, 5);
m_extruder_panel_sizer->Add(m_switch_filament_btn, 0, wxALIGN_CENTER_VERTICAL | wxALL, 1);
m_extruder_panel_sizer->Add(m_manual_right_panel, 1, wxEXPAND | wxALL, 5);
m_manual_left_panel->Layout();
m_manual_left_panel->Fit();
m_manual_right_panel->Layout();
m_manual_right_panel->Fit();
m_auto_left_panel = new DragDropPanel(this, wxT("Left nozzle:"), true);
m_auto_right_panel = new DragDropPanel(this, wxT("Right nozzle:"), true);
for (size_t i = 0; i < filament_map.size(); ++i) {
auto iter = std::find(extruders.begin(), extruders.end(), i + 1);
if (iter == extruders.end()) continue;
if (filament_map[i] == 1) {
m_auto_left_panel->AddColorBlock(hex_to_color(filament_color[i]), i + 1);
} else if (filament_map[i] == 2) {
m_auto_right_panel->AddColorBlock(hex_to_color(filament_color[i]), i + 1);
} else {
assert(false);
}
}
m_extruder_panel_sizer->Add(m_auto_left_panel, 1, wxEXPAND | wxALL, 5);
m_extruder_panel_sizer->Add(m_switch_filament_btn_auto, 0, wxALIGN_CENTER_VERTICAL | wxALL, 1);
m_extruder_panel_sizer->Add(m_auto_right_panel, 1, wxEXPAND | wxALL, 5);
m_auto_left_panel->Layout();
m_auto_left_panel->Fit();
m_auto_right_panel->Layout();
m_auto_right_panel->Fit();
main_sizer->Add(m_extruder_panel_sizer, 1, wxEXPAND | wxALL, 10);
m_below_tip_text = new wxStaticText(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
m_below_tip_text->SetLabel(manual_below_tips);
main_sizer->Add(m_below_tip_text, 0, wxALIGN_LEFT | wxLEFT, 15);
if (is_auto) {
m_manual_left_panel->Hide();
m_manual_right_panel->Hide();
m_switch_filament_btn->Hide();
m_below_tip_text->Hide();
if (m_has_auto_result) {
m_tip_text->SetLabel(auto_tips_with_result);
}
else {
m_auto_left_panel->Hide();
m_auto_right_panel->Hide();
m_switch_filament_btn_auto->Hide();
m_tip_text->SetLabel(auto_tips);
}
}
else {
m_auto_left_panel->Hide();
m_auto_right_panel->Hide();
m_switch_filament_btn_auto->Hide();
m_tip_text->SetLabel(manual_tips);
m_below_tip_text->Show();
}
wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
Button * ok_btn = new Button(this, _L("OK"));
Button * cancel_btn = new Button(this, _L("Cancel"));
button_sizer->Add(ok_btn, 0, wxALL, 5);
button_sizer->Add(cancel_btn, 0, wxALL, 5);
wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
m_ok_btn = new Button(this, _L("OK"));
m_cancel_btn = new Button(this, _L("Cancel"));
button_sizer->Add(m_ok_btn, 0, wxALL, 5);
button_sizer->Add(m_cancel_btn, 0, wxALL, 5);
main_sizer->Add(button_sizer, 0, wxALIGN_CENTER | wxALL, 10);
ok_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_ok, this);
cancel_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_cancle, this);
m_ok_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_ok, this);
m_cancel_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_cancle, this);
m_auto_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_switch_mode, this);
m_manual_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_switch_mode, this);
if (show_default) m_default_btn->Bind(wxEVT_BUTTON, &FilamentMapDialog::on_switch_mode, this);
SetSizer(main_sizer);
Layout();
Fit();
CenterOnParent();
GUI::wxGetApp().UpdateDarkUIWin(this);
}
bool FilamentMapDialog::is_auto() const
FilamentMapMode FilamentMapDialog::get_mode()
{
if (m_mode_switch_btn->GetValue()) {
return true;
}
return false;
if (m_page_type == PageType::ptAuto)
return m_auto_map_panel->GetMode();
if (m_page_type == PageType::ptManual)
return fmmManual;
return fmmDefault;
}
int FilamentMapDialog::ShowModal()
{
update_panel_status(m_page_type);
return wxDialog::ShowModal();
}
void FilamentMapDialog::on_ok(wxCommandEvent &event)
{
if (!is_auto()) {
std::vector<int> left_filaments = m_manual_left_panel->GetAllFilaments();
std::vector<int> right_filaments = m_manual_right_panel->GetAllFilaments();
if (m_page_type == PageType::ptManual) {
std::vector<int> left_filaments = m_manual_map_panel->GetLeftFilaments();
std::vector<int> right_filaments = m_manual_map_panel->GetRightFilaments();
for (int i = 0; i < m_filament_map.size(); ++i) {
if (std::find(left_filaments.begin(), left_filaments.end(), i + 1) != left_filaments.end()) {
m_filament_map[i] = 1;
} else if (std::find(right_filaments.begin(), right_filaments.end(), i + 1) != right_filaments.end()) {
}
else if (std::find(right_filaments.begin(), right_filaments.end(), i + 1) != right_filaments.end()) {
m_filament_map[i] = 2;
}
}
@ -215,63 +123,62 @@ void FilamentMapDialog::on_ok(wxCommandEvent &event)
EndModal(wxID_OK);
}
void FilamentMapDialog::on_cancle(wxCommandEvent &event)
void FilamentMapDialog::on_cancle(wxCommandEvent &event) { EndModal(wxID_CANCEL); }
void FilamentMapDialog::update_panel_status(PageType page)
{
EndModal(wxID_CANCEL);
if (page == PageType::ptDefault) {
if (m_default_btn && m_default_map_panel) {
m_default_btn->Select(true);
m_default_map_panel->Show();
}
m_manual_btn->Select(false);
m_manual_map_panel->Hide();
m_auto_btn->Select(false);
m_auto_map_panel->Hide();
}
if (page == PageType::ptManual) {
if (m_default_btn && m_default_map_panel) {
m_default_btn->Select(false);
m_default_map_panel->Hide();
}
m_manual_btn->Select(true);
m_manual_map_panel->Show();
m_auto_btn->Select(false);
m_auto_map_panel->Hide();
}
if (page == PageType::ptAuto) {
if (m_default_btn && m_default_map_panel) {
m_default_btn->Select(false);
m_default_map_panel->Hide();
}
m_manual_btn->Select(false);
m_manual_map_panel->Hide();
m_auto_btn->Select(true);
m_auto_map_panel->Show();
}
Layout();
Fit();
}
void FilamentMapDialog::on_switch_mode(wxCommandEvent &event)
{
bool value = dynamic_cast<SwitchButton *>(event.GetEventObject())->GetValue();
if (value) { // auto
m_manual_left_panel->Hide();
m_manual_right_panel->Hide();
m_switch_filament_btn->Hide();
m_below_tip_text->Hide();
if (m_has_auto_result) {
m_auto_left_panel->Show();
m_auto_right_panel->Show();
m_switch_filament_btn_auto->Show();
m_tip_text->SetLabel(auto_tips_with_result);
}
else {
m_auto_left_panel->Hide();
m_auto_right_panel->Hide();
m_switch_filament_btn_auto->Hide();
m_tip_text->SetLabel(auto_tips);
}
} else { // manual
m_manual_left_panel->Show();
m_manual_right_panel->Show();
m_switch_filament_btn->Show();
m_below_tip_text->Show();
int win_id = event.GetId();
m_page_type = PageType(win_id);
m_auto_left_panel->Hide();
m_auto_right_panel->Hide();
m_switch_filament_btn_auto->Hide();
m_tip_text->SetLabel(manual_tips);
}
Layout();
Fit();
update_panel_status(m_page_type);
event.Skip();
}
void FilamentMapDialog::on_switch_filaments(wxCommandEvent &event)
void FilamentMapDialog::set_modal_btn_labels(const wxString &ok_label, const wxString &cancel_label)
{
std::vector<ColorPanel *> left_blocks = m_manual_left_panel->get_filament_blocks();
std::vector<ColorPanel *> right_blocks = m_manual_right_panel->get_filament_blocks();
for (ColorPanel* block : left_blocks) {
m_manual_right_panel->AddColorBlock(block->GetColor(), block->GetFilamentId(), false);
m_manual_left_panel->RemoveColorBlock(block, false);
}
for (auto block : right_blocks) {
m_manual_left_panel->AddColorBlock(block->GetColor(), block->GetFilamentId(), false);
m_manual_right_panel->RemoveColorBlock(block, false);
}
Layout();
Fit();
m_ok_btn->SetLabel(ok_label);
m_cancel_btn->SetLabel(cancel_label);
}
}} // namespace Slic3r::GUI

View File

@ -2,10 +2,13 @@
#define slic3r_FilamentMapDialog_hpp_
#include "GUI.hpp"
#include "FilamentMapPanel.hpp"
#include <wx/simplebook.h>
#include <wx/dialog.h>
#include <wx/timer.h>
#include <vector>
#include "SelectMachine.hpp"
#include "CapsuleButton.hpp"
class SwitchButton;
class ScalableButton;
@ -17,42 +20,52 @@ class DynamicPrintConfig;
namespace GUI {
class DragDropPanel;
class FilamentMapDialog : public wxDialog
{
enum PageType {
ptAuto,
ptManual,
ptDefault
};
public:
FilamentMapDialog(wxWindow *parent,
const DynamicPrintConfig *config,
const std::vector<std::string>& filament_color,
const std::vector<int> &filament_map,
const std::vector<int> &extruders,
bool is_auto,
bool has_auto_result
const std::vector<int> &filaments,
const FilamentMapMode mode,
bool show_default=true
);
bool is_auto() const;
FilamentMapMode get_mode();
const std::vector<int>& get_filament_maps() const { return m_filament_map; }
int ShowModal();
void set_modal_btn_labels(const wxString& left_label, const wxString& right_label);
private:
void on_ok(wxCommandEvent &event);
void on_cancle(wxCommandEvent &event);
void on_switch_mode(wxCommandEvent &event);
void on_switch_filaments(wxCommandEvent &event);
void update_panel_status(PageType page);
private:
FilamentMapManualPanel* m_manual_map_panel;
FilamentMapAutoPanel* m_auto_map_panel;
FilamentMapDefaultPanel* m_default_map_panel;
CapsuleButton* m_auto_btn;
CapsuleButton* m_manual_btn;
CapsuleButton* m_default_btn;
Button* m_ok_btn;
Button* m_cancel_btn;
PageType m_page_type;
private:
wxStaticText * m_tip_text;
wxStaticText * m_below_tip_text;
SwitchButton * m_mode_switch_btn;
wxBoxSizer * m_extruder_panel_sizer;
DragDropPanel* m_manual_left_panel;
DragDropPanel* m_manual_right_panel;
DragDropPanel* m_auto_left_panel;
DragDropPanel* m_auto_right_panel;
ScalableButton* m_switch_filament_btn;
ScalableButton* m_switch_filament_btn_auto; // for placeholder
private:
const DynamicPrintConfig* m_config;
std::vector<int> m_filament_map;
bool m_has_auto_result;
std::vector<std::string> m_filament_color;
};
}} // namespace Slic3r::GUI

View File

@ -0,0 +1,324 @@
#include "FilamentMapPanel.hpp"
#include "GUI_App.hpp"
#include "wx/graphics.h"
namespace Slic3r { namespace GUI {
FilamentMapManualPanel::FilamentMapManualPanel(wxWindow *parent,
const std::vector<std::string> &color,
const std::vector<int> &filament_list,
const std::vector<int> &filament_map)
: wxPanel(parent), m_filament_map(filament_map), m_filament_color(color), m_filament_list(filament_list)
{
SetBackgroundColour(wxColor(255, 255, 255));
auto top_sizer = new wxBoxSizer(wxVERTICAL);
m_description = new Label(this, _L("We will slice according to this grouping method:"));
top_sizer->Add(m_description, 0, wxALIGN_LEFT | wxLEFT, FromDIP(15));
top_sizer->AddSpacer(FromDIP(8));
auto drag_sizer = new wxBoxSizer(wxHORIZONTAL);
m_left_panel = new DragDropPanel(this, wxT("Left Nozzle:"), false);
m_right_panel = new DragDropPanel(this, wxT("Right Nozzle:"), false);
m_switch_btn = new ScalableButton(this, wxID_ANY, "switch_filament_maps");
for (size_t idx = 0; idx < m_filament_map.size(); ++idx) {
auto iter = std::find(m_filament_list.begin(), m_filament_list.end(), idx + 1);
if (iter == m_filament_list.end()) continue;
wxColor color = Hex2Color(m_filament_color[idx]);
if (m_filament_map[idx] == 1) {
m_left_panel->AddColorBlock(color, idx + 1);
} else {
assert(m_filament_map[idx] == 2);
m_right_panel->AddColorBlock(color, idx + 1);
}
}
drag_sizer->Add(m_left_panel, 1, wxALIGN_CENTER | wxEXPAND | wxLEFT, FromDIP(20));
drag_sizer->AddSpacer(FromDIP(7));
drag_sizer->Add(m_switch_btn, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, FromDIP(1));
drag_sizer->AddSpacer(FromDIP(7));
drag_sizer->Add(m_right_panel, 1, wxALIGN_CENTER | wxEXPAND | wxRIGHT, FromDIP(20));
top_sizer->Add(drag_sizer, 0, wxALIGN_CENTER|wxEXPAND);
m_tips = new Label(this, _L("Tips: You can drag the filaments to change which extruder they are assigned to.\n"
"But your filament arrangement may not be the most filament-efficient."));
m_tips->SetFont(Label::Body_14);
m_tips->SetForegroundColour(wxColour("#6B6B6B"));
top_sizer->AddSpacer(FromDIP(8));
top_sizer->Add(m_tips, 0, wxALIGN_LEFT | wxLEFT, FromDIP(15));
m_switch_btn->Bind(wxEVT_BUTTON, &FilamentMapManualPanel::OnSwitchFilament, this);
SetSizer(top_sizer);
Layout();
Fit();
GUI::wxGetApp().UpdateDarkUIWin(this);
}
void FilamentMapManualPanel::OnSwitchFilament(wxCommandEvent &)
{
auto left_blocks = m_left_panel->get_filament_blocks();
auto right_blocks = m_right_panel->get_filament_blocks();
for (auto &block : left_blocks) {
m_right_panel->AddColorBlock(block->GetColor(), block->GetFilamentId(), false);
m_left_panel->RemoveColorBlock(block, false);
}
for (auto &block : right_blocks) {
m_left_panel->AddColorBlock(block->GetColor(), block->GetFilamentId(), false);
m_right_panel->RemoveColorBlock(block, false);
}
Layout();
Fit();
}
void FilamentMapManualPanel::Hide()
{
m_left_panel->Hide();
m_right_panel->Hide();
m_switch_btn->Hide();
wxPanel::Hide();
}
void FilamentMapManualPanel::Show()
{
m_left_panel->Show();
m_right_panel->Show();
m_switch_btn->Show();
wxPanel::Show();
}
GUI::FilamentMapBtnPanel::FilamentMapBtnPanel(wxWindow *parent, const wxString &label, const wxString &detail, const std::string &icon) : wxPanel(parent)
{
SetBackgroundColour(*wxWHITE);
SetBackgroundStyle(wxBG_STYLE_PAINT);
m_hover = false;
const int horizontal_margin = FromDIP(12);
auto sizer = new wxBoxSizer(wxVERTICAL);
auto bmp = create_scaled_bitmap(icon, nullptr, 20);
m_btn = new wxBitmapButton(this, wxID_ANY, bmp, wxDefaultPosition, wxDefaultSize, wxNO_BORDER);
m_btn->SetBackgroundColour(*wxWHITE);
m_label = new wxStaticText(this, wxID_ANY, label);
m_label->SetFont(Label::Head_14);
auto label_sizer = new wxBoxSizer(wxHORIZONTAL);
label_sizer->AddStretchSpacer();
label_sizer->Add(m_btn, 0, wxALIGN_CENTER|wxEXPAND);
label_sizer->Add(m_label, 0, wxALIGN_CENTER|wxEXPAND);
label_sizer->AddStretchSpacer();
sizer->AddSpacer(FromDIP(32));
sizer->Add(label_sizer, 0, wxALIGN_CENTER | wxEXPAND);
sizer->AddSpacer(FromDIP(24));
auto detail_sizer = new wxBoxSizer(wxHORIZONTAL);
m_detail = new Label(this, detail);
m_detail->SetFont(Label::Body_12);
m_detail->SetForegroundColour(wxColour("#6B6B6B"));
m_detail->Wrap(FromDIP(180));
detail_sizer->AddStretchSpacer();
detail_sizer->Add(m_detail, 0, wxALIGN_CENTER | wxLEFT | wxRIGHT, horizontal_margin);
detail_sizer->AddStretchSpacer();
sizer->Add(detail_sizer, 0, wxALIGN_CENTER | wxEXPAND);
sizer->AddSpacer(FromDIP(10));
SetSizer(sizer);
Layout();
Fit();
GUI::wxGetApp().UpdateDarkUIWin(this);
auto forward_click_to_parent = [this](wxMouseEvent &event) {
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, &FilamentMapBtnPanel::OnPaint, this);
Bind(wxEVT_ENTER_WINDOW, &FilamentMapBtnPanel::OnEnterWindow, this);
Bind(wxEVT_LEAVE_WINDOW, &FilamentMapBtnPanel::OnLeaveWindow, this);
}
void FilamentMapBtnPanel::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 ? wxColour("#EBF9F0") : wxColour("#FFFFFF");
wxColour border_color = m_hover || m_selected ? wxColour("#00AE42") : wxColour("#CECECE");
int cornerRadius = 8;
gc->SetBrush(wxBrush(bg_color));
gc->SetPen(wxPen(border_color, 2));
gc->DrawRoundedRectangle(1, 1, rect.width - 2, rect.height - 2, cornerRadius);
delete gc;
}
}
void FilamentMapBtnPanel::UpdateStatus()
{
const wxColour selected_color = wxColour("#EBF9F0");
const wxColour normal_color = wxColour("#FFFFFF");
if (m_selected) {
m_btn->SetBackgroundColour(selected_color);
m_label->SetBackgroundColour(selected_color);
m_detail->SetBackgroundColour(selected_color);
} else {
m_btn->SetBackgroundColour(normal_color);
m_label->SetBackgroundColour(normal_color);
m_detail->SetBackgroundColour(normal_color);
}
}
void FilamentMapBtnPanel::OnEnterWindow(wxMouseEvent &event)
{
if (!m_hover) {
m_hover = true;
UpdateStatus();
Refresh();
event.Skip();
}
}
void FilamentMapBtnPanel::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 FilamentMapBtnPanel::Select(bool selected)
{
m_selected = selected;
UpdateStatus();
Refresh();
}
void GUI::FilamentMapBtnPanel::Hide()
{
m_btn->Hide();
m_label->Hide();
m_detail->Hide();
wxPanel::Hide();
}
void GUI::FilamentMapBtnPanel::Show()
{
m_btn->Show();
m_label->Show();
m_detail->Show();
wxPanel::Show();
}
FilamentMapAutoPanel::FilamentMapAutoPanel(wxWindow *parent, FilamentMapMode mode) : wxPanel(parent)
{
static const wxString AutoForFlushDetail = _L("Disregrad the filaments in AMS. Optimize filament usage "
"by calculating the best allocation for the left and right "
"nozzles. Arrange the filaments according on the printer according to "
"the slicing results.");
static const wxString AutoForMatchDetail = _L("Based on the current filaments in the AMS, allocate the "
"filaments to the left and right nozzles.");
auto sizer = new wxBoxSizer(wxHORIZONTAL);
m_flush_panel = new FilamentMapBtnPanel(this, _L("Material-Saving Mode"), AutoForFlushDetail, "flush_mode_panel_icon");
m_match_panel = new FilamentMapBtnPanel(this, _L("Convenient Mode"), AutoForMatchDetail,"match_mode_panel_icon");
sizer->AddStretchSpacer();
sizer->Add(m_flush_panel, 1, wxEXPAND);
sizer->AddSpacer(FromDIP(12));
sizer->Add(m_match_panel, 1, wxEXPAND);
sizer->AddStretchSpacer();
m_flush_panel->Bind(wxEVT_LEFT_DOWN, [this](auto &event) { this->OnModeSwitch(FilamentMapMode::fmmAutoForFlush); });
m_match_panel->Bind(wxEVT_LEFT_DOWN, [this](auto &event) { this->OnModeSwitch(FilamentMapMode::fmmAutoForMatch); });
m_mode = mode;
UpdateStatus();
SetSizerAndFit(sizer);
Layout();
GUI::wxGetApp().UpdateDarkUIWin(this);
}
void FilamentMapAutoPanel::Hide()
{
m_flush_panel->Hide();
m_match_panel->Hide();
wxPanel::Hide();
}
void FilamentMapAutoPanel::Show()
{
m_flush_panel->Show();
m_match_panel->Show();
wxPanel::Show();
}
void FilamentMapAutoPanel::UpdateStatus()
{
if (m_mode == fmmAutoForFlush) {
m_flush_panel->Select(true);
m_match_panel->Select(false);
} else {
m_flush_panel->Select(false);
m_match_panel->Select(true);
}
}
void FilamentMapAutoPanel::OnModeSwitch(FilamentMapMode mode)
{
m_mode = mode;
UpdateStatus();
}
FilamentMapDefaultPanel::FilamentMapDefaultPanel(wxWindow *parent) : wxPanel(parent)
{
auto sizer = new wxBoxSizer(wxHORIZONTAL);
m_label = new Label(this, _L("The material allocation for the current disk follows the global settings."));
m_label->SetFont(Label::Body_14);
m_label->SetBackgroundColour(*wxWHITE);
sizer->AddStretchSpacer();
sizer->Add(m_label, 1, wxEXPAND|wxALIGN_CENTER);
sizer->AddStretchSpacer();
SetSizerAndFit(sizer);
Layout();
GUI::wxGetApp().UpdateDarkUIWin(this);
}
void FilamentMapDefaultPanel::Hide()
{
m_label->Hide();
wxPanel::Hide();
}
void FilamentMapDefaultPanel::Show()
{
m_label->Show();
wxPanel::Show();
}
}} // namespace Slic3r::GUI

View File

@ -0,0 +1,89 @@
#ifndef FILAMENT_MAP_PANEL_HPP
#define FILAMENT_MAP_PANEL_HPP
#include "GUI.hpp"
#include "DragDropPanel.hpp"
#include "Widgets/SwitchButton.hpp"
namespace Slic3r { namespace GUI {
class FilamentMapManualPanel : public wxPanel
{
public:
FilamentMapManualPanel(wxWindow *parent, const std::vector<std::string> &color, const std::vector<int> &filament_list, const std::vector<int> &filament_map);
std::vector<int> GetFilamentMaps() const { return m_filament_map; }
std::vector<int> GetLeftFilaments() const { return m_left_panel->GetAllFilaments(); }
std::vector<int> GetRightFilaments() const { return m_right_panel->GetAllFilaments(); }
void Hide();
void Show();
private:
void OnSwitchFilament(wxCommandEvent &);
DragDropPanel *m_left_panel;
DragDropPanel *m_right_panel;
Label *m_description;
Label *m_tips;
ScalableButton *m_switch_btn;
std::vector<int> m_filament_map;
std::vector<int> m_filament_list;
std::vector<std::string> m_filament_color;
};
class FilamentMapBtnPanel : public wxPanel
{
public:
FilamentMapBtnPanel(wxWindow *parent, const wxString &label, const wxString &detail, const std::string &icon_path);
void Hide();
void Show();
void Select(bool selected);
protected:
void OnPaint(wxPaintEvent &event);
private:
void OnEnterWindow(wxMouseEvent &event);
void OnLeaveWindow(wxMouseEvent &evnet);
void UpdateStatus();
wxBitmapButton *m_btn;
wxStaticText *m_label;
Label *m_detail;
bool m_hover{false};
bool m_selected{false};
};
class FilamentMapAutoPanel : public wxPanel
{
public:
FilamentMapAutoPanel(wxWindow *parent, FilamentMapMode mode);
void Hide();
void Show();
FilamentMapMode GetMode() const { return m_mode; }
private:
void OnModeSwitch(FilamentMapMode mode);
void UpdateStatus();
FilamentMapBtnPanel *m_flush_panel;
FilamentMapBtnPanel *m_match_panel;
FilamentMapMode m_mode;
};
class FilamentMapDefaultPanel : public wxPanel
{
public:
FilamentMapDefaultPanel(wxWindow *parent);
void Hide();
void Show();
private:
Label *m_label;
};
}} // namespace Slic3r::GUI
#endif

View File

@ -4626,7 +4626,7 @@ void GCodeViewer::render_legend_color_arr_recommen(float window_padding)
Plater *plater = wxGetApp().plater();
wxCommandEvent evt(EVT_OPEN_FILAMENT_MAP_SETTINGS_DIALOG);
evt.SetEventObject(plater);
evt.SetInt(0b0010); //0010 means from gcode view, manual mode
evt.SetInt(1); // 1 means from gcode viewer
wxPostEvent(plater, evt);
}
}

View File

@ -60,6 +60,7 @@
#include "ConfigWizard.hpp"
#include "Widgets/WebView.hpp"
#include "DailyTips.hpp"
#include "FilamentMapDialog.hpp"
#ifdef _WIN32
#include <dbt.h>
@ -1593,6 +1594,8 @@ wxBoxSizer* MainFrame::create_side_tools()
sizer->Layout();
m_filament_group_popup = new FilamentGroupPopup(m_slice_btn);
m_slice_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event)
{
m_plater->reset_check_status();
@ -1602,14 +1605,62 @@ wxBoxSizer* MainFrame::create_side_tools()
//this->m_plater->select_view_3D("Preview");
m_plater->exit_gizmo();
m_plater->update(true, true);
if (m_slice_select == eSliceAll)
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_ALL));
else
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE));
this->m_tabpanel->SetSelection(tpPreview);
bool slice = true;
auto full_config = wxGetApp().preset_bundle->full_config();
std::vector<int>g_filament_map = full_config.option<ConfigOptionInts>("filament_map")->values;
FilamentMapMode g_filament_map_mode = get_prefered_map_mode();
if (is_pop_up_required()) {
auto filament_colors = full_config.option<ConfigOptionStrings>("filament_colour")->values;
g_filament_map.resize(filament_colors.size());
std::vector<int> filament_lists(filament_colors.size());
std::iota(filament_lists.begin(), filament_lists.end(), 1);
FilamentMapDialog filament_dlg(this,
filament_colors,
g_filament_map,
filament_lists,
FilamentMapMode::fmmManual,
false
);
auto ret = filament_dlg.ShowModal();
if (ret == wxID_OK) {
g_filament_map_mode = filament_dlg.get_mode();
g_filament_map = filament_dlg.get_filament_maps();
}
else {
slice = false;
}
}
if (slice) {
m_plater->set_global_filament_map_mode(g_filament_map_mode);
if (g_filament_map_mode == FilamentMapMode::fmmManual)
m_plater->set_global_filament_map(g_filament_map);
if (m_slice_select == eSliceAll)
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_ALL));
else
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SLICE_PLATE));
this->m_tabpanel->SetSelection(tpPreview);
}
});
m_slice_btn->Bind(wxEVT_ENTER_WINDOW, [this](wxMouseEvent& event) {
m_filament_group_popup->SetSize(wxSize(FromDIP(380),-1));
wxPoint pos = m_slice_btn->ClientToScreen(wxPoint(0, 0));
pos.y += m_slice_btn->GetRect().height * 1.25;
pos.x -= (m_slice_option_btn->GetRect().width + m_filament_group_popup->GetRect().width * 0.6);
m_filament_group_popup->SetPosition(pos);
m_filament_group_popup->tryPopup(m_plater->check_ams_status());
});
m_slice_btn->Bind(wxEVT_LEAVE_WINDOW, [this](auto& event) {
m_filament_group_popup->tryClose();
});
m_print_btn->Bind(wxEVT_BUTTON, [this](wxCommandEvent& event)
{
//this->m_plater->select_view_3D("Preview");
@ -3868,6 +3919,7 @@ void MainFrame::technology_changed()
m_menubar->SetMenuLabel(id, pt == ptSLA ? _omitL("Material Settings") : _L("Filament Settings"));
}
//
// Called after the Preferences dialog is closed and the program settings are saved.
// Update the UI based on the current preferences.

View File

@ -27,6 +27,8 @@
#include "UnsavedChangesDialog.hpp"
#include "Widgets/SideButton.hpp"
#include "Widgets/SideMenuPopup.hpp"
#include "FilamentGroupPopup.hpp"
// BBS
#include "BBLTopbar.hpp"
@ -339,6 +341,7 @@ public:
void technology_changed();
//BBS
void load_url(wxString url);
void load_printer_url(wxString url);
@ -391,6 +394,8 @@ public:
SideButton* m_slice_option_btn{ nullptr };
SideButton* m_print_btn{ nullptr };
SideButton* m_print_option_btn{ nullptr };
FilamentGroupPopup* m_filament_group_popup{ nullptr };
mutable bool m_slice_enable{ true };
mutable bool m_print_enable{ true };
bool get_enable_slice_status();

View File

@ -15352,9 +15352,9 @@ void Plater::open_platesettings_dialog(wxCommandEvent& evt) {
void Plater::open_filament_map_setting_dialog(wxCommandEvent &evt)
{
PartPlate* curr_plate = p->partplate_list.get_curr_plate();
int value = evt.GetInt();
bool is_auto = value & 1; //0000 means manual, 0001 means auto
bool need_slice = value & (1 << 1); //0010 means from gcode view, 0000 means not from gcode view
int value = evt.GetInt(); //1 means from gcode view
bool force_manual = value == 1; // If from gcode view, should display manual page
bool need_slice = value ==1; // If from gcode view, should slice
const auto& project_config = wxGetApp().preset_bundle->project_config;
auto filament_colors = config()->option<ConfigOptionStrings>("filament_colour")->values;
@ -15363,20 +15363,22 @@ void Plater::open_filament_map_setting_dialog(wxCommandEvent &evt)
if (plate_filament_maps.size() != filament_colors.size()) // refine it later, save filament map to app config
plate_filament_maps.resize(filament_colors.size(), 1);
FilamentMapMode display_mode = force_manual ? FilamentMapMode::fmmManual : plate_filament_map_mode;
FilamentMapDialog filament_dlg(this,
config(),
filament_colors,
plate_filament_maps,
curr_plate->get_extruders(true),
plate_filament_map_mode < FilamentMapMode::fmmManual,
false
display_mode,
true
);
if (filament_dlg.ShowModal() == wxID_OK) {
std::vector<int> new_filament_maps = filament_dlg.get_filament_maps();
std::vector<int> old_filament_maps = plate_filament_maps;
std::vector<int> old_filament_maps = curr_plate->get_filament_maps();
FilamentMapMode old_map_mode = plate_filament_map_mode;
FilamentMapMode new_map_mode = filament_dlg.is_auto() ? fmmAutoForFlush : fmmManual;
FilamentMapMode new_map_mode = filament_dlg.get_mode();
bool need_invalidate = (old_map_mode != new_map_mode ||
old_filament_maps != new_filament_maps);
@ -15575,7 +15577,7 @@ int Plater::select_plate_by_hover_id(int hover_id, bool right_click, bool isModi
if (!ret) {
PartPlate * curr_plate = p->partplate_list.get_curr_plate();
wxCommandEvent evt(EVT_OPEN_FILAMENT_MAP_SETTINGS_DIALOG);
evt.SetInt(curr_plate->get_filament_map_mode() < FilamentMapMode::fmmManual ? 1 : 0);
evt.SetInt(0); // 0 means not from gcodeviewer
evt.SetEventObject(this);
wxPostEvent(this, evt);
} else {

View File

@ -446,6 +446,7 @@ public:
void on_filaments_delete(size_t extruders_count, size_t filament_id, int replace_filament_id = -1);
// BBS
void on_bed_type_change(BedType bed_type,bool is_gcode_file = false);
bool update_filament_colors_in_full_config();
void config_change_notification(const DynamicPrintConfig &config, const std::string& key);
void on_config_change(const DynamicPrintConfig &config);

View File

@ -1242,6 +1242,10 @@ wxWindow* PreferencesDialog::create_general_page()
auto item_darkmode = create_item_darkmode_checkbox(_L("Enable dark mode"), page,_L("Enable dark mode"), 50, "dark_color_mode");
#endif
auto title_filament_group = create_item_title(_L("Filament Group"), page, _L("Filament Group"));
auto item_ignore_ext_filament = create_item_checkbox(_L("Ignore ext filament when auto grouping."), page, _L("Ignore ext filament when auto grouping"), 50, "ignore_ext_filament_when_group");
auto item_pop_filament_group_mode = create_item_checkbox(_L("Pop up to select filament map mode."), page, _L("Pop up to select filament map mode"), 50, "pop_up_filament_map_mode");
auto title_user_experience = create_item_title(_L("User Experience"), page, _L("User Experience"));
auto item_priv_policy = create_item_checkbox(_L("Join Customer Experience Improvement Program."), page, "", 50, "privacyuse");
wxHyperlinkCtrl* hyperlink = new wxHyperlinkCtrl(page, wxID_ANY, _L("What data would be collected?"), "https://bambulab.com/en/policies/privacy");
@ -1312,6 +1316,10 @@ wxWindow* PreferencesDialog::create_general_page()
sizer_page->Add(item_darkmode, 0, wxEXPAND, FromDIP(3));
#endif
sizer_page->Add(title_filament_group, 0, wxTOP | wxEXPAND, FromDIP(20));
sizer_page->Add(item_ignore_ext_filament, 0, wxEXPAND, FromDIP(3));
sizer_page->Add(item_pop_filament_group_mode, 0, wxEXPAND, FromDIP(3));
sizer_page->Add(title_user_experience, 0, wxTOP | wxEXPAND, FromDIP(20));
sizer_page->Add(item_priv_policy, 0, wxTOP, FromDIP(3));