mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-08-27 11:59:27 +00:00
feat: additional events
This commit is contained in:
@@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
// LifecycleEvents.hpp
|
// LifecycleEvents.hpp
|
||||||
// --------------------
|
// --------------------
|
||||||
// Application lifecycle events (project, slicing, plate editing, preset, printer connection
|
// Application lifecycle events (project, slicing, plate editing, preset, printer connection, and
|
||||||
// activity) that other subsystems -- chiefly the plugin layer above libslic3r -- may want to
|
// job activity) that other subsystems -- chiefly the plugin layer above libslic3r -- may want to
|
||||||
// observe. Lives in libslic3r rather than the plugin layer because some events fire from inside
|
// observe. Lives in libslic3r rather than the plugin layer because some events fire from inside
|
||||||
// the slicing engine itself; see fire_lifecycle_event() below.
|
// the slicing engine itself; see fire_lifecycle_event() below.
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ namespace Slic3r
|
|||||||
ProjectBeforeSave,
|
ProjectBeforeSave,
|
||||||
ProjectAfterSave,
|
ProjectAfterSave,
|
||||||
ProjectClosed,
|
ProjectClosed,
|
||||||
|
ProjectDirtyChanged,
|
||||||
|
|
||||||
// Slicing pipeline
|
// Slicing pipeline
|
||||||
SliceStarted,
|
SliceStarted,
|
||||||
@@ -32,6 +33,12 @@ namespace Slic3r
|
|||||||
ObjectAdded,
|
ObjectAdded,
|
||||||
ObjectDeleted,
|
ObjectDeleted,
|
||||||
ObjectTransformed,
|
ObjectTransformed,
|
||||||
|
ObjectChanged,
|
||||||
|
ObjectRenamed,
|
||||||
|
PlateCreated,
|
||||||
|
PlateDeleted,
|
||||||
|
PlateSelected,
|
||||||
|
PlateRenamed,
|
||||||
|
|
||||||
// Preset
|
// Preset
|
||||||
PresetSelected,
|
PresetSelected,
|
||||||
@@ -46,6 +53,12 @@ namespace Slic3r
|
|||||||
DeviceDisconnected,
|
DeviceDisconnected,
|
||||||
UploadStarted,
|
UploadStarted,
|
||||||
UploadFinished,
|
UploadFinished,
|
||||||
|
|
||||||
|
// Print/send jobs
|
||||||
|
PrintJobStarted,
|
||||||
|
PrintJobFinished,
|
||||||
|
SendJobStarted,
|
||||||
|
SendJobFinished,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Scoped so callers must qualify (LifecycleEvtCode::Error, not ERROR) -- ERROR/OK collide with
|
// Scoped so callers must qualify (LifecycleEvtCode::Error, not ERROR) -- ERROR/OK collide with
|
||||||
@@ -66,6 +79,28 @@ namespace Slic3r
|
|||||||
// Optional human-readable detail or diagnostic text. It is not a stable parsing contract;
|
// Optional human-readable detail or diagnostic text. It is not a stable parsing contract;
|
||||||
// machine-readable data should be represented by a dedicated field or event instead.
|
// machine-readable data should be represented by a dedicated field or event instead.
|
||||||
std::string msg;
|
std::string msg;
|
||||||
|
|
||||||
|
// Stable subject/object identifier, when the source model provides one.
|
||||||
|
std::string id;
|
||||||
|
|
||||||
|
// Previous value for rename and other before/after events.
|
||||||
|
std::string previous_name;
|
||||||
|
|
||||||
|
// Device identifier for printer and job events.
|
||||||
|
std::string device_id;
|
||||||
|
|
||||||
|
// Job identifier when the originating queue/task provides one.
|
||||||
|
std::string job_id;
|
||||||
|
|
||||||
|
// Source subsystem or operation detail, suitable for filtering but not guaranteed to be
|
||||||
|
// exhaustive across versions.
|
||||||
|
std::string source;
|
||||||
|
|
||||||
|
// Plate, object, or volume index when the source uses an index rather than a stable id.
|
||||||
|
int index = -1;
|
||||||
|
|
||||||
|
// Aggregate project dirty state for ProjectDirtyChanged.
|
||||||
|
bool dirty = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string lifecycle_event_to_string(LifecycleEvent event)
|
inline std::string lifecycle_event_to_string(LifecycleEvent event)
|
||||||
@@ -76,6 +111,7 @@ namespace Slic3r
|
|||||||
case LifecycleEvent::ProjectBeforeSave: return "ProjectBeforeSave";
|
case LifecycleEvent::ProjectBeforeSave: return "ProjectBeforeSave";
|
||||||
case LifecycleEvent::ProjectAfterSave: return "ProjectAfterSave";
|
case LifecycleEvent::ProjectAfterSave: return "ProjectAfterSave";
|
||||||
case LifecycleEvent::ProjectClosed: return "ProjectClosed";
|
case LifecycleEvent::ProjectClosed: return "ProjectClosed";
|
||||||
|
case LifecycleEvent::ProjectDirtyChanged: return "ProjectDirtyChanged";
|
||||||
|
|
||||||
case LifecycleEvent::SliceStarted: return "SliceStarted";
|
case LifecycleEvent::SliceStarted: return "SliceStarted";
|
||||||
case LifecycleEvent::SliceGeometryFinished: return "SliceGeometryFinished";
|
case LifecycleEvent::SliceGeometryFinished: return "SliceGeometryFinished";
|
||||||
@@ -86,6 +122,12 @@ namespace Slic3r
|
|||||||
case LifecycleEvent::ObjectAdded: return "ObjectAdded";
|
case LifecycleEvent::ObjectAdded: return "ObjectAdded";
|
||||||
case LifecycleEvent::ObjectDeleted: return "ObjectDeleted";
|
case LifecycleEvent::ObjectDeleted: return "ObjectDeleted";
|
||||||
case LifecycleEvent::ObjectTransformed: return "ObjectTransformed";
|
case LifecycleEvent::ObjectTransformed: return "ObjectTransformed";
|
||||||
|
case LifecycleEvent::ObjectChanged: return "ObjectChanged";
|
||||||
|
case LifecycleEvent::ObjectRenamed: return "ObjectRenamed";
|
||||||
|
case LifecycleEvent::PlateCreated: return "PlateCreated";
|
||||||
|
case LifecycleEvent::PlateDeleted: return "PlateDeleted";
|
||||||
|
case LifecycleEvent::PlateSelected: return "PlateSelected";
|
||||||
|
case LifecycleEvent::PlateRenamed: return "PlateRenamed";
|
||||||
|
|
||||||
case LifecycleEvent::PresetSelected: return "PresetSelected";
|
case LifecycleEvent::PresetSelected: return "PresetSelected";
|
||||||
case LifecycleEvent::PresetSaved: return "PresetSaved";
|
case LifecycleEvent::PresetSaved: return "PresetSaved";
|
||||||
@@ -99,6 +141,10 @@ namespace Slic3r
|
|||||||
|
|
||||||
case LifecycleEvent::UploadStarted: return "UploadStarted";
|
case LifecycleEvent::UploadStarted: return "UploadStarted";
|
||||||
case LifecycleEvent::UploadFinished: return "UploadFinished";
|
case LifecycleEvent::UploadFinished: return "UploadFinished";
|
||||||
|
case LifecycleEvent::PrintJobStarted: return "PrintJobStarted";
|
||||||
|
case LifecycleEvent::PrintJobFinished: return "PrintJobFinished";
|
||||||
|
case LifecycleEvent::SendJobStarted: return "SendJobStarted";
|
||||||
|
case LifecycleEvent::SendJobFinished: return "SendJobFinished";
|
||||||
default: return "Unknown";
|
default: return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
|
#include "libslic3r/LifecycleEvents.hpp"
|
||||||
#include "GUI_ObjectList.hpp"
|
#include "GUI_ObjectList.hpp"
|
||||||
#include "GUI_Factories.hpp"
|
#include "GUI_Factories.hpp"
|
||||||
//#include "GUI_ObjectLayers.hpp"
|
//#include "GUI_ObjectLayers.hpp"
|
||||||
@@ -1200,17 +1201,39 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const
|
|||||||
if (m_objects_model->GetItemType(item) & itObject) {
|
if (m_objects_model->GetItemType(item) & itObject) {
|
||||||
std::string name = m_objects_model->GetName(item).ToUTF8().data();
|
std::string name = m_objects_model->GetName(item).ToUTF8().data();
|
||||||
if (obj->name != name) {
|
if (obj->name != name) {
|
||||||
|
const std::string previous_name = obj->name;
|
||||||
obj->name = name;
|
obj->name = name;
|
||||||
// if object has just one volume, rename this volume too
|
// if object has just one volume, rename this volume too
|
||||||
if (obj->volumes.size() == 1)
|
if (obj->volumes.size() == 1)
|
||||||
obj->volumes[0]->name = obj->name;
|
obj->volumes[0]->name = obj->name;
|
||||||
Slic3r::save_object_mesh(*obj);
|
Slic3r::save_object_mesh(*obj);
|
||||||
|
|
||||||
|
LifecycleEventContext ctx;
|
||||||
|
ctx.name = name;
|
||||||
|
ctx.previous_name = previous_name;
|
||||||
|
ctx.id = std::to_string(obj->id().id);
|
||||||
|
ctx.index = obj_idx;
|
||||||
|
ctx.source = "object";
|
||||||
|
fire_lifecycle_event(LifecycleEvent::ObjectRenamed, ctx);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (volume_id < 0) return;
|
if (volume_id < 0) return;
|
||||||
obj->volumes[volume_id]->name = m_objects_model->GetName(item).ToUTF8().data();
|
std::string name = m_objects_model->GetName(item).ToUTF8().data();
|
||||||
|
if (obj->volumes[volume_id]->name == name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const std::string previous_name = obj->volumes[volume_id]->name;
|
||||||
|
obj->volumes[volume_id]->name = name;
|
||||||
|
|
||||||
|
LifecycleEventContext ctx;
|
||||||
|
ctx.name = name;
|
||||||
|
ctx.previous_name = previous_name;
|
||||||
|
ctx.id = std::to_string(obj->volumes[volume_id]->id().id);
|
||||||
|
ctx.index = volume_id;
|
||||||
|
ctx.source = "volume";
|
||||||
|
fire_lifecycle_event(LifecycleEvent::ObjectRenamed, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectList::update_name_in_list(int obj_idx, int vol_idx) const
|
void ObjectList::update_name_in_list(int obj_idx, int vol_idx) const
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "PrintJob.hpp"
|
#include "PrintJob.hpp"
|
||||||
|
#include "libslic3r/LifecycleEvents.hpp"
|
||||||
#include "libslic3r/MTUtils.hpp"
|
#include "libslic3r/MTUtils.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
@@ -133,6 +134,13 @@ wxString PrintJob::get_http_error_msg(unsigned int status, std::string body)
|
|||||||
|
|
||||||
void PrintJob::process(Ctl &ctl)
|
void PrintJob::process(Ctl &ctl)
|
||||||
{
|
{
|
||||||
|
LifecycleEventContext start_ctx;
|
||||||
|
start_ctx.name = m_project_name;
|
||||||
|
start_ctx.device_id = m_dev_id;
|
||||||
|
start_ctx.source = "print_job";
|
||||||
|
fire_lifecycle_event(LifecycleEvent::PrintJobStarted, start_ctx);
|
||||||
|
m_lifecycle_started = true;
|
||||||
|
|
||||||
/* display info */
|
/* display info */
|
||||||
std::string msg;
|
std::string msg;
|
||||||
wxString error_str;
|
wxString error_str;
|
||||||
@@ -689,6 +697,7 @@ void PrintJob::process(Ctl &ctl)
|
|||||||
}
|
}
|
||||||
wxQueueEvent(m_plater, evt);
|
wxQueueEvent(m_plater, evt);
|
||||||
m_job_finished = true;
|
m_job_finished = true;
|
||||||
|
m_lifecycle_success = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -701,6 +710,19 @@ void PrintJob::finalize(bool canceled, std::exception_ptr &eptr) {
|
|||||||
eptr = std::current_exception();
|
eptr = std::current_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_lifecycle_started && !m_lifecycle_finished) {
|
||||||
|
LifecycleEventContext finish_ctx;
|
||||||
|
finish_ctx.name = m_project_name;
|
||||||
|
finish_ctx.device_id = m_dev_id;
|
||||||
|
finish_ctx.source = "print_job";
|
||||||
|
finish_ctx.code = canceled ? LifecycleEvtCode::Warn :
|
||||||
|
(eptr || !m_lifecycle_success ? LifecycleEvtCode::Error : LifecycleEvtCode::Ok);
|
||||||
|
finish_ctx.msg = canceled ? "cancelled" : (eptr ? "exception" :
|
||||||
|
(m_lifecycle_success ? "" : "failed"));
|
||||||
|
fire_lifecycle_event(LifecycleEvent::PrintJobFinished, finish_ctx);
|
||||||
|
m_lifecycle_finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (canceled || eptr)
|
if (canceled || eptr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ class PrintJob : public Job
|
|||||||
std::function<void()> m_success_fun{nullptr};
|
std::function<void()> m_success_fun{nullptr};
|
||||||
std::string m_dev_id;
|
std::string m_dev_id;
|
||||||
bool m_job_finished{ false };
|
bool m_job_finished{ false };
|
||||||
|
bool m_lifecycle_started{ false };
|
||||||
|
bool m_lifecycle_finished{ false };
|
||||||
|
bool m_lifecycle_success{ false };
|
||||||
int m_print_job_completed_id = 0;
|
int m_print_job_completed_id = 0;
|
||||||
wxString m_completed_evt_data;
|
wxString m_completed_evt_data;
|
||||||
std::function<void()> m_enter_ip_address_fun_fail{ nullptr };
|
std::function<void()> m_enter_ip_address_fun_fail{ nullptr };
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "SendJob.hpp"
|
#include "SendJob.hpp"
|
||||||
|
#include "libslic3r/LifecycleEvents.hpp"
|
||||||
#include "libslic3r/MTUtils.hpp"
|
#include "libslic3r/MTUtils.hpp"
|
||||||
#include "libslic3r/Model.hpp"
|
#include "libslic3r/Model.hpp"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
@@ -146,6 +147,13 @@ void SendJob::process(Ctl &ctl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LifecycleEventContext start_ctx;
|
||||||
|
start_ctx.name = m_project_name;
|
||||||
|
start_ctx.device_id = m_dev_id;
|
||||||
|
start_ctx.source = "send_job";
|
||||||
|
fire_lifecycle_event(LifecycleEvent::SendJobStarted, start_ctx);
|
||||||
|
m_lifecycle_started = true;
|
||||||
|
|
||||||
int total_plate_num = m_plater->get_partplate_list().get_plate_count();
|
int total_plate_num = m_plater->get_partplate_list().get_plate_count();
|
||||||
|
|
||||||
PartPlate* plate = m_plater->get_partplate_list().get_plate(job_data.plate_idx);
|
PartPlate* plate = m_plater->get_partplate_list().get_plate(job_data.plate_idx);
|
||||||
@@ -423,6 +431,19 @@ void SendJob::finalize(bool canceled, std::exception_ptr &eptr)
|
|||||||
eptr = std::current_exception();
|
eptr = std::current_exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_lifecycle_started && !m_lifecycle_finished) {
|
||||||
|
LifecycleEventContext finish_ctx;
|
||||||
|
finish_ctx.name = m_project_name;
|
||||||
|
finish_ctx.device_id = m_dev_id;
|
||||||
|
finish_ctx.source = "send_job";
|
||||||
|
finish_ctx.code = canceled ? LifecycleEvtCode::Warn :
|
||||||
|
(eptr ? LifecycleEvtCode::Error : (m_job_finished ? LifecycleEvtCode::Ok : LifecycleEvtCode::Error));
|
||||||
|
finish_ctx.msg = canceled ? "cancelled" : (eptr ? "exception" :
|
||||||
|
(m_job_finished ? "" : "failed"));
|
||||||
|
fire_lifecycle_event(LifecycleEvent::SendJobFinished, finish_ctx);
|
||||||
|
m_lifecycle_finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (canceled || eptr)
|
if (canceled || eptr)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ class SendJob : public Job
|
|||||||
PrintPrepareData job_data;
|
PrintPrepareData job_data;
|
||||||
std::string m_dev_id;
|
std::string m_dev_id;
|
||||||
bool m_job_finished{ false };
|
bool m_job_finished{ false };
|
||||||
|
bool m_lifecycle_started{ false };
|
||||||
|
bool m_lifecycle_finished{ false };
|
||||||
int m_print_job_completed_id = 0;
|
int m_print_job_completed_id = 0;
|
||||||
bool m_is_check_mode{false};
|
bool m_is_check_mode{false};
|
||||||
bool m_check_and_continue{false};
|
bool m_check_and_continue{false};
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "libslic3r/Tesselate.hpp"
|
#include "libslic3r/Tesselate.hpp"
|
||||||
#include "libslic3r/GCode/ThumbnailData.hpp"
|
#include "libslic3r/GCode/ThumbnailData.hpp"
|
||||||
#include "libslic3r/Utils.hpp"
|
#include "libslic3r/Utils.hpp"
|
||||||
|
#include "libslic3r/LifecycleEvents.hpp"
|
||||||
|
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
@@ -2527,11 +2528,20 @@ void PartPlate::set_plate_name(const std::string& name)
|
|||||||
if (boost::equals(m_name, name))
|
if (boost::equals(m_name, name))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
const std::string previous_name = m_name;
|
||||||
m_name = name;
|
m_name = name;
|
||||||
if (m_print != nullptr)
|
if (m_print != nullptr)
|
||||||
m_print->set_plate_name(name);
|
m_print->set_plate_name(name);
|
||||||
|
|
||||||
invalidate_plate_name_texture();
|
invalidate_plate_name_texture();
|
||||||
|
|
||||||
|
if (m_plater != nullptr && !m_plater->is_loading_project()) {
|
||||||
|
LifecycleEventContext ctx;
|
||||||
|
ctx.name = name;
|
||||||
|
ctx.previous_name = previous_name;
|
||||||
|
ctx.index = m_plate_index;
|
||||||
|
fire_lifecycle_event(LifecycleEvent::PlateRenamed, ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//get the print's object, result and index
|
//get the print's object, result and index
|
||||||
@@ -4638,9 +4648,16 @@ int PartPlateList::create_plate(bool adjust_position)
|
|||||||
|
|
||||||
if (m_plater) {
|
if (m_plater) {
|
||||||
// In GUI mode
|
// In GUI mode
|
||||||
wxGetApp().obj_list()->on_plate_added(plate);
|
wxGetApp().obj_list()->on_plate_added(plate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_plater != nullptr && m_intialized && !m_plater->is_loading_project()) {
|
||||||
|
LifecycleEventContext ctx;
|
||||||
|
ctx.name = plate->get_plate_name();
|
||||||
|
ctx.index = new_index;
|
||||||
|
fire_lifecycle_event(LifecycleEvent::PlateCreated, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":created a new plate %1%") % new_index;
|
BOOST_LOG_TRIVIAL(debug) << __FUNCTION__ << boost::format(":created a new plate %1%") % new_index;
|
||||||
return new_index;
|
return new_index;
|
||||||
}
|
}
|
||||||
@@ -4739,6 +4756,7 @@ int PartPlateList::delete_plate(int index)
|
|||||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":plate %1%, has an invalid index %2%") % index % plate->get_index();
|
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(":plate %1%, has an invalid index %2%") % index % plate->get_index();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
const std::string plate_name = plate->get_plate_name();
|
||||||
|
|
||||||
if (m_plater) {
|
if (m_plater) {
|
||||||
// In GUI mode
|
// In GUI mode
|
||||||
@@ -4821,6 +4839,13 @@ int PartPlateList::delete_plate(int index)
|
|||||||
|
|
||||||
delete plate;
|
delete plate;
|
||||||
|
|
||||||
|
if (m_plater != nullptr && m_intialized && !m_plater->is_loading_project()) {
|
||||||
|
LifecycleEventContext ctx;
|
||||||
|
ctx.name = plate_name;
|
||||||
|
ctx.index = index;
|
||||||
|
fire_lifecycle_event(LifecycleEvent::PlateDeleted, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
// FIX: context of BackgroundSliceProcess and gcode preview need to be updated before ObjectList::reload_all_plates().
|
// FIX: context of BackgroundSliceProcess and gcode preview need to be updated before ObjectList::reload_all_plates().
|
||||||
#if 0
|
#if 0
|
||||||
if (m_plater != nullptr) {
|
if (m_plater != nullptr) {
|
||||||
@@ -4929,6 +4954,7 @@ int PartPlateList::select_plate(int index)
|
|||||||
if (m_plate_list.empty() || index >= m_plate_list.size()) {
|
if (m_plate_list.empty() || index >= m_plate_list.size()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
const int previous_index = m_current_plate;
|
||||||
|
|
||||||
// BBS: erase unnecessary snapshot
|
// BBS: erase unnecessary snapshot
|
||||||
if (get_curr_plate_index() != index && m_intialized) {
|
if (get_curr_plate_index() != index && m_intialized) {
|
||||||
@@ -4955,6 +4981,13 @@ int PartPlateList::select_plate(int index)
|
|||||||
//wxQueueEvent(m_plater, new SimpleEvent(EVT_GLCANVAS_PLATE_SELECT));
|
//wxQueueEvent(m_plater, new SimpleEvent(EVT_GLCANVAS_PLATE_SELECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (previous_index != index && m_intialized && m_plater != nullptr && !m_plater->is_loading_project()) {
|
||||||
|
LifecycleEventContext ctx;
|
||||||
|
ctx.name = m_plate_list[index]->get_plate_name();
|
||||||
|
ctx.index = index;
|
||||||
|
fire_lifecycle_event(LifecycleEvent::PlateSelected, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,7 @@
|
|||||||
#include <wx/aui/aui.h>
|
#include <wx/aui/aui.h>
|
||||||
|
|
||||||
#include "libslic3r/libslic3r.h"
|
#include "libslic3r/libslic3r.h"
|
||||||
|
#include "libslic3r/LifecycleEvents.hpp"
|
||||||
#include "libslic3r/Format/STL.hpp"
|
#include "libslic3r/Format/STL.hpp"
|
||||||
#include "libslic3r/Format/DRC.hpp"
|
#include "libslic3r/Format/DRC.hpp"
|
||||||
#include "libslic3r/Format/STEP.hpp"
|
#include "libslic3r/Format/STEP.hpp"
|
||||||
@@ -8470,6 +8471,11 @@ void Plater::priv::delete_all_objects_from_model()
|
|||||||
|
|
||||||
void Plater::priv::reset(bool apply_presets_change)
|
void Plater::priv::reset(bool apply_presets_change)
|
||||||
{
|
{
|
||||||
|
// TakeSnapshot below and load_current_presets() further down each re-evaluate the
|
||||||
|
// aggregate dirty flag against a baseline that hasn't been reset yet, so they can toggle
|
||||||
|
// is_dirty() back and forth several times before it settles; coalesce those into one event.
|
||||||
|
ProjectDirtyStateManager::NotificationSuppressor dirty_notify_suppressor(dirty_state);
|
||||||
|
|
||||||
Plater::TakeSnapshot snapshot(q, _u8L("Reset Project"), UndoRedo::SnapshotType::ProjectSeparator);
|
Plater::TakeSnapshot snapshot(q, _u8L("Reset Project"), UndoRedo::SnapshotType::ProjectSeparator);
|
||||||
|
|
||||||
clear_warnings();
|
clear_warnings();
|
||||||
@@ -13118,21 +13124,28 @@ int Plater::new_project(bool skip_confirm, bool silent, const wxString& project_
|
|||||||
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
ctx.code = Slic3r::LifecycleEvtCode::Ok;
|
||||||
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::NewProject, ctx);
|
Slic3r::fire_lifecycle_event(Slic3r::LifecycleEvent::NewProject, ctx);
|
||||||
}
|
}
|
||||||
reset(transfer_preset_changes);
|
{
|
||||||
reset_project_dirty_after_save();
|
// Same rationale as in Plater::priv::reset(): the whole reset + preset-reload +
|
||||||
reset_project_dirty_initial_presets();
|
// baseline-reset sequence below settles into its final dirty state only once it
|
||||||
wxGetApp().update_saved_preset_from_current_preset();
|
// completes, so hold notifications until then to avoid firing on transient flips.
|
||||||
update_project_dirty_from_presets();
|
ProjectDirtyStateManager::NotificationSuppressor dirty_notify_suppressor(p->dirty_state);
|
||||||
|
|
||||||
//reset project
|
reset(transfer_preset_changes);
|
||||||
p->project.reset();
|
reset_project_dirty_after_save();
|
||||||
//set project name
|
reset_project_dirty_initial_presets();
|
||||||
if (project_name.empty())
|
wxGetApp().update_saved_preset_from_current_preset();
|
||||||
p->set_project_name(_L("Untitled"));
|
update_project_dirty_from_presets();
|
||||||
else
|
|
||||||
p->set_project_name(project_name);
|
|
||||||
|
|
||||||
Plater::TakeSnapshot snapshot(this, "New Project", UndoRedo::SnapshotType::ProjectSeparator);
|
//reset project
|
||||||
|
p->project.reset();
|
||||||
|
//set project name
|
||||||
|
if (project_name.empty())
|
||||||
|
p->set_project_name(_L("Untitled"));
|
||||||
|
else
|
||||||
|
p->set_project_name(project_name);
|
||||||
|
|
||||||
|
Plater::TakeSnapshot snapshot(this, "New Project", UndoRedo::SnapshotType::ProjectSeparator);
|
||||||
|
}
|
||||||
|
|
||||||
Model m;
|
Model m;
|
||||||
model().load_from(m); // new id avoid same path name
|
model().load_from(m); // new id avoid same path name
|
||||||
@@ -18339,6 +18352,14 @@ void Plater::changed_object(ModelObject &object){
|
|||||||
|
|
||||||
// Check outside bed
|
// Check outside bed
|
||||||
get_current_canvas3D()->requires_check_outside_state();
|
get_current_canvas3D()->requires_check_outside_state();
|
||||||
|
|
||||||
|
if (!is_loading_project()) {
|
||||||
|
LifecycleEventContext ctx;
|
||||||
|
ctx.name = object.name;
|
||||||
|
ctx.id = std::to_string(object.id().id);
|
||||||
|
ctx.source = "geometry";
|
||||||
|
fire_lifecycle_event(LifecycleEvent::ObjectChanged, ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::changed_object(int obj_idx)
|
void Plater::changed_object(int obj_idx)
|
||||||
@@ -18375,6 +18396,20 @@ void Plater::changed_objects(const std::vector<size_t>& object_idxs)
|
|||||||
|
|
||||||
// update print
|
// update print
|
||||||
this->p->schedule_background_process();
|
this->p->schedule_background_process();
|
||||||
|
|
||||||
|
if (!is_loading_project()) {
|
||||||
|
for (size_t obj_idx : object_idxs) {
|
||||||
|
if (obj_idx >= p->model.objects.size() || p->model.objects[obj_idx] == nullptr)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
LifecycleEventContext ctx;
|
||||||
|
ctx.name = p->model.objects[obj_idx]->name;
|
||||||
|
ctx.id = std::to_string(p->model.objects[obj_idx]->id().id);
|
||||||
|
ctx.index = static_cast<int>(obj_idx);
|
||||||
|
ctx.source = "geometry";
|
||||||
|
fire_lifecycle_event(LifecycleEvent::ObjectChanged, ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Plater::schedule_background_process(bool schedule/* = true*/)
|
void Plater::schedule_background_process(bool schedule/* = true*/)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "MainFrame.hpp"
|
#include "MainFrame.hpp"
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
#include "Plater.hpp"
|
#include "Plater.hpp"
|
||||||
|
#include "libslic3r/LifecycleEvents.hpp"
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
|
||||||
@@ -17,13 +18,23 @@ namespace GUI {
|
|||||||
|
|
||||||
void ProjectDirtyStateManager::update_from_undo_redo_stack(bool dirty)
|
void ProjectDirtyStateManager::update_from_undo_redo_stack(bool dirty)
|
||||||
{
|
{
|
||||||
|
const bool was_dirty = is_dirty();
|
||||||
m_plater_dirty = dirty;
|
m_plater_dirty = dirty;
|
||||||
|
notify_dirty_change(was_dirty, "undo_redo");
|
||||||
if (const Plater *plater = wxGetApp().plater(); plater && wxGetApp().initialized())
|
if (const Plater *plater = wxGetApp().plater(); plater && wxGetApp().initialized())
|
||||||
wxGetApp().mainframe->update_title();
|
wxGetApp().mainframe->update_title();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProjectDirtyStateManager::set_plater_dirty(bool is_dirty)
|
||||||
|
{
|
||||||
|
const bool was_dirty = this->is_dirty();
|
||||||
|
m_plater_dirty = is_dirty;
|
||||||
|
notify_dirty_change(was_dirty, "plater");
|
||||||
|
}
|
||||||
|
|
||||||
void ProjectDirtyStateManager::update_from_presets()
|
void ProjectDirtyStateManager::update_from_presets()
|
||||||
{
|
{
|
||||||
|
const bool was_dirty = is_dirty();
|
||||||
m_presets_dirty = false;
|
m_presets_dirty = false;
|
||||||
// check switching of the presets only for exist/loaded project, but not for new
|
// check switching of the presets only for exist/loaded project, but not for new
|
||||||
GUI_App &app = wxGetApp();
|
GUI_App &app = wxGetApp();
|
||||||
@@ -45,18 +56,53 @@ void ProjectDirtyStateManager::update_from_presets()
|
|||||||
}
|
}
|
||||||
m_presets_dirty |= app.has_unsaved_preset_changes();
|
m_presets_dirty |= app.has_unsaved_preset_changes();
|
||||||
m_project_config_dirty = m_initial_project_config != app.preset_bundle->project_config;
|
m_project_config_dirty = m_initial_project_config != app.preset_bundle->project_config;
|
||||||
|
notify_dirty_change(was_dirty, "presets");
|
||||||
app.mainframe->update_title();
|
app.mainframe->update_title();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProjectDirtyStateManager::reset_after_save()
|
void ProjectDirtyStateManager::reset_after_save()
|
||||||
{
|
{
|
||||||
|
const bool was_dirty = is_dirty();
|
||||||
this->reset_initial_presets();
|
this->reset_initial_presets();
|
||||||
m_plater_dirty = false;
|
m_plater_dirty = false;
|
||||||
m_presets_dirty = false;
|
m_presets_dirty = false;
|
||||||
m_project_config_dirty = false;
|
m_project_config_dirty = false;
|
||||||
|
notify_dirty_change(was_dirty, "save");
|
||||||
wxGetApp().mainframe->update_title();
|
wxGetApp().mainframe->update_title();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProjectDirtyStateManager::notify_dirty_change(bool was_dirty, const char *source)
|
||||||
|
{
|
||||||
|
if (m_suppress_depth > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const bool dirty = is_dirty();
|
||||||
|
if (was_dirty == dirty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LifecycleEventContext ctx;
|
||||||
|
ctx.code = LifecycleEvtCode::Ok;
|
||||||
|
ctx.dirty = dirty;
|
||||||
|
ctx.source = source;
|
||||||
|
fire_lifecycle_event(LifecycleEvent::ProjectDirtyChanged, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectDirtyStateManager::begin_suppress_notifications()
|
||||||
|
{
|
||||||
|
if (m_suppress_depth == 0)
|
||||||
|
m_suppress_entry_dirty = is_dirty();
|
||||||
|
++m_suppress_depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectDirtyStateManager::end_suppress_notifications()
|
||||||
|
{
|
||||||
|
assert(m_suppress_depth > 0);
|
||||||
|
if (m_suppress_depth > 0)
|
||||||
|
--m_suppress_depth;
|
||||||
|
if (m_suppress_depth == 0)
|
||||||
|
notify_dirty_change(m_suppress_entry_dirty, "batch");
|
||||||
|
}
|
||||||
|
|
||||||
void ProjectDirtyStateManager::reset_initial_presets()
|
void ProjectDirtyStateManager::reset_initial_presets()
|
||||||
{
|
{
|
||||||
m_initial_presets.fill(std::string{});
|
m_initial_presets.fill(std::string{});
|
||||||
@@ -168,4 +214,3 @@ void ProjectDirtyStateManager::render_debug_window() const
|
|||||||
|
|
||||||
} // namespace GUI
|
} // namespace GUI
|
||||||
} // namespace Slic3r
|
} // namespace Slic3r
|
||||||
|
|
||||||
|
|||||||
@@ -14,21 +14,42 @@ public:
|
|||||||
void reset_after_save();
|
void reset_after_save();
|
||||||
void reset_initial_presets();
|
void reset_initial_presets();
|
||||||
|
|
||||||
void set_plater_dirty(bool is_dirty) { m_plater_dirty = is_dirty; }
|
void set_plater_dirty(bool is_dirty);
|
||||||
bool is_dirty() const { return m_plater_dirty || m_project_config_dirty || m_presets_dirty; }
|
bool is_dirty() const { return m_plater_dirty || m_project_config_dirty || m_presets_dirty; }
|
||||||
bool is_presets_dirty() const { return m_presets_dirty; }
|
bool is_presets_dirty() const { return m_presets_dirty; }
|
||||||
|
|
||||||
|
// RAII guard coalescing dirty-state updates: while any guard is alive, ProjectDirtyChanged
|
||||||
|
// notifications are held back; when the outermost guard is destroyed, at most one
|
||||||
|
// notification fires, reflecting only the net change across the whole guarded scope.
|
||||||
|
class NotificationSuppressor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit NotificationSuppressor(ProjectDirtyStateManager &owner) : m_owner(owner) { m_owner.begin_suppress_notifications(); }
|
||||||
|
~NotificationSuppressor() { m_owner.end_suppress_notifications(); }
|
||||||
|
NotificationSuppressor(const NotificationSuppressor &) = delete;
|
||||||
|
NotificationSuppressor &operator=(const NotificationSuppressor &) = delete;
|
||||||
|
private:
|
||||||
|
ProjectDirtyStateManager &m_owner;
|
||||||
|
};
|
||||||
|
|
||||||
#if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW
|
#if ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW
|
||||||
void render_debug_window() const;
|
void render_debug_window() const;
|
||||||
#endif // ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW
|
#endif // ENABLE_PROJECT_DIRTY_STATE_DEBUG_WINDOW
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void notify_dirty_change(bool was_dirty, const char *source);
|
||||||
|
void begin_suppress_notifications();
|
||||||
|
void end_suppress_notifications();
|
||||||
|
|
||||||
// Does the Undo / Redo stack indicate the project is dirty?
|
// Does the Undo / Redo stack indicate the project is dirty?
|
||||||
bool m_plater_dirty { false };
|
bool m_plater_dirty { false };
|
||||||
// Do the presets indicate the project is dirty?
|
// Do the presets indicate the project is dirty?
|
||||||
bool m_presets_dirty { false };
|
bool m_presets_dirty { false };
|
||||||
// Is the project config dirty?
|
// Is the project config dirty?
|
||||||
bool m_project_config_dirty { false };
|
bool m_project_config_dirty { false };
|
||||||
|
// NotificationSuppressor nesting depth and the dirty state observed when the outermost guard began.
|
||||||
|
int m_suppress_depth { 0 };
|
||||||
|
bool m_suppress_entry_dirty { false };
|
||||||
// Keeps track of preset names selected at the time of last project save.
|
// Keeps track of preset names selected at the time of last project save.
|
||||||
std::array<std::string, Preset::TYPE_COUNT> m_initial_presets;
|
std::array<std::string, Preset::TYPE_COUNT> m_initial_presets;
|
||||||
DynamicPrintConfig m_initial_project_config;
|
DynamicPrintConfig m_initial_project_config;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "TaskManager.hpp"
|
#include "TaskManager.hpp"
|
||||||
|
|
||||||
#include "libslic3r/Thread.hpp"
|
#include "libslic3r/Thread.hpp"
|
||||||
|
#include "libslic3r/LifecycleEvents.hpp"
|
||||||
#include "nlohmann/json.hpp"
|
#include "nlohmann/json.hpp"
|
||||||
#include "MainFrame.hpp"
|
#include "MainFrame.hpp"
|
||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
@@ -210,6 +211,13 @@ int TaskManager::schedule(TaskStateInfo* task)
|
|||||||
assert(task->state() == TaskState::TS_PENDING);
|
assert(task->state() == TaskState::TS_PENDING);
|
||||||
task->set_state(TaskState::TS_SENDING);
|
task->set_state(TaskState::TS_SENDING);
|
||||||
|
|
||||||
|
LifecycleEventContext start_ctx;
|
||||||
|
start_ctx.name = task->params().project_name;
|
||||||
|
start_ctx.device_id = task->params().dev_id;
|
||||||
|
start_ctx.job_id = std::to_string(task->task_info_id);
|
||||||
|
start_ctx.source = "task_manager";
|
||||||
|
fire_lifecycle_event(LifecycleEvent::PrintJobStarted, start_ctx);
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(trace) << "task_manager: schedule a task to dev_id = " << task->params().dev_id;
|
BOOST_LOG_TRIVIAL(trace) << "task_manager: schedule a task to dev_id = " << task->params().dev_id;
|
||||||
boost::thread* new_sending_thread = new boost::thread();
|
boost::thread* new_sending_thread = new boost::thread();
|
||||||
*new_sending_thread = Slic3r::create_thread(
|
*new_sending_thread = Slic3r::create_thread(
|
||||||
@@ -238,6 +246,16 @@ int TaskManager::schedule(TaskStateInfo* task)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LifecycleEventContext finish_ctx;
|
||||||
|
finish_ctx.name = task->params().project_name;
|
||||||
|
finish_ctx.device_id = task->params().dev_id;
|
||||||
|
finish_ctx.job_id = std::to_string(task->task_info_id);
|
||||||
|
finish_ctx.source = "task_manager";
|
||||||
|
finish_ctx.code = result == 0 ? LifecycleEvtCode::Ok :
|
||||||
|
(task->is_canceled() ? LifecycleEvtCode::Warn : LifecycleEvtCode::Error);
|
||||||
|
finish_ctx.msg = result == 0 ? "" : (task->is_canceled() ? "cancelled" : "failed");
|
||||||
|
fire_lifecycle_event(LifecycleEvent::PrintJobFinished, finish_ctx);
|
||||||
|
|
||||||
/* remove from sending task list */
|
/* remove from sending task list */
|
||||||
m_scedule_mutex.lock();
|
m_scedule_mutex.lock();
|
||||||
auto it = std::find(m_scedule_list.begin(), m_scedule_list.end(), task);
|
auto it = std::find(m_scedule_list.begin(), m_scedule_list.end(), task);
|
||||||
|
|||||||
@@ -345,6 +345,7 @@ void bind_python_api(pybind11::module_& m)
|
|||||||
.value("ProjectBeforeSave", LifecycleEvent::ProjectBeforeSave)
|
.value("ProjectBeforeSave", LifecycleEvent::ProjectBeforeSave)
|
||||||
.value("ProjectAfterSave", LifecycleEvent::ProjectAfterSave)
|
.value("ProjectAfterSave", LifecycleEvent::ProjectAfterSave)
|
||||||
.value("ProjectClosed", LifecycleEvent::ProjectClosed)
|
.value("ProjectClosed", LifecycleEvent::ProjectClosed)
|
||||||
|
.value("ProjectDirtyChanged", LifecycleEvent::ProjectDirtyChanged)
|
||||||
.value("SliceStarted", LifecycleEvent::SliceStarted)
|
.value("SliceStarted", LifecycleEvent::SliceStarted)
|
||||||
.value("SliceGeometryFinished", LifecycleEvent::SliceGeometryFinished)
|
.value("SliceGeometryFinished", LifecycleEvent::SliceGeometryFinished)
|
||||||
.value("GCodeExportStarted", LifecycleEvent::GCodeExportStarted)
|
.value("GCodeExportStarted", LifecycleEvent::GCodeExportStarted)
|
||||||
@@ -353,6 +354,12 @@ void bind_python_api(pybind11::module_& m)
|
|||||||
.value("ObjectAdded", LifecycleEvent::ObjectAdded)
|
.value("ObjectAdded", LifecycleEvent::ObjectAdded)
|
||||||
.value("ObjectDeleted", LifecycleEvent::ObjectDeleted)
|
.value("ObjectDeleted", LifecycleEvent::ObjectDeleted)
|
||||||
.value("ObjectTransformed", LifecycleEvent::ObjectTransformed)
|
.value("ObjectTransformed", LifecycleEvent::ObjectTransformed)
|
||||||
|
.value("ObjectChanged", LifecycleEvent::ObjectChanged)
|
||||||
|
.value("ObjectRenamed", LifecycleEvent::ObjectRenamed)
|
||||||
|
.value("PlateCreated", LifecycleEvent::PlateCreated)
|
||||||
|
.value("PlateDeleted", LifecycleEvent::PlateDeleted)
|
||||||
|
.value("PlateSelected", LifecycleEvent::PlateSelected)
|
||||||
|
.value("PlateRenamed", LifecycleEvent::PlateRenamed)
|
||||||
.value("PresetSelected", LifecycleEvent::PresetSelected)
|
.value("PresetSelected", LifecycleEvent::PresetSelected)
|
||||||
.value("PresetSaved", LifecycleEvent::PresetSaved)
|
.value("PresetSaved", LifecycleEvent::PresetSaved)
|
||||||
.value("PrintStateChanged", LifecycleEvent::PrintStateChanged)
|
.value("PrintStateChanged", LifecycleEvent::PrintStateChanged)
|
||||||
@@ -363,6 +370,10 @@ void bind_python_api(pybind11::module_& m)
|
|||||||
.value("DeviceDisconnected", LifecycleEvent::DeviceDisconnected)
|
.value("DeviceDisconnected", LifecycleEvent::DeviceDisconnected)
|
||||||
.value("UploadStarted", LifecycleEvent::UploadStarted)
|
.value("UploadStarted", LifecycleEvent::UploadStarted)
|
||||||
.value("UploadFinished", LifecycleEvent::UploadFinished)
|
.value("UploadFinished", LifecycleEvent::UploadFinished)
|
||||||
|
.value("PrintJobStarted", LifecycleEvent::PrintJobStarted)
|
||||||
|
.value("PrintJobFinished", LifecycleEvent::PrintJobFinished)
|
||||||
|
.value("SendJobStarted", LifecycleEvent::SendJobStarted)
|
||||||
|
.value("SendJobFinished", LifecycleEvent::SendJobFinished)
|
||||||
.export_values();
|
.export_values();
|
||||||
|
|
||||||
py::enum_<LifecycleEvtCode>(m, "LifecycleEvtCode", "Outcome code accompanying a LifecycleEventContext")
|
py::enum_<LifecycleEvtCode>(m, "LifecycleEvtCode", "Outcome code accompanying a LifecycleEventContext")
|
||||||
@@ -375,7 +386,14 @@ void bind_python_api(pybind11::module_& m)
|
|||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def_readonly("name", &LifecycleEventContext::name)
|
.def_readonly("name", &LifecycleEventContext::name)
|
||||||
.def_readonly("code", &LifecycleEventContext::code)
|
.def_readonly("code", &LifecycleEventContext::code)
|
||||||
.def_readonly("msg", &LifecycleEventContext::msg);
|
.def_readonly("msg", &LifecycleEventContext::msg)
|
||||||
|
.def_readonly("id", &LifecycleEventContext::id)
|
||||||
|
.def_readonly("previous_name", &LifecycleEventContext::previous_name)
|
||||||
|
.def_readonly("device_id", &LifecycleEventContext::device_id)
|
||||||
|
.def_readonly("job_id", &LifecycleEventContext::job_id)
|
||||||
|
.def_readonly("source", &LifecycleEventContext::source)
|
||||||
|
.def_readonly("index", &LifecycleEventContext::index)
|
||||||
|
.def_readonly("dirty", &LifecycleEventContext::dirty);
|
||||||
|
|
||||||
py::class_<PluginContext>(m, "PluginContext", "Context shared with plugin entry points")
|
py::class_<PluginContext>(m, "PluginContext", "Context shared with plugin entry points")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
|
|||||||
Reference in New Issue
Block a user