mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-26 10:21:00 +00:00
Merge branch 'main' into feature/update_wipetower
This commit is contained in:
@@ -88,6 +88,10 @@ if (SLIC3R_GUI)
|
||||
list(FILTER wxWidgets_LIBRARIES EXCLUDE REGEX OpenGL)
|
||||
|
||||
# list(REMOVE_ITEM wxWidgets_LIBRARIES oleacc)
|
||||
|
||||
find_package(wxInspector REQUIRED)
|
||||
list(APPEND wxWidgets_LIBRARIES "wxInspector::wxInspector")
|
||||
|
||||
message(STATUS "wx libs: ${wxWidgets_LIBRARIES}")
|
||||
|
||||
add_subdirectory(slic3r)
|
||||
|
||||
+18
-3
@@ -5685,10 +5685,17 @@ LayerResult GCode::process_layer(
|
||||
for (const auto &layer_to_print : layers) {
|
||||
if (layer_to_print.object_layer) {
|
||||
const auto& regions = layer_to_print.object_layer->regions();
|
||||
const bool enable_overhang_speed = std::any_of(regions.begin(), regions.end(), [this](const LayerRegion* r) {
|
||||
const bool has_extrusions = std::any_of(regions.begin(), regions.end(), [](const LayerRegion* r) {
|
||||
return r->has_extrusions();
|
||||
});
|
||||
const bool enable_overhang_speed = std::any_of(regions.begin(), regions.end(), [this](const LayerRegion* r) {
|
||||
return r->has_extrusions() && r->region().config().enable_overhang_speed.get_at(get_nozzle_config_index(m_writer.filament()->id()));
|
||||
});
|
||||
if (enable_overhang_speed) {
|
||||
const bool enable_overhang_fan = m_enable_cooling_markers && has_extrusions &&
|
||||
std::any_of(m_config.enable_overhang_bridge_fan.values.begin(),
|
||||
m_config.enable_overhang_bridge_fan.values.end(),
|
||||
[](unsigned char value) { return value != 0; });
|
||||
if (enable_overhang_speed || enable_overhang_fan) {
|
||||
m_extrusion_quality_estimator.prepare_for_new_layer(layer_to_print.original_object,
|
||||
layer_to_print.object_layer);
|
||||
}
|
||||
@@ -7527,7 +7534,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
bool variable_speed = false;
|
||||
std::vector<ProcessedPoint> new_points {};
|
||||
|
||||
if (NOZZLE_CONFIG(enable_overhang_speed) && !this->on_first_layer() && !object_layer_over_raft() &&
|
||||
const bool need_overhang_detection = NOZZLE_CONFIG(enable_overhang_speed) ||
|
||||
(FILAMENT_CONFIG(enable_overhang_bridge_fan) && m_enable_cooling_markers);
|
||||
|
||||
if (need_overhang_detection && !this->on_first_layer() && !object_layer_over_raft() &&
|
||||
(is_bridge(path.role()) || is_perimeter(path.role()))) {
|
||||
bool is_external = is_external_perimeter(path.role());
|
||||
double ref_speed = is_external ? NOZZLE_CONFIG(outer_wall_speed) : NOZZLE_CONFIG(inner_wall_speed);
|
||||
@@ -7586,6 +7596,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, std::string description,
|
||||
}
|
||||
variable_speed = std::any_of(new_points.begin(), new_points.end(),
|
||||
[speed](const ProcessedPoint &p) { return fabs(double(p.speed) - speed) > 1; }); // Ignore small speed variations (under 1mm/sec)
|
||||
if (!NOZZLE_CONFIG(enable_overhang_speed) && FILAMENT_CONFIG(enable_overhang_bridge_fan) && m_enable_cooling_markers) {
|
||||
for (ProcessedPoint &point : new_points)
|
||||
point.speed = speed;
|
||||
variable_speed = new_points.size() > 1;
|
||||
}
|
||||
}
|
||||
|
||||
double F = speed * 60; // convert mm/sec to mm/min
|
||||
|
||||
@@ -844,7 +844,10 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
ironing_fan_control = false; // ORCA: Add support for ironing fan speed control
|
||||
ironing_fan_speed = 0; // ORCA: Add support for ironing fan speed control
|
||||
}
|
||||
if (fan_speed_new != m_fan_speed) {
|
||||
// A tool change may keep the same configured base fan speed while the physical fan is
|
||||
// still running at the previous filament's overhang speed. Restore the base speed before
|
||||
// emitting G-code for the new tool in that case.
|
||||
if (fan_speed_new != m_fan_speed || (immediately_apply && m_current_fan_speed != fan_speed_new)) {
|
||||
m_fan_speed = fan_speed_new;
|
||||
m_current_fan_speed = fan_speed_new;
|
||||
if (immediately_apply)
|
||||
@@ -1040,8 +1043,10 @@ std::string CoolingBuffer::apply_layer_cooldown(
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_current_fan_speed, part_cooling_fan_min_pwm);
|
||||
fan_speed_change_requests[CoolingLine::TYPE_FORCE_RESUME_FAN] = false;
|
||||
}
|
||||
else
|
||||
else {
|
||||
new_gcode += GCodeWriter::set_fan(m_config.gcode_flavor, m_fan_speed, part_cooling_fan_min_pwm);
|
||||
m_current_fan_speed = m_fan_speed;
|
||||
}
|
||||
need_set_fan = false;
|
||||
}
|
||||
pos = line_end;
|
||||
|
||||
@@ -51,4 +51,9 @@
|
||||
// Enable extension of tool position imgui dialog to show actual speed profile
|
||||
#define ENABLE_ACTUAL_SPEED_DEBUG 1
|
||||
|
||||
// Disable layout inspector for public release
|
||||
#if BBL_RELEASE_TO_PUBLIC
|
||||
#define WXINSPECTOR_DISABLE
|
||||
#endif
|
||||
|
||||
#endif // _prusaslicer_technologies_h_
|
||||
|
||||
@@ -752,6 +752,11 @@ set(SLIC3R_GUI_SOURCES
|
||||
Utils/WxFontUtils.hpp
|
||||
Utils/FileTransferUtils.cpp
|
||||
Utils/FileTransferUtils.hpp
|
||||
Utils/wxInspectorPlugins/DPIAwarePlugin.hpp
|
||||
Utils/wxInspectorPlugins/DPIAwarePlugin.cpp
|
||||
Utils/wxInspectorPlugins/CustomWidgetsPlugin.hpp
|
||||
Utils/wxInspectorPlugins/CustomWidgetsPlugin.cpp
|
||||
Utils/wxInspectorPlugins/Registration.hpp
|
||||
)
|
||||
|
||||
add_subdirectory(GUI/DeviceCore)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
#include "../Utils/PresetUpdater.hpp"
|
||||
#include "../Utils/PrintHost.hpp"
|
||||
#include "../Utils/Process.hpp"
|
||||
#include "../Utils/wxInspectorPlugins/Registration.hpp"
|
||||
#include "../Utils/MacDarkMode.hpp"
|
||||
#include "../Utils/Http.hpp"
|
||||
#include "../Utils/InstanceID.hpp"
|
||||
@@ -2835,6 +2836,9 @@ bool GUI_App::on_init_inner()
|
||||
|
||||
::Label::initSysFont();
|
||||
|
||||
// Register wxInspector plugins for Orca custom controls
|
||||
RegisterOrcaInspectorPlugins();
|
||||
|
||||
// Set initialization of image handlers before any UI actions - See GH issue #7469
|
||||
wxInitAllImageHandlers();
|
||||
#ifdef NDEBUG
|
||||
@@ -3704,13 +3708,13 @@ bool GUI_App::on_init_network(bool try_backup)
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << ": on_init_network, load dll failed";
|
||||
// A failed install can leave the config naming a build that never made it to
|
||||
// disk (download_plugin() adopts the downloaded version up front so that
|
||||
// install_plugin() can name the library after it). If the whitelisted latest
|
||||
// is still installed, fall back to it instead of dropping the user into the
|
||||
// re-download flow without networking.
|
||||
// A failed install can leave the config naming a build that never made it to disk;
|
||||
// fall back to the installed latest instead of dropping the user into the re-download
|
||||
// flow. Only when the configured library is genuinely absent, though - a pinned series
|
||||
// that is on disk but failed to load once must keep its pin, not be rewritten for good.
|
||||
std::string latest = get_latest_network_version();
|
||||
if (config_version != latest && BBLNetworkPlugin::versioned_library_exists(latest)) {
|
||||
if (config_version != latest && !BBLNetworkPlugin::versioned_library_exists(config_version)
|
||||
&& BBLNetworkPlugin::versioned_library_exists(latest)) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": falling back to installed " << latest;
|
||||
config_version = latest;
|
||||
app_config->set_network_plugin_version(latest);
|
||||
@@ -3814,7 +3818,14 @@ bool GUI_App::on_init_network(bool try_backup)
|
||||
m_user_manager = new Slic3r::UserManager();
|
||||
}
|
||||
|
||||
if (should_load_networking_plugin && m_networking_compatible && !use_legacy_network_plugin()) {
|
||||
// A version pinned to something other than the latest series is a deliberate choice, so it
|
||||
// is exempt from the upgrade prompt the same way the legacy pin already is - otherwise the
|
||||
// dialog reappears on every launch for as long as the pin is held.
|
||||
const std::string pinned_version = app_config->get_network_plugin_version();
|
||||
const bool pinned_to_older_series = !pinned_version.empty() &&
|
||||
network_plugin_series(pinned_version) != network_plugin_series(get_latest_network_version());
|
||||
|
||||
if (should_load_networking_plugin && m_networking_compatible && !pinned_to_older_series) {
|
||||
app_config->clear_remind_network_update_later();
|
||||
|
||||
if (has_network_update_available()) {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <wx/settings.h>
|
||||
#include <wx/dataview.h>
|
||||
#include <wx/statbox.h>
|
||||
#include <wx/inspector/inspector.h>
|
||||
|
||||
#include <chrono>
|
||||
#include "Event.hpp"
|
||||
@@ -88,7 +89,7 @@ void update_dark_ui(wxWindow* window);
|
||||
|
||||
extern std::deque<wxDialog*> dialogStack;
|
||||
|
||||
template<class P> class DPIAware : public P
|
||||
template<class P> class DPIAware : public P, public wxInspector::wxInspectable
|
||||
{
|
||||
public:
|
||||
DPIAware(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &pos=wxDefaultPosition,
|
||||
@@ -107,6 +108,7 @@ public:
|
||||
this->SetFont(m_normal_font);
|
||||
#endif
|
||||
this->CenterOnParent();
|
||||
SetupInspectorAccelerator(this);
|
||||
#ifdef _WIN32
|
||||
update_dark_ui(this);
|
||||
#endif
|
||||
@@ -182,6 +184,11 @@ public:
|
||||
|
||||
float scale_factor() const { return m_scale_factor; }
|
||||
float prev_scale_factor() const { return m_prev_scale_factor; }
|
||||
// Only meant to be used by inspector, not public API
|
||||
void set_scale_factor(float v) { m_scale_factor = v; }
|
||||
void set_prev_scale_factor(float v) { m_prev_scale_factor = v; }
|
||||
void set_em_unit(int v) { m_em_unit = v; }
|
||||
bool force_rescale() const { return m_force_rescale; }
|
||||
|
||||
int em_unit() const { return m_em_unit; }
|
||||
// int font_size() const { return m_font_size; }
|
||||
|
||||
@@ -739,7 +739,7 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, BORDERLESS_FRAME_
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.CmdDown() && evt.GetKeyCode() == 'I') {
|
||||
if (evt.CmdDown() && evt.GetKeyCode() == 'I' && !evt.ShiftDown()) {
|
||||
if (!can_add_models()) return;
|
||||
if (m_plater) { m_plater->add_file(); }
|
||||
return;
|
||||
|
||||
@@ -4552,6 +4552,9 @@ int PartPlateList::create_plate(bool adjust_position)
|
||||
return -1;
|
||||
int cols = compute_colum_count(new_index + 1);
|
||||
int old_cols = compute_colum_count(new_index);
|
||||
// Orca: Rebuild plate membership before moving instances during a grid reflow.
|
||||
if (adjust_position && old_cols != cols)
|
||||
reload_all_objects();
|
||||
|
||||
origin = compute_origin(new_index, cols);
|
||||
plate = new PartPlate(this, origin, m_plate_width, m_plate_depth, m_plate_height, m_plater, m_model, true, printer_technology);
|
||||
@@ -5041,6 +5044,9 @@ int PartPlateList::move_plate_to_index(int old_index, int new_index)
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Orca: Rebuild plate membership before moving the plates.
|
||||
reload_all_objects();
|
||||
|
||||
if (old_index < new_index)
|
||||
{
|
||||
delta = 1;
|
||||
|
||||
@@ -8000,7 +8000,9 @@ void Tab::update_extruder_variants(int extruder_id, bool reload)
|
||||
m_actual_nozzle_volumes.resize(extruder_nums, NozzleVolumeType::nvtStandard);
|
||||
for (int i = 0; i < extruder_nums; i++) m_actual_nozzle_volumes[i] = (NozzleVolumeType)nozzle_volumes->values[i];
|
||||
|
||||
if (extruder_nums == 2) {
|
||||
// Orca: a non-Bambu dual-nozzle printer has two extruders but a single variant column, so
|
||||
// the nozzle switch and sync button have nothing to act on. Only enable with real variants.
|
||||
if (extruder_nums == 2 && m_preset_bundle->support_different_extruders()) {
|
||||
auto options = generate_extruder_options();
|
||||
m_extruder_switch->SetOptions(options);
|
||||
|
||||
|
||||
@@ -77,6 +77,11 @@ public:
|
||||
|
||||
void SetSelected(bool selected = true) { m_selected = selected; }
|
||||
|
||||
// Only meant to be used by inspector, not public API
|
||||
ButtonStyle GetStyle() const { return m_style; }
|
||||
ButtonType GetType() const { return m_type; }
|
||||
bool IsSelected() const { return m_selected; }
|
||||
|
||||
bool Enable(bool enable = true) override;
|
||||
void EnableTooltipEvenDisabled();// The tip will be shown even if the button is disabled
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@ public:
|
||||
|
||||
void SetHalfChecked(bool value = true);
|
||||
|
||||
// Only meant to be used by inspector, not public API
|
||||
bool IsHalfChecked() const { return m_half_checked; }
|
||||
|
||||
void Rescale();
|
||||
|
||||
#ifdef __WXOSX__
|
||||
|
||||
@@ -46,6 +46,12 @@ public:
|
||||
|
||||
bool Enable(bool enable) override;
|
||||
|
||||
// Only meant to be used by inspector, not public API
|
||||
int GetCornerRadius() const { return m_radius; }
|
||||
int GetBorderWidth() const { return m_border_width; }
|
||||
StateColor GetBorderColor() const { return border_color; }
|
||||
float GetScale() const { return m_scale; }
|
||||
|
||||
private:
|
||||
void PickDC(wxDC& dc);
|
||||
|
||||
|
||||
@@ -43,6 +43,9 @@ public:
|
||||
|
||||
void SetCornerRadius(double radius);
|
||||
|
||||
// Only meant to be used by inspector, not public API
|
||||
int GetCornerRadius() const { return static_cast<int>(radius); }
|
||||
|
||||
void SetLabel(const wxString& label);
|
||||
|
||||
void SetStaticTips(const wxString& tips, const wxBitmap& bitmap);
|
||||
|
||||
@@ -602,6 +602,12 @@ WXLRESULT wxMediaCtrl2::MSWWindowProc(WXUINT nMsg,
|
||||
WXWPARAM wParam,
|
||||
WXLPARAM lParam)
|
||||
{
|
||||
// The stream source sends WM_USER+1000 with a synchronous SendMessage from its own threads,
|
||||
// so this runs re-entrantly on the UI thread at whatever message-retrieval point the player
|
||||
// happens to be in - often nested inside an Orca log statement. Never BOOST_LOG_TRIVIAL here:
|
||||
// boost::log is not re-entrant on one thread, and doing so corrupted its per-thread record
|
||||
// state, crashing later in unrelated places (the player, the log filter, a plug-in heap free).
|
||||
// Post the string out (as the stat branch does) and log it on a clean stack instead.
|
||||
if (nMsg == WM_USER + 1000) {
|
||||
wxString msg((wchar_t const *) lParam);
|
||||
if (wParam == 1) {
|
||||
@@ -619,7 +625,6 @@ WXLRESULT wxMediaCtrl2::MSWWindowProc(WXUINT nMsg,
|
||||
wxPostEvent(this, evt);
|
||||
}
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(trace) << msg.ToUTF8().data();
|
||||
return 0;
|
||||
}
|
||||
return wxMediaCtrl::MSWWindowProc(nMsg, wParam, lParam);
|
||||
|
||||
@@ -17,6 +17,20 @@ namespace Slic3r {
|
||||
|
||||
#define BAMBU_SOURCE_LIBRARY "BambuSource"
|
||||
|
||||
namespace {
|
||||
|
||||
// Named in the load log: the bound generation is what ties a crash report to an ABI choice.
|
||||
// The label is the whitelist row's series, so it can never drift from the dispatch table.
|
||||
const char* network_abi_name(NetworkAbi abi)
|
||||
{
|
||||
for (size_t i = 0; i < AVAILABLE_NETWORK_VERSIONS_COUNT; ++i)
|
||||
if (AVAILABLE_NETWORK_VERSIONS[i].abi == abi)
|
||||
return AVAILABLE_NETWORK_VERSIONS[i].version;
|
||||
return "unsupported";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// ============================================================================
|
||||
// Singleton Implementation
|
||||
// ============================================================================
|
||||
@@ -162,19 +176,20 @@ int BBLNetworkPlugin::initialize(bool using_backup, const std::string& version)
|
||||
// Load all function pointers
|
||||
load_all_function_pointers();
|
||||
|
||||
// Sync legacy network flag from loaded plugin
|
||||
m_use_legacy_network = is_legacy_version(version);
|
||||
// Key the generation on the library that actually loaded, not the version asked for:
|
||||
// resolve_library_path() serves any same-series build. m_get_version is read directly, not
|
||||
// via get_version(), which would substitute the "00.00.00.00" sentinel and pick no generation.
|
||||
const std::string loaded_version = m_get_version ? m_get_version() : std::string();
|
||||
m_network_abi = network_plugin_abi(loaded_version.empty() ? version : loaded_version);
|
||||
|
||||
std::string loaded_version;
|
||||
if (m_get_version) {
|
||||
loaded_version = m_get_version();
|
||||
if (!loaded_version.empty()) {
|
||||
m_use_legacy_network = is_legacy_version(loaded_version);
|
||||
}
|
||||
// A library reporting a series this build has no ABI for stays loaded but uncallable -
|
||||
// check_networking_version() then reports it as incompatible and offers the update flow.
|
||||
if (m_network_abi == NetworkAbi::Unsupported) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "BBLNetworkPlugin::initialize: no ABI for version "
|
||||
<< (loaded_version.empty() ? version : loaded_version) << ", plug-in calls are disabled";
|
||||
}
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "BBLNetworkPlugin::initialize: legacy_mode="
|
||||
<< (m_use_legacy_network ? "true" : "false")
|
||||
BOOST_LOG_TRIVIAL(info) << "BBLNetworkPlugin::initialize: abi=" << network_abi_name(m_network_abi)
|
||||
<< ", library=" << library
|
||||
<< ", version=" << (loaded_version.empty() ? "unknown" : loaded_version)
|
||||
<< ", send_message=" << (m_send_message ? "loaded" : "null")
|
||||
@@ -217,7 +232,9 @@ int BBLNetworkPlugin::unload()
|
||||
|
||||
clear_all_function_pointers();
|
||||
|
||||
m_use_legacy_network = false;
|
||||
// Safe to reset only because every pointer was nulled just above and every dispatcher is
|
||||
// guarded on a non-null pointer, so no stale generation is reachable.
|
||||
m_network_abi = NetworkAbi::Unsupported;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -520,7 +537,7 @@ void BBLNetworkPlugin::set_load_error(const std::string& message,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Legacy Helper
|
||||
// ABI Conversion Helpers
|
||||
// ============================================================================
|
||||
|
||||
PrintParams_Legacy BBLNetworkPlugin::as_legacy(PrintParams& param)
|
||||
@@ -564,6 +581,57 @@ PrintParams_Legacy BBLNetworkPlugin::as_legacy(PrintParams& param)
|
||||
return l;
|
||||
}
|
||||
|
||||
// Every PrintParams field except the four the 02.08.01 series added
|
||||
// (task_timelapse_use_internal, extruder_cali_manual_mode, svc_context, slicer_uid).
|
||||
PrintParams_0203 BBLNetworkPlugin::as_0203(PrintParams& param)
|
||||
{
|
||||
PrintParams_0203 p;
|
||||
|
||||
p.dev_id = std::move(param.dev_id);
|
||||
p.task_name = std::move(param.task_name);
|
||||
p.project_name = std::move(param.project_name);
|
||||
p.preset_name = std::move(param.preset_name);
|
||||
p.filename = std::move(param.filename);
|
||||
p.config_filename = std::move(param.config_filename);
|
||||
p.plate_index = param.plate_index;
|
||||
p.ftp_folder = std::move(param.ftp_folder);
|
||||
p.ftp_file = std::move(param.ftp_file);
|
||||
p.ftp_file_md5 = std::move(param.ftp_file_md5);
|
||||
p.nozzle_mapping = std::move(param.nozzle_mapping);
|
||||
p.ams_mapping = std::move(param.ams_mapping);
|
||||
p.ams_mapping2 = std::move(param.ams_mapping2);
|
||||
p.ams_mapping_info = std::move(param.ams_mapping_info);
|
||||
p.nozzles_info = std::move(param.nozzles_info);
|
||||
p.connection_type = std::move(param.connection_type);
|
||||
p.comments = std::move(param.comments);
|
||||
p.origin_profile_id = param.origin_profile_id;
|
||||
p.stl_design_id = param.stl_design_id;
|
||||
p.origin_model_id = std::move(param.origin_model_id);
|
||||
p.print_type = std::move(param.print_type);
|
||||
p.dst_file = std::move(param.dst_file);
|
||||
p.dev_name = std::move(param.dev_name);
|
||||
p.dev_ip = std::move(param.dev_ip);
|
||||
p.use_ssl_for_ftp = param.use_ssl_for_ftp;
|
||||
p.use_ssl_for_mqtt = param.use_ssl_for_mqtt;
|
||||
p.username = std::move(param.username);
|
||||
p.password = std::move(param.password);
|
||||
p.task_bed_leveling = param.task_bed_leveling;
|
||||
p.task_flow_cali = param.task_flow_cali;
|
||||
p.task_vibration_cali = param.task_vibration_cali;
|
||||
p.task_layer_inspect = param.task_layer_inspect;
|
||||
p.task_record_timelapse = param.task_record_timelapse;
|
||||
p.task_use_ams = param.task_use_ams;
|
||||
p.task_bed_type = std::move(param.task_bed_type);
|
||||
p.extra_options = std::move(param.extra_options);
|
||||
p.auto_bed_leveling = param.auto_bed_leveling;
|
||||
p.auto_flow_cali = param.auto_flow_cali;
|
||||
p.auto_offset_cali = param.auto_offset_cali;
|
||||
p.task_ext_change_assist = param.task_ext_change_assist;
|
||||
p.try_emmc_print = param.try_emmc_print;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Function Pointer Loading
|
||||
// ============================================================================
|
||||
@@ -669,7 +737,8 @@ void BBLNetworkPlugin::load_all_function_pointers()
|
||||
m_get_mw_user_preference = reinterpret_cast<func_get_mw_user_preference>(get_function("bambu_network_get_mw_user_preference"));
|
||||
m_get_mw_user_4ulist = reinterpret_cast<func_get_mw_user_4ulist>(get_function("bambu_network_get_mw_user_4ulist"));
|
||||
|
||||
// Added by the 02.08.01.52 plugin ABI; resolve to null on older plugins so callers no-op.
|
||||
// Bound late; anything a generation does not export resolves to null so callers no-op.
|
||||
// See the typedefs for which generation introduced each of these.
|
||||
m_set_on_user_login_fn = reinterpret_cast<func_set_on_user_login_fn>(get_function("bambu_network_set_on_user_login_fn"));
|
||||
m_get_studio_info_url = reinterpret_cast<func_get_studio_info_url>(get_function("bambu_network_get_studio_info_url"));
|
||||
m_report_consent = reinterpret_cast<func_report_consent>(get_function("bambu_network_report_consent"));
|
||||
|
||||
@@ -119,7 +119,7 @@ typedef int (*func_get_model_mall_rating_result)(void *agent, int job_id, std::s
|
||||
typedef int (*func_get_mw_user_preference)(void *agent, std::function<void(std::string)> callback);
|
||||
typedef int (*func_get_mw_user_4ulist)(void *agent, int seed, int limit, std::function<void(std::string)> callback);
|
||||
|
||||
// Legacy function pointer types (for older DLL versions)
|
||||
// Legacy function pointer types (for the 01.10.01 DLL)
|
||||
typedef int (*func_start_print_legacy)(void *agent, PrintParams_Legacy params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn);
|
||||
typedef int (*func_start_local_print_with_record_legacy)(void *agent, PrintParams_Legacy params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn);
|
||||
typedef int (*func_start_send_gcode_to_sdcard_legacy)(void *agent, PrintParams_Legacy params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn);
|
||||
@@ -128,10 +128,25 @@ typedef int (*func_start_sdcard_print_legacy)(void* agent, PrintParams_Legacy pa
|
||||
typedef int (*func_send_message_legacy)(void* agent, std::string dev_id, std::string json_str, int qos);
|
||||
typedef int (*func_send_message_to_printer_legacy)(void* agent, std::string dev_id, std::string json_str, int qos);
|
||||
|
||||
// Added by the 02.08.01.52 plugin ABI (null on older plugins).
|
||||
// 02.03.00 function pointer types. Only PrintParams differs from the current ABI; send_message
|
||||
// and send_message_to_printer already take the flag argument in this series.
|
||||
typedef int (*func_start_print_0203)(void *agent, PrintParams_0203 params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn);
|
||||
typedef int (*func_start_local_print_with_record_0203)(void *agent, PrintParams_0203 params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn);
|
||||
typedef int (*func_start_send_gcode_to_sdcard_0203)(void *agent, PrintParams_0203 params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn);
|
||||
typedef int (*func_start_local_print_0203)(void *agent, PrintParams_0203 params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn);
|
||||
typedef int (*func_start_sdcard_print_0203)(void* agent, PrintParams_0203 params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn);
|
||||
|
||||
// bind() gained dev_model in 02.08.01; the legacy and 02.03.00 series share the older form.
|
||||
typedef int (*func_bind_pre0208)(void *agent, std::string dev_ip, std::string dev_id, std::string sec_link, std::string timezone, bool improved, OnUpdateStatusFn update_fn);
|
||||
|
||||
// Exported by every supported generation, but only bound here.
|
||||
typedef int (*func_set_on_user_login_fn)(void *agent, OnUserLoginFn fn);
|
||||
typedef std::string (*func_get_studio_info_url)(void *agent);
|
||||
|
||||
// Present since 02.03.00, null on the legacy plugin.
|
||||
typedef int (*func_report_consent)(void *agent, std::string expand);
|
||||
|
||||
// Added by the 02.08.01.52 plugin ABI (null on older plugins).
|
||||
typedef int (*func_get_camera_url_for_golive)(void *agent, std::string dev_id, std::string sdev_id, std::function<void(std::string)> callback);
|
||||
typedef int (*func_get_hms_snapshot)(void *agent, std::string& dev_id, std::string& file_name, std::function<void(std::string, int)> callback);
|
||||
typedef int (*func_get_filament_spools)(void *agent, FilamentQueryParams params, std::string* http_body);
|
||||
@@ -279,12 +294,13 @@ public:
|
||||
const std::string& attempted_path);
|
||||
|
||||
// ========================================================================
|
||||
// Legacy Network Flag
|
||||
// Plug-in ABI Generation
|
||||
// ========================================================================
|
||||
|
||||
static bool is_legacy_version(const std::string& version) { return version == BAMBU_NETWORK_AGENT_VERSION_LEGACY; }
|
||||
bool use_legacy_network() const { return m_use_legacy_network; }
|
||||
void set_use_legacy_network(bool legacy) { m_use_legacy_network = legacy; }
|
||||
// The generation the loaded library speaks - what every call must dispatch on.
|
||||
NetworkAbi network_abi() const { return m_network_abi; }
|
||||
bool use_legacy_network() const { return m_network_abi == NetworkAbi::Legacy; }
|
||||
|
||||
// ========================================================================
|
||||
// Function Pointer Accessors
|
||||
@@ -401,10 +417,12 @@ public:
|
||||
func_sync_ams_filaments get_sync_ams_filaments() const { return m_sync_ams_filaments; }
|
||||
|
||||
// ========================================================================
|
||||
// Legacy Helper
|
||||
// ABI Conversion Helpers
|
||||
// ========================================================================
|
||||
|
||||
// Both move out of `param`, so convert only inside the branch that will actually run.
|
||||
static PrintParams_Legacy as_legacy(PrintParams& param);
|
||||
static PrintParams_0203 as_0203(PrintParams& param);
|
||||
|
||||
private:
|
||||
// Singleton instance pointer (heap-allocated for explicit lifetime control)
|
||||
@@ -431,8 +449,8 @@ private:
|
||||
// Load error state
|
||||
NetworkLibraryLoadError m_load_error;
|
||||
|
||||
// Legacy network compatibility flag
|
||||
bool m_use_legacy_network{false};
|
||||
// ABI generation of the currently loaded library
|
||||
NetworkAbi m_network_abi{NetworkAbi::Unsupported};
|
||||
|
||||
// Function pointers
|
||||
func_check_debug_consistent m_check_debug_consistent{nullptr};
|
||||
|
||||
@@ -26,11 +26,19 @@ int BBLPrinterAgent::send_message(std::string dev_id, std::string json_str, int
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_send_message();
|
||||
if (func && agent) {
|
||||
if (plugin.use_legacy_network()) {
|
||||
// Only the legacy plug-in lacks `flag`; 02.03.00 already takes it, and routing that
|
||||
// series through the legacy form would silently drop MessageFlag sign/encrypt.
|
||||
switch (plugin.network_abi()) {
|
||||
case NetworkAbi::Legacy: {
|
||||
auto legacy_func = reinterpret_cast<func_send_message_legacy>(func);
|
||||
return legacy_func(agent, dev_id, json_str, qos);
|
||||
return legacy_func(agent, std::move(dev_id), std::move(json_str), qos);
|
||||
}
|
||||
case NetworkAbi::V0203:
|
||||
case NetworkAbi::Current:
|
||||
return func(agent, std::move(dev_id), std::move(json_str), qos, flag);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return func(agent, dev_id, json_str, qos, flag);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -63,11 +71,17 @@ int BBLPrinterAgent::send_message_to_printer(std::string dev_id, std::string jso
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_send_message_to_printer();
|
||||
if (func && agent) {
|
||||
if (plugin.use_legacy_network()) {
|
||||
switch (plugin.network_abi()) {
|
||||
case NetworkAbi::Legacy: {
|
||||
auto legacy_func = reinterpret_cast<func_send_message_to_printer_legacy>(func);
|
||||
return legacy_func(agent, dev_id, json_str, qos);
|
||||
return legacy_func(agent, std::move(dev_id), std::move(json_str), qos);
|
||||
}
|
||||
case NetworkAbi::V0203:
|
||||
case NetworkAbi::Current:
|
||||
return func(agent, std::move(dev_id), std::move(json_str), qos, flag);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return func(agent, dev_id, json_str, qos, flag);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -144,7 +158,19 @@ int BBLPrinterAgent::bind(std::string dev_ip, std::string dev_id, std::string de
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_bind();
|
||||
if (func && agent) {
|
||||
return func(agent, dev_ip, dev_id, dev_model, sec_link, timezone, improved, update_fn);
|
||||
// dev_model was added in 02.08.01. Passing it to a plug-in that takes the 7-argument
|
||||
// form shifts every following argument, so the older generations get the older call.
|
||||
switch (plugin.network_abi()) {
|
||||
case NetworkAbi::Legacy:
|
||||
case NetworkAbi::V0203: {
|
||||
auto older_func = reinterpret_cast<func_bind_pre0208>(func);
|
||||
return older_func(agent, dev_ip, dev_id, sec_link, timezone, improved, update_fn);
|
||||
}
|
||||
case NetworkAbi::Current:
|
||||
return func(agent, dev_ip, dev_id, dev_model, sec_link, timezone, improved, update_fn);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -281,84 +307,62 @@ AgentInfo BBLPrinterAgent::get_agent_info_static()
|
||||
// Print Job Operations
|
||||
// ============================================================================
|
||||
|
||||
int BBLPrinterAgent::start_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn)
|
||||
namespace {
|
||||
|
||||
// Shared dispatcher for the start_* operations, whose params layout differs per generation.
|
||||
// The per-generation typedefs are template arguments so a swapped pair fails to compile
|
||||
// (each arm's converted params must match the casted signature). Each arm converts and calls
|
||||
// in one step: as_legacy()/as_0203() move out of `params` and their prvalue result lands in
|
||||
// the by-value ABI argument without another copy; the Current arm moves `params` outright.
|
||||
template <typename LegacyFn, typename Fn0203, typename CurrentFn, typename... CallbackFns>
|
||||
int dispatch_start(CurrentFn func, PrintParams& params, const CallbackFns&... callbacks)
|
||||
{
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_start_print();
|
||||
if (func && agent) {
|
||||
if (plugin.use_legacy_network()) {
|
||||
auto legacy_func = reinterpret_cast<func_start_print_legacy>(func);
|
||||
auto legacy_params = BBLNetworkPlugin::as_legacy(params);
|
||||
return legacy_func(agent, legacy_params, update_fn, cancel_fn, wait_fn);
|
||||
}
|
||||
return func(agent, params, update_fn, cancel_fn, wait_fn);
|
||||
if (!func || !agent)
|
||||
return -1;
|
||||
switch (plugin.network_abi()) {
|
||||
case NetworkAbi::Legacy:
|
||||
return reinterpret_cast<LegacyFn>(func)(agent, BBLNetworkPlugin::as_legacy(params), callbacks...);
|
||||
case NetworkAbi::V0203:
|
||||
return reinterpret_cast<Fn0203>(func)(agent, BBLNetworkPlugin::as_0203(params), callbacks...);
|
||||
case NetworkAbi::Current:
|
||||
return func(agent, std::move(params), callbacks...);
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int BBLPrinterAgent::start_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn)
|
||||
{
|
||||
return dispatch_start<func_start_print_legacy, func_start_print_0203>(
|
||||
BBLNetworkPlugin::instance().get_start_print(), params, update_fn, cancel_fn, wait_fn);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::start_local_print_with_record(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn)
|
||||
{
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_start_local_print_with_record();
|
||||
if (func && agent) {
|
||||
if (plugin.use_legacy_network()) {
|
||||
auto legacy_func = reinterpret_cast<func_start_local_print_with_record_legacy>(func);
|
||||
auto legacy_params = BBLNetworkPlugin::as_legacy(params);
|
||||
return legacy_func(agent, legacy_params, update_fn, cancel_fn, wait_fn);
|
||||
}
|
||||
return func(agent, params, update_fn, cancel_fn, wait_fn);
|
||||
}
|
||||
return -1;
|
||||
return dispatch_start<func_start_local_print_with_record_legacy, func_start_local_print_with_record_0203>(
|
||||
BBLNetworkPlugin::instance().get_start_local_print_with_record(), params, update_fn, cancel_fn, wait_fn);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::start_send_gcode_to_sdcard(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn, OnWaitFn wait_fn)
|
||||
{
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_start_send_gcode_to_sdcard();
|
||||
if (func && agent) {
|
||||
if (plugin.use_legacy_network()) {
|
||||
auto legacy_func = reinterpret_cast<func_start_send_gcode_to_sdcard_legacy>(func);
|
||||
auto legacy_params = BBLNetworkPlugin::as_legacy(params);
|
||||
return legacy_func(agent, legacy_params, update_fn, cancel_fn, wait_fn);
|
||||
}
|
||||
return func(agent, params, update_fn, cancel_fn, wait_fn);
|
||||
}
|
||||
return -1;
|
||||
return dispatch_start<func_start_send_gcode_to_sdcard_legacy, func_start_send_gcode_to_sdcard_0203>(
|
||||
BBLNetworkPlugin::instance().get_start_send_gcode_to_sdcard(), params, update_fn, cancel_fn, wait_fn);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::start_local_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn)
|
||||
{
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_start_local_print();
|
||||
if (func && agent) {
|
||||
if (plugin.use_legacy_network()) {
|
||||
auto legacy_func = reinterpret_cast<func_start_local_print_legacy>(func);
|
||||
auto legacy_params = BBLNetworkPlugin::as_legacy(params);
|
||||
return legacy_func(agent, legacy_params, update_fn, cancel_fn);
|
||||
}
|
||||
return func(agent, params, update_fn, cancel_fn);
|
||||
}
|
||||
return -1;
|
||||
return dispatch_start<func_start_local_print_legacy, func_start_local_print_0203>(
|
||||
BBLNetworkPlugin::instance().get_start_local_print(), params, update_fn, cancel_fn);
|
||||
}
|
||||
|
||||
int BBLPrinterAgent::start_sdcard_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn)
|
||||
{
|
||||
auto& plugin = BBLNetworkPlugin::instance();
|
||||
auto agent = plugin.get_agent();
|
||||
auto func = plugin.get_start_sdcard_print();
|
||||
if (func && agent) {
|
||||
if (plugin.use_legacy_network()) {
|
||||
auto legacy_func = reinterpret_cast<func_start_sdcard_print_legacy>(func);
|
||||
auto legacy_params = BBLNetworkPlugin::as_legacy(params);
|
||||
return legacy_func(agent, legacy_params, update_fn, cancel_fn);
|
||||
}
|
||||
return func(agent, params, update_fn, cancel_fn);
|
||||
}
|
||||
return -1;
|
||||
return dispatch_start<func_start_sdcard_print_legacy, func_start_sdcard_print_0203>(
|
||||
BBLNetworkPlugin::instance().get_start_sdcard_print(), params, update_fn, cancel_fn);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -230,6 +230,59 @@ struct PrintParams_Legacy {
|
||||
std::string extra_options;
|
||||
};
|
||||
|
||||
/* print job, as the 02.03.00 series expects it. The 02.08.01 series inserted
|
||||
task_timelapse_use_internal, extruder_cali_manual_mode, svc_context and slicer_uid into
|
||||
PrintParams; two of them sit mid-struct, so an older plug-in misreads every field from
|
||||
task_use_ams onwards if handed the current layout. Rebuild it with as_0203() instead. */
|
||||
struct PrintParams_0203 {
|
||||
/* basic info */
|
||||
std::string dev_id;
|
||||
std::string task_name;
|
||||
std::string project_name;
|
||||
std::string preset_name;
|
||||
std::string filename;
|
||||
std::string config_filename;
|
||||
int plate_index;
|
||||
std::string ftp_folder;
|
||||
std::string ftp_file;
|
||||
std::string ftp_file_md5;
|
||||
std::string nozzle_mapping;
|
||||
std::string ams_mapping;
|
||||
std::string ams_mapping2;
|
||||
std::string ams_mapping_info;
|
||||
std::string nozzles_info;
|
||||
std::string connection_type;
|
||||
std::string comments;
|
||||
int origin_profile_id = 0;
|
||||
int stl_design_id = 0;
|
||||
std::string origin_model_id;
|
||||
std::string print_type;
|
||||
std::string dst_file;
|
||||
std::string dev_name;
|
||||
|
||||
/* access options */
|
||||
std::string dev_ip;
|
||||
bool use_ssl_for_ftp;
|
||||
bool use_ssl_for_mqtt;
|
||||
std::string username;
|
||||
std::string password;
|
||||
|
||||
/*user options */
|
||||
bool task_bed_leveling; /* bed leveling of task */
|
||||
bool task_flow_cali; /* flow calibration of task */
|
||||
bool task_vibration_cali; /* vibration calibration of task */
|
||||
bool task_layer_inspect; /* first layer inspection of task */
|
||||
bool task_record_timelapse; /* record timelapse of task */
|
||||
bool task_use_ams;
|
||||
std::string task_bed_type;
|
||||
std::string extra_options;
|
||||
int auto_bed_leveling{ 0 };
|
||||
int auto_flow_cali{ 0 };
|
||||
int auto_offset_cali{ 0 };
|
||||
bool task_ext_change_assist;
|
||||
bool try_emmc_print;
|
||||
};
|
||||
|
||||
/* print job*/
|
||||
struct PrintParams {
|
||||
/* basic info */
|
||||
@@ -351,21 +404,34 @@ struct CertificateInformation {
|
||||
std::string serial_number;
|
||||
};
|
||||
|
||||
// The plug-in ABI generation a library speaks. Generations differ in by-value struct layouts and
|
||||
// function signatures, so a call must go through the matching typedefs (see BBLPrinterAgent) -
|
||||
// the wrong one corrupts the stack rather than failing cleanly.
|
||||
enum class NetworkAbi {
|
||||
Unsupported, // no generation in this build can call it - never dispatch through it
|
||||
Legacy, // 01.10.01: PrintParams_Legacy; send_message/send_message_to_printer take no flag
|
||||
V0203, // 02.03.00: PrintParams_0203; bind takes no dev_model
|
||||
Current, // 02.08.01: the layouts and signatures this build declares directly
|
||||
};
|
||||
|
||||
struct NetworkLibraryVersion {
|
||||
const char* version;
|
||||
const char* display_name;
|
||||
const char* url_override;
|
||||
bool is_latest;
|
||||
const char* warning;
|
||||
NetworkAbi abi;
|
||||
};
|
||||
|
||||
// Only the latest series and the legacy build are offered/loadable: the host binds the
|
||||
// modern ABI (by-value struct layouts, function signatures) of exactly one series, plus
|
||||
// a dedicated shim for the legacy build. Older 02.0x series expect different layouts
|
||||
// and must not be loaded - see is_supported_network_version().
|
||||
// Every row names the generation that can call it, so a series can never be offered without a
|
||||
// host-side ABI for it. Series with no generation - 02.01.01, 02.00.02 and older - must stay out;
|
||||
// is_supported_network_version() is the gate that keeps them from loading.
|
||||
static const NetworkLibraryVersion AVAILABLE_NETWORK_VERSIONS[] = {
|
||||
{"02.08.01", "02.08.01", nullptr, true, nullptr},
|
||||
{BAMBU_NETWORK_AGENT_VERSION_LEGACY, BAMBU_NETWORK_AGENT_VERSION_LEGACY " (legacy)", nullptr, false, nullptr},
|
||||
{"02.08.01", "02.08.01", nullptr, true, nullptr, NetworkAbi::Current},
|
||||
{"02.03.00", "02.03.00", nullptr, false,
|
||||
"An older plug-in series. Features that need newer plug-in support, such as print-failure "
|
||||
"snapshots in the device error dialog, are unavailable.", NetworkAbi::V0203},
|
||||
{BAMBU_NETWORK_AGENT_VERSION_LEGACY, BAMBU_NETWORK_AGENT_VERSION_LEGACY " (legacy)", nullptr, false, nullptr, NetworkAbi::Legacy},
|
||||
};
|
||||
|
||||
static const size_t AVAILABLE_NETWORK_VERSIONS_COUNT = sizeof(AVAILABLE_NETWORK_VERSIONS) / sizeof(AVAILABLE_NETWORK_VERSIONS[0]);
|
||||
@@ -378,23 +444,43 @@ inline const char* get_latest_network_version() {
|
||||
return AVAILABLE_NETWORK_VERSIONS[0].version;
|
||||
}
|
||||
|
||||
// True when the version can be loaded through the ABI this build was compiled against:
|
||||
// an exact whitelist entry, or a build from the same AA.BB.CC series as a non-legacy
|
||||
// whitelist entry (the plugin ABI is stable within a series, and the OTA sync only ever
|
||||
// installs same-series updates). Anything else - in particular older 02.0x series a
|
||||
// previous Orca release whitelisted - expects different by-value struct layouts and
|
||||
// function signatures and must not be loaded.
|
||||
inline bool is_supported_network_version(const std::string& version) {
|
||||
// The AA.BB.CC series of a modern version string - the plug-in's stored identity. The 4th
|
||||
// component is only which build of the series happens to be installed and is read live from
|
||||
// the loaded plug-in for display. Legacy keeps its exact string (the shim matches exactly).
|
||||
inline std::string network_plugin_series(const std::string& version) {
|
||||
if (version.empty() || version == BAMBU_NETWORK_AGENT_VERSION_LEGACY)
|
||||
return version;
|
||||
return version.size() >= 8 ? version.substr(0, 8) : version;
|
||||
}
|
||||
|
||||
// Index of the whitelist entry that can load this version: an exact match, or a build of the same
|
||||
// AA.BB.CC series as a non-legacy entry (the ABI is stable within a series, and the OTA sync only
|
||||
// installs same-series updates). Legacy matches exactly only - a sibling build of that series
|
||||
// would come through the modern layout. AVAILABLE_NETWORK_VERSIONS_COUNT when nothing matches.
|
||||
inline size_t find_network_version_index(const std::string& version) {
|
||||
const std::string series = network_plugin_series(version);
|
||||
for (size_t i = 0; i < AVAILABLE_NETWORK_VERSIONS_COUNT; ++i) {
|
||||
const std::string base = AVAILABLE_NETWORK_VERSIONS[i].version;
|
||||
if (version == base)
|
||||
return true;
|
||||
return i;
|
||||
if (base == BAMBU_NETWORK_AGENT_VERSION_LEGACY)
|
||||
continue;
|
||||
if (version.size() >= 8 && base.size() >= 8 && version.compare(0, 8, base, 0, 8) == 0)
|
||||
return true;
|
||||
if (series == base)
|
||||
return i;
|
||||
}
|
||||
return false;
|
||||
return AVAILABLE_NETWORK_VERSIONS_COUNT;
|
||||
}
|
||||
|
||||
// True when a whitelisted series can load the version through an ABI this build implements.
|
||||
inline bool is_supported_network_version(const std::string& version) {
|
||||
return find_network_version_index(version) < AVAILABLE_NETWORK_VERSIONS_COUNT;
|
||||
}
|
||||
|
||||
// The generation to call a loaded library through. Unsupported for anything the load gate rejects,
|
||||
// so a mislabelled library reaches no plug-in call instead of a layout it does not share.
|
||||
inline NetworkAbi network_plugin_abi(const std::string& version) {
|
||||
const size_t i = find_network_version_index(version);
|
||||
return i < AVAILABLE_NETWORK_VERSIONS_COUNT ? AVAILABLE_NETWORK_VERSIONS[i].abi : NetworkAbi::Unsupported;
|
||||
}
|
||||
|
||||
struct NetworkLibraryVersionInfo {
|
||||
@@ -441,15 +527,6 @@ inline std::string extract_suffix(const std::string& full_version) {
|
||||
return (pos == std::string::npos) ? "" : full_version.substr(pos + 1);
|
||||
}
|
||||
|
||||
// The AA.BB.CC series of a modern version string - the plug-in's stored identity. The 4th
|
||||
// component is only which build of the series happens to be installed and is read live from
|
||||
// the loaded plug-in for display. Legacy keeps its exact string (the shim matches exactly).
|
||||
inline std::string network_plugin_series(const std::string& version) {
|
||||
if (version.empty() || version == BAMBU_NETWORK_AGENT_VERSION_LEGACY)
|
||||
return version;
|
||||
return version.size() >= 8 ? version.substr(0, 8) : version;
|
||||
}
|
||||
|
||||
// True when the version is a pure dotted-numeric build (AA.BB.CC or AA.BB.CC.DD) whose identity
|
||||
// collapses to its series - the managed/OTA build. Legacy and any custom-named build
|
||||
// (02.08.01_custom, 02.08.01.52-dev) are NOT managed: they are genuinely distinct files kept
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
#include "CustomWidgetsPlugin.hpp"
|
||||
|
||||
#include "slic3r/GUI/Widgets/Button.hpp"
|
||||
#include "slic3r/GUI/Widgets/CheckBox.hpp"
|
||||
#include "slic3r/GUI/Widgets/TextInput.hpp"
|
||||
#include "slic3r/GUI/Widgets/SwitchButton.hpp"
|
||||
#include "slic3r/GUI/Widgets/ProgressBar.hpp"
|
||||
#include "slic3r/GUI/Widgets/Label.hpp"
|
||||
#include "slic3r/GUI/Widgets/LabeledStaticBox.hpp"
|
||||
|
||||
#include <wx/window.h>
|
||||
#include <wx/tglbtn.h>
|
||||
|
||||
wxString CustomWidgetsPlugin::GetName() const
|
||||
{
|
||||
return "OrcaCustomWidgets";
|
||||
}
|
||||
|
||||
bool CustomWidgetsPlugin::CanProvideProperties(wxClassInfo* info)
|
||||
{
|
||||
return info->IsKindOf(CLASSINFO(wxWindow));
|
||||
}
|
||||
|
||||
wxVector<wxInspector::PropertyDef> CustomWidgetsPlugin::GetProperties(
|
||||
wxInspector::InspectableObject& obj)
|
||||
{
|
||||
wxVector<wxInspector::PropertyDef> props;
|
||||
wxWindow* win = obj.AsWindow();
|
||||
if (!win) return props;
|
||||
|
||||
if (auto* btn = dynamic_cast<Button*>(win))
|
||||
addButtonProps(btn, props);
|
||||
if (auto* cb = dynamic_cast<CheckBox*>(win))
|
||||
addCheckBoxProps(cb, props);
|
||||
if (auto* ti = dynamic_cast<TextInput*>(win))
|
||||
addTextInputProps(ti, props);
|
||||
if (auto* sb = dynamic_cast<SwitchButton*>(win))
|
||||
addSwitchButtonProps(sb, props);
|
||||
if (auto* pb = dynamic_cast<ProgressBar*>(win))
|
||||
addProgressBarProps(pb, props);
|
||||
if (auto* lbl = dynamic_cast<Label*>(win))
|
||||
addLabelProps(lbl, props);
|
||||
if (auto* lsb = dynamic_cast<LabeledStaticBox*>(win))
|
||||
addLabeledStaticBoxProps(lsb, props);
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
void CustomWidgetsPlugin::addButtonProps(Button* btn,
|
||||
wxVector<wxInspector::PropertyDef>& props)
|
||||
{
|
||||
using namespace wxInspector;
|
||||
|
||||
wxVector<wxString> styleChoices;
|
||||
styleChoices.push_back("Regular");
|
||||
styleChoices.push_back("Confirm");
|
||||
styleChoices.push_back("Alert");
|
||||
styleChoices.push_back("Disabled");
|
||||
|
||||
auto styleToStr = [](ButtonStyle s) -> wxString {
|
||||
switch (s) {
|
||||
case ButtonStyle::Regular: return "Regular";
|
||||
case ButtonStyle::Confirm: return "Confirm";
|
||||
case ButtonStyle::Alert: return "Alert";
|
||||
case ButtonStyle::Disabled: return "Disabled";
|
||||
}
|
||||
return "Regular";
|
||||
};
|
||||
|
||||
props.push_back({"Button Style", "Orca Button", PropertyType::Choice,
|
||||
styleToStr(btn->GetStyle()), false, styleChoices,
|
||||
[btn, styleToStr]() { return styleToStr(btn->GetStyle()); },
|
||||
[btn](const wxString& v) {
|
||||
ButtonStyle s = ButtonStyle::Regular;
|
||||
if (v == "Confirm") s = ButtonStyle::Confirm;
|
||||
else if (v == "Alert") s = ButtonStyle::Alert;
|
||||
else if (v == "Disabled") s = ButtonStyle::Disabled;
|
||||
btn->SetStyle(s, btn->GetType());
|
||||
return true;
|
||||
}});
|
||||
|
||||
wxVector<wxString> typeChoices;
|
||||
typeChoices.push_back("Compact");
|
||||
typeChoices.push_back("Window");
|
||||
typeChoices.push_back("Choice");
|
||||
typeChoices.push_back("Parameter");
|
||||
typeChoices.push_back("Icon");
|
||||
typeChoices.push_back("Expanded");
|
||||
|
||||
auto typeToStr = [](ButtonType t) -> wxString {
|
||||
switch (t) {
|
||||
case ButtonType::Compact: return "Compact";
|
||||
case ButtonType::Window: return "Window";
|
||||
case ButtonType::Choice: return "Choice";
|
||||
case ButtonType::Parameter: return "Parameter";
|
||||
case ButtonType::Icon: return "Icon";
|
||||
case ButtonType::Expanded: return "Expanded";
|
||||
}
|
||||
return "Compact";
|
||||
};
|
||||
|
||||
props.push_back({"Button Type", "Orca Button", PropertyType::Choice,
|
||||
typeToStr(btn->GetType()), false, typeChoices,
|
||||
[btn, typeToStr]() { return typeToStr(btn->GetType()); },
|
||||
[btn](const wxString& v) {
|
||||
ButtonType t = ButtonType::Compact;
|
||||
if (v == "Window") t = ButtonType::Window;
|
||||
else if (v == "Choice") t = ButtonType::Choice;
|
||||
else if (v == "Parameter") t = ButtonType::Parameter;
|
||||
else if (v == "Icon") t = ButtonType::Icon;
|
||||
else if (v == "Expanded") t = ButtonType::Expanded;
|
||||
btn->SetStyle(btn->GetStyle(), t);
|
||||
return true;
|
||||
}});
|
||||
|
||||
props.push_back({"Selected", "Orca Button", PropertyType::Boolean,
|
||||
btn->IsSelected() ? "true" : "false", false, {},
|
||||
[btn]() { return btn->IsSelected() ? "true" : "false"; },
|
||||
[btn](const wxString& v) {
|
||||
btn->SetSelected(v == "true");
|
||||
btn->Refresh();
|
||||
return true;
|
||||
}});
|
||||
}
|
||||
|
||||
void CustomWidgetsPlugin::addCheckBoxProps(CheckBox* cb,
|
||||
wxVector<wxInspector::PropertyDef>& props)
|
||||
{
|
||||
using namespace wxInspector;
|
||||
|
||||
props.push_back({"Half Checked", "Orca CheckBox", PropertyType::Boolean,
|
||||
cb->IsHalfChecked() ? "true" : "false", false, {},
|
||||
[cb]() { return cb->IsHalfChecked() ? "true" : "false"; },
|
||||
[cb](const wxString& v) {
|
||||
cb->SetHalfChecked(v == "true");
|
||||
return true;
|
||||
}});
|
||||
}
|
||||
|
||||
void CustomWidgetsPlugin::addTextInputProps(TextInput* ti,
|
||||
wxVector<wxInspector::PropertyDef>& props)
|
||||
{
|
||||
using namespace wxInspector;
|
||||
|
||||
props.push_back({"Label", "Orca TextInput", PropertyType::String,
|
||||
ti->GetLabel(), false, {},
|
||||
[ti]() { return ti->GetLabel(); },
|
||||
[ti](const wxString& v) { ti->SetLabel(v); return true; }});
|
||||
|
||||
props.push_back({"Text Value", "Orca TextInput", PropertyType::String,
|
||||
ti->GetTextCtrl()->GetValue(), false, {},
|
||||
[ti]() { return ti->GetTextCtrl()->GetValue(); },
|
||||
[ti](const wxString& v) { ti->GetTextCtrl()->SetValue(v); return true; }});
|
||||
|
||||
props.push_back({"Corner Radius", "Orca TextInput", PropertyType::Integer,
|
||||
wxString::Format("%d", ti->GetCornerRadius()), false, {},
|
||||
[ti]() { return wxString::Format("%d", ti->GetCornerRadius()); },
|
||||
[ti](const wxString& v) {
|
||||
long val;
|
||||
if (!v.ToLong(&val)) return false;
|
||||
ti->SetCornerRadius((double) val);
|
||||
ti->Refresh();
|
||||
return true;
|
||||
}});
|
||||
}
|
||||
|
||||
void CustomWidgetsPlugin::addSwitchButtonProps(SwitchButton* sb,
|
||||
wxVector<wxInspector::PropertyDef>& props)
|
||||
{
|
||||
using namespace wxInspector;
|
||||
|
||||
props.push_back({"Value", "Orca SwitchButton", PropertyType::Boolean,
|
||||
sb->GetValue() ? "true" : "false", false, {},
|
||||
[sb]() { return sb->GetValue() ? "true" : "false"; },
|
||||
[sb](const wxString& v) {
|
||||
sb->SetValue(v == "true");
|
||||
return true;
|
||||
}});
|
||||
}
|
||||
|
||||
void CustomWidgetsPlugin::addProgressBarProps(ProgressBar* pb,
|
||||
wxVector<wxInspector::PropertyDef>& props)
|
||||
{
|
||||
using namespace wxInspector;
|
||||
|
||||
props.push_back({"Proportion", "Orca ProgressBar", PropertyType::String,
|
||||
wxString::Format("%.2f", pb->m_proportion), false, {},
|
||||
[pb]() { return wxString::Format("%.2f", pb->m_proportion); },
|
||||
[pb](const wxString& v) {
|
||||
double val;
|
||||
if (wxSscanf(v, "%lf", &val) != 1) return false;
|
||||
pb->m_proportion = val;
|
||||
pb->Refresh();
|
||||
return true;
|
||||
}});
|
||||
|
||||
props.push_back({"Show Number", "Orca ProgressBar", PropertyType::Boolean,
|
||||
pb->m_shownumber ? "true" : "false", false, {},
|
||||
[pb]() { return pb->m_shownumber ? "true" : "false"; },
|
||||
[pb](const wxString& v) {
|
||||
pb->m_shownumber = (v == "true");
|
||||
pb->Refresh();
|
||||
return true;
|
||||
}});
|
||||
}
|
||||
|
||||
void CustomWidgetsPlugin::addLabelProps(Label* lbl,
|
||||
wxVector<wxInspector::PropertyDef>& props)
|
||||
{
|
||||
using namespace wxInspector;
|
||||
|
||||
bool isHyperlink = (lbl->GetWindowStyleFlag() & LB_HYPERLINK) != 0;
|
||||
|
||||
props.push_back({"Is Hyperlink", "Orca Label", PropertyType::Boolean,
|
||||
isHyperlink ? "true" : "false", true, {},
|
||||
[lbl]() {
|
||||
return (lbl->GetWindowStyleFlag() & LB_HYPERLINK) ? "true" : "false";
|
||||
},
|
||||
nullptr});
|
||||
|
||||
props.push_back({"Font Point Size", "Orca Label", PropertyType::ReadOnly,
|
||||
wxString::Format("%d", lbl->GetFont().GetPointSize()), true, {},
|
||||
[lbl]() {
|
||||
return wxString::Format("%d", lbl->GetFont().GetPointSize());
|
||||
},
|
||||
nullptr});
|
||||
}
|
||||
|
||||
void CustomWidgetsPlugin::addLabeledStaticBoxProps(LabeledStaticBox* lsb,
|
||||
wxVector<wxInspector::PropertyDef>& props)
|
||||
{
|
||||
using namespace wxInspector;
|
||||
|
||||
props.push_back({"Corner Radius", "LabeledStaticBox", PropertyType::Integer,
|
||||
wxString::Format("%d", lsb->GetCornerRadius()), false, {},
|
||||
[lsb]() { return wxString::Format("%d", lsb->GetCornerRadius()); },
|
||||
[lsb](const wxString& v) {
|
||||
long val;
|
||||
if (!v.ToLong(&val)) return false;
|
||||
lsb->SetCornerRadius((int) val);
|
||||
return true;
|
||||
}});
|
||||
|
||||
props.push_back({"Border Width", "LabeledStaticBox", PropertyType::Integer,
|
||||
wxString::Format("%d", lsb->GetBorderWidth()), false, {},
|
||||
[lsb]() { return wxString::Format("%d", lsb->GetBorderWidth()); },
|
||||
[lsb](const wxString& v) {
|
||||
long val;
|
||||
if (!v.ToLong(&val)) return false;
|
||||
lsb->SetBorderWidth((int) val);
|
||||
return true;
|
||||
}});
|
||||
|
||||
// Border Color: display as hex string
|
||||
wxColour bc = lsb->GetBorderColor().colorForStates(0);
|
||||
props.push_back({"Border Color", "LabeledStaticBox", PropertyType::String,
|
||||
bc.GetAsString(wxC2S_HTML_SYNTAX), false, {},
|
||||
[lsb]() {
|
||||
return lsb->GetBorderColor()
|
||||
.colorForStates(0)
|
||||
.GetAsString(wxC2S_HTML_SYNTAX);
|
||||
},
|
||||
[lsb](const wxString& v) {
|
||||
wxColour c(v);
|
||||
if (!c.IsOk()) return false;
|
||||
lsb->SetBorderColor(StateColor(c));
|
||||
return true;
|
||||
}});
|
||||
|
||||
props.push_back({"Scale", "LabeledStaticBox", PropertyType::ReadOnly,
|
||||
wxString::Format("%.2f", lsb->GetScale()), true, {},
|
||||
[lsb]() { return wxString::Format("%.2f", lsb->GetScale()); },
|
||||
nullptr});
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <wx/inspector/plugin.h>
|
||||
|
||||
class CustomWidgetsPlugin : public wxInspector::wxInspectorPlugin
|
||||
{
|
||||
public:
|
||||
wxString GetName() const override;
|
||||
|
||||
bool CanProvideProperties(wxClassInfo* info) override;
|
||||
|
||||
wxVector<wxInspector::PropertyDef> GetProperties(
|
||||
wxInspector::InspectableObject& obj) override;
|
||||
|
||||
private:
|
||||
void addButtonProps(class Button* btn,
|
||||
wxVector<wxInspector::PropertyDef>& props);
|
||||
void addCheckBoxProps(class CheckBox* cb,
|
||||
wxVector<wxInspector::PropertyDef>& props);
|
||||
void addTextInputProps(class TextInput* ti,
|
||||
wxVector<wxInspector::PropertyDef>& props);
|
||||
void addSwitchButtonProps(class SwitchButton* sb,
|
||||
wxVector<wxInspector::PropertyDef>& props);
|
||||
void addProgressBarProps(class ProgressBar* pb,
|
||||
wxVector<wxInspector::PropertyDef>& props);
|
||||
void addLabelProps(class Label* lbl,
|
||||
wxVector<wxInspector::PropertyDef>& props);
|
||||
void addLabeledStaticBoxProps(class LabeledStaticBox* lsb,
|
||||
wxVector<wxInspector::PropertyDef>& props);
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "DPIAwarePlugin.hpp"
|
||||
|
||||
#include "slic3r/GUI/GUI_Utils.hpp" // DPIFrame, DPIDialog, DPIAware<P>
|
||||
|
||||
#include <wx/window.h>
|
||||
#include <wx/crt.h>
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename T>
|
||||
void addDPIProps(T* dpi, wxVector<wxInspector::PropertyDef>& props)
|
||||
{
|
||||
using namespace wxInspector;
|
||||
|
||||
props.push_back({"Scale Factor", "DPI Scaling", PropertyType::String,
|
||||
wxString::Format("%.2f", dpi->scale_factor()), false, {},
|
||||
[dpi]() { return wxString::Format("%.2f", dpi->scale_factor()); },
|
||||
[dpi](const wxString& v) {
|
||||
double val;
|
||||
if (wxSscanf(v, "%lf", &val) != 1) return false;
|
||||
dpi->set_scale_factor((float) val);
|
||||
return true;
|
||||
}});
|
||||
|
||||
props.push_back({"Prev Scale Factor", "DPI Scaling", PropertyType::String,
|
||||
wxString::Format("%.2f", dpi->prev_scale_factor()), false, {},
|
||||
[dpi]() { return wxString::Format("%.2f", dpi->prev_scale_factor()); },
|
||||
[dpi](const wxString& v) {
|
||||
double val;
|
||||
if (wxSscanf(v, "%lf", &val) != 1) return false;
|
||||
dpi->set_prev_scale_factor((float) val);
|
||||
return true;
|
||||
}});
|
||||
|
||||
props.push_back({"EM Unit", "DPI Scaling", PropertyType::Integer,
|
||||
wxString::Format("%d", dpi->em_unit()), false, {},
|
||||
[dpi]() { return wxString::Format("%d", dpi->em_unit()); },
|
||||
[dpi](const wxString& v) {
|
||||
long val;
|
||||
if (!v.ToLong(&val)) return false;
|
||||
dpi->set_em_unit((int) val);
|
||||
return true;
|
||||
}});
|
||||
|
||||
props.push_back({"Normal Font", "DPI Scaling", PropertyType::ReadOnly,
|
||||
dpi->normal_font().GetNativeFontInfoDesc(), true, {},
|
||||
[dpi]() { return dpi->normal_font().GetNativeFontInfoDesc(); },
|
||||
nullptr});
|
||||
|
||||
props.push_back({"Force Rescale", "DPI Scaling", PropertyType::Boolean,
|
||||
dpi->force_rescale() ? "true" : "false", true, {},
|
||||
[dpi]() { return dpi->force_rescale() ? "true" : "false"; },
|
||||
nullptr});
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
wxString DPIAwarePlugin::GetName() const
|
||||
{
|
||||
return "OrcaDPIAware";
|
||||
}
|
||||
|
||||
bool DPIAwarePlugin::CanProvideProperties(wxClassInfo* info)
|
||||
{
|
||||
return info->IsKindOf(CLASSINFO(wxWindow));
|
||||
}
|
||||
|
||||
wxVector<wxInspector::PropertyDef> DPIAwarePlugin::GetProperties(
|
||||
wxInspector::InspectableObject& obj)
|
||||
{
|
||||
wxVector<wxInspector::PropertyDef> props;
|
||||
wxWindow* win = obj.AsWindow();
|
||||
if (!win) return props;
|
||||
|
||||
if (auto* frame = dynamic_cast<Slic3r::GUI::DPIFrame*>(win)) {
|
||||
addDPIProps(frame, props);
|
||||
} else if (auto* dlg = dynamic_cast<Slic3r::GUI::DPIDialog*>(win)) {
|
||||
addDPIProps(dlg, props);
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <wx/inspector/plugin.h>
|
||||
|
||||
class DPIAwarePlugin : public wxInspector::wxInspectorPlugin
|
||||
{
|
||||
public:
|
||||
wxString GetName() const override;
|
||||
|
||||
bool CanProvideProperties(wxClassInfo* info) override;
|
||||
|
||||
wxVector<wxInspector::PropertyDef> GetProperties(
|
||||
wxInspector::InspectableObject& obj) override;
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "DPIAwarePlugin.hpp"
|
||||
#include "CustomWidgetsPlugin.hpp"
|
||||
|
||||
#include <wx/inspector/inspector.h>
|
||||
|
||||
inline void RegisterOrcaInspectorPlugins()
|
||||
{
|
||||
static DPIAwarePlugin dpiaware;
|
||||
static CustomWidgetsPlugin customWidgets;
|
||||
wxInspector::RegisterPlugin(&dpiaware);
|
||||
wxInspector::RegisterPlugin(&customWidgets);
|
||||
}
|
||||
Reference in New Issue
Block a user