mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-26 18:31:11 +00:00
feat: initial draft of lifecycle events API for plugins
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#include "slic3r/GUI/I18N.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/plugin/PluginManager.hpp"
|
||||
|
||||
#include "libslic3r/Time.hpp"
|
||||
|
||||
@@ -328,7 +329,10 @@ namespace Slic3r
|
||||
obj->bind_state = "free";
|
||||
|
||||
obj->last_alive = Slic3r::Utils::get_current_time_utc();
|
||||
obj->m_is_online = true;
|
||||
// Route through set_online_state() (rather than writing m_is_online directly) so the
|
||||
// DeviceOnlineChanged lifecycle event fires consistently; same effective value/behavior
|
||||
// here since the object was already online in the common case.
|
||||
obj->set_online_state(true);
|
||||
obj->set_dev_name(dev_name);
|
||||
/* if (!obj->dev_ip.empty()) {
|
||||
Slic3r::GUI::wxGetApp().app_config->set_str("ip_address", obj->dev_id, obj->dev_ip);
|
||||
@@ -345,6 +349,10 @@ namespace Slic3r
|
||||
obj->bind_sec_link = sec_link;
|
||||
obj->dev_connection_name = connection_name;
|
||||
obj->bind_ssdp_version = ssdp_version;
|
||||
// Discovery establishes the initial reachability state. Do not report it as an
|
||||
// online transition; DeviceDiscovered below is the lifecycle event for a new
|
||||
// device. Subsequent updates route through set_online_state(), so a known device
|
||||
// still emits DeviceOnlineChanged when its reachability actually changes.
|
||||
obj->m_is_online = true;
|
||||
|
||||
//load access code
|
||||
@@ -361,6 +369,15 @@ namespace Slic3r
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " New Machine, dev_id= " << dev_id
|
||||
<< ", ip = " << dev_ip <<", printer_name = " << dev_name
|
||||
<< ", con_type= " << connect_type <<", signal= " << printer_signal << ", bind_state= " << bind_state;
|
||||
|
||||
// First discovery of a genuinely new device (not a periodic SSDP/heartbeat update to
|
||||
// an already-known one, which is handled in the branch above).
|
||||
{
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = dev_id;
|
||||
ctx.code = LifecycleEvtCode::Ok;
|
||||
fire_lifecycle_event(LifecycleEvent::DeviceDiscovered, ctx);
|
||||
}
|
||||
}
|
||||
update_local_machine(*obj);
|
||||
}
|
||||
@@ -935,8 +952,14 @@ namespace Slic3r
|
||||
}
|
||||
|
||||
void DeviceManager::OnSelectedMachineChanged(const std::string& /*pre_dev_id*/,
|
||||
const std::string& /*new_dev_id*/)
|
||||
const std::string& new_dev_id)
|
||||
{
|
||||
{
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = new_dev_id; // empty string is a valid deselection
|
||||
ctx.code = LifecycleEvtCode::Ok;
|
||||
fire_lifecycle_event(LifecycleEvent::DeviceSelected, ctx);
|
||||
}
|
||||
if (MachineObject* obj_ = get_selected_machine()) {
|
||||
GUI::wxGetApp().sidebar().update_sync_status(obj_);
|
||||
if(m_agent->get_filament_sync_mode() == FilamentSyncMode::subscription)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "libslic3r/Time.hpp"
|
||||
#include "libslic3r/Thread.hpp"
|
||||
#include "slic3r/Utils/NetworkAgent.hpp"
|
||||
#include "slic3r/plugin/PluginManager.hpp"
|
||||
#include "GuiColor.hpp"
|
||||
|
||||
#include "GUI_App.hpp"
|
||||
@@ -2591,7 +2592,15 @@ void MachineObject::reset()
|
||||
|
||||
void MachineObject::set_print_state(std::string status)
|
||||
{
|
||||
const bool changed = (print_status != status);
|
||||
print_status = status;
|
||||
if (changed) {
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = dev_id;
|
||||
ctx.code = LifecycleEvtCode::Ok;
|
||||
ctx.msg = print_status;
|
||||
fire_lifecycle_event(LifecycleEvent::PrintStateChanged, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
int MachineObject::connect(bool use_openssl)
|
||||
@@ -2613,6 +2622,10 @@ int MachineObject::connect(bool use_openssl)
|
||||
int MachineObject::disconnect()
|
||||
{
|
||||
if (m_agent) {
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = dev_id;
|
||||
ctx.code = LifecycleEvtCode::Ok;
|
||||
fire_lifecycle_event(LifecycleEvent::DeviceDisconnected, ctx);
|
||||
return m_agent->disconnect_printer();
|
||||
}
|
||||
return -1;
|
||||
@@ -2643,8 +2656,16 @@ bool MachineObject::is_connecting()
|
||||
|
||||
void MachineObject::set_online_state(bool on_off)
|
||||
{
|
||||
const bool changed = (m_is_online != on_off);
|
||||
m_is_online = on_off;
|
||||
if (!on_off) m_active_state = NotActive;
|
||||
if (changed) {
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = dev_id;
|
||||
ctx.code = LifecycleEvtCode::Ok;
|
||||
ctx.msg = on_off ? "online" : "offline";
|
||||
fire_lifecycle_event(LifecycleEvent::DeviceOnlineChanged, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
bool MachineObject::is_info_ready(bool check_version) const
|
||||
@@ -4566,8 +4587,13 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
|
||||
try {
|
||||
if (j.contains("event")) {
|
||||
if (j["event"].contains("event")) {
|
||||
if (j["event"]["event"].get<std::string>() == "client.disconnected")
|
||||
if (j["event"]["event"].get<std::string>() == "client.disconnected") {
|
||||
set_online_state(false);
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = dev_id;
|
||||
ctx.code = LifecycleEvtCode::Ok;
|
||||
fire_lifecycle_event(LifecycleEvent::DeviceDisconnected, ctx);
|
||||
}
|
||||
else if (j["event"]["event"].get<std::string>() == "client.connected")
|
||||
set_online_state(true);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include "slic3r/GUI/Gizmos/GLGizmoPainterBase.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "slic3r/Utils/MacDarkMode.hpp"
|
||||
#include "slic3r/plugin/PluginManager.hpp"
|
||||
|
||||
#include <slic3r/GUI/GUI_Utils.hpp>
|
||||
|
||||
@@ -5061,8 +5062,16 @@ void GLCanvas3D::do_move(const std::string& snapshot_type)
|
||||
//BBS: nofity object list to update
|
||||
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
|
||||
|
||||
if (object_moved)
|
||||
if (object_moved) {
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
ctx.msg = "moved";
|
||||
if (done.size() == 1)
|
||||
ctx.name = m_model->objects[done.begin()->first]->name;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
|
||||
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED));
|
||||
}
|
||||
|
||||
// BBS: support wipe-tower for multi-plates
|
||||
for (int plate_id = 0; plate_id < wipe_tower_origins.size(); plate_id++) {
|
||||
@@ -5183,8 +5192,16 @@ void GLCanvas3D::do_rotate(const std::string& snapshot_type)
|
||||
//BBS: nofity object list to update
|
||||
wxGetApp().plater()->sidebar().obj_list()->update_plate_values_for_items();
|
||||
|
||||
if (!done.empty())
|
||||
if (!done.empty()) {
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
ctx.msg = "rotated";
|
||||
if (done.size() == 1)
|
||||
ctx.name = m_model->objects[done.begin()->first]->name;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
|
||||
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_ROTATED));
|
||||
}
|
||||
|
||||
m_dirty = true;
|
||||
}
|
||||
@@ -5275,8 +5292,16 @@ void GLCanvas3D::do_scale(const std::string& snapshot_type)
|
||||
//BBS: notify object info update
|
||||
wxGetApp().plater()->show_object_info();
|
||||
|
||||
if (!done.empty())
|
||||
if (!done.empty()) {
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
ctx.msg = "scaled";
|
||||
if (done.size() == 1)
|
||||
ctx.name = m_model->objects[done.begin()->first]->name;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
|
||||
|
||||
post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_SCALED));
|
||||
}
|
||||
|
||||
m_dirty = true;
|
||||
}
|
||||
|
||||
@@ -2169,6 +2169,11 @@ void GUI_App::init_networking_callbacks()
|
||||
obj->command_get_access_code();
|
||||
if (m_agent)
|
||||
m_agent->install_device_cert(obj->get_dev_id(), obj->is_lan_mode_printer());
|
||||
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = obj->get_dev_id();
|
||||
ctx.code = LifecycleEvtCode::Ok;
|
||||
fire_lifecycle_event(LifecycleEvent::DeviceConnected, ctx);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -2207,6 +2212,11 @@ void GUI_App::init_networking_callbacks()
|
||||
obj->command_get_version();
|
||||
event.SetInt(0);
|
||||
event.SetString(obj->get_dev_id());
|
||||
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = obj->get_dev_id();
|
||||
ctx.code = LifecycleEvtCode::Ok;
|
||||
fire_lifecycle_event(LifecycleEvent::DeviceConnected, ctx);
|
||||
} else if (state == ConnectStatus::ConnectStatusFailed) {
|
||||
// Orca: only update status if same device id
|
||||
if (m_device_manager->selected_machine != dev_id) return;
|
||||
@@ -2222,10 +2232,22 @@ void GUI_App::init_networking_callbacks()
|
||||
wxGetApp().show_dialog(text);
|
||||
}
|
||||
event.SetInt(-1);
|
||||
|
||||
{
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = dev_id;
|
||||
ctx.code = LifecycleEvtCode::Ok;
|
||||
fire_lifecycle_event(LifecycleEvent::DeviceDisconnected, ctx);
|
||||
}
|
||||
} else if (state == ConnectStatus::ConnectStatusLost) {
|
||||
m_device_manager->set_selected_machine("");
|
||||
event.SetInt(-1);
|
||||
BOOST_LOG_TRIVIAL(info) << "set_on_local_connect_fn: state = lost";
|
||||
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = dev_id;
|
||||
ctx.code = LifecycleEvtCode::Ok;
|
||||
fire_lifecycle_event(LifecycleEvent::DeviceDisconnected, ctx);
|
||||
} else {
|
||||
event.SetInt(-1);
|
||||
BOOST_LOG_TRIVIAL(info) << "set_on_local_connect_fn: state = " << state;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "BitmapComboBox.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "slic3r/plugin/PluginManager.hpp"
|
||||
|
||||
#include "OptionsGroup.hpp"
|
||||
#include "Tab.hpp"
|
||||
@@ -3530,7 +3531,14 @@ void ObjectList::delete_all_connectors_for_object(int obj_idx)
|
||||
obj->delete_connectors();
|
||||
|
||||
if (obj->volumes.empty() || !obj->has_solid_mesh()) {
|
||||
const std::string deleted_obj_name = obj->name;
|
||||
model.delete_object(idx);
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.name = deleted_obj_name;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectDeleted, ctx);
|
||||
}
|
||||
m_objects_model->Delete(m_objects_model->GetItemById(idx));
|
||||
continue;
|
||||
}
|
||||
@@ -4099,6 +4107,13 @@ void ObjectList::add_object_to_list(size_t obj_idx, bool call_selection_changed,
|
||||
const auto item = m_objects_model->AddObject(model_object, warning_bitmap, model_object->is_cut());
|
||||
Expand(m_objects_model->GetParent(item));
|
||||
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.name = model_object->name;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectAdded, ctx);
|
||||
}
|
||||
|
||||
if (!do_info_update)
|
||||
return;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "slic3r/GUI/NotificationManager.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
#include "slic3r/plugin/PluginManager.hpp"
|
||||
|
||||
#include "libnest2d/common.hpp"
|
||||
|
||||
@@ -699,6 +700,13 @@ void ArrangeJob::finalize(bool canceled, std::exception_ptr &eptr) {
|
||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":arrange m_unprintable: name: %4%, bed_id %1%, trans {%2%,%3%}") % ap.bed_idx % unscale<double>(ap.translation(X)) % unscale<double>(ap.translation(Y)) % ap.name;
|
||||
}
|
||||
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
ctx.msg = "arranged";
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
|
||||
}
|
||||
|
||||
m_plater->update();
|
||||
// BBS
|
||||
//wxGetApp().obj_manipul()->set_dirty();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "slic3r/GUI/Plater.hpp"
|
||||
#include "slic3r/GUI/GLCanvas3D.hpp"
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
#include "slic3r/plugin/PluginManager.hpp"
|
||||
#include "libnest2d/common.hpp"
|
||||
|
||||
#include <numeric>
|
||||
@@ -347,6 +348,13 @@ void FillBedJob::finalize(bool canceled, std::exception_ptr &eptr)
|
||||
m_plater->arrange();
|
||||
}
|
||||
m_plater->update();
|
||||
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
ctx.msg = "arranged";
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
m_plater->mark_plate_toolbar_image_dirty();
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "slic3r/GUI/GUI.hpp"
|
||||
#include "slic3r/GUI/GUI_App.hpp"
|
||||
#include "slic3r/GUI/NotificationManager.hpp"
|
||||
#include "slic3r/plugin/PluginManager.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
|
||||
|
||||
@@ -254,6 +255,12 @@ void OrientJob::finalize(bool canceled, std::exception_ptr &eptr)
|
||||
mesh.apply();
|
||||
}
|
||||
|
||||
if (!m_selected.empty()) {
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
ctx.msg = "auto_oriented";
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectTransformed, ctx);
|
||||
}
|
||||
|
||||
m_plater->update();
|
||||
|
||||
|
||||
@@ -8375,7 +8375,14 @@ void Plater::priv::remove(size_t obj_idx)
|
||||
view3D->enable_layers_editing(false);
|
||||
|
||||
m_worker.cancel_all();
|
||||
std::string obj_name = (obj_idx < model.objects.size()) ? model.objects[obj_idx]->name : std::to_string(obj_idx);
|
||||
model.delete_object(obj_idx);
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.name = obj_name;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectDeleted, ctx);
|
||||
}
|
||||
//BBS: notify partplate the instance removed
|
||||
partplate_list.notify_instance_removed(obj_idx, -1);
|
||||
update();
|
||||
@@ -8408,7 +8415,14 @@ bool Plater::priv::delete_object_from_model(size_t obj_idx, bool refresh_immedia
|
||||
if (obj->is_cut())
|
||||
sidebar->obj_list()->invalidate_cut_info_for_object(obj_idx);
|
||||
|
||||
std::string obj_name = obj->name;
|
||||
model.delete_object(obj_idx);
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.name = obj_name;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ObjectDeleted, ctx);
|
||||
}
|
||||
//BBS: notify partplate the instance removed
|
||||
partplate_list.notify_instance_removed(obj_idx, -1);
|
||||
|
||||
@@ -8458,6 +8472,14 @@ void Plater::priv::reset(bool apply_presets_change)
|
||||
|
||||
clear_warnings();
|
||||
|
||||
const std::string closed_project_name = into_u8(get_project_filename());
|
||||
if (!closed_project_name.empty() || !model.objects.empty()) {
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.name = closed_project_name;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ProjectClosed, ctx);
|
||||
}
|
||||
|
||||
set_project_filename("");
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " call set_project_filename: empty";
|
||||
|
||||
@@ -10868,11 +10890,15 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
||||
notification_manager->set_slicing_progress_export_possible();
|
||||
|
||||
// Reset the "export G-code path" name, so that the automatic background processing will be enabled again.
|
||||
const std::string lifecycle_job_name = this->background_process.fff_print() ?
|
||||
this->background_process.fff_print()->output_filename() : std::string();
|
||||
this->background_process.reset_export();
|
||||
// This bool stops showing export finished notification even when process_completed_with_error is false
|
||||
bool has_error = false;
|
||||
std::string lifecycle_error_msg;
|
||||
if (evt.error()) {
|
||||
auto message = evt.format_error_message();
|
||||
lifecycle_error_msg = message.first;
|
||||
if (evt.critical_error()) {
|
||||
if (q->m_tracking_popup_menu) {
|
||||
// We don't want to pop-up a message box when tracking a pop-up menu.
|
||||
@@ -10910,6 +10936,14 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
|
||||
is_finished = true;
|
||||
}
|
||||
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.name = lifecycle_job_name;
|
||||
ctx.code = evt.cancelled() ? Slic3r::LifecycleEvtCode::Warn : (has_error ? Slic3r::LifecycleEvtCode::Error : Slic3r::LifecycleEvtCode::Ok);
|
||||
ctx.msg = evt.cancelled() ? "cancelled" : (has_error ? lifecycle_error_msg : std::string());
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::SlicingJobComplete, ctx);
|
||||
}
|
||||
|
||||
//BBS: set the current plater's slice result to valid
|
||||
if (!this->background_process.empty())
|
||||
this->background_process.get_current_plate()->update_slice_result_valid_state(evt.success());
|
||||
@@ -13068,6 +13102,11 @@ int Plater::new_project(bool skip_confirm, bool silent, const wxString& project_
|
||||
//get_partplate_list().reinit();
|
||||
//get_partplate_list().update_slice_context_to_current_plate(p->background_process);
|
||||
//p->preview->update_gcode_result(p->partplate_list.get_current_slice_result());
|
||||
if (!silent) {
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::NewProject, ctx);
|
||||
}
|
||||
reset(transfer_preset_changes);
|
||||
reset_project_dirty_after_save();
|
||||
reset_project_dirty_initial_presets();
|
||||
@@ -13199,6 +13238,13 @@ void Plater::load_project(wxString const& filename2,
|
||||
p->set_project_name(_L("Untitled"));
|
||||
}
|
||||
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.name = into_u8(load_restore ? originfile : filename);
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ProjectOpened, ctx);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (using_exported_file()) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " using ecported set project filename: " << filename;
|
||||
@@ -13261,11 +13307,23 @@ int Plater::save_project(bool saveAs)
|
||||
if (full_pathnames) {
|
||||
save_strategy = save_strategy | SaveStrategy::FullPathSources;
|
||||
}
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.name = into_u8(filename);
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ProjectBeforeSave, ctx);
|
||||
}
|
||||
if (export_3mf(into_path(filename), save_strategy) < 0) {
|
||||
MessageDialog(this, _L("Failed to save the project.\nPlease check whether the folder exists online or if other programs have the project file open."),
|
||||
_L("Save project"), wxOK | wxICON_WARNING).ShowModal();
|
||||
return wxID_CANCEL;
|
||||
}
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.name = into_u8(filename);
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::ProjectAfterSave, ctx);
|
||||
}
|
||||
|
||||
Slic3r::remove_backup(model(), false);
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "slic3r/Utils/NetworkAgentFactory.hpp"
|
||||
#include "slic3r/Utils/PresetUpdater.hpp"
|
||||
#include "slic3r/plugin/PluginConfig.hpp"
|
||||
#include "slic3r/plugin/PluginManager.hpp"
|
||||
#include "Plater.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "format.hpp"
|
||||
@@ -6900,6 +6901,20 @@ bool Tab::select_preset(
|
||||
}
|
||||
load_current_preset();
|
||||
|
||||
{
|
||||
Slic3r::LifecycleEventContext ctx;
|
||||
ctx.name = preset_name;
|
||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||
switch (m_type) {
|
||||
case Preset::TYPE_PRINT: ctx.msg = "print"; break;
|
||||
case Preset::TYPE_SLA_PRINT: ctx.msg = "sla_print"; break;
|
||||
case Preset::TYPE_FILAMENT: ctx.msg = "filament"; break;
|
||||
case Preset::TYPE_SLA_MATERIAL: ctx.msg = "sla_material"; break;
|
||||
case Preset::TYPE_PRINTER: ctx.msg = "printer"; break;
|
||||
default: break;
|
||||
}
|
||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::PresetSelected, ctx);
|
||||
}
|
||||
|
||||
if (delete_third_printer) {
|
||||
wxGetApp().CallAfter([filament_presets, process_presets]() {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "CrealityPrint.hpp"
|
||||
#include "../GUI/PrintHostDialogs.hpp"
|
||||
#include "../GUI/MainFrame.hpp"
|
||||
#include "slic3r/plugin/PluginManager.hpp"
|
||||
#include "Obico.hpp"
|
||||
#include "Flashforge.hpp"
|
||||
#include "SimplyPrint.hpp"
|
||||
@@ -358,12 +359,29 @@ void PrintHostJobQueue::priv::perform_job(PrintHostJob the_job)
|
||||
{
|
||||
emit_progress(0); // Indicate the upload is starting
|
||||
|
||||
// Captured before upload_data is moved into upload() below.
|
||||
const std::string upload_filename = the_job.upload_data.source_path.filename().string();
|
||||
|
||||
{
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = upload_filename;
|
||||
ctx.code = LifecycleEvtCode::Ok;
|
||||
fire_lifecycle_event(LifecycleEvent::UploadStarted, ctx);
|
||||
}
|
||||
|
||||
bool success = the_job.printhost->upload(std::move(the_job.upload_data),
|
||||
[this](Http::Progress progress, bool &cancel) { this->progress_fn(std::move(progress), cancel); },
|
||||
[this](wxString error) { this->error_fn(std::move(error)); },
|
||||
[this](wxString tag, wxString host) { this->info_fn(std::move(tag), std::move(host)); }
|
||||
);
|
||||
|
||||
{
|
||||
LifecycleEventContext ctx;
|
||||
ctx.name = upload_filename;
|
||||
ctx.code = success ? LifecycleEvtCode::Ok : LifecycleEvtCode::Error;
|
||||
fire_lifecycle_event(LifecycleEvent::UploadFinished, ctx);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
emit_progress(100);
|
||||
if (the_job.switch_to_device_tab) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "libslic3r/Exception.hpp"
|
||||
#include "libslic3r/LifecycleEvents.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r_version.h"
|
||||
|
||||
@@ -46,6 +47,16 @@ void install_capability_resolver()
|
||||
});
|
||||
}
|
||||
|
||||
// Global libslic3r-side seam (Slic3r::fire_lifecycle_event, in libslic3r/LifecycleEvents.hpp):
|
||||
// broadcasts to every loaded, enabled capability regardless of type, unlike the SlicingPipeline
|
||||
// hook below which only targets picker-selected SlicingPipeline capabilities.
|
||||
void install_lifecycle_event_hook()
|
||||
{
|
||||
set_lifecycle_hook_fn([](LifecycleEvent event, const LifecycleEventContext& ctx) {
|
||||
PluginManager::instance().dispatch_lifecycle_event(event, ctx);
|
||||
});
|
||||
}
|
||||
|
||||
// Print::process() fires this hook at each pipeline seam on the slicing worker
|
||||
// thread; here we run the picker-selected SlicingPipeline capabilities. Per
|
||||
// capability we acquire the GIL, honor cancellation, and convert a plugin
|
||||
@@ -122,12 +133,14 @@ void install()
|
||||
{
|
||||
install_capability_resolver();
|
||||
install_slicing_pipeline_hook();
|
||||
install_lifecycle_event_hook();
|
||||
}
|
||||
|
||||
void uninstall()
|
||||
{
|
||||
ConfigBase::set_resolve_capability_fn(nullptr);
|
||||
Print::set_slicing_pipeline_hook_fn(nullptr);
|
||||
set_lifecycle_hook_fn(nullptr);
|
||||
}
|
||||
|
||||
} // namespace Slic3r::plugin_hooks
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "PluginManager.hpp"
|
||||
|
||||
#include <exception>
|
||||
#include <libslic3r/Utils.hpp>
|
||||
#include <memory>
|
||||
#include <pybind11/embed.h>
|
||||
@@ -1987,4 +1988,24 @@ ExecutionResult PluginManager::run_script_capability(const std::string& plugin_k
|
||||
return result;
|
||||
}
|
||||
|
||||
void PluginManager::dispatch_lifecycle_event(LifecycleEvent evt, const LifecycleEventContext& ctx) {
|
||||
for (const auto& cap : get_plugin_capabilities()) {
|
||||
if (!cap || !cap->is_enabled()) continue;
|
||||
try {
|
||||
cap->on_lifecycle_event(evt, ctx);
|
||||
} catch (const std::exception& ex) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": plugin '" << cap->audit_plugin_key() << "/" << cap->name()
|
||||
<< "' on_lifecycle_event(" << lifecycle_event_to_string(evt) << ") threw: " << ex.what()
|
||||
<< " [ctx name='" << ctx.name << "', code=" << lifecycle_evt_code_to_string(ctx.code)
|
||||
<< ", msg='" << ctx.msg << "']";
|
||||
} catch (...) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": plugin '" << cap->audit_plugin_key() << "/" << cap->name()
|
||||
<< "' on_lifecycle_event(" << lifecycle_event_to_string(evt)
|
||||
<< ") threw a non-standard exception"
|
||||
<< " [ctx name='" << ctx.name << "', code=" << lifecycle_evt_code_to_string(ctx.code)
|
||||
<< ", msg='" << ctx.msg << "']";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <libslic3r/Config.hpp>
|
||||
#include <libslic3r/LifecycleEvents.hpp>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -20,7 +21,6 @@
|
||||
#include <pybind11/embed.h>
|
||||
|
||||
#include "CloudPluginService.hpp"
|
||||
#include "PluginFsUtils.hpp"
|
||||
#include "PluginDescriptor.hpp"
|
||||
#include "PluginLoader.hpp"
|
||||
#include "PluginConfig.hpp"
|
||||
@@ -204,6 +204,8 @@ public:
|
||||
|
||||
ExecutionResult run_script_capability(const std::string& plugin_key, const std::string& capability_name, std::string& error);
|
||||
|
||||
void dispatch_lifecycle_event(LifecycleEvent evt, const LifecycleEventContext& ctx);
|
||||
|
||||
private:
|
||||
PluginManager() = default;
|
||||
PluginManager(const PluginManager&) = delete;
|
||||
|
||||
@@ -129,6 +129,12 @@ public:
|
||||
{
|
||||
ORCA_PY_OVERRIDE_AUDITED(::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE, void, Base, on_cancelled);
|
||||
}
|
||||
|
||||
void on_lifecycle_event(LifecycleEvent event, const LifecycleEventContext& ctx) override
|
||||
{
|
||||
ORCA_PY_OVERRIDE_AUDITED(
|
||||
::Slic3r::PluginAuditManager::AuditMode::Loading, [] {}, PYBIND11_OVERRIDE, void, Base, on_lifecycle_event, event, ctx);
|
||||
}
|
||||
};
|
||||
|
||||
class PyPluginInterfaceTrampoline : public PyPluginCommonTrampoline<PluginCapabilityInterface>
|
||||
|
||||
@@ -338,6 +338,44 @@ void bind_python_api(pybind11::module_& m)
|
||||
.value("FatalError", PluginResult::FatalError)
|
||||
.export_values();
|
||||
|
||||
py::enum_<LifecycleEvent>(m, "LifecycleEvent", "Application lifecycle moment passed to on_lifecycle_event")
|
||||
.value("NewProject", LifecycleEvent::NewProject)
|
||||
.value("ProjectOpened", LifecycleEvent::ProjectOpened)
|
||||
.value("ProjectBeforeSave", LifecycleEvent::ProjectBeforeSave)
|
||||
.value("ProjectAfterSave", LifecycleEvent::ProjectAfterSave)
|
||||
.value("ProjectClosed", LifecycleEvent::ProjectClosed)
|
||||
.value("SliceStarted", LifecycleEvent::SliceStarted)
|
||||
.value("SliceGeometryFinished", LifecycleEvent::SliceGeometryFinished)
|
||||
.value("GCodeExportStarted", LifecycleEvent::GCodeExportStarted)
|
||||
.value("GCodeExportFinished", LifecycleEvent::GCodeExportFinished)
|
||||
.value("SlicingJobComplete", LifecycleEvent::SlicingJobComplete)
|
||||
.value("ObjectAdded", LifecycleEvent::ObjectAdded)
|
||||
.value("ObjectDeleted", LifecycleEvent::ObjectDeleted)
|
||||
.value("ObjectTransformed", LifecycleEvent::ObjectTransformed)
|
||||
.value("PresetSelected", LifecycleEvent::PresetSelected)
|
||||
.value("PresetSaved", LifecycleEvent::PresetSaved)
|
||||
.value("PrintStateChanged", LifecycleEvent::PrintStateChanged)
|
||||
.value("DeviceOnlineChanged", LifecycleEvent::DeviceOnlineChanged)
|
||||
.value("DeviceDiscovered", LifecycleEvent::DeviceDiscovered)
|
||||
.value("DeviceSelected", LifecycleEvent::DeviceSelected)
|
||||
.value("DeviceConnected", LifecycleEvent::DeviceConnected)
|
||||
.value("DeviceDisconnected", LifecycleEvent::DeviceDisconnected)
|
||||
.value("UploadStarted", LifecycleEvent::UploadStarted)
|
||||
.value("UploadFinished", LifecycleEvent::UploadFinished)
|
||||
.export_values();
|
||||
|
||||
py::enum_<LifecycleEvtCode>(m, "LifecycleEvtCode", "Outcome code accompanying a LifecycleEventContext")
|
||||
.value("Ok", LifecycleEvtCode::Ok)
|
||||
.value("Error", LifecycleEvtCode::Error)
|
||||
.value("Warn", LifecycleEvtCode::Warn)
|
||||
.export_values();
|
||||
|
||||
py::class_<LifecycleEventContext>(m, "LifecycleEventContext", "Payload accompanying a LifecycleEvent")
|
||||
.def(py::init<>())
|
||||
.def_readonly("name", &LifecycleEventContext::name)
|
||||
.def_readonly("code", &LifecycleEventContext::code)
|
||||
.def_readonly("msg", &LifecycleEventContext::msg);
|
||||
|
||||
py::class_<PluginContext>(m, "PluginContext", "Context shared with plugin entry points")
|
||||
.def(py::init<>())
|
||||
.def_readwrite("orca_version", &PluginContext::orca_version);
|
||||
@@ -362,6 +400,9 @@ void bind_python_api(pybind11::module_& m)
|
||||
.def("get_type", &PluginCapabilityInterface::get_type)
|
||||
.def("on_load", &PluginCapabilityInterface::on_load)
|
||||
.def("on_unload", &PluginCapabilityInterface::on_unload)
|
||||
.def("on_lifecycle_event", &PluginCapabilityInterface::on_lifecycle_event,
|
||||
"Override to react to an application lifecycle moment (LifecycleEvent) and its\n"
|
||||
"LifecycleEventContext payload. Available on every capability type.")
|
||||
.def("has_config_ui", &PluginCapabilityInterface::has_config_ui,
|
||||
"Override to return True to replace the host's default JSON editor with your own HTML\n"
|
||||
"UI, returned by get_config_ui(). Every capability is configurable and appears in the\n"
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <pybind11/embed.h>
|
||||
|
||||
#include <libslic3r/LifecycleEvents.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
enum class PluginCapabilityType { PrinterConnection = 0, Automation, Analysis, Importer, Exporter, Visualization, Script, SlicingPipeline, Unknown };
|
||||
@@ -167,6 +169,8 @@ public:
|
||||
virtual void on_unload() {}
|
||||
virtual void on_cancelled() {}
|
||||
|
||||
virtual void on_lifecycle_event(LifecycleEvent event, const LifecycleEventContext& ctx) { (void) event; (void) ctx; }
|
||||
|
||||
// ── C++-only host state, never exposed to Python. Set by the loader at materialization. ──
|
||||
//
|
||||
// The capability owns its own identity and enable flag: they are read once under the GIL, live
|
||||
|
||||
Reference in New Issue
Block a user