mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-03 16:22:08 +00:00
X2D Support (#13388)
# Description Adresses #13294 - Adds the X2D printer definition, machine presets, process presets, filament presets, BBL profile index entries, CLI config entries, filament blacklist updates, and printer/load/calibration/cover assets. - Updates dual-nozzle handling to use configured toolhead labels and match Bambu X2D hotend placeholders. - Adds X2D-specific wipe tower cooling placeholder support and 3MF filament/nozzle change sequence metadata import/export plumbing. # Note I own a P2S and an X2D. That's all. I frankly have no idea if my changes cause regression on other printers, and have no capability to test. I know that for my X2D, which runs an AMS, .2mm nozzles, SuperTack, and in LAN mode, this has been working without issue. # Screenshots/Recordings/Graphs <img width="606" height="380" alt="Dual nozzle control" src="https://github.com/user-attachments/assets/0d1c1063-4621-4097-b97c-d739557bf18c" /> *Dual nozzle control* <img width="726" height="260" alt="image" src="https://github.com/user-attachments/assets/270355b7-ca67-4ca3-ad19-582b8f11411b" /> *Multi nozzle filament override* <img width="416" height="202" alt="X2D Machine config and dual nozzle support" src="https://github.com/user-attachments/assets/6a5c07b2-0d20-4819-8f42-d60731313249" /> *X2D Machine config and dual nozzle support* <img width="397" height="142" alt="Filament for Supports test prints" src="https://github.com/user-attachments/assets/3c7546bd-0e27-4d56-89b7-d9ca18c976f9" /> *Filament for Supports has been used in over 20 hours of test prints* <img width="210" height="263" alt="Left vs Right filament distinction" src="https://github.com/user-attachments/assets/03322268-b669-4f14-8d77-c4d96843d219" /> *Left vs Right filament distinction* <img width="557" height="327" alt="Custom filament mapping" src="https://github.com/user-attachments/assets/c1c4396f-7359-474e-80bd-78fec22f9c82" /> *Custom filament mapping* <img width="556" height="314" alt="Auto map" src="https://github.com/user-attachments/assets/d83e3217-edce-4340-886e-043962003a30" /> *Auto map* <img width="689" height="664" alt="LAN mode send print with X2D preview and no errors" src="https://github.com/user-attachments/assets/76009bbf-31d3-4a6c-979c-8643b487c824" /> *LAN mode send print with X2D preview and no errors, dual nozzle selection* ## Tests - 20 hours of dual-nozzle printing. - 100% CTest tests passed - Validated 208 changed JSON files. <!-- > A guide for users on how to download the artifacts from this PR. --> [How to Download Pull Requests Artifacts for Testing](https://www.orcaslicer.com/wiki/how_to_download_pr_artifacts) Fix #13294
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#include "SwitchButton.hpp"
|
||||
#include "Button.hpp"
|
||||
#include "Label.hpp"
|
||||
#include "StaticBox.hpp"
|
||||
|
||||
@@ -19,7 +20,10 @@
|
||||
#include <wx/dcclient.h>
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
wxDEFINE_EVENT(wxCUSTOMEVT_SWITCH_POS, wxCommandEvent);
|
||||
wxDEFINE_EVENT(wxCUSTOMEVT_MULTISWITCH_SELECTION, wxCommandEvent);
|
||||
|
||||
SwitchButton::SwitchButton(wxWindow* parent, wxWindowID id)
|
||||
: wxBitmapToggleButton(parent, id, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | wxBU_EXACTFIT)
|
||||
@@ -391,6 +395,192 @@ void ModeSwitchButton::update_tooltip()
|
||||
SetToolTip(m_tooltips[m_selection]);
|
||||
}
|
||||
|
||||
MultiSwitchButton::MultiSwitchButton(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style)
|
||||
: StaticBox(parent, id, pos, size, style)
|
||||
, m_bg_color(StateColor(
|
||||
std::make_pair(0xE8E8E8, (int) StateColor::NotChecked),
|
||||
std::make_pair(0x009688, (int) StateColor::Normal)))
|
||||
, m_text_color(StateColor(
|
||||
std::make_pair(0x6B6B6B, (int) StateColor::NotChecked),
|
||||
std::make_pair(0xFFFFFE, (int) StateColor::Normal)))
|
||||
, m_button_radius(10.0)
|
||||
, m_button_padding(10, 6)
|
||||
{
|
||||
SetCornerRadius(m_button_radius);
|
||||
SetBorderWidth(0);
|
||||
|
||||
sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto *hsizer = new wxBoxSizer(wxVERTICAL);
|
||||
hsizer->Add(sizer, 1, wxEXPAND);
|
||||
SetSizer(hsizer);
|
||||
SetMinSize(wxSize(-1, 20));
|
||||
|
||||
Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MultiSwitchButton::button_clicked, this);
|
||||
SetFont(Label::Body_12);
|
||||
}
|
||||
|
||||
MultiSwitchButton::~MultiSwitchButton()
|
||||
{
|
||||
DeleteAllOptions();
|
||||
}
|
||||
|
||||
int MultiSwitchButton::AppendOption(const wxString &option, void *clientData)
|
||||
{
|
||||
Button *btn = new Button();
|
||||
btn->Create(this, option, "", wxBORDER_NONE);
|
||||
btn->SetFont(GetFont());
|
||||
btn->SetBackgroundColor(m_bg_color);
|
||||
btn->SetTextColor(m_text_color);
|
||||
btn->SetCornerRadius(m_button_radius);
|
||||
btn->SetPaddingSize(m_button_padding);
|
||||
btn->SetClientData(clientData);
|
||||
|
||||
btns.push_back(btn);
|
||||
sizer->Add(btn, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
wxSize text_size = btn->GetTextExtent(option);
|
||||
btn->SetMinSize(wxSize(text_size.x + m_button_padding.x * 2 + 6, -1));
|
||||
|
||||
return int(btns.size()) - 1;
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetOptions(const std::vector<wxString> &options)
|
||||
{
|
||||
DeleteAllOptions();
|
||||
for (const auto &option : options)
|
||||
AppendOption(option);
|
||||
|
||||
Layout();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::DeleteAllOptions()
|
||||
{
|
||||
sel = -1;
|
||||
for (auto *btn : btns) {
|
||||
if (btn)
|
||||
btn->Destroy();
|
||||
}
|
||||
btns.clear();
|
||||
if (sizer)
|
||||
sizer->Clear();
|
||||
}
|
||||
|
||||
unsigned int MultiSwitchButton::GetCount() const
|
||||
{
|
||||
return (unsigned int) btns.size();
|
||||
}
|
||||
|
||||
int MultiSwitchButton::GetSelection() const
|
||||
{
|
||||
return sel;
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetSelection(int index)
|
||||
{
|
||||
if (index < 0 || index >= (int) btns.size() || index == sel)
|
||||
return;
|
||||
|
||||
sel = index;
|
||||
update_button_styles();
|
||||
send_selection_event();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
wxString MultiSwitchButton::GetSelectedText() const
|
||||
{
|
||||
return sel >= 0 && sel < (int) btns.size() ? btns[sel]->GetLabel() : wxString();
|
||||
}
|
||||
|
||||
wxString MultiSwitchButton::GetOptionText(unsigned int index) const
|
||||
{
|
||||
return index < btns.size() ? btns[index]->GetLabel() : wxString();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetOptionText(unsigned int index, const wxString &text)
|
||||
{
|
||||
if (index >= btns.size())
|
||||
return;
|
||||
btns[index]->SetLabel(text);
|
||||
}
|
||||
|
||||
void *MultiSwitchButton::GetOptionData(unsigned int index) const
|
||||
{
|
||||
return index < btns.size() ? btns[index]->GetClientData() : nullptr;
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetOptionData(unsigned int index, void *clientData)
|
||||
{
|
||||
if (index >= btns.size())
|
||||
return;
|
||||
btns[index]->SetClientData(clientData);
|
||||
}
|
||||
|
||||
void MultiSwitchButton::update_button_styles()
|
||||
{
|
||||
for (int i = 0; i < (int) btns.size(); ++i) {
|
||||
btns[i]->SetValue(i == sel);
|
||||
btns[i]->SetBackgroundColor(m_bg_color);
|
||||
btns[i]->SetTextColor(m_text_color);
|
||||
btns[i]->Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetBackgroundColor(const StateColor &color)
|
||||
{
|
||||
m_bg_color = color;
|
||||
update_button_styles();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetTextColor(const StateColor &color)
|
||||
{
|
||||
m_text_color = color;
|
||||
update_button_styles();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetButtonCornerRadius(double radius)
|
||||
{
|
||||
m_button_radius = radius;
|
||||
SetCornerRadius(radius);
|
||||
for (auto *btn : btns)
|
||||
btn->SetCornerRadius(radius);
|
||||
Layout();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetButtonPadding(const wxSize &padding)
|
||||
{
|
||||
m_button_padding = padding;
|
||||
for (auto *btn : btns)
|
||||
btn->SetPaddingSize(padding);
|
||||
Layout();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::Rescale()
|
||||
{
|
||||
for (auto *btn : btns)
|
||||
btn->Rescale();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::button_clicked(wxCommandEvent &event)
|
||||
{
|
||||
SetFocus();
|
||||
auto *btn = event.GetEventObject();
|
||||
auto iter = std::find(btns.begin(), btns.end(), btn);
|
||||
SetSelection(iter == btns.end() ? -1 : int(iter - btns.begin()));
|
||||
}
|
||||
|
||||
bool MultiSwitchButton::send_selection_event()
|
||||
{
|
||||
wxCommandEvent evt(wxCUSTOMEVT_MULTISWITCH_SELECTION, GetId());
|
||||
evt.SetEventObject(this);
|
||||
evt.SetInt(sel);
|
||||
evt.SetString(GetSelectedText());
|
||||
GetEventHandler()->ProcessEvent(evt);
|
||||
return true;
|
||||
}
|
||||
|
||||
SwitchBoard::SwitchBoard(wxWindow *parent, wxString leftL, wxString right, wxSize size)
|
||||
: wxWindow(parent, wxID_ANY, wxDefaultPosition, size)
|
||||
{
|
||||
@@ -554,4 +744,4 @@ bool SwitchBoard::Enable(bool enable /* = true */)
|
||||
is_enable = enable;
|
||||
Refresh();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user