mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-05 07:18:19 +03:00
Compare commits
7 Commits
feat/print
...
refactor/p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
56236f56a8 | ||
|
|
df5a08517a | ||
|
|
5d953f915a | ||
|
|
dd2cb92685 | ||
|
|
b2f08c3ff8 | ||
|
|
75a2460649 | ||
|
|
01493d4e3a |
@@ -2273,6 +2273,8 @@ public:
|
||||
plugin_picker,
|
||||
// Raw JSON string value, edited through a dialog behind a button rather than in the row.
|
||||
plugin_config,
|
||||
// PrinterAgentChoice
|
||||
printer_agent_select,
|
||||
};
|
||||
|
||||
// Identifier of this option. It is stored here so that it is accessible through the by_serialization_key_ordinal map.
|
||||
|
||||
@@ -496,6 +496,26 @@ namespace Slic3r
|
||||
OnSelectedMachineChanged(previous_selected_machine, selected_machine);
|
||||
}
|
||||
|
||||
void DeviceManager::clear_other_devices()
|
||||
{
|
||||
// why: on agent swap, keep "My Devices" but drop the transient "Other Devices"
|
||||
// Those belong to the previous agent's network scan; the new agent's start_discovery re-populates its own.
|
||||
const auto my = get_my_machine_list();
|
||||
for (auto it = localMachineList.begin(); it != localMachineList.end();)
|
||||
{
|
||||
if (my.find(it->first) == my.end())
|
||||
{
|
||||
// not a "My Device" -> an "Other Device"
|
||||
delete it->second;
|
||||
it = localMachineList.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool DeviceManager::set_selected_machine(std::string dev_id)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << "set_selected_machine=" << dev_id
|
||||
@@ -558,7 +578,6 @@ namespace Slic3r
|
||||
}
|
||||
else
|
||||
{
|
||||
Slic3r::GUI::wxGetApp().reset_unsigned_plugin_warning();
|
||||
if (m_agent)
|
||||
{
|
||||
if (it->second->connection_type() != "lan" || it->second->connection_type().empty())
|
||||
@@ -592,7 +611,6 @@ namespace Slic3r
|
||||
}
|
||||
|
||||
selected_machine = dev_id;
|
||||
record_user_last_machine(selected_machine);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -851,44 +869,26 @@ namespace Slic3r
|
||||
int result = m_agent->get_user_print_info(&http_code, &body, provider);
|
||||
if (result == 0)
|
||||
{
|
||||
parse_user_print_info(body);
|
||||
// parse_user_print_info and on_machine_alive (SSDP for discovery) both mutate the same userMachineList map.
|
||||
// on_machine_alive mutates the map on the UI thread, do the same for parse_user_print_info.
|
||||
Slic3r::GUI::wxGetApp().CallAfter([this, body]() { parse_user_print_info(body); });
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceManager::record_user_last_machine(const std::string& dev_id)
|
||||
{
|
||||
if (Slic3r::GUI::wxGetApp().app_config) {
|
||||
Slic3r::GUI::wxGetApp().app_config->set("user_last_selected_machine", dev_id);
|
||||
}
|
||||
}
|
||||
|
||||
std::string DeviceManager::get_user_last_machine() const
|
||||
{
|
||||
if (Slic3r::GUI::wxGetApp().app_config) {
|
||||
const auto& user_last_machine = Slic3r::GUI::wxGetApp().app_config->get("user_last_selected_machine");
|
||||
if (!user_last_machine.empty()) {
|
||||
return user_last_machine;
|
||||
} else if (m_agent) {
|
||||
return m_agent->get_user_selected_machine();
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void DeviceManager::load_last_machine()
|
||||
{
|
||||
if (userMachineList.empty()) return;
|
||||
else if (userMachineList.size() == 1) {
|
||||
this->set_selected_machine(userMachineList.begin()->second->get_dev_id());
|
||||
} else {
|
||||
const auto& last_monitor_machine = get_user_last_machine();
|
||||
if (userMachineList.find(last_monitor_machine) != userMachineList.end()) {
|
||||
set_selected_machine(last_monitor_machine);
|
||||
} else {
|
||||
this->set_selected_machine(userMachineList.begin()->second->get_dev_id());
|
||||
}
|
||||
}
|
||||
// Get all available machines, include cloud machines and lan machines that have access right
|
||||
auto all_machines = get_my_machine_list();
|
||||
if (all_machines.empty())
|
||||
return;
|
||||
|
||||
// Reconnect the machine the user last selected, if it's still available.
|
||||
// why: no first-available fallback - auto-connecting an arbitrary machine
|
||||
// fights the agent-swap reset, which intentionally leaves nothing selected.
|
||||
const std::string last_monitor_machine = m_agent ? m_agent->get_user_selected_machine() : "";
|
||||
const auto last_machine = all_machines.find(last_monitor_machine);
|
||||
if (last_machine != all_machines.end())
|
||||
this->set_selected_machine(last_machine->second->get_dev_id());
|
||||
}
|
||||
|
||||
void DeviceManager::OnMachineBindStateChanged(MachineObject* obj, const std::string& new_state)
|
||||
|
||||
@@ -48,8 +48,9 @@ public:
|
||||
MachineObject* get_selected_machine();
|
||||
bool set_selected_machine(std::string dev_id);
|
||||
|
||||
void record_user_last_machine(const std::string& dev_id);
|
||||
std::string get_user_last_machine() const;
|
||||
// why: clears stale sidebar sync-status / AMS visuals. Public so the printer-agent
|
||||
// swap path can reuse it instead of duplicating the two sidebar calls.
|
||||
void OnSelectedMachineLost();
|
||||
|
||||
// local machine
|
||||
void set_local_selected_machine(std::string dev_id) { local_selected_machine = dev_id; };
|
||||
@@ -70,6 +71,8 @@ public:
|
||||
void erase_user_machine(std::string dev_id) { userMachineList.erase(dev_id); }
|
||||
void clean_user_info(bool keep_local_selection = false);
|
||||
|
||||
void clear_other_devices();
|
||||
|
||||
void load_last_machine();
|
||||
void update_user_machine_list_info(const std::string& provider);
|
||||
void parse_user_print_info(std::string body);
|
||||
@@ -110,7 +113,6 @@ private:
|
||||
void check_pushing();
|
||||
|
||||
void OnMachineBindStateChanged(MachineObject* obj, const std::string& new_state);
|
||||
void OnSelectedMachineLost();
|
||||
void OnSelectedMachineChanged(const std::string& pre_dev_id, const std::string& new_dev_id);
|
||||
|
||||
|
||||
|
||||
@@ -1733,9 +1733,11 @@ int MachineObject::command_ams_user_settings(bool start_read_opt, bool tray_read
|
||||
|
||||
int MachineObject::command_ams_calibrate(int ams_id)
|
||||
{
|
||||
std::string gcode_cmd = (boost::format("M620 C%1% \n") % ams_id).str();
|
||||
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode_cmd;
|
||||
return this->publish_gcode(gcode_cmd);
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_ams_calibrate(get_dev_id(), ams_id, MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
}
|
||||
|
||||
int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::string filament_id, std::string setting_id, std::string tray_color, std::string tray_type, int nozzle_temp_min, int nozzle_temp_max)
|
||||
@@ -1773,9 +1775,11 @@ int MachineObject::command_ams_filament_settings(int ams_id, int slot_id, std::s
|
||||
|
||||
int MachineObject::command_ams_refresh_rfid(std::string tray_id)
|
||||
{
|
||||
std::string gcode_cmd = (boost::format("M620 R%1% \n") % tray_id).str();
|
||||
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode_cmd;
|
||||
return this->publish_gcode(gcode_cmd);
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_ams_refresh_rfid(get_dev_id(), tray_id, MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
}
|
||||
|
||||
int MachineObject::command_ams_refresh_rfid2(int ams_id, int slot_id)
|
||||
@@ -1791,9 +1795,11 @@ int MachineObject::command_ams_refresh_rfid2(int ams_id, int slot_id)
|
||||
|
||||
int MachineObject::command_ams_select_tray(std::string tray_id)
|
||||
{
|
||||
std::string gcode_cmd = (boost::format("M620 P%1% \n") % tray_id).str();
|
||||
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode_cmd;
|
||||
return this->publish_gcode(gcode_cmd);
|
||||
if (!m_agent) return -1;
|
||||
int rtn = m_agent->command_ams_select_tray(get_dev_id(), tray_id, MachineObject::m_sequence_id++, is_lan_mode_printer());
|
||||
if (rtn == ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED || rtn == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE)
|
||||
show_unsupported_dlg(rtn);
|
||||
return rtn;
|
||||
}
|
||||
|
||||
int MachineObject::command_ams_control(std::string action)
|
||||
@@ -4647,6 +4653,40 @@ void MachineObject::set_ctt_dlg( wxString text){
|
||||
}
|
||||
}
|
||||
|
||||
void MachineObject::show_unsupported_dlg(int code)
|
||||
{
|
||||
// why: a dead control invites repeat clicks, and the frame is modeless - without the guard
|
||||
// every click stacks another one. Same shape as set_ctt_dlg above, including the reset on
|
||||
// both hide and close so a dismissed dialog can reappear on the next attempt.
|
||||
if (m_unsupported_dlg_shown) {
|
||||
return;
|
||||
}
|
||||
m_unsupported_dlg_shown = true;
|
||||
|
||||
// why: two codes so the user learns which kind of dead end this is - the slicer having no
|
||||
// translation for the command, or the printer's own config lacking the hardware to run it.
|
||||
const wxString text = (code == ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE) ?
|
||||
_L("This printer is not configured with the hardware this control needs.") :
|
||||
_L("This control is not supported on this printer.");
|
||||
|
||||
// note: constructed directly rather than through CallAfter because every publish_json caller
|
||||
// is on the UI thread - clicks come from wx handlers, and the agent marshals its own push
|
||||
// callbacks back to main before parse_json runs. set_ctt_dlg relies on the same property.
|
||||
auto unsupported_dlg = new GUI::SecondaryCheckDialog(nullptr, wxID_ANY, _L("Warning"),
|
||||
GUI::SecondaryCheckDialog::VisibleButtons::ONLY_CONFIRM);
|
||||
unsupported_dlg->update_text(text);
|
||||
unsupported_dlg->Bind(wxEVT_SHOW, [this](auto& e) {
|
||||
if (!e.IsShown()) {
|
||||
m_unsupported_dlg_shown = false;
|
||||
}
|
||||
});
|
||||
unsupported_dlg->Bind(wxEVT_CLOSE_WINDOW, [this](auto& e) {
|
||||
e.Skip();
|
||||
m_unsupported_dlg_shown = false;
|
||||
});
|
||||
unsupported_dlg->on_show();
|
||||
}
|
||||
|
||||
int MachineObject::publish_gcode(std::string gcode_str)
|
||||
{
|
||||
json j;
|
||||
|
||||
@@ -272,9 +272,11 @@ public:
|
||||
bool m_is_online;
|
||||
bool m_lan_mode_connection_state{false};
|
||||
bool m_set_ctt_dlg{ false };
|
||||
bool m_unsupported_dlg_shown{ false };
|
||||
void set_lan_mode_connection_state(bool state) {m_lan_mode_connection_state = state;};
|
||||
bool get_lan_mode_connection_state() {return m_lan_mode_connection_state;};
|
||||
void set_ctt_dlg( wxString text);
|
||||
void show_unsupported_dlg(int code);
|
||||
int parse_msg_count = 0;
|
||||
int keep_alive_count = 0;
|
||||
std::chrono::system_clock::time_point last_update_time; /* last received print data from machine */
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "Widgets/TextCtrl.h"
|
||||
|
||||
#include "../Utils/ColorSpaceConvert.hpp"
|
||||
#include "../Utils/NetworkAgentFactory.hpp"
|
||||
#ifdef __WXOSX__
|
||||
#define wxOSX true
|
||||
#else
|
||||
@@ -1403,39 +1404,6 @@ using choice_ctrl = ::ComboBox; // BBS
|
||||
|
||||
static std::map<std::string, DynamicList*> dynamic_lists;
|
||||
|
||||
static bool is_plugin_printer_agent_key(const std::string& value)
|
||||
{
|
||||
return value.rfind("plugin:", 0) == 0;
|
||||
}
|
||||
|
||||
static int printer_agent_item_for_enum_index(const choice_ctrl* field, int enum_index)
|
||||
{
|
||||
if (!field)
|
||||
return -1;
|
||||
|
||||
const unsigned int count = field->GetCount();
|
||||
for (unsigned int idx = 0; idx < count; ++idx) {
|
||||
if (void* data = field->GetClientData(idx)) {
|
||||
const int stored = static_cast<int>(reinterpret_cast<uintptr_t>(data)) - 1;
|
||||
if (stored == enum_index)
|
||||
return static_cast<int>(idx);
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int printer_agent_enum_index_for_item(const choice_ctrl* field, int item_index, int fallback)
|
||||
{
|
||||
if (!field || item_index < 0)
|
||||
return fallback;
|
||||
|
||||
if (void* data = field->GetClientData(item_index))
|
||||
return static_cast<int>(reinterpret_cast<uintptr_t>(data)) - 1;
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
void Choice::register_dynamic_list(std::string const &optname, DynamicList *list) { dynamic_lists.emplace(optname, list); }
|
||||
|
||||
void DynamicList::update()
|
||||
@@ -1518,33 +1486,7 @@ void Choice::BUILD()
|
||||
window = dynamic_cast<wxWindow*>(temp);
|
||||
|
||||
if (! m_opt.enum_labels.empty() || ! m_opt.enum_values.empty()) {
|
||||
if (m_opt_id == "printer_agent") {
|
||||
const bool has_builtin_agents = std::any_of(m_opt.enum_values.begin(), m_opt.enum_values.end(),
|
||||
[](const std::string& value) { return !is_plugin_printer_agent_key(value); });
|
||||
const bool has_plugin_agents = std::any_of(m_opt.enum_values.begin(), m_opt.enum_values.end(),
|
||||
[](const std::string& value) { return is_plugin_printer_agent_key(value); });
|
||||
|
||||
auto append_agent_rows = [this, temp](bool plugins) {
|
||||
for (size_t i = 0; i < m_opt.enum_values.size(); ++i) {
|
||||
const bool is_plugin = is_plugin_printer_agent_key(m_opt.enum_values[i]);
|
||||
if (is_plugin != plugins)
|
||||
continue;
|
||||
|
||||
const wxString label = i < m_opt.enum_labels.size() ? _(m_opt.enum_labels[i]) : wxString(m_opt.enum_values[i]);
|
||||
const int item = temp->Append(label);
|
||||
temp->SetClientData(item, reinterpret_cast<void*>(static_cast<uintptr_t>(i + 1)));
|
||||
}
|
||||
};
|
||||
|
||||
if (has_builtin_agents) {
|
||||
temp->Append(_L("System agents"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM | DD_ITEM_STYLE_DISABLED);
|
||||
append_agent_rows(false);
|
||||
}
|
||||
if (has_plugin_agents) {
|
||||
temp->Append(_L("Plugins"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM | DD_ITEM_STYLE_DISABLED);
|
||||
append_agent_rows(true);
|
||||
}
|
||||
} else if (m_opt.enum_labels.empty()) {
|
||||
if (m_opt.enum_labels.empty()) {
|
||||
// Append non-localized enum_values
|
||||
for (auto el : m_opt.enum_values)
|
||||
temp->Append(el);
|
||||
@@ -1651,7 +1593,7 @@ void Choice::set_selection()
|
||||
switch (m_opt.type) {
|
||||
case coEnum:{
|
||||
const int val = m_opt.default_value->getInt();
|
||||
field->SetSelection(m_opt_id == "printer_agent" ? printer_agent_item_for_enum_index(field, val) : val);
|
||||
field->SetSelection(val);
|
||||
break;
|
||||
}
|
||||
case coFloat:
|
||||
@@ -1701,12 +1643,7 @@ void Choice::set_value(const std::string& value, bool change_event) //! Redunda
|
||||
}
|
||||
|
||||
choice_ctrl* field = dynamic_cast<choice_ctrl*>(window);
|
||||
if (m_opt_id == "printer_agent") {
|
||||
const int enum_index = idx == m_opt.enum_values.size() ?
|
||||
(m_opt.default_value ? m_opt.default_value->getInt() : 0) :
|
||||
static_cast<int>(idx);
|
||||
field->SetSelection(printer_agent_item_for_enum_index(field, enum_index));
|
||||
} else if (idx == m_opt.enum_values.size())
|
||||
if (idx == m_opt.enum_values.size())
|
||||
field->SetValue(value);
|
||||
else
|
||||
field->SetSelection(idx);
|
||||
@@ -1772,33 +1709,11 @@ void Choice::set_value(const boost::any& value, bool change_event)
|
||||
case coEnum:
|
||||
// BBS
|
||||
case coEnums: {
|
||||
auto printer_agent_index_from_key = [this](const std::string& key) {
|
||||
auto it = std::find(m_opt.enum_values.begin(), m_opt.enum_values.end(), key);
|
||||
if (it != m_opt.enum_values.end())
|
||||
return static_cast<int>(it - m_opt.enum_values.begin());
|
||||
return m_opt.default_value ? m_opt.default_value->getInt() : 0;
|
||||
};
|
||||
|
||||
int val = 0;
|
||||
if (m_opt_id == "printer_agent") {
|
||||
if (const int* int_value = boost::any_cast<int>(&value))
|
||||
val = *int_value;
|
||||
else if (const wxString* wx_value = boost::any_cast<wxString>(&value))
|
||||
val = printer_agent_index_from_key(into_u8(*wx_value));
|
||||
else if (const std::string* string_value = boost::any_cast<std::string>(&value))
|
||||
val = printer_agent_index_from_key(*string_value);
|
||||
else {
|
||||
m_disable_change_event = false;
|
||||
return;
|
||||
}
|
||||
} else
|
||||
val = boost::any_cast<int>(value);
|
||||
int val = boost::any_cast<int>(value);
|
||||
|
||||
int selection = val;
|
||||
|
||||
if (m_opt_id == "printer_agent") {
|
||||
selection = printer_agent_item_for_enum_index(field, val);
|
||||
} else if (m_opt_id == "input_shaping_type") {
|
||||
if (m_opt_id == "input_shaping_type") {
|
||||
if (field != nullptr) {
|
||||
const unsigned int count = field->GetCount();
|
||||
int match_index = -1;
|
||||
@@ -1920,12 +1835,6 @@ boost::any& Choice::get_value()
|
||||
{
|
||||
if (m_opt.nullable && field->GetSelection() == -1)
|
||||
m_value = ConfigOptionEnumsGenericNullable::nil_value();
|
||||
else if (m_opt_id == "printer_agent")
|
||||
{
|
||||
const int selection = field->GetSelection();
|
||||
const int fallback = m_opt.default_value ? m_opt.default_value->getInt() : 0;
|
||||
m_value = printer_agent_enum_index_for_item(field, selection, fallback);
|
||||
}
|
||||
else if (m_opt_id == "input_shaping_type")
|
||||
{
|
||||
int selection = field->GetSelection();
|
||||
@@ -2067,6 +1976,171 @@ void Choice::msw_rescale()
|
||||
}
|
||||
|
||||
|
||||
// PrinterAgentChoice
|
||||
|
||||
void PrinterAgentChoice::reload_rows()
|
||||
{
|
||||
auto* combo = dynamic_cast<choice_ctrl*>(window); // wxWidgets ComboBox
|
||||
if (!combo)
|
||||
return;
|
||||
|
||||
// clear ComboBox
|
||||
combo->Clear();
|
||||
|
||||
// helpers
|
||||
const auto agents = NetworkAgentFactory::get_registered_printer_agents();
|
||||
const bool has_builtin_agents = std::any_of(agents.begin(), agents.end(),
|
||||
[](const PrinterAgentInfo& a) { return !a.is_plugin(); });
|
||||
const bool has_plugin_agents = std::any_of(agents.begin(), agents.end(),
|
||||
[](const PrinterAgentInfo& a) { return a.is_plugin(); });
|
||||
|
||||
auto append_agent_rows = [combo](bool is_plugin)
|
||||
{
|
||||
const auto agents = NetworkAgentFactory::get_registered_printer_agents();
|
||||
for (size_t i = 0; i < agents.size(); ++i)
|
||||
{
|
||||
if (agents[i].is_plugin() != is_plugin)
|
||||
continue;
|
||||
const int item = combo->Append(_(agents[i].display_name));
|
||||
// why: carry the agent-id string on the row. alias is an owned wxString (auto-freed, never rendered)
|
||||
combo->SetItemAlias(item, from_u8(agents[i].id));
|
||||
}
|
||||
};
|
||||
|
||||
// append rows
|
||||
if (has_builtin_agents)
|
||||
{
|
||||
combo->Append(_L("System agents"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM | DD_ITEM_STYLE_DISABLED);
|
||||
append_agent_rows(false); // append rows for agents that are not plugins
|
||||
}
|
||||
if (has_plugin_agents)
|
||||
{
|
||||
combo->Append(_L("Plugins"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM | DD_ITEM_STYLE_DISABLED);
|
||||
append_agent_rows(true); // append rows for agents that are plugins
|
||||
}
|
||||
}
|
||||
|
||||
void PrinterAgentChoice::BUILD()
|
||||
{
|
||||
wxSize size(def_width_wider() * m_em_unit, wxDefaultCoord);
|
||||
if (m_opt.height >= 0) size.SetHeight(m_opt.height * m_em_unit);
|
||||
if (m_opt.width >= 0) size.SetWidth(m_opt.width * m_em_unit);
|
||||
|
||||
static Builder<choice_ctrl> builder;
|
||||
choice_ctrl* temp = builder.build(m_parent, wxID_ANY, wxString(""), wxDefaultPosition, size, 0, nullptr,
|
||||
wxCB_READONLY);
|
||||
temp->Clear();
|
||||
temp->GetDropDown().SetUseContentWidth(true);
|
||||
if (parent_is_custom_ctrl && m_opt.height < 0)
|
||||
opt_height = (double)temp->GetTextCtrl()->GetSize().GetHeight() / m_em_unit;
|
||||
temp->SetTextLabel(_L(m_opt.sidetext));
|
||||
m_combine_side_text = true;
|
||||
#ifdef __WXGTK3__
|
||||
wxSize best_sz = temp->GetBestSize();
|
||||
if (best_sz.x > size.x) temp->SetSize(best_sz);
|
||||
#endif
|
||||
if (!wxOSX) temp->SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
|
||||
window = dynamic_cast<wxWindow*>(temp);
|
||||
|
||||
reload_rows();
|
||||
|
||||
temp->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { on_change_field(); }, temp->GetId());
|
||||
temp->SetToolTip(get_tooltip_text(temp->GetValue()));
|
||||
}
|
||||
|
||||
// Resolve CONFIG id string to a matching row in the live REGISTRY. "" uses the vendor default.
|
||||
// An unregistered id clears selection and shows "<id> (missing)" as free text.
|
||||
void PrinterAgentChoice::set_value(const std::string& value, bool change_event)
|
||||
{
|
||||
m_disable_change_event = !change_event;
|
||||
|
||||
auto* field = dynamic_cast<choice_ctrl*>(window);
|
||||
|
||||
// check if any row's corresponding id matches the agent id we are attempting to set
|
||||
const std::string effective_agent_id = wxGetApp().resolve_printer_agent_id(value);
|
||||
const unsigned int count = field->GetCount();
|
||||
int match = wxNOT_FOUND;
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
{
|
||||
if (into_u8(field->GetItemAlias(i)) == effective_agent_id) // if alias == id
|
||||
{
|
||||
match = static_cast<int>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// based on match or not, set selection and value
|
||||
// - SetSelection and SetValue are UI to manipulate the display of the ComboBox
|
||||
// - SetSelection automatically calls SetValue for the same value
|
||||
// - we can also SetValue separately from SetSelection
|
||||
if (match == wxNOT_FOUND)
|
||||
{
|
||||
field->SetSelection(wxNOT_FOUND); // nothing shows as selected in the dropdown
|
||||
field->SetValue(from_u8(value + " (missing)")); // set a value not in the selection (upper display field)
|
||||
}
|
||||
else
|
||||
{
|
||||
// display name of agent shows both in upper display field and appears selected in dropdown
|
||||
field->SetSelection(match);
|
||||
}
|
||||
|
||||
m_disable_change_event = false;
|
||||
}
|
||||
|
||||
// Accept boost::any values from callers (usually to OptionsGroup/Field parent classes) and normalize them to an agent id.
|
||||
// Then use PrinterAgentChoice::set_value(std::string& value, ...)
|
||||
void PrinterAgentChoice::set_value(const boost::any& value, bool change_event)
|
||||
{
|
||||
m_disable_change_event = !change_event;
|
||||
|
||||
auto* field = dynamic_cast<choice_ctrl*>(window);
|
||||
if (value.empty())
|
||||
{
|
||||
field->SetValue("");
|
||||
m_value = value;
|
||||
m_disable_change_event = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string id;
|
||||
if (const std::string* s = boost::any_cast<std::string>(&value))
|
||||
id = *s;
|
||||
else if (const wxString* w = boost::any_cast<wxString>(&value))
|
||||
id = into_u8(*w);
|
||||
set_value(id, change_event);
|
||||
}
|
||||
|
||||
// A real row returns its alias, which is the agent id. Header rows, missing rows,
|
||||
// and no selection return empty boost::any so the custom writer leaves config unchanged.
|
||||
boost::any& PrinterAgentChoice::get_value()
|
||||
{
|
||||
auto* field = dynamic_cast<choice_ctrl*>(window);
|
||||
const int sel = field->GetSelection();
|
||||
const std::string id = sel < 0 ? std::string{} : into_u8(field->GetItemAlias(sel));
|
||||
if (id.empty())
|
||||
m_value = boost::any{};
|
||||
else
|
||||
m_value = id;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void PrinterAgentChoice::enable() { dynamic_cast<choice_ctrl*>(window)->Enable(); }
|
||||
void PrinterAgentChoice::disable() { dynamic_cast<choice_ctrl*>(window)->Disable(); }
|
||||
|
||||
void PrinterAgentChoice::msw_rescale()
|
||||
{
|
||||
Field::msw_rescale();
|
||||
|
||||
auto* field = dynamic_cast<choice_ctrl*>(window)->GetTextCtrl();
|
||||
wxSize size(wxDefaultSize);
|
||||
size.SetWidth((m_opt.width > 0 ? m_opt.width : def_width_wider()) * m_em_unit);
|
||||
field->SetMinSize(wxSize(-1, int(1.5f * field->GetFont().GetPixelSize().y + 0.5f)));
|
||||
field->SetSize(size);
|
||||
|
||||
dynamic_cast<choice_ctrl*>(window)->Rescale();
|
||||
}
|
||||
|
||||
void PluginField::BUILD()
|
||||
{
|
||||
auto* panel = new wxPanel(m_parent, wxID_ANY);
|
||||
|
||||
@@ -469,6 +469,44 @@ public:
|
||||
void suppress_scroll();
|
||||
};
|
||||
|
||||
// printer_agent is a coString whose choices come from the live agent registry.
|
||||
// PrinterAgentChoice uses a ComboBox directly because Choice expects static config enums.
|
||||
// Real rows carry the stored agent id in the row alias (SetItemAlias/GetItemAlias).
|
||||
class PrinterAgentChoice : public Field
|
||||
{
|
||||
using Field::Field;
|
||||
|
||||
public:
|
||||
PrinterAgentChoice(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id)
|
||||
{
|
||||
}
|
||||
|
||||
PrinterAgentChoice(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(
|
||||
parent, opt, id)
|
||||
{
|
||||
}
|
||||
|
||||
~PrinterAgentChoice()
|
||||
{
|
||||
}
|
||||
|
||||
wxWindow* window{nullptr};
|
||||
|
||||
void BUILD() override;
|
||||
// Clear and repopulate rows from the live registry (grouped System agents / Plugins).
|
||||
// Does not change selection; the caller follows with set_value(stored id).
|
||||
void reload_rows();
|
||||
|
||||
void set_value(const std::string& value, bool change_event = false);
|
||||
void set_value(const boost::any& value, bool change_event = false) override;
|
||||
boost::any& get_value() override;
|
||||
|
||||
void enable() override;
|
||||
void disable() override;
|
||||
void msw_rescale() override;
|
||||
wxWindow* getWindow() override { return window; }
|
||||
};
|
||||
|
||||
class PluginField : public Field {
|
||||
using Field::Field;
|
||||
public:
|
||||
|
||||
@@ -2809,16 +2809,58 @@ void GUI_App::init_plugin_gui_wiring()
|
||||
});
|
||||
};
|
||||
|
||||
// why: a newly loaded plugin only adds a selectable agent
|
||||
// refresh the dropdown and leave the live agent alone
|
||||
auto refresh_printer_agent_dropdown_after_load = [](const std::string&)
|
||||
{
|
||||
if (!wxTheApp)
|
||||
return;
|
||||
|
||||
GUI_App* app = &GUI::wxGetApp();
|
||||
if (app->is_closing())
|
||||
return;
|
||||
|
||||
app->CallAfter([app]
|
||||
{
|
||||
if (!app->is_closing())
|
||||
app->refresh_printer_agent_dropdown();
|
||||
});
|
||||
};
|
||||
|
||||
// why: the unloaded plugin may have been the provider of the live agent
|
||||
// re-run selection, where a now-missing agent will be cleared
|
||||
// refresh dropdown after
|
||||
auto switch_printer_agent_after_unload = [](const std::string&)
|
||||
{
|
||||
if (!wxTheApp)
|
||||
return;
|
||||
|
||||
GUI_App* app = &GUI::wxGetApp();
|
||||
if (app->is_closing())
|
||||
return;
|
||||
|
||||
app->CallAfter([app] {
|
||||
if (app->is_closing())
|
||||
return;
|
||||
|
||||
app->switch_printer_agent();
|
||||
app->refresh_printer_agent_dropdown();
|
||||
});
|
||||
};
|
||||
|
||||
plugin_mgr.subscribe_on_unload_callback(PluginHostUi::close_windows_for_plugin);
|
||||
plugin_mgr.subscribe_on_load_callback([refresh_plugins_dialog](const std::string&) { refresh_plugins_dialog(); });
|
||||
plugin_mgr.subscribe_on_unload_callback([refresh_plugins_dialog](const std::string&) { refresh_plugins_dialog(); });
|
||||
plugin_mgr.subscribe_on_load_callback(NetworkAgentFactory::register_python_plugin);
|
||||
plugin_mgr.subscribe_on_unload_callback(NetworkAgentFactory::deregister_python_plugin);
|
||||
plugin_mgr.subscribe_on_load_callback(refresh_printer_agent_dropdown_after_load);
|
||||
plugin_mgr.subscribe_on_unload_callback(switch_printer_agent_after_unload);
|
||||
plugin_mgr.subscribe_on_capability_load_callback(
|
||||
[refresh_plugins_dialog](const PluginCapabilityId& capability) {
|
||||
[refresh_plugins_dialog, refresh_printer_agent_dropdown_after_load](const PluginCapabilityId& capability) {
|
||||
if (capability.type == PluginCapabilityType::PrinterConnection)
|
||||
NetworkAgentFactory::register_python_printer_agent(capability.plugin_key, capability.name);
|
||||
refresh_plugins_dialog();
|
||||
refresh_printer_agent_dropdown_after_load(capability.plugin_key);
|
||||
// A newly loaded capability may satisfy a missing-plugin notification; re-validate the
|
||||
// current plate (on the UI thread) so the notification clears once its plugin is available.
|
||||
if (wxTheApp && !wxGetApp().is_closing())
|
||||
@@ -2828,10 +2870,11 @@ void GUI_App::init_plugin_gui_wiring()
|
||||
});
|
||||
});
|
||||
plugin_mgr.subscribe_on_capability_unload_callback(
|
||||
[refresh_plugins_dialog](const PluginCapabilityId& capability) {
|
||||
[refresh_plugins_dialog, switch_printer_agent_after_unload](const PluginCapabilityId& capability) {
|
||||
if (capability.type == PluginCapabilityType::PrinterConnection)
|
||||
NetworkAgentFactory::deregister_python_printer_agent(capability.plugin_key, capability.name);
|
||||
refresh_plugins_dialog();
|
||||
switch_printer_agent_after_unload(capability.plugin_key);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3873,6 +3916,48 @@ unsigned GUI_App::get_colour_approx_luma(const wxColour &colour)
|
||||
));
|
||||
}
|
||||
|
||||
void GUI_App::refresh_printer_agent_dropdown()
|
||||
{
|
||||
if (Tab* tab = get_tab(Preset::TYPE_PRINTER))
|
||||
{
|
||||
if (auto* printer_tab = dynamic_cast<TabPrinter*>(tab))
|
||||
printer_tab->refresh_printer_agent_dropdown();
|
||||
}
|
||||
}
|
||||
|
||||
void GUI_App::set_live_printer_agent(std::shared_ptr<IPrinterAgent> agent)
|
||||
{
|
||||
if (!m_agent)
|
||||
return;
|
||||
|
||||
// why: tearing down the old machine selection is only ever the prefix of setting the live
|
||||
// agent (to a new one, or to null when the selection is missing) - so it lives here, not as
|
||||
// a standalone helper. Pass nullptr to clear the selection.
|
||||
if (DeviceManager* dev = getDeviceManager())
|
||||
{
|
||||
dev->set_selected_machine(""); // why: empty id disconnects and deselects the current machine
|
||||
m_agent->set_user_selected_machine("");
|
||||
// note: belt-and-suspenders (precedent: DeviceManagerRefresher::on_timer)
|
||||
dev->OnSelectedMachineLost(); // why: clear stale sidebar sync-status / AMS
|
||||
dev->clear_other_devices(); // why: drop stale LAN discoveries; keep My Devices
|
||||
}
|
||||
|
||||
m_agent->set_printer_agent(agent);
|
||||
sidebar().update_all_preset_comboboxes();
|
||||
}
|
||||
|
||||
std::string GUI_App::resolve_printer_agent_id(const std::string& stored_id)
|
||||
{
|
||||
if (!stored_id.empty())
|
||||
return stored_id;
|
||||
return (preset_bundle && preset_bundle->is_bbl_vendor()) ? BBL_PRINTER_AGENT_ID : ORCA_PRINTER_AGENT_ID;
|
||||
}
|
||||
|
||||
std::string GUI_App::canonical_printer_agent_id(const std::string& picked_id)
|
||||
{
|
||||
return picked_id == resolve_printer_agent_id("") ? std::string() : picked_id;
|
||||
}
|
||||
|
||||
void GUI_App::switch_printer_agent()
|
||||
{
|
||||
if (!m_agent) {
|
||||
@@ -3880,24 +3965,17 @@ void GUI_App::switch_printer_agent()
|
||||
return;
|
||||
}
|
||||
|
||||
// Read printer_agent from config, falling back to default
|
||||
std::string effective_agent_id = ORCA_PRINTER_AGENT_ID;
|
||||
if (preset_bundle->is_bbl_vendor())
|
||||
effective_agent_id = BBL_PRINTER_AGENT_ID;
|
||||
|
||||
const DynamicPrintConfig& config = preset_bundle->printers.get_edited_preset().config;
|
||||
if (config.has("printer_agent")) {
|
||||
const std::string& value = config.option<ConfigOptionString>("printer_agent")->value;
|
||||
if (!value.empty())
|
||||
effective_agent_id = value;
|
||||
}
|
||||
const std::string effective_agent_id = resolve_printer_agent_id(config.opt_string("printer_agent"));
|
||||
|
||||
// Check if agent is registered
|
||||
const PrinterAgentInfo* agent_info_ptr = NetworkAgentFactory::get_printer_agent_info(effective_agent_id);
|
||||
if (!agent_info_ptr) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": unregistered agent ID '" << effective_agent_id
|
||||
<< "', keeping current agent";
|
||||
// Keep current agent, don't switch
|
||||
// why: the selected agent's provider is gone (e.g. plugin unloaded); leaving the old
|
||||
// live agent up would keep talking to a machine the user can no longer select.
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": agent ID '" << effective_agent_id
|
||||
<< "' is unregistered; clearing live printer agent";
|
||||
set_live_printer_agent(nullptr);
|
||||
return;
|
||||
}
|
||||
const PrinterAgentInfo agent_info = *agent_info_ptr;
|
||||
@@ -3911,7 +3989,9 @@ void GUI_App::switch_printer_agent()
|
||||
NetworkAgentFactory::create_printer_agent_by_id(effective_agent_id, cloud_agent, log_dir);
|
||||
|
||||
if (!new_printer_agent) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": failed to create agent '" << effective_agent_id << "', keeping current agent";
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": failed to create agent '" << effective_agent_id
|
||||
<< "'; clearing live printer agent";
|
||||
set_live_printer_agent(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3934,9 +4014,9 @@ void GUI_App::switch_printer_agent()
|
||||
return;
|
||||
}
|
||||
|
||||
// Swap the agent
|
||||
m_agent->set_printer_agent(new_printer_agent);
|
||||
sidebar().update_all_preset_comboboxes();
|
||||
// Swap the agent; set_live_printer_agent resets the device selection so the new
|
||||
// agent starts clean (#124).
|
||||
set_live_printer_agent(new_printer_agent);
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": printer agent switched to " << effective_agent_id;
|
||||
|
||||
|
||||
@@ -365,9 +365,14 @@ public:
|
||||
HMSQuery* get_hms_query() { return hms_query; }
|
||||
NetworkAgent* getAgent() { return m_agent; }
|
||||
|
||||
// Dynamic printer agent switching
|
||||
// Reconcile the live printer agent with the stored preset selection.
|
||||
void switch_printer_agent();
|
||||
|
||||
std::string resolve_printer_agent_id(const std::string& stored_id);
|
||||
// ORCA TODO: in the future, bbl presets should specify "bbl" printer agent id
|
||||
// then, all resolve and canonical would just be ORCA<->""
|
||||
std::string canonical_printer_agent_id(const std::string& picked_id);
|
||||
|
||||
FilamentColorCodeQuery* get_filament_color_code_query();
|
||||
bool is_editor() const { return m_app_mode == EAppMode::Editor; }
|
||||
bool is_gcode_viewer() const { return m_app_mode == EAppMode::GCodeViewer; }
|
||||
@@ -798,6 +803,11 @@ private:
|
||||
void window_pos_center(wxTopLevelWindow *window);
|
||||
bool select_language();
|
||||
|
||||
// Dynamic printer agent selection - internal helpers for switch_printer_agent
|
||||
// and the plugin load/unload callbacks (init_plugin_gui_wiring).
|
||||
void refresh_printer_agent_dropdown();
|
||||
void set_live_printer_agent(std::shared_ptr<IPrinterAgent> agent); // null clears the selection
|
||||
|
||||
bool config_wizard_startup();
|
||||
void check_updates(const bool verbose);
|
||||
|
||||
|
||||
@@ -708,7 +708,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
|
||||
m_print_enable = get_enable_print_status();
|
||||
m_print_btn->Enable(m_print_enable);
|
||||
if (m_print_enable) {
|
||||
if (wxGetApp().preset_bundle->use_bbl_network())
|
||||
if (wxGetApp().preset_bundle->use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents"))
|
||||
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_PRINT_PLATE));
|
||||
else
|
||||
wxPostEvent(m_plater, SimpleEvent(EVT_GLTOOLBAR_SEND_GCODE));
|
||||
@@ -1999,7 +1999,8 @@ wxBoxSizer* MainFrame::create_side_tools()
|
||||
SidePopup* p = new SidePopup(this);
|
||||
|
||||
if (wxGetApp().preset_bundle
|
||||
&& !wxGetApp().preset_bundle->is_bbl_vendor()) {
|
||||
&& !wxGetApp().preset_bundle->is_bbl_vendor()
|
||||
&& !wxGetApp().app_config->get_bool("use_printer_agents")) {
|
||||
// ThirdParty Buttons
|
||||
SideButton* export_gcode_btn = new SideButton(p, _L("Export G-code file"), "");
|
||||
export_gcode_btn->SetCornerRadius(0);
|
||||
@@ -2132,7 +2133,7 @@ wxBoxSizer* MainFrame::create_side_tools()
|
||||
|
||||
const auto preset_bundle = wxGetApp().preset_bundle;
|
||||
if (preset_bundle) {
|
||||
if (preset_bundle->use_bbl_network()) {
|
||||
if (preset_bundle->use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents")) {
|
||||
// BBL network support everything
|
||||
} else {
|
||||
support_send = false; // All 3rd print hosts do not have the send options
|
||||
@@ -4253,7 +4254,7 @@ void MainFrame::load_printer_url(wxString url, wxString apikey)
|
||||
void MainFrame::load_printer_url()
|
||||
{
|
||||
PresetBundle &preset_bundle = *wxGetApp().preset_bundle;
|
||||
if (preset_bundle.use_bbl_device_tab() || NetworkAgentFactory::is_current_printer_agent_plugin())
|
||||
if (preset_bundle.use_bbl_device_tab() || wxGetApp().app_config->get_bool("use_printer_agents"))
|
||||
return;
|
||||
|
||||
auto cfg = preset_bundle.printers.get_edited_preset().config;
|
||||
|
||||
@@ -54,6 +54,9 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
|
||||
case ConfigOptionDef::GUIType::one_string: m_fields.emplace(id, TextCtrl::Create<TextCtrl>(this->ctrl_parent(), opt, id)); break;
|
||||
case ConfigOptionDef::GUIType::plugin_picker: m_fields.emplace(id, PluginField::Create<PluginField>(this->ctrl_parent(), opt, id)); break;
|
||||
case ConfigOptionDef::GUIType::plugin_config: m_fields.emplace(id, PluginConfigField::Create<PluginConfigField>(this->ctrl_parent(), opt, id)); break;
|
||||
case ConfigOptionDef::GUIType::printer_agent_select: m_fields.emplace(
|
||||
id, PrinterAgentChoice::Create<PrinterAgentChoice>(this->ctrl_parent(), opt, id));
|
||||
break;
|
||||
default:
|
||||
switch (opt.type) {
|
||||
case coFloatOrPercent:
|
||||
@@ -654,6 +657,16 @@ Option ConfigOptionsGroup::get_option(const std::string& opt_key, int opt_index
|
||||
|
||||
void ConfigOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const boost::any& value)
|
||||
{
|
||||
if (opt_id == "printer_agent") {
|
||||
// TODO: Replace this option-specific branch with a generic value adapter if
|
||||
// more fields need custom field-value to config-value conversion.
|
||||
if (const std::string* id = boost::any_cast<std::string>(&value))
|
||||
this->change_opt_value("printer_agent", wxGetApp().canonical_printer_agent_id(*id));
|
||||
|
||||
OptionsGroup::on_change_OG(opt_id, value);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_opt_map.empty()) {
|
||||
auto it = m_opt_map.find(opt_id);
|
||||
if (it == m_opt_map.end()) {
|
||||
@@ -772,6 +785,19 @@ void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config,
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else if (opt_key == "printer_agent")
|
||||
{
|
||||
// why: printer_agent is a coString kept out of m_opt_map. The generic non-opt_map revert
|
||||
// below restores the edited config from get_value(), but a deregistered/"(missing)" saved
|
||||
// id has no selectable row, so the field yields no value and the edited config keeps the
|
||||
// user's interim pick -> stuck dirty. Restore the SAVED id straight into the edited config
|
||||
// (displayable or not; config is the saved or system baseline), then repaint and notify.
|
||||
const std::string saved_id = config.opt_string("printer_agent");
|
||||
set_value(opt_key, saved_id);
|
||||
this->change_opt_value(opt_key, saved_id);
|
||||
OptionsGroup::on_change_OG(opt_key, saved_id);
|
||||
return;
|
||||
}
|
||||
else if (m_opt_map.find(opt_key) == m_opt_map.end() ||
|
||||
// This option don't have corresponded field
|
||||
opt_key == "printable_area" || opt_key == "compatible_printers" || opt_key == "compatible_prints" || opt_key == "thumbnails" ||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "GUI.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "slic3r/Utils/NetworkAgentFactory.hpp"
|
||||
#include "format.hpp"
|
||||
#include "Tab.hpp"
|
||||
#include "wxExtensions.hpp"
|
||||
@@ -128,22 +127,8 @@ PhysicalPrinterDialog::~PhysicalPrinterDialog()
|
||||
void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgroup)
|
||||
{
|
||||
m_optgroup->m_on_change = [this](t_config_option_key opt_key, boost::any value) {
|
||||
// Special handling for printer_agent: convert fake enum index to string agent ID
|
||||
if (opt_key == "printer_agent") {
|
||||
try {
|
||||
int selected_idx = boost::any_cast<int>(value);
|
||||
auto agents = NetworkAgentFactory::get_registered_printer_agents();
|
||||
if (selected_idx >= 0 && selected_idx < static_cast<int>(agents.size())) {
|
||||
m_config->set_key_value("printer_agent",
|
||||
new ConfigOptionString(agents[selected_idx].id));
|
||||
}
|
||||
} catch (const boost::bad_any_cast&) {
|
||||
// If value is not an int, ignore
|
||||
}
|
||||
if (opt_key == "host_type" || opt_key == "printhost_authorization_type")
|
||||
this->update();
|
||||
} else if (opt_key == "host_type" || opt_key == "printhost_authorization_type") {
|
||||
this->update();
|
||||
}
|
||||
if (opt_key == "print_host")
|
||||
this->update_printhost_buttons();
|
||||
if (opt_key == "printhost_port")
|
||||
@@ -154,47 +139,6 @@ void PhysicalPrinterDialog::build_printhost_settings(ConfigOptionsGroup* m_optgr
|
||||
|
||||
m_optgroup->append_single_option_line("host_type");
|
||||
|
||||
// Build printer agent dropdown from registry (only if network agent is available)
|
||||
if (wxGetApp().getAgent() != nullptr) {
|
||||
auto agents = NetworkAgentFactory::get_registered_printer_agents();
|
||||
|
||||
if (!agents.empty()) {
|
||||
// Create a fake enum option to force a Choice widget instead of TextCtrl
|
||||
// (printer_agent is coString in config, but we need a dropdown)
|
||||
ConfigOptionDef def;
|
||||
def.type = coEnum;
|
||||
def.width = Field::def_width_wider();
|
||||
def.label = L("Printer Agent");
|
||||
def.tooltip = L("Select the network agent implementation for printer communication. "
|
||||
"Available agents are registered at startup.");
|
||||
def.mode = comAdvanced;
|
||||
|
||||
// Populate enum values and labels from registered agents
|
||||
for (const auto& agent : agents) {
|
||||
def.enum_values.push_back(agent.id);
|
||||
def.enum_labels.push_back(agent.display_name);
|
||||
}
|
||||
|
||||
// Resolve selected agent: use config value if valid, otherwise fall back to default
|
||||
std::string selected_agent = m_config->opt_string("printer_agent");
|
||||
auto it = std::find_if(agents.begin(), agents.end(), [&selected_agent](const auto& a) { return a.id == selected_agent; });
|
||||
if (it == agents.end()) {
|
||||
selected_agent = ORCA_PRINTER_AGENT_ID;
|
||||
it = std::find_if(agents.begin(), agents.end(), [&selected_agent](const auto& a) { return a.id == selected_agent; });
|
||||
}
|
||||
|
||||
if (it != agents.end()) {
|
||||
size_t default_idx = std::distance(agents.begin(), it);
|
||||
def.set_default_value(new ConfigOptionInt(static_cast<int>(default_idx)));
|
||||
}
|
||||
|
||||
// Create and append the option line
|
||||
auto agent_option = Option(def, "printer_agent");
|
||||
Line agent_line = m_optgroup->create_single_option_line(agent_option);
|
||||
m_optgroup->append_line(agent_line);
|
||||
}
|
||||
}
|
||||
|
||||
auto create_sizer_with_btn = [](wxWindow* parent, Button** btn, const std::string& icon_name, const wxString& label) {
|
||||
*btn = new Button(parent, label);
|
||||
(*btn)->SetStyle(ButtonStyle::Regular, ButtonType::Parameter);
|
||||
@@ -725,7 +669,7 @@ void PhysicalPrinterDialog::update(bool printer_change)
|
||||
}
|
||||
|
||||
// For bbl printers, show option to control the device tab
|
||||
if (wxGetApp().preset_bundle->is_bbl_vendor()) {
|
||||
if (wxGetApp().preset_bundle->is_bbl_vendor() || wxGetApp().app_config->get_bool("use_printer_agents")) {
|
||||
m_optgroup->show_field("bbl_use_print_host_webui");
|
||||
const bool use_print_host_webui = !current_webui.empty();
|
||||
if (Field* printhost_webui_field = m_optgroup->get_field("bbl_use_print_host_webui"); printhost_webui_field) {
|
||||
@@ -816,31 +760,6 @@ void PhysicalPrinterDialog::update_host_type(bool printer_change)
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalPrinterDialog::update_printer_agent_type()
|
||||
{
|
||||
if (m_config == nullptr)
|
||||
return;
|
||||
|
||||
Field* agent_field = m_optgroup->get_field("printer_agent");
|
||||
if (!agent_field)
|
||||
return;
|
||||
|
||||
Choice* agent_choice = dynamic_cast<Choice*>(agent_field);
|
||||
if (!agent_choice)
|
||||
return;
|
||||
|
||||
// Sync selection with current config value
|
||||
const std::string current_agent = m_config->opt_string("printer_agent");
|
||||
|
||||
auto agents = NetworkAgentFactory::get_registered_printer_agents();
|
||||
for (size_t i = 0; i < agents.size(); ++i) {
|
||||
if (agents[i].id == current_agent) {
|
||||
agent_choice->set_value(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicalPrinterDialog::update_printers()
|
||||
{
|
||||
wxBusyCursor wait;
|
||||
@@ -894,11 +813,6 @@ void PhysicalPrinterDialog::OnOK(wxEvent& event)
|
||||
{
|
||||
wxGetApp().get_tab(Preset::TYPE_PRINTER)->save_preset("", false, false, true, m_preset_name);
|
||||
event.Skip();
|
||||
|
||||
// Defer printer agent switch to ensure preset save completes first
|
||||
wxGetApp().CallAfter([] {
|
||||
wxGetApp().switch_printer_agent();
|
||||
});
|
||||
}
|
||||
|
||||
}} // namespace Slic3r::GUI
|
||||
|
||||
@@ -60,7 +60,6 @@ public:
|
||||
|
||||
void update(bool printer_change = false);
|
||||
void update_host_type(bool printer_change);
|
||||
void update_printer_agent_type();
|
||||
void update_preset_input();
|
||||
void update_printhost_buttons();
|
||||
void update_printers();
|
||||
|
||||
@@ -3246,7 +3246,7 @@ void Sidebar::update_all_preset_comboboxes()
|
||||
|
||||
auto p_mainframe = wxGetApp().mainframe;
|
||||
auto cfg = preset_bundle.printers.get_edited_preset().config;
|
||||
const bool use_native_device_tab = preset_bundle.use_bbl_device_tab() || NetworkAgentFactory::is_current_printer_agent_plugin();
|
||||
const bool use_native_device_tab = preset_bundle.use_bbl_device_tab() || wxGetApp().app_config->get_bool("use_printer_agents");
|
||||
|
||||
if (preset_bundle.use_bbl_network()) {
|
||||
//only show connection button for not-BBL printer
|
||||
@@ -3258,7 +3258,8 @@ void Sidebar::update_all_preset_comboboxes()
|
||||
p_mainframe->set_print_button_to_default(MainFrame::PrintSelectType::ePrintPlate);
|
||||
} else {
|
||||
//p->btn_connect_printer->Show();
|
||||
p->m_printer_connect->Show();
|
||||
// ORCA: hide the physical-printer connection button when printer agents are enabled
|
||||
p->m_printer_connect->Show(!wxGetApp().app_config->get_bool("use_printer_agents"));
|
||||
|
||||
// ORCA: show/hide sync-ams button based on filament sync mode
|
||||
auto agent = wxGetApp().getAgent();
|
||||
@@ -3280,7 +3281,9 @@ void Sidebar::update_all_preset_comboboxes()
|
||||
const auto host_type = cfg.option<ConfigOptionEnum<PrintHostType>>("host_type")->value;
|
||||
if (cfg.has("printhost_apikey") && (host_type != htSimplyPrint))
|
||||
apikey = cfg.opt_string("printhost_apikey");
|
||||
print_btn_type = preset_bundle.is_bbl_vendor() ? MainFrame::PrintSelectType::ePrintPlate : MainFrame::PrintSelectType::eSendGcode;
|
||||
print_btn_type = (preset_bundle.is_bbl_vendor() || wxGetApp().app_config->get_bool("use_printer_agents"))
|
||||
? MainFrame::PrintSelectType::ePrintPlate
|
||||
: MainFrame::PrintSelectType::eSendGcode;
|
||||
}
|
||||
|
||||
if (!use_native_device_tab)
|
||||
@@ -3439,7 +3442,10 @@ void Sidebar::update_presets(Preset::Type preset_type)
|
||||
|
||||
bool isBBL = preset_bundle.is_bbl_vendor();
|
||||
bool is_dual_extruder = extruder_variants->size() == 2;
|
||||
p->layout_printer(preset_bundle.use_bbl_network(), isBBL && is_dual_extruder);
|
||||
// why: agent mode drives the native device tab, so the sidebar lays out like BBL
|
||||
// (no physical-printer connect button).
|
||||
p->layout_printer(preset_bundle.use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents"),
|
||||
isBBL && is_dual_extruder);
|
||||
|
||||
// Update nozzle titles from printer config (e.g. "Main Nozzle" / "Auxiliary Nozzle" for N6)
|
||||
// UI left = DEPUTY_EXTRUDER_ID(1), UI right = MAIN_EXTRUDER_ID(0)
|
||||
@@ -5625,6 +5631,7 @@ struct Plater::priv
|
||||
void on_action_slice_all(SimpleEvent&);
|
||||
void on_action_publish(wxCommandEvent &evt);
|
||||
void on_action_print_plate(SimpleEvent&);
|
||||
void open_machine_select_dialog(int plate_idx, PrintFromType print_type = PrintFromType::FROM_NORMAL);
|
||||
void on_action_print_all(SimpleEvent&);
|
||||
void on_action_export_gcode(SimpleEvent&);
|
||||
void on_action_send_gcode(SimpleEvent&);
|
||||
@@ -11166,18 +11173,23 @@ void Plater::priv::on_action_print_plate(SimpleEvent&)
|
||||
}
|
||||
|
||||
PresetBundle& preset_bundle = *wxGetApp().preset_bundle;
|
||||
if (preset_bundle.use_bbl_network()) {
|
||||
// BBS
|
||||
if (!m_select_machine_dlg)
|
||||
m_select_machine_dlg = new SelectMachineDialog(q);
|
||||
m_select_machine_dlg->set_print_type(PrintFromType::FROM_NORMAL);
|
||||
m_select_machine_dlg->prepare(partplate_list.get_curr_plate_index());
|
||||
m_select_machine_dlg->ShowModal();
|
||||
if (preset_bundle.use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents")) {
|
||||
open_machine_select_dialog(partplate_list.get_curr_plate_index());
|
||||
} else {
|
||||
q->send_gcode_legacy(PLATE_CURRENT_IDX, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Plater::priv::open_machine_select_dialog(int plate_idx, PrintFromType print_type)
|
||||
{
|
||||
// BBS
|
||||
if (!m_select_machine_dlg)
|
||||
m_select_machine_dlg = new SelectMachineDialog(q);
|
||||
m_select_machine_dlg->set_print_type(print_type);
|
||||
m_select_machine_dlg->prepare(plate_idx);
|
||||
m_select_machine_dlg->ShowModal();
|
||||
}
|
||||
|
||||
void Plater::priv::on_action_send_to_multi_machine(SimpleEvent&)
|
||||
{
|
||||
if (!m_send_multi_dlg)
|
||||
@@ -11193,10 +11205,7 @@ void Plater::priv::on_action_print_plate_from_sdcard(SimpleEvent&)
|
||||
}
|
||||
|
||||
//BBS
|
||||
if (!m_select_machine_dlg) m_select_machine_dlg = new SelectMachineDialog(q);
|
||||
m_select_machine_dlg->set_print_type(PrintFromType::FROM_SDCARD_VIEW);
|
||||
m_select_machine_dlg->prepare(0);
|
||||
m_select_machine_dlg->ShowModal();
|
||||
open_machine_select_dialog(0, PrintFromType::FROM_SDCARD_VIEW);
|
||||
}
|
||||
|
||||
void Plater::priv::on_tab_selection_changing(wxBookCtrlEvent& e)
|
||||
@@ -11211,13 +11220,13 @@ void Plater::priv::on_tab_selection_changing(wxBookCtrlEvent& e)
|
||||
sidebar_layout.show = new_sel == MainFrame::tp3DEditor || new_sel == MainFrame::tpPreview;
|
||||
update_sidebar();
|
||||
int old_sel = e.GetOldSelection();
|
||||
const bool is_printer_agent_plugin = NetworkAgentFactory::is_current_printer_agent_plugin();
|
||||
const bool use_printer_agents = wxGetApp().app_config->get_bool("use_printer_agents");
|
||||
const bool use_native_device_tab = wxGetApp().preset_bundle &&
|
||||
(wxGetApp().preset_bundle->use_bbl_device_tab() || is_printer_agent_plugin);
|
||||
(wxGetApp().preset_bundle->use_bbl_device_tab() || use_printer_agents);
|
||||
if (use_native_device_tab && new_sel == MainFrame::tpMonitor) {
|
||||
// BBL network module is only required for BBL-vendor printers.
|
||||
// Non-BBL Python plugins (e.g. moonraker) drive the Device tab without it.
|
||||
if (!is_printer_agent_plugin && wxGetApp().preset_bundle->is_bbl_vendor() && !Slic3r::NetworkAgent::is_network_module_loaded()) {
|
||||
if (!use_printer_agents && wxGetApp().preset_bundle->is_bbl_vendor() && !Slic3r::NetworkAgent::is_network_module_loaded()) {
|
||||
e.Veto();
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("skipped tab switch from %1% to %2%, lack of network plugins") % old_sel % new_sel;
|
||||
if (q) {
|
||||
@@ -11273,13 +11282,8 @@ void Plater::priv::on_action_print_all(SimpleEvent&)
|
||||
}
|
||||
|
||||
PresetBundle& preset_bundle = *wxGetApp().preset_bundle;
|
||||
if (preset_bundle.use_bbl_network()) {
|
||||
// BBS
|
||||
if (!m_select_machine_dlg)
|
||||
m_select_machine_dlg = new SelectMachineDialog(q);
|
||||
m_select_machine_dlg->set_print_type(PrintFromType::FROM_NORMAL);
|
||||
m_select_machine_dlg->prepare(PLATE_ALL_IDX);
|
||||
m_select_machine_dlg->ShowModal();
|
||||
if (preset_bundle.use_bbl_network() || wxGetApp().app_config->get_bool("use_printer_agents")) {
|
||||
open_machine_select_dialog(PLATE_ALL_IDX);
|
||||
} else {
|
||||
q->send_gcode_legacy(PLATE_ALL_IDX, nullptr);
|
||||
}
|
||||
|
||||
@@ -1135,6 +1135,14 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too
|
||||
wxGetApp().plater()->sidebar().update_presets(Preset::TYPE_FILAMENT);
|
||||
}
|
||||
|
||||
if (param == "use_printer_agents")
|
||||
{
|
||||
// Rebuild the Device tab so the native/web-UI choice reflects the new flag
|
||||
// immediately, instead of only on the next printer-preset change or restart.
|
||||
if (wxGetApp().plater())
|
||||
wxGetApp().plater()->sidebar().update_all_preset_comboboxes();
|
||||
}
|
||||
|
||||
if (param == "enable_high_low_temp_mixed_printing") {
|
||||
if (checkbox->GetValue()) {
|
||||
const wxString warning_title = _L("Bed Temperature Difference Warning");
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "slic3r/Utils/NetworkAgentFactory.hpp"
|
||||
#include "slic3r/Utils/PresetUpdater.hpp"
|
||||
#include "slic3r/plugin/PluginConfig.hpp"
|
||||
#include "Plater.hpp"
|
||||
@@ -5018,6 +5019,40 @@ void TabPrinter::build_fff()
|
||||
optgroup->append_single_option_line("gcode_flavor", "printer_basic_information_advanced#g-code-flavor");
|
||||
optgroup->append_single_option_line("pellet_modded_printer", "printer_basic_information_advanced#pellet-modded-printer");
|
||||
optgroup->append_single_option_line("bbl_use_printhost", "printer_basic_information_advanced#use-3rd-party-print-host");
|
||||
|
||||
// "Printer Agent" dropdown - printer_agent is a coString; gui_type routes it to
|
||||
// PrinterAgentChoice instead of a TextCtrl. Rows and values come from the live agent
|
||||
// registry, and the value is stored as the agent-id string.
|
||||
if (wxGetApp().getAgent() != nullptr)
|
||||
{
|
||||
auto registered_printer_agents = NetworkAgentFactory::get_registered_printer_agents();
|
||||
if (!registered_printer_agents.empty())
|
||||
{
|
||||
ConfigOptionDef def;
|
||||
def.type = coString;
|
||||
def.gui_type = ConfigOptionDef::GUIType::printer_agent_select;
|
||||
def.width = 3 * Field::def_width_wider() / 2;
|
||||
def.label = L("Printer Agent");
|
||||
def.tooltip = L("Select the network agent implementation for printer communication. "
|
||||
"Available agents are registered at startup.");
|
||||
def.mode = comAdvanced;
|
||||
|
||||
// Create the field without get_option() so it is not registered in m_opt_map.
|
||||
// ConfigOptionsGroup handles printer_agent before the generic mapped write path.
|
||||
Line agent_line = optgroup->create_single_option_line(Option(def, "printer_agent"));
|
||||
optgroup->append_line(agent_line);
|
||||
if (Field* agent_field = get_field("printer_agent"))
|
||||
{
|
||||
if (auto* choice = dynamic_cast<PrinterAgentChoice*>(agent_field); choice && choice->getWindow())
|
||||
choice->set_value(m_config->opt_string("printer_agent"), false);
|
||||
}
|
||||
|
||||
// Register by hand so the UnsavedChanges dialog can render a row for it.
|
||||
wxGetApp().sidebar().get_searcher().add_key("printer_agent", m_type, optgroup->title,
|
||||
optgroup->config_category());
|
||||
}
|
||||
}
|
||||
|
||||
optgroup->append_single_option_line("use_3mf");
|
||||
optgroup->append_single_option_line("scan_first_layer" , "printer_basic_information_advanced#scan-first-layer");
|
||||
optgroup->append_single_option_line("enable_power_loss_recovery", "printer_basic_information_advanced#power-loss-recovery");
|
||||
@@ -5884,6 +5919,16 @@ void TabPrinter::reload_config()
|
||||
// so update it implicitly
|
||||
if (m_active_page && m_active_page->title() == "Multimaterial")
|
||||
m_active_page->set_value("extruders_count", int(m_extruders_count));
|
||||
|
||||
// m_opt_map-driven reload does not cover printer_agent, so sync this custom field explicitly.
|
||||
if (Field* agent_field = get_field("printer_agent"))
|
||||
{
|
||||
if (auto* choice = dynamic_cast<PrinterAgentChoice*>(agent_field); choice && choice->getWindow())
|
||||
{
|
||||
const std::string selected_agent = m_config->opt_string("printer_agent");
|
||||
choice->set_value(selected_agent, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabPrinter::activate_selected_page(std::function<void()> throw_if_canceled)
|
||||
@@ -5894,6 +5939,16 @@ void TabPrinter::activate_selected_page(std::function<void()> throw_if_canceled)
|
||||
// so update it implicitly
|
||||
if (m_active_page && m_active_page->title() == "Multimaterial")
|
||||
m_active_page->set_value("extruders_count", int(m_extruders_count));
|
||||
|
||||
// m_opt_map-driven reload does not cover printer_agent, so sync this custom field explicitly.
|
||||
if (Field* agent_field = get_field("printer_agent"))
|
||||
{
|
||||
if (auto* choice = dynamic_cast<PrinterAgentChoice*>(agent_field); choice && choice->getWindow())
|
||||
{
|
||||
const std::string selected_agent = m_config->opt_string("printer_agent");
|
||||
choice->set_value(selected_agent, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TabPrinter::clear_pages()
|
||||
@@ -7852,6 +7907,24 @@ bool TabPrinter::apply_extruder_cnt_from_cache()
|
||||
return false;
|
||||
}
|
||||
|
||||
void TabPrinter::refresh_printer_agent_dropdown() const
|
||||
{
|
||||
auto* choice = dynamic_cast<PrinterAgentChoice*>(get_field("printer_agent"));
|
||||
if (!choice || !choice->getWindow())
|
||||
return;
|
||||
|
||||
const auto agents = NetworkAgentFactory::get_registered_printer_agents();
|
||||
if (agents.empty())
|
||||
return;
|
||||
|
||||
// why: rows live on PrinterAgentChoice now; rebuild them from the live registry and re-select the stored id.
|
||||
const std::string selected_agent = wxGetApp().preset_bundle->printers.get_edited_preset()
|
||||
.config.opt_string("printer_agent");
|
||||
choice->reload_rows();
|
||||
choice->set_value(selected_agent, false);
|
||||
this->GetParent()->Layout();
|
||||
}
|
||||
|
||||
bool Tab::validate_custom_gcodes()
|
||||
{
|
||||
if (m_type != Preset::TYPE_FILAMENT &&
|
||||
|
||||
@@ -675,6 +675,7 @@ public:
|
||||
wxSizer* create_bed_shape_widget(wxWindow* parent);
|
||||
void cache_extruder_cnt(const DynamicPrintConfig* config = nullptr);
|
||||
bool apply_extruder_cnt_from_cache();
|
||||
void refresh_printer_agent_dropdown() const;
|
||||
};
|
||||
|
||||
class TabSLAMaterial : public Tab
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#include "BBLNetworkPlugin.hpp"
|
||||
#include "NetworkAgentFactory.hpp"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -20,6 +22,65 @@ void BBLPrinterAgent::set_cloud_agent(std::shared_ptr<ICloudServiceAgent> cloud)
|
||||
// Communication
|
||||
// ============================================================================
|
||||
|
||||
std::string BBLPrinterAgent::ams_refresh_rfid_gcode(const std::string& tray_id)
|
||||
{
|
||||
return (boost::format("M620 R%1% \n") % tray_id).str();
|
||||
}
|
||||
|
||||
std::string BBLPrinterAgent::ams_calibrate_gcode(int ams_id)
|
||||
{
|
||||
return (boost::format("M620 C%1% \n") % ams_id).str();
|
||||
}
|
||||
|
||||
std::string BBLPrinterAgent::ams_select_tray_gcode(const std::string& tray_id)
|
||||
{
|
||||
return (boost::format("M620 P%1% \n") % tray_id).str();
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_ams_refresh_rfid(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode)
|
||||
{
|
||||
const std::string gcode = ams_refresh_rfid_gcode(tray_id);
|
||||
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode;
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = gcode;
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode)
|
||||
{
|
||||
const std::string gcode = ams_calibrate_gcode(ams_id);
|
||||
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode;
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = gcode;
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode)
|
||||
{
|
||||
const std::string gcode = ams_select_tray_gcode(tray_id);
|
||||
BOOST_LOG_TRIVIAL(trace) << "ams_debug: gcode_cmd" << gcode;
|
||||
nlohmann::json j;
|
||||
j["print"]["command"] = "gcode_line";
|
||||
j["print"]["param"] = gcode;
|
||||
j["print"]["sequence_id"] = std::to_string(sequence_id);
|
||||
return publish(dev_id, j, lan_mode);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::publish(const std::string& dev_id, const nlohmann::json& j, bool lan_mode)
|
||||
{
|
||||
const int rtn = lan_mode ? send_message_to_printer(dev_id, j.dump(), 0, 0) : send_message(dev_id, j.dump(), 0, 0);
|
||||
if (rtn == 0) {
|
||||
BOOST_LOG_TRIVIAL(info) << "publish_json: " << j.dump() << " code: " << rtn;
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << "publish_json: " << j.dump() << " code: " << rtn;
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::send_message(std::string dev_id, std::string json_str, int qos, int flag)
|
||||
{
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "ICloudServiceAgent.hpp"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -28,6 +29,12 @@ public:
|
||||
|
||||
// Communication
|
||||
int send_message(std::string dev_id, std::string json_str, int qos, int flag) override;
|
||||
static std::string ams_refresh_rfid_gcode(const std::string& tray_id);
|
||||
static std::string ams_calibrate_gcode(int ams_id);
|
||||
static std::string ams_select_tray_gcode(const std::string& tray_id);
|
||||
int command_ams_refresh_rfid(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode) override;
|
||||
int command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode) override;
|
||||
int command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode) override;
|
||||
int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl) override;
|
||||
int disconnect_printer() override;
|
||||
int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag) override;
|
||||
@@ -85,6 +92,9 @@ public:
|
||||
FilamentSyncMode get_filament_sync_mode() const override;
|
||||
|
||||
private:
|
||||
// why: the lan/cloud DECISION stays machine-side; keep this mechanical branch in sync with publish_json.
|
||||
int publish(const std::string& dev_id, const nlohmann::json& j, bool lan_mode);
|
||||
|
||||
std::shared_ptr<ICloudServiceAgent> m_cloud_agent;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,13 @@
|
||||
#define __I_PRINTER_AGENT_HPP__
|
||||
|
||||
#include "bambu_networking.hpp"
|
||||
// why: these extend the BAMBU_NETWORK_* return space rather than opening a new one - the value
|
||||
// flows through the same int domain callers already compare against BAMBU_NETWORK_SUCCESS.
|
||||
// They live here and not in bambu_networking.hpp because that file is a vendor header replaced
|
||||
// wholesale by header-sync commits (see c09252ce11), which would silently clobber them.
|
||||
// -70xx is free: the vendor occupies -1..-25 and -10xx through -60xx.
|
||||
#define ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED -7010 // no translation exists for this command
|
||||
#define ORCA_NETWORK_ERR_CAP_NOT_AVAILABLE -7020 // a translation exists; this printer lacks the capability
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
@@ -77,6 +84,16 @@ public:
|
||||
*/
|
||||
virtual int send_message(std::string dev_id, std::string json_str, int qos, int flag) = 0;
|
||||
|
||||
// why: gcode is firmware dialect, not a waist concept - commands whose body is Bambu-dialect
|
||||
// gcode live on the agent that speaks it; the default is an honest refusal that MachineObject's
|
||||
// publish funnel turns into a dialog.
|
||||
virtual int command_ams_refresh_rfid(std::string, std::string, int, bool)
|
||||
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
|
||||
virtual int command_ams_calibrate(std::string, int, int, bool)
|
||||
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
|
||||
virtual int command_ams_select_tray(std::string, std::string, int, bool)
|
||||
{ return ORCA_NETWORK_ERR_CMD_NOT_SUPPORTED; }
|
||||
|
||||
/**
|
||||
* Establish a direct LAN connection to a printer.
|
||||
*/
|
||||
|
||||
@@ -767,6 +767,27 @@ int NetworkAgent::send_message(std::string dev_id, std::string json_str, int qos
|
||||
return -1;
|
||||
}
|
||||
|
||||
int NetworkAgent::command_ams_refresh_rfid(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode)
|
||||
{
|
||||
if (m_printer_agent)
|
||||
return m_printer_agent->command_ams_refresh_rfid(dev_id, tray_id, sequence_id, lan_mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int NetworkAgent::command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode)
|
||||
{
|
||||
if (m_printer_agent)
|
||||
return m_printer_agent->command_ams_calibrate(dev_id, ams_id, sequence_id, lan_mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int NetworkAgent::command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode)
|
||||
{
|
||||
if (m_printer_agent)
|
||||
return m_printer_agent->command_ams_select_tray(dev_id, tray_id, sequence_id, lan_mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int NetworkAgent::connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl)
|
||||
{
|
||||
if (m_printer_agent)
|
||||
|
||||
@@ -142,6 +142,9 @@ public:
|
||||
int set_on_local_message_fn(OnMessageFn fn);
|
||||
int set_server_callback(OnServerErrFn fn);
|
||||
int send_message(std::string dev_id, std::string json_str, int qos, int flag);
|
||||
int command_ams_refresh_rfid(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode);
|
||||
int command_ams_calibrate(std::string dev_id, int ams_id, int sequence_id, bool lan_mode);
|
||||
int command_ams_select_tray(std::string dev_id, std::string tray_id, int sequence_id, bool lan_mode);
|
||||
int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password, bool use_ssl);
|
||||
int disconnect_printer();
|
||||
int send_message_to_printer(std::string dev_id, std::string json_str, int qos, int flag);
|
||||
|
||||
@@ -465,25 +465,5 @@ void NetworkAgentFactory::deregister_python_printer_agent(const std::string& plu
|
||||
<< plugin_key << "' with agent ID '" << agent_id << "'";
|
||||
}
|
||||
|
||||
bool NetworkAgentFactory::is_current_printer_agent_plugin()
|
||||
{
|
||||
auto* preset_bundle = GUI::wxGetApp().preset_bundle;
|
||||
if (!preset_bundle)
|
||||
return false;
|
||||
|
||||
std::string agent_key = ORCA_PRINTER_AGENT_ID;
|
||||
if (preset_bundle->is_bbl_vendor())
|
||||
agent_key = BBL_PRINTER_AGENT_ID;
|
||||
|
||||
const auto& cfg = preset_bundle->printers.get_edited_preset().config;
|
||||
if (cfg.has("printer_agent")) {
|
||||
const std::string& value = cfg.option<ConfigOptionString>("printer_agent")->value;
|
||||
if (!value.empty())
|
||||
agent_key = value;
|
||||
}
|
||||
|
||||
const PrinterAgentInfo* info = get_printer_agent_info(agent_key);
|
||||
return info && info->is_plugin();
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -166,8 +166,6 @@ public:
|
||||
static void register_python_printer_agent(const std::string& plugin_key, const std::string& capability_name);
|
||||
static void deregister_python_printer_agent(const std::string& plugin_key, const std::string& capability_name);
|
||||
|
||||
static bool is_current_printer_agent_plugin();
|
||||
|
||||
private:
|
||||
// Factory is not instantiable
|
||||
NetworkAgentFactory() = delete;
|
||||
|
||||
Reference in New Issue
Block a user