Add support for printing gcode files in the Storage tab

This commit is contained in:
Lam Wei Lun
2026-10-05 18:22:29 +08:00
parent 3942ba7005
commit 0a8fce0913
6 changed files with 62 additions and 30 deletions
+3 -3
View File
@@ -275,7 +275,7 @@ void Slic3r::GUI::ImageGrid::UpdateFocusRange()
bool Slic3r::GUI::ImageGrid::hasSecondAction(const FileGridCard &card) const
{
return m_show_download || card.downloading ||
(m_model->GetFileType() == FileGridType::Model && m_model->supports_print_action());
(m_model->GetFileType() == FileGridType::Model && card.printable);
}
std::pair<int, size_t> Slic3r::GUI::ImageGrid::HitTest(wxPoint const &pt)
@@ -308,7 +308,7 @@ std::pair<int, size_t> Slic3r::GUI::ImageGrid::HitTest(wxPoint const &pt)
const FileGridCard &card = m_model->GetFile(index);
int btn = card.downloading && card.download_progress >= 0 ? 3 : 2;
if (m_model->GetFileType() == FileGridType::Model) {
if (m_show_download && m_model->supports_print_action())
if (m_show_download && card.printable)
btn = 3;
hover_rect.y -= m_content_rect.GetHeight() * 64 / 264;
}
@@ -686,7 +686,7 @@ void Slic3r::GUI::ImageGrid::renderContent1(wxDC &dc, wxPoint const &pt, int ind
thirdAction = wxString::Format(L"%d%%...", progress);
}
}
if (m_model->GetFileType() == FileGridType::Model && m_model->supports_print_action()) {
if (m_model->GetFileType() == FileGridType::Model && card.printable) {
if (secondAction != _L("Play"))
thirdAction = secondAction;
secondAction = _L_CONTEXT("Print", "Verb");
+35 -13
View File
@@ -10,6 +10,8 @@
#include "Widgets/Label.hpp"
#include "Widgets/StaticBox.hpp"
#include "Widgets/StateColor.hpp"
#include "slic3r/Utils/NetworkAgent.hpp"
#include "slic3r/Utils/bambu_networking.hpp"
#include <boost/make_shared.hpp>
#include <wx/colour.h>
@@ -102,8 +104,7 @@ OrcaFilesPanel::OrcaFilesPanel(wxWindow* parent)
});
m_image_grid->Bind(EVT_ITEM_ACTION, [this](wxCommandEvent& event) {
if (event.GetInt() != 0) // only Delete is wired for this grid
return;
const int action = event.GetInt();
if (!m_model || m_device_id.empty())
return;
@@ -116,18 +117,39 @@ OrcaFilesPanel::OrcaFilesPanel(wxWindow* parent)
const std::string path = card.id;
const std::string name = card.name;
MessageDialog dlg(this,
wxString::Format(_L("Do you want to delete the file '%s' from printer?"), from_u8(name)),
_L("Delete file"), wxYES_NO | wxICON_WARNING);
if (dlg.ShowModal() != wxID_YES)
return;
m_model->DeleteFile(path, [this](bool ok) {
if (ok)
if (action == 0) {
MessageDialog dlg(this,
wxString::Format(_L("Do you want to delete the file '%s' from printer?"), from_u8(name)),
_L("Delete file"), wxYES_NO | wxICON_WARNING);
if (dlg.ShowModal() != wxID_YES)
return;
MessageDialog(this, _L("Failed to delete the file from printer."), _L("Delete file"),
wxOK | wxICON_ERROR).ShowModal();
});
m_model->DeleteFile(path, [this](bool ok) {
if (ok)
return;
MessageDialog(this, _L("Failed to delete the file from printer."), _L("Delete file"),
wxOK | wxICON_ERROR).ShowModal();
});
} else if (action == 1) {
// Print is .gcode-only for now; .gcode.3mf support to be added later.
MessageDialog dlg(this,
wxString::Format(_L("Do you want to print the file '%s' from printer?"), from_u8(name)),
_L("Print file"), wxYES_NO | wxICON_WARNING);
if (dlg.ShowModal() != wxID_YES)
return;
NetworkAgent* agent = wxGetApp().getAgent();
if (!agent)
return;
PrintParams params;
params.dev_id = m_device_id;
params.dst_file = path;
params.connection_type = "lan";
if (agent->start_sdcard_print(params, {}, {}) != BAMBU_NETWORK_SUCCESS)
MessageDialog(this, _L("Failed to start the print job."), _L("Print file"),
wxOK | wxICON_ERROR).ShowModal();
}
});
}
+1 -3
View File
@@ -27,6 +27,7 @@ struct FileGridCard {
bool downloading = false;
int download_progress = 0; // -1 waiting, <0 failed, 0..100 progress
bool selected = false;
bool printable = true;
wxBitmap thumbnail;
};
@@ -48,9 +49,6 @@ public:
// When true, the thumbnail is fitted inside the tile instead of stretched to fill it.
virtual bool preserve_thumbnail_aspect() const { return false; }
// When false, a Model tile omits the Print action. Default keeps Bambu behavior.
virtual bool supports_print_action() const { return true; }
virtual size_t GetIndexAtTime(time_t time) const = 0;
virtual size_t EnterSubGroup(size_t index) = 0;
+19 -9
View File
@@ -34,18 +34,27 @@ std::string durationString(long duration)
return boost::regex_replace(time.str(), rx, "");
}
// Case-insensitive suffix test shared by the file filters below.
bool ends_with_ci(const std::string& name, const std::string& suffix)
{
return name.size() >= suffix.size() &&
std::equal(suffix.rbegin(), suffix.rend(), name.rbegin(),
[](char a, char b) {
return std::tolower(static_cast<unsigned char>(a)) ==
std::tolower(static_cast<unsigned char>(b));
});
}
// .gcode / .3mf only, case-insensitive; a .gcode.3mf name matches via the .3mf suffix.
bool is_displayable_file(const std::string& name)
{
auto ends_with_ci = [&name](const std::string& suffix) {
return name.size() >= suffix.size() &&
std::equal(suffix.rbegin(), suffix.rend(), name.rbegin(),
[](char a, char b) {
return std::tolower(static_cast<unsigned char>(a)) ==
std::tolower(static_cast<unsigned char>(b));
});
};
return ends_with_ci(".gcode") || ends_with_ci(".3mf");
return ends_with_ci(name, ".gcode") || ends_with_ci(name, ".3mf");
}
// Only .gcode is printable today; .gcode.3mf support to be added later.
bool is_printable_gcode(const std::string& name)
{
return ends_with_ci(name, ".gcode");
}
}
@@ -127,6 +136,7 @@ void RemoteFileGridModel::onFilesLoaded(std::uint64_t request, const std::string
card.id = file.path;
card.name = file.name;
card.time = static_cast<time_t>(file.modified);
card.printable = is_printable_gcode(file.name);
m_cards.emplace_back(std::move(card));
}
buildGroups();
@@ -49,7 +49,6 @@ public:
int GetLastError() const override;
void DownloadCheckFiles(const std::string& path) override;
bool preserve_thumbnail_aspect() const override { return true; }
bool supports_print_action() const override { return false; }
// Delete `path` from the printer; `done` reports success on the UI thread.
void DeleteFile(const std::string& path, std::function<void(bool ok)> done);
+4 -1
View File
@@ -2239,7 +2239,10 @@ int OrcaPrinterAgent::start_sdcard_print(PrintParams params, OnUpdateStatusFn up
// dst_file, when set, names a file already on the printer (print-from-SD flow);
// otherwise start what start_send_gcode_to_sdcard just uploaded to `gcodes`.
const std::string target = params.dst_file.empty() ? remote_gcode_name(params) : fs::path(params.dst_file).filename().string();
// Keep the gcodes-relative path with subfolders preserved, minus a leading '/'.
std::string target = params.dst_file.empty() ? remote_gcode_name(params) : params.dst_file;
if (!target.empty() && target.front() == '/')
target.erase(target.begin());
// Per-print mapping. A mapped print is refused when the connector did not
// advertise filament_mapping: the GUI send gates make this visible first, and