mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2026-01-17 13:25:41 -07:00
Implement filament consumption dialog and undo functionality
This commit is contained in:
parent
1005067526
commit
bf17e8e998
15 changed files with 241 additions and 49 deletions
|
|
@ -407,6 +407,9 @@ void AppConfig::set_defaults()
|
|||
set_str("print", "timelapse", "1");
|
||||
}
|
||||
|
||||
if (get("spoolman", "consumption_type").empty())
|
||||
set_str("spoolman", "consumption_type", "weight");
|
||||
|
||||
// Remove legacy window positions/sizes
|
||||
erase("app", "main_frame_maximized");
|
||||
erase("app", "main_frame_pos");
|
||||
|
|
|
|||
|
|
@ -1566,32 +1566,15 @@ void GCode::do_export(Print* print, const char* path, GCodeProcessorResult* resu
|
|||
result->filename = path;
|
||||
}
|
||||
|
||||
std::vector<int> filaments_with_spoolman_idxs;
|
||||
for (int l = 0; l < print->config().filament_density.size(); ++l) {
|
||||
if (print->config().filament_spoolman_enabled.get_at(l))
|
||||
filaments_with_spoolman_idxs.push_back(l);
|
||||
}
|
||||
// Check the consumption of filament against the remaining filament as reported by Spoolman
|
||||
for (const auto& est : print->get_spoolman_filament_consumption_estimates()) {
|
||||
double remaining_length = print->config().filament_remaining_length.get_at(est.print_config_idx);
|
||||
double remaining_weight = print->config().filament_remaining_weight.get_at(est.print_config_idx);
|
||||
|
||||
if (!filaments_with_spoolman_idxs.empty()) {
|
||||
// get used filament (meters and grams) from used volume in respect to the active extruder
|
||||
auto get_used_filament_from_volume = [&](int extruder_id) {
|
||||
double volume = print->m_print_statistics.filament_stats[extruder_id];
|
||||
std::pair<double, double> ret = { volume / (PI * sqr(0.5 * print->config().filament_diameter.get_at(extruder_id))),
|
||||
volume * print->config().filament_density.get_at(extruder_id) * 0.001 };
|
||||
return ret;
|
||||
};
|
||||
|
||||
for (const auto& item : filaments_with_spoolman_idxs) {
|
||||
auto [est_used_length, est_used_weight] = get_used_filament_from_volume(item);
|
||||
double remaining_length = print->config().filament_remaining_length.get_at(item);
|
||||
double remaining_weight = print->config().filament_remaining_weight.get_at(item);
|
||||
|
||||
if (est_used_length > remaining_length || est_used_weight > remaining_weight) {
|
||||
std::string filament_name = print->config().filament_settings_id.get_at(item);
|
||||
std::string msg = boost::str(boost::format(_("Filament %1% does not have enough material for the print. Used: %2$.2f m, %3$.2f g, Remaining: %4$.2f m, %5$.2f g")) %
|
||||
filament_name % (est_used_length * 0.001) % est_used_weight % (remaining_length * 0.001) % remaining_weight);
|
||||
print->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, msg, PrintStateBase::SlicingNotificationType::SlicingNotEnoughFilament);
|
||||
}
|
||||
if (est.est_used_length > remaining_length || est.est_used_weight > remaining_weight) {
|
||||
std::string msg = boost::str(boost::format(_("Filament %1% does not have enough material for the print. Used: %2$.2f m, %3$.2f g, Remaining: %4$.2f m, %5$.2f g")) %
|
||||
est.filament_name % (est.est_used_length * 0.001) % est.est_used_weight % (remaining_length * 0.001) % remaining_weight);
|
||||
print->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL, msg, PrintStateBase::SlicingNotificationType::SlicingNotEnoughFilament);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -249,7 +249,7 @@ public:
|
|||
// works for filament and printer profiles. All other profiles return false
|
||||
bool spoolman_enabled() const {
|
||||
if (type == TYPE_FILAMENT)
|
||||
return config.opt_int("spoolman_spool_id") > 0;
|
||||
return config.opt_int("spoolman_spool_id", 0) > 0;
|
||||
if (type == TYPE_PRINTER)
|
||||
return config.opt_bool("spoolman_enabled");
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -2127,7 +2127,6 @@ DynamicPrintConfig PresetBundle::full_fff_config() const
|
|||
std::vector<std::string> print_compatible_printers;
|
||||
//BBS: add logic for settings check between different system presets
|
||||
std::vector<std::string> different_settings;
|
||||
std::vector<unsigned char> filament_spoolman_enabled;
|
||||
std::vector<double> filament_remaining_weight;
|
||||
std::vector<double> filament_remaining_length;
|
||||
std::string different_print_settings, different_printer_settings;
|
||||
|
|
@ -2152,7 +2151,6 @@ DynamicPrintConfig PresetBundle::full_fff_config() const
|
|||
out.apply(this->filaments.get_edited_preset().config);
|
||||
compatible_printers_condition.emplace_back(this->filaments.get_edited_preset().compatible_printers_condition());
|
||||
compatible_prints_condition .emplace_back(this->filaments.get_edited_preset().compatible_prints_condition());
|
||||
filament_spoolman_enabled.emplace_back(this->filaments.get_edited_preset().spoolman_enabled());
|
||||
filament_remaining_weight.emplace_back(this->filaments.get_edited_preset().spoolman_statistics->remaining_weight);
|
||||
filament_remaining_length.emplace_back(this->filaments.get_edited_preset().spoolman_statistics->remaining_length);
|
||||
//BBS: add logic for settings check between different system presets
|
||||
|
|
@ -2196,7 +2194,6 @@ DynamicPrintConfig PresetBundle::full_fff_config() const
|
|||
DynamicPrintConfig &cfg_rw = *const_cast<DynamicPrintConfig*>(cfg);
|
||||
compatible_printers_condition.emplace_back(Preset::compatible_printers_condition(cfg_rw));
|
||||
compatible_prints_condition .emplace_back(Preset::compatible_prints_condition(cfg_rw));
|
||||
filament_spoolman_enabled.emplace_back(preset->spoolman_enabled());
|
||||
filament_remaining_weight.emplace_back(preset->spoolman_statistics->remaining_weight);
|
||||
filament_remaining_length.emplace_back(preset->spoolman_statistics->remaining_length);
|
||||
|
||||
|
|
@ -2306,7 +2303,6 @@ DynamicPrintConfig PresetBundle::full_fff_config() const
|
|||
out.option<ConfigOptionStrings>("filament_settings_id", true)->values = this->filament_presets;
|
||||
out.option<ConfigOptionString >("printer_settings_id", true)->value = this->printers.get_selected_preset_name();
|
||||
out.option<ConfigOptionStrings>("filament_ids", true)->values = filament_ids;
|
||||
out.option<ConfigOptionBools>("filament_spoolman_enabled", true)->values = filament_spoolman_enabled;
|
||||
out.option<ConfigOptionFloats>("filament_remaining_weight", true)->values = filament_remaining_weight;
|
||||
out.option<ConfigOptionFloats>("filament_remaining_length", true)->values = filament_remaining_length;
|
||||
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include "GCode/ConflictChecker.hpp"
|
||||
#include "slic3r/Utils/Spoolman.hpp"
|
||||
|
||||
#include <codecvt>
|
||||
|
||||
|
|
@ -3058,6 +3059,33 @@ Vec3d Print::shrinkage_compensation() const
|
|||
return { xy_compensation, xy_compensation, z_compensation };
|
||||
}
|
||||
|
||||
std::vector<SpoolmanFilamentConsumptionEstimate> Print::get_spoolman_filament_consumption_estimates() const
|
||||
{
|
||||
std::vector<SpoolmanFilamentConsumptionEstimate> spoolman_filament_consumption;
|
||||
|
||||
std::vector<int> filaments_with_spoolman_idxs;
|
||||
for (int l = 0; l < m_config.spoolman_spool_id.size(); ++l) {
|
||||
if (m_config.spoolman_spool_id.get_at(l) > 0)
|
||||
filaments_with_spoolman_idxs.push_back(l);
|
||||
}
|
||||
|
||||
// get used filament (meters and grams) from used volume in respect to the active extruder
|
||||
auto get_used_filament_from_volume = [&](const int& extruder_id) {
|
||||
// confirm the item exists in the stats map
|
||||
if (m_print_statistics.filament_stats.count(extruder_id) <= 0)
|
||||
return std::pair {0., 0.};
|
||||
|
||||
const double& volume = m_print_statistics.filament_stats.at(extruder_id);
|
||||
return std::pair { volume / (PI * sqr(0.5 * m_config.filament_diameter.get_at(extruder_id))),
|
||||
volume * m_config.filament_density.get_at(extruder_id) * 0.001 };
|
||||
};
|
||||
|
||||
for (const auto& idx : filaments_with_spoolman_idxs)
|
||||
spoolman_filament_consumption.emplace_back(idx, m_config, get_used_filament_from_volume(idx));
|
||||
|
||||
return spoolman_filament_consumption;
|
||||
}
|
||||
|
||||
const std::string PrintStatistics::FilamentUsedG = "filament used [g]";
|
||||
const std::string PrintStatistics::FilamentUsedGMask = "; filament used [g] =";
|
||||
|
||||
|
|
|
|||
|
|
@ -812,6 +812,28 @@ enum FilamentTempType {
|
|||
HighLowCompatible,
|
||||
Undefine
|
||||
};
|
||||
|
||||
struct SpoolmanFilamentConsumptionEstimate
|
||||
{
|
||||
const unsigned int print_config_idx;
|
||||
const unsigned int spoolman_spool_id;
|
||||
const std::string filament_name;
|
||||
const double est_used_length;
|
||||
const double est_used_weight;
|
||||
|
||||
SpoolmanFilamentConsumptionEstimate(const unsigned int& print_config_idx, const PrintConfig& config, const double& est_used_length, const double& est_used_weight)
|
||||
: print_config_idx(print_config_idx)
|
||||
, spoolman_spool_id(config.spoolman_spool_id.get_at(print_config_idx))
|
||||
, filament_name(config.filament_settings_id.get_at(print_config_idx))
|
||||
, est_used_length(est_used_length)
|
||||
, est_used_weight(est_used_weight)
|
||||
{}
|
||||
|
||||
// Alternate that allows the estimates to be provided as a std::pair [est_used_length, est_used_weight]
|
||||
SpoolmanFilamentConsumptionEstimate(const unsigned int& print_config_idx, const PrintConfig& config, const std::pair<double, double>& estimates) :
|
||||
SpoolmanFilamentConsumptionEstimate(print_config_idx, config, estimates.first, estimates.second) {}
|
||||
};
|
||||
|
||||
// The complete print tray with possibly multiple objects.
|
||||
class Print : public PrintBaseWithState<PrintStep, psCount>
|
||||
{
|
||||
|
|
@ -990,6 +1012,8 @@ public:
|
|||
|
||||
std::tuple<float, float> object_skirt_offset(double margin_height = 0) const;
|
||||
|
||||
std::vector<SpoolmanFilamentConsumptionEstimate> get_spoolman_filament_consumption_estimates() const;
|
||||
|
||||
protected:
|
||||
// Invalidates the step, and its depending steps in Print.
|
||||
bool invalidate_step(PrintStep step);
|
||||
|
|
|
|||
|
|
@ -2198,10 +2198,6 @@ void PrintConfigDef::init_fff_params()
|
|||
def->set_default_value(new ConfigOptionStrings());
|
||||
def->cli = ConfigOptionDef::nocli;
|
||||
|
||||
def = this->add("filament_spoolman_enabled", coBools);
|
||||
def->set_default_value(new ConfigOptionBools());
|
||||
def->cli = ConfigOptionDef::nocli;
|
||||
|
||||
def = this->add("filament_remaining_weight", coFloats);
|
||||
def->set_default_value(new ConfigOptionFloats());
|
||||
def->cli = ConfigOptionDef::nocli;
|
||||
|
|
@ -2217,13 +2213,13 @@ void PrintConfigDef::init_fff_params()
|
|||
def->set_default_value(new ConfigOptionStrings{L("(Undefined)")});
|
||||
def->cli = ConfigOptionDef::nocli;
|
||||
|
||||
def = this->add("spoolman_spool_id", coInt);
|
||||
def = this->add("spoolman_spool_id", coInts);
|
||||
def->label = L("Spoolman ID");
|
||||
def->tooltip = L("The spool ID of this filament profile within your Spoolman instance. This will allow automatic spool switching when "
|
||||
"using moonraker to track spool usage and one touch updating of this filament profile from the Spoolman properties. "
|
||||
"Setting this to a value of 0 disables its functionality.");
|
||||
def->mode = comSimple;
|
||||
def->set_default_value(new ConfigOptionInt());
|
||||
def->set_default_value(new ConfigOptionInts({ 0 }));
|
||||
def->cli = ConfigOptionDef::nocli;
|
||||
|
||||
def = this->add("infill_direction", coFloat);
|
||||
|
|
|
|||
|
|
@ -1163,7 +1163,7 @@ PRINT_CONFIG_CLASS_DEFINE(
|
|||
((ConfigOptionStrings, small_area_infill_flow_compensation_model))
|
||||
|
||||
((ConfigOptionBool, has_scarf_joint_seam))
|
||||
((ConfigOptionBools, filament_spoolman_enabled))
|
||||
((ConfigOptionInts, spoolman_spool_id))
|
||||
((ConfigOptionFloats, filament_remaining_weight))
|
||||
((ConfigOptionFloats, filament_remaining_length))
|
||||
)
|
||||
|
|
|
|||
|
|
@ -250,9 +250,11 @@ void BackgroundSlicingProcess::process_fff()
|
|||
finalize_gcode();
|
||||
else
|
||||
export_gcode();
|
||||
wxQueueEvent(wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_finished_id));
|
||||
} else if (! m_upload_job.empty()) {
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_began_id));
|
||||
prepare_upload();
|
||||
wxQueueEvent(wxGetApp().mainframe->m_plater, new wxCommandEvent(m_event_export_finished_id));
|
||||
} else {
|
||||
m_print->set_status(100, _utf8(L("Slicing complete")));
|
||||
}
|
||||
|
|
@ -883,10 +885,10 @@ void BackgroundSlicingProcess::export_gcode()
|
|||
}
|
||||
|
||||
// BBS
|
||||
auto evt = new wxCommandEvent(m_event_export_finished_id, GUI::wxGetApp().mainframe->m_plater->GetId());
|
||||
wxString output_gcode_str = wxString::FromUTF8(export_path.c_str(), export_path.length());
|
||||
evt->SetString(output_gcode_str);
|
||||
wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt);
|
||||
// auto evt = new wxCommandEvent(m_event_export_finished_id, GUI::wxGetApp().mainframe->m_plater->GetId());
|
||||
// wxString output_gcode_str = wxString::FromUTF8(export_path.c_str(), export_path.length());
|
||||
// evt->SetString(output_gcode_str);
|
||||
// wxQueueEvent(GUI::wxGetApp().mainframe->m_plater, evt);
|
||||
|
||||
// BBS: to be checked. Whether use export_path or output_path.
|
||||
gcode_add_line_number(export_path, m_fff_print->full_print_config());
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#endif
|
||||
#include "Spoolman.hpp"
|
||||
|
||||
#include <imgui/imgui_internal.h>
|
||||
|
||||
static constexpr float GAP_WIDTH = 10.0f;
|
||||
|
|
@ -2087,6 +2089,19 @@ void NotificationManager::push_import_finished_notification(const std::string& p
|
|||
set_slicing_progress_hidden();
|
||||
}
|
||||
|
||||
void NotificationManager::push_spoolman_consumption_finished_notification()
|
||||
{
|
||||
close_notification_of_type(NotificationType::SpoolmanConsumptionFinished);
|
||||
auto callback = [](wxEvtHandler*) {
|
||||
if (Spoolman::get_instance()->undo_use_spoolman_spools())
|
||||
return true;
|
||||
show_error(nullptr, _L("Failed to undo Spoolman filament consumption"));
|
||||
return false;
|
||||
};
|
||||
NotificationData data {NotificationType::SpoolmanConsumptionFinished, NotificationLevel::RegularNotificationLevel, 0, _u8L("Spoolman consumption finished successfully.") + " ", _u8L("Undo"), callback };
|
||||
push_notification_data(data, 0);
|
||||
}
|
||||
|
||||
void NotificationManager::push_download_URL_progress_notification(size_t id, const std::string& text, std::function<bool(DownloaderUserAction, int)> user_action_callback)
|
||||
{
|
||||
// If already exists
|
||||
|
|
|
|||
|
|
@ -126,6 +126,8 @@ enum class NotificationType
|
|||
NetfabbFinished,
|
||||
// Short meesage to fill space between start and finish of export
|
||||
ExportOngoing,
|
||||
// A message showing that Spoolman filament consumption finished and allow a rollback of the action
|
||||
SpoolmanConsumptionFinished,
|
||||
// Progressbar of download from prusaslicer://url
|
||||
URLDownload,
|
||||
// BBS: Short meesage to fill space between start and finish of arranging
|
||||
|
|
@ -250,6 +252,8 @@ public:
|
|||
void push_exporting_finished_notification(const std::string& path, const std::string& dir_path, bool on_removable);
|
||||
void push_import_finished_notification(const std::string& path, const std::string& dir_path, bool on_removable);
|
||||
|
||||
void push_spoolman_consumption_finished_notification();
|
||||
|
||||
// Download URL progress notif
|
||||
void push_download_URL_progress_notification(size_t id, const std::string& text, std::function<bool(DownloaderUserAction, int)> user_action_callback);
|
||||
void set_download_URL_progress(size_t id, float percentage);
|
||||
|
|
|
|||
|
|
@ -2564,6 +2564,10 @@ struct Plater::priv
|
|||
// Returns true if current_warnings vector is empty without showning the dialog
|
||||
bool warnings_dialog();
|
||||
|
||||
// If Spoolman is active, the server is valid, and at least one Spoolman spool is used,
|
||||
// a dialog will be show asking if the user would like to consume the estimated filament usage
|
||||
void spoolman_consumption_dialog(const bool& all_plates);
|
||||
|
||||
void on_action_add(SimpleEvent&);
|
||||
void on_action_add_plate(SimpleEvent&);
|
||||
void on_action_del_plate(SimpleEvent&);
|
||||
|
|
@ -6760,8 +6764,12 @@ void Plater::priv::on_export_began(wxCommandEvent& evt)
|
|||
|
||||
void Plater::priv::on_export_finished(wxCommandEvent& evt)
|
||||
{
|
||||
if (!m_export_all || (m_cur_slice_plate == (partplate_list.get_plate_count() - 1)))
|
||||
spoolman_consumption_dialog(m_export_all);
|
||||
#if 0
|
||||
//BBS: also export 3mf to the same directory for debugging
|
||||
if (evt.GetString().empty())
|
||||
return;
|
||||
std::string gcode_path_str(evt.GetString().ToUTF8().data());
|
||||
fs::path gcode_path(gcode_path_str);
|
||||
|
||||
|
|
@ -6866,6 +6874,60 @@ bool Plater::priv::warnings_dialog()
|
|||
return res == wxID_YES;
|
||||
}
|
||||
|
||||
void Plater::priv::spoolman_consumption_dialog(const bool& all_plates)
|
||||
{
|
||||
if (!wxGetApp().preset_bundle->printers.get_edited_preset().spoolman_enabled())
|
||||
return;
|
||||
if (!Spoolman::is_server_valid())
|
||||
return;
|
||||
|
||||
auto spoolman = Spoolman::get_instance();
|
||||
const auto& consumption_type = wxGetApp().app_config->get("spoolman", "consumption_type");
|
||||
std::string unit = consumption_type == "weight" ? "g" : consumption_type == "length" ? "mm" : "";
|
||||
|
||||
if (unit.empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "The specified consumption type is not valid";
|
||||
return;
|
||||
}
|
||||
|
||||
std::map<unsigned, double> estimates;
|
||||
std::map<unsigned, wxString> messages;
|
||||
|
||||
auto apply_estimates_from_plate = [&] (PartPlate* plate) {
|
||||
for (const auto& est : plate->fff_print()->get_spoolman_filament_consumption_estimates()) {
|
||||
auto& id = est.spoolman_spool_id;
|
||||
if (consumption_type == "weight") {
|
||||
estimates[id] += est.est_used_weight;
|
||||
} else if (consumption_type == "length") {
|
||||
estimates[id] += est.est_used_length;
|
||||
} else return;
|
||||
messages[id] = wxString::FromUTF8((boost::format("%1%: %2% %3%") % est.filament_name % double_to_string(estimates[id], 2) % unit).str());
|
||||
}
|
||||
};
|
||||
|
||||
if (all_plates)
|
||||
for (const auto& plate : partplate_list.get_plate_list())
|
||||
apply_estimates_from_plate(plate);
|
||||
else
|
||||
apply_estimates_from_plate(partplate_list.get_curr_plate());
|
||||
|
||||
if (estimates.empty()) return;
|
||||
|
||||
auto msg = _L("Would you like to consume the used filaments registered in Spoolman?") + "\n\n";
|
||||
for (const auto& [id, message] : messages)
|
||||
msg += message + "\n";
|
||||
|
||||
auto dlg = MessageDialog(nullptr, msg, _L("Spoolman Filament Consumption"), wxYES_NO);
|
||||
if (dlg.ShowModal() == wxID_YES) {
|
||||
if (spoolman->use_spoolman_spools(estimates, consumption_type)) {
|
||||
notification_manager->push_spoolman_consumption_finished_notification();
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to consume filament from Spoolman";
|
||||
show_error(nullptr, _L("Failed to consume filament from Spoolman"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//BBS: add project slice logic
|
||||
void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3712,7 +3712,7 @@ void TabFilament::toggle_options()
|
|||
}
|
||||
|
||||
if (m_active_page->title() == L("Spoolman")) {
|
||||
toggle_line("spoolman_update", m_config->opt_int("spoolman_spool_id") > 0);
|
||||
toggle_line("spoolman_update", m_config->opt_int("spoolman_spool_id", 0) > 0);
|
||||
update_spoolman_statistics();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -152,10 +152,10 @@ bool Spoolman::pull_spoolman_spools()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Spoolman::use_spoolman_spool(const unsigned int& spool_id, const double& weight_used)
|
||||
bool Spoolman::use_spoolman_spool(const unsigned int& spool_id, const double& usage, const std::string& usage_type)
|
||||
{
|
||||
pt::ptree tree;
|
||||
tree.put("use_weight", weight_used);
|
||||
tree.put("use_" + usage_type, usage);
|
||||
|
||||
std::string endpoint = (boost::format("spool/%1%/use") % spool_id).str();
|
||||
tree = put_spoolman_json(endpoint, tree);
|
||||
|
|
@ -166,6 +166,46 @@ bool Spoolman::use_spoolman_spool(const unsigned int& spool_id, const double& we
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Spoolman::use_spoolman_spools(const std::map<unsigned int, double>& data, const std::string& usage_type)
|
||||
{
|
||||
if (!(usage_type == "length" || usage_type == "weight"))
|
||||
return false;
|
||||
|
||||
std::vector<unsigned int> spool_ids;
|
||||
|
||||
for (auto& [spool_id, usage] : data) {
|
||||
if (!use_spoolman_spool(spool_id, usage, usage_type))
|
||||
return false;
|
||||
spool_ids.emplace_back(spool_id);
|
||||
}
|
||||
|
||||
update_specific_spool_statistics(spool_ids);
|
||||
|
||||
m_use_undo_buffer = data;
|
||||
m_last_usage_type = usage_type;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Spoolman::undo_use_spoolman_spools()
|
||||
{
|
||||
if (m_use_undo_buffer.empty() || m_last_usage_type.empty())
|
||||
return false;
|
||||
|
||||
std::vector<unsigned int> spool_ids;
|
||||
|
||||
for (auto& [spool_id, usage] : m_use_undo_buffer) {
|
||||
if (!use_spoolman_spool(spool_id, usage * -1, m_last_usage_type))
|
||||
return false;
|
||||
spool_ids.emplace_back(spool_id);
|
||||
}
|
||||
|
||||
update_specific_spool_statistics(spool_ids);
|
||||
|
||||
m_use_undo_buffer.clear();
|
||||
m_last_usage_type.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
SpoolmanResult Spoolman::create_filament_preset_from_spool(const SpoolmanSpoolShrPtr& spool,
|
||||
const Preset* base_profile,
|
||||
bool detach,
|
||||
|
|
@ -192,7 +232,7 @@ SpoolmanResult Spoolman::create_filament_preset_from_spool(const SpoolmanSpoolSh
|
|||
// Check for presets with the same spool ID
|
||||
int visible(0), invisible(0);
|
||||
for (const auto& item : filaments()) { // count num of visible and invisible
|
||||
if (item.config.opt_int("spoolman_spool_id") == spool->id) {
|
||||
if (item.config.opt_int("spoolman_spool_id", 0) == spool->id) {
|
||||
if (item.is_visible)
|
||||
visible++;
|
||||
else
|
||||
|
|
@ -241,7 +281,7 @@ SpoolmanResult Spoolman::update_filament_preset_from_spool(Preset* filament_pres
|
|||
result.messages.emplace_back("Preset is not a filament preset");
|
||||
return result;
|
||||
}
|
||||
const int& spool_id = filament_preset->config.opt_int("spoolman_spool_id");
|
||||
const int& spool_id = filament_preset->config.opt_int("spoolman_spool_id", 0);
|
||||
if (spool_id < 1) {
|
||||
result.messages.emplace_back(
|
||||
"Preset provided does not have a valid Spoolman spool ID"); // IDs below 1 are not used by spoolman and should be ignored
|
||||
|
|
@ -271,12 +311,34 @@ void Spoolman::update_visible_spool_statistics(bool clear_cache)
|
|||
if (item->is_user() && item->spoolman_enabled()) {
|
||||
if (auto res = update_filament_preset_from_spool(item, true, true); res.has_failed())
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": Failed to update spoolman statistics with the following error: "
|
||||
<< res.build_single_line_message() << "Spool ID: " << item->config.opt_int("spoolman_spool_id");
|
||||
<< res.build_single_line_message() << "Spool ID: " << item->config.opt_int("spoolman_spool_id", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Spoolman::update_specific_spool_statistics(const std::vector<unsigned int>& spool_ids)
|
||||
{
|
||||
PresetBundle* preset_bundle = GUI::wxGetApp().preset_bundle;
|
||||
PresetCollection& printers = preset_bundle->printers;
|
||||
PresetCollection& filaments = preset_bundle->filaments;
|
||||
|
||||
std::set spool_ids_set(spool_ids.begin(), spool_ids.end());
|
||||
// make sure '0' is not a value
|
||||
spool_ids_set.erase(0);
|
||||
|
||||
if (printers.get_edited_preset().spoolman_enabled() && is_server_valid()) {
|
||||
for (auto item : filaments.get_visible()) {
|
||||
if (item->is_user() && spool_ids_set.count(item->config.opt_int("spoolman_spool_id", 0)) > 0) {
|
||||
if (auto res = update_filament_preset_from_spool(item, true, true); res.has_failed())
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << ": Failed to update spoolman statistics with the following error: "
|
||||
<< res.build_single_line_message() << "Spool ID: " << item->config.opt_int("spoolman_spool_id", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Spoolman::is_server_valid()
|
||||
{
|
||||
bool res = false;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ class Spoolman
|
|||
|
||||
bool m_initialized{false};
|
||||
|
||||
std::map<unsigned int, double> m_use_undo_buffer{};
|
||||
std::string m_last_usage_type{};
|
||||
|
||||
std::map<unsigned int, SpoolmanVendorShrPtr> m_vendors{};
|
||||
std::map<unsigned int, SpoolmanFilamentShrPtr> m_filaments{};
|
||||
std::map<unsigned int, SpoolmanSpoolShrPtr> m_spools{};
|
||||
|
|
@ -71,10 +74,21 @@ class Spoolman
|
|||
/// get all the spools from the api and store them
|
||||
/// \returns if succeeded
|
||||
bool pull_spoolman_spools();
|
||||
public:
|
||||
|
||||
/// uses/consumes filament from the specified spool then updates the spool
|
||||
/// \param usage_type The consumption metric to be used. Should be "length" or "weight". This will NOT be checked.
|
||||
/// \returns if succeeded
|
||||
bool use_spoolman_spool(const unsigned int& spool_id, const double& weight_used);
|
||||
bool use_spoolman_spool(const unsigned int& spool_id, const double& usage, const std::string& usage_type);
|
||||
public:
|
||||
/// uses/consumes filament from multiple specified spools then updates them
|
||||
/// \param data a map with the spool ID as the key and the amount to be consumed as the value
|
||||
/// \param usage_type The consumption metric to be used. Should be "length" or "weight". This will be checked.
|
||||
/// \returns if succeeded
|
||||
bool use_spoolman_spools(const std::map<unsigned int, double>& data, const std::string& usage_type);
|
||||
|
||||
/// undo the previous use/consumption
|
||||
/// \returns if succeeded
|
||||
bool undo_use_spoolman_spools();
|
||||
|
||||
static SpoolmanResult create_filament_preset_from_spool(const SpoolmanSpoolShrPtr& spool,
|
||||
const Preset* base_profile,
|
||||
|
|
@ -88,6 +102,9 @@ public:
|
|||
/// clear_cache should be set true if the update is due to a change in printer profile or other change that requires it
|
||||
static void update_visible_spool_statistics(bool clear_cache = false);
|
||||
|
||||
/// Update the statistics values for the filament profiles tied to the specified spool IDs
|
||||
static void update_specific_spool_statistics(const std::vector<unsigned int>& spool_ids);
|
||||
|
||||
static bool is_server_valid();
|
||||
|
||||
const std::map<unsigned int, SpoolmanSpoolShrPtr>& get_spoolman_spools(bool update = false)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue