fix: merge branch feat/plugin-feature

This commit is contained in:
Ian Chua
2026-07-17 14:02:10 +08:00
151 changed files with 5144 additions and 1418 deletions
+23 -1
View File
@@ -495,7 +495,29 @@ void GLVolume::render_with_outline(const GUI::Size& cnv_size)
simple_render(shader, model_objects, colors);
return;
}
// 0th. render pass, render the model using stencil buffer
glsafe(::glEnable(GL_STENCIL_TEST));
glsafe(::glStencilMask(0xFF));
glsafe(::glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE));
glsafe(::glClearStencil(0));
glsafe(::glClear(GL_STENCIL_BUFFER_BIT));
glsafe(::glStencilFunc(GL_ALWAYS, 0xFF, 0xFF));
if (tverts_range == std::make_pair<size_t, size_t>(0, -1))
model.render(shader);
else
model.render(this->tverts_range, shader);
glsafe(::glStencilFunc(GL_NOTEQUAL, 0xFF, 0xFF));
glsafe(::glStencilMask(0x00));
shader->set_uniform("is_outline", true);
shader->set_uniform("screen_size", Vec2f{cnv_size.get_width(), cnv_size.get_height()});
if (tverts_range == std::make_pair<size_t, size_t>(0, -1))
model.render(shader);
else
model.render(this->tverts_range, shader);
shader->set_uniform("is_outline", false);
glsafe(::glStencilMask(0xFF));
glsafe(::glDisable(GL_STENCIL_TEST));
// render the outline using depth buffer and discard the pixels that are not on the outline
// 1st. render pass, render the model into a separate render target that has only depth buffer
GLuint depth_fbo = 0;
GLuint depth_tex = 0;
File diff suppressed because it is too large Load Diff
+253
View File
@@ -0,0 +1,253 @@
#pragma once
#include "GUI_ObjectLayers.hpp"
#include "slic3r/GUI/Widgets/AMSItem.hpp"
#include "slic3r/GUI/Widgets/Label.hpp"
#include "slic3r/GUI/Widgets/PopupWindow.hpp"
#include "slic3r/GUI/wxExtensions.hpp"
#include "slic3r/GUI/DeviceCore/DevFilaSystem.h"
#include "slic3r/GUI/I18N.hpp"
#include <chrono>
#include <optional>
//Previous defintions
class wxGrid;
namespace Slic3r {
namespace GUI {
enum class DryCtrState {
IDLE,
DRY_WHEN_PRINT,
UNKNOWN
};
enum class DryCtrDev {
N3S,
N3F,
UNKNOWN
};
struct DryingPreset {
DryCtrState state;
DryCtrDev dev;
int dry_temp;
int dry_time;
};
class FilamentItemPanel : public wxPanel
{
public:
FilamentItemPanel(wxWindow* parent, const wxString& text, const std::string& icon_name = "",
wxWindowID id = wxID_ANY);
void SetText(const wxString& text);
void SetIcon(const std::string& icon_name);
void msw_rescale();
private:
void OnPaint(wxPaintEvent& event);
void OnSize(wxSizeEvent& event);
Label* m_text_label;
wxStaticBitmap* m_icon_bitmap;
int m_target_size;
std::string m_icon_name;
ScalableBitmap m_icon;
};
class AMSFilamentPanel : public wxPanel
{
wxBoxSizer* m_filament_sizer;
Label* m_ams_name_label;
int m_border_radius;
wxPanel* m_filament_container{nullptr};
std::vector<FilamentItemPanel*> m_filament_items;
public:
AMSFilamentPanel(wxWindow* parent, const wxString& ams_name, wxWindowID id = wxID_ANY);
void AddFilamentItem(const wxString& text, const std::string& icon_name);
void AddFilamentItem(FilamentItemPanel* panel);
void SetAmsName(const wxString& ams_name);
void Clear();
void msw_rescale();
private:
void OnPaint(wxPaintEvent& event);
};
class AMSDryCtrWin : public DPIDialog
{
public:
AMSDryCtrWin(wxWindow *parent);
~AMSDryCtrWin();
void msw_rescale();
void update(std::shared_ptr<DevFilaSystem> fila_system, MachineObject* obj);
void set_ams_id(const std::string& ams_id);
protected:
void on_dpi_changed(const wxRect &suggested_rect) override;
private:
wxSimplebook* m_main_simplebook{nullptr};
wxPanel* m_original_page{nullptr};
wxWindow* m_amswin{nullptr};
wxBoxSizer* m_sizer_ams_items{nullptr};
wxScrolledWindow* m_panel_prv_left {nullptr};
wxScrolledWindow* m_panel_prv_right{nullptr};
wxBoxSizer* m_sizer_prv_left{nullptr};
wxBoxSizer* m_sizer_prv_right{nullptr};
// left panel related members
ScalableBitmap m_humidity_image;
wxStaticBitmap* m_humidity_img{nullptr};
Label* m_image_description{nullptr};
wxStaticBitmap* m_image_description_icon{nullptr};
ScalableBitmap m_description_icon_bitmap;
Label* m_humidity_data_label = nullptr;
Label* m_temperature_data_label = nullptr;
Label* m_time_data_label = nullptr;
wxBoxSizer* m_time_descrition_container = nullptr;
// right panel related members
wxBoxSizer* m_normal_state_sizer{nullptr};
wxBoxSizer* m_cannot_dry_sizer{nullptr};
wxBoxSizer* m_dry_error_sizer{nullptr};
Label* m_cannot_dry_description_label = nullptr;
// right panel normal state
ComboBox* m_trays_combo;
std::vector<FilamentBaseInfo> m_tray_ids;
wxTextCtrl* m_temperature_input;
wxTextCtrl* m_time_input;
Label* m_normal_description;
Button* m_start_button{nullptr};
Button* m_next_button{nullptr};
Button* m_stop_button{nullptr};
Button* m_back_button{nullptr};
Button* m_unload_button{nullptr};
// guide page description
Label* m_guide_title_label{nullptr};
Label* m_guide_description_label{nullptr};
wxCheckBox* m_rotate_spool_toggle{nullptr};
wxPanel* m_progress_page;
ProgressBar* m_progress_gauge;
wxTimer* m_progress_timer;
std::optional<std::chrono::steady_clock::time_point> m_stop_button_restore_deadline;
std::optional<std::chrono::steady_clock::time_point> m_unload_button_restore_deadline;
Label* m_progress_title;
int m_progress_value;
int m_progress_message_index;
std::vector<wxString> m_progress_text = {
_L("Starting: Checking adapter connection"),
_L("Starting: Checking filament status"),
_L("Starting: Checking drying presets"),
_L("Starting: Checking filament location"),
_L("Starting: Checking air intake"),
_L("Starting: Checking air vent")
};
// Guide page
wxPanel* m_guide_page{nullptr};
AMSFilamentPanel* m_ams_filament_panel{nullptr};
std::map<std::string, FilamentItemPanel*> m_filament_items;
wxStaticBitmap* m_image_placeholder{nullptr};
ScalableBitmap m_guide_image;
bool m_is_ams_changed = false;
std::weak_ptr<DevFilaSystem> m_fila_system;
struct {
std::string m_ams_id;
DevAmsType m_model = DevAmsType::EXT_SPOOL;
DevAms::DryStatus m_dry_status = DevAms::DryStatus::Off;
DevAms::DrySubStatus m_dry_sub_status = DevAms::DrySubStatus::Off;
int m_humidity_percent;
int m_temperature;
int m_left_dry_time;
float m_recommand_dry_temp;
} m_ams_info;
struct {
std::unordered_map<std::string, std::string> m_filament_names;
std::unordered_map<std::string, std::string> m_filament_type;
std::unordered_map<std::string, int> m_dry_temp;
std::unordered_map<std::string, int> m_dry_time;
} m_dry_setting;
struct {
bool m_is_printing = false;
} m_printer_status;
private:
void create();
wxBoxSizer* create_guide_page_sizer(wxPanel* parent);
wxBoxSizer* create_main_content_section(wxPanel* parent);
wxBoxSizer* create_guide_info_filament(wxPanel* parent);
wxBoxSizer* create_guide_info_section(wxPanel* parent);
wxBoxSizer* create_guide_right_section(wxPanel* parent);
wxBoxSizer* create_main_page_sizer(wxPanel* parent);
wxBoxSizer* create_left_panel(wxPanel* parent);
wxBoxSizer* create_humidity_status_section(wxPanel* parent);
wxBoxSizer* create_description_item(wxPanel* parent, const wxString& title, Label*& dataLabel);
wxBoxSizer* create_status_descriptions_section(wxPanel* parent);
wxBoxSizer* create_right_panel(wxPanel* parent);
wxBoxSizer* create_normal_state_panel(wxPanel* parent);
wxBoxSizer* create_cannot_dry_panel(wxPanel* parent);
wxBoxSizer* create_drying_error_panel(wxPanel* parent);
Button* create_button(wxPanel* parent, const wxString& title,
const wxColour& background_color, const wxColour& border_color, const wxColour& text_color);
wxBoxSizer* create_progress_page_sizer(wxPanel* parent);
void OnProgressTimer(wxTimerEvent& event);
void OnClose(wxCloseEvent& event);
void OnShow(wxShowEvent& event);
void OnFilamentSelectionChanged(wxCommandEvent& event);
wxScrolledWindow* create_preview_scrolled_window(wxWindow* parent);
bool check_values_changed(DevAms* dev_ams);
int update_image(DevAmsType type, DevAms::DryStatus status, DevAms::DrySubStatus sub_status, int humidity_percent);
void update_img_description(DevAms::DryStatus status, DevAms::DrySubStatus sub_status);
void update_normal_description(DevAms* dev_ams);
int update_state(DevAms* dev_ams);
int update_dryness_status(DevAms* dev_ams);
int update_ams_change(DevAms* dev_ams);
int update_filament_list(DevAms* dev_ams, MachineObject* obj);
void update_filament_guide_info(DevAms* dev_ams);
void update_normal_state(DevAms* dev_ams);
void update_printer_state(MachineObject* obj);
std::shared_ptr<DevFilaSystem> get_fila_system() const;
void start_sending_drying_command();
void restore_stop_button_if_deadline_passed();
void restore_unload_button_if_deadline_passed();
void update_button_size(Button* button);
bool is_dry_status_changed(DevAms* dev_ams);
bool is_dry_ctr_idle(DevAms* dev_ams);
bool is_ams_changed(DevAms* dev_ams);
bool is_dry_ctr_idle();
bool is_tray_changed(DevAms* dev_ams);
bool is_dry_ctr_err(DevAms* dev_ams);
};
} // GUI
} // Slic3r
+2 -2
View File
@@ -1440,7 +1440,7 @@ PageTemperatures::PageTemperatures(ConfigWizard *parent)
spin_bed->SetValue(default_bed != nullptr && default_bed->size() > 0 ? default_bed->get_at(0) : 0);
append_text(_L("Enter the nozzle_temperature needed for extruding your filament."));
append_text(_L("A rule of thumb is 160 to 230 °C for PLA, and 215 to 250 °C for ABS."));
append_text(_L("A rule of thumb is 160 to 230℃ for PLA, and 215 to 250℃ for ABS."));
#endif
auto *sizer_extr = new wxFlexGridSizer(3, 5, 5);
@@ -1455,7 +1455,7 @@ PageTemperatures::PageTemperatures(ConfigWizard *parent)
append_spacer(VERTICAL_SPACING);
append_text(_L("Enter the bed temperature needed for getting your filament to stick to your heated bed."));
append_text(_L("A rule of thumb is 60 °C for PLA and 110 °C for ABS. Leave zero if you have no heated bed."));
append_text(_L("A rule of thumb is 60℃ for PLA and 110℃ for ABS. Leave zero if you have no heated bed."));
auto *sizer_bed = new wxFlexGridSizer(3, 5, 5);
auto *text_bed = new wxStaticText(this, wxID_ANY, _L("Bed Temperature:"));
+10
View File
@@ -41,6 +41,16 @@ enum AmsStatusMain
AMS_STATUS_MAIN_UNKNOWN = 0xFF,
};
enum DevAmsType : int
{
EXT_SPOOL = 0, // EXT
AMS = 1, // AMS1
AMS_LITE = 2, // AMS-Lite
N3F = 3, // N3F, AMS 2PRO
N3S = 4, // N3S, AMS HT
AMS_LITE_MIXED = 5, // AMS-Lite for N9
};
// Device-numbered filament-change step codes. Newer firmware reports the exact change-step
// sequence through the AMS (ams.cfs), keyed by these codes, instead of the client hardcoding
// steps per model. Distinct from the legacy GUI-side Slic3r::GUI::FilamentStep enum.
+63 -12
View File
@@ -7,6 +7,7 @@
#include "slic3r/GUI/I18N.hpp"
#include "DevUtil.h"
#include "DevUtilBackend.h"
using namespace nlohmann;
@@ -99,6 +100,11 @@ std::string DevAmsTray::get_filament_type()
return m_fila_type;
}
std::optional<Slic3r::DevFilamentDryingPreset> DevAmsTray::get_ams_drying_preset() const
{
return DevUtilBackend::GetFilamentDryingPreset(setting_id);
}
DevAms::DevAms(const std::string& ams_id, int extruder_id, AmsType type)
{
@@ -112,7 +118,7 @@ DevAms::DevAms(const std::string& ams_id, int nozzle_id, int type)
m_ams_id = ams_id;
m_ext_id = nozzle_id;
m_ams_type = (AmsType)type;
assert(DUMMY < type && m_ams_type <= AMS_LITE_MIXED);
assert(EXT_SPOOL < type && m_ams_type <= AMS_LITE_MIXED);
}
DevAms::~DevAms()
@@ -193,6 +199,27 @@ DevAmsTray* DevAms::GetTray(const std::string& tray_id) const
return nullptr;
}
bool DevAms::IsSupportRemoteDry(const MachineObject* obj) const
{
if (obj && obj->is_support_remote_dry) {
return SupportDrying();
}
return false;
}
bool DevAms::AmsIsDrying()
{
if (!GetDryStatus().has_value()) {
return false;
}
return GetDryStatus().value() == DevAms::DryStatus::Checking
|| GetDryStatus().value() == DevAms::DryStatus::Drying
|| GetDryStatus().value() == DevAms::DryStatus::Error
|| GetDryStatus().value() == DevAms::DryStatus::CannotStopHeatOutofControl;
}
DevFilaSystem::~DevFilaSystem()
{
for (auto it = amsList.begin(); it != amsList.end(); it++)
@@ -515,9 +542,18 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS
;
}
if (it->contains("dry_time") && (*it)["dry_time"].is_number())
if (it->contains("temp"))
{
curr_ams->m_left_dry_time = (*it)["dry_time"].get<int>();
std::string temp = (*it)["temp"].get<std::string>();
try
{
curr_ams->m_current_temperature = DevUtil::string_to_float(temp);
}
catch (...)
{
curr_ams->m_current_temperature = INVALID_AMS_TEMPERATURE;
}
}
if (it->contains("humidity"))
@@ -546,17 +582,32 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS
}
}
if (it->contains("temp"))
if (it->contains("dry_time") && (*it)["dry_time"].is_number())
{
std::string temp = (*it)["temp"].get<std::string>();
try
{
curr_ams->m_current_temperature = DevUtil::string_to_float(temp);
curr_ams->m_left_dry_time = (*it)["dry_time"].get<int>();
}
// Drying status — only parse if printer supports remote drying
if (obj->is_support_remote_dry) {
if (it->contains("info")) {
const std::string& info = (*it)["info"].get<std::string>();
curr_ams->m_dry_status = (DevAms::DryStatus)DevUtil::get_flag_bits(info, 4, 4);
curr_ams->m_dry_fan1_status = (DevAms::DryFanStatus)DevUtil::get_flag_bits(info, 18, 2);
curr_ams->m_dry_fan2_status = (DevAms::DryFanStatus)DevUtil::get_flag_bits(info, 20, 2);
curr_ams->m_dry_sub_status = (DevAms::DrySubStatus)DevUtil::get_flag_bits(info, 22, 2);
}
catch (...)
{
curr_ams->m_current_temperature = INVALID_AMS_TEMPERATURE;
if (it->contains("dry_setting")) {
const auto& j_dry_settings = (*it)["dry_setting"];
DevAms::DrySettings dry_settings;
DevJsonValParser::ParseVal(j_dry_settings, "dry_filament", dry_settings.dry_filament);
DevJsonValParser::ParseVal(j_dry_settings, "dry_temperature", dry_settings.dry_temp);
DevJsonValParser::ParseVal(j_dry_settings, "dry_duration", dry_settings.dry_hour);
curr_ams->m_dry_settings = dry_settings;
}
if (it->contains("dry_sf_reason")) {
curr_ams->m_dry_cannot_reasons = DevJsonValParser::GetVal<std::vector<DevAms::CannotDryReason>>((*it), "dry_sf_reason");
}
}
+105 -11
View File
@@ -12,6 +12,9 @@
#include <vector>
#include <optional>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <wx/string.h>
#include <wx/colour.h>
@@ -20,6 +23,7 @@
namespace Slic3r
{
class MachineObject;
struct DevFilamentDryingPreset;
/**
* DevAmsTray - Represents a single filament tray/slot in an AMS unit or virtual tray.
@@ -106,6 +110,8 @@ public:
// static
static wxColour decode_color(const std::string& color);
std::optional<DevFilamentDryingPreset> get_ams_drying_preset() const;
};
/**
@@ -133,14 +139,67 @@ class DevAms
{
friend class DevFilaSystemParser;
public:
enum AmsType : int
using AmsType = DevAmsType;
static constexpr AmsType EXT_SPOOL = DevAmsType::EXT_SPOOL;
static constexpr AmsType AMS = DevAmsType::AMS;
static constexpr AmsType AMS_LITE = DevAmsType::AMS_LITE;
static constexpr AmsType N3F = DevAmsType::N3F;
static constexpr AmsType N3S = DevAmsType::N3S;
static constexpr AmsType AMS_LITE_MIXED = DevAmsType::AMS_LITE_MIXED;
public:
enum class DryCtrlMode : int
{
DUMMY = 0,
AMS = 1, // AMS
AMS_LITE = 2, // AMS-Lite
N3F = 3, // N3F
N3S = 4, // N3S
AMS_LITE_MIXED = 5, // AMS-Lite mixed (A2L / N9). Presents as AMS_LITE to generic callers; see GetAmsType()/IsAmsLiteMixed().
Off = 0,
OnTime = 1,
OnHumidity = 2,
};
enum class DryStatus : char
{
Off = 0,
Checking = 1,
Drying = 2,
Cooling = 3,
Stopping = 4,
Error = 5,
CannotStopHeatOutofControl = 6,
PrdTesting = 7,
};
enum class DrySubStatus
{
Off = 0,
Heating = 1,
Dehumidify = 2,
};
enum class DryFanStatus : char
{
Off = 0,
On = 1,
};
enum class CannotDryReason : int
{
TaskOccupied = 0,
InsufficientPower = 1,
AmsBusy = 2,
ConsumableAtAmsOutlet = 3,
InitiatingAmsDrying = 4,
NotSupportedIn2dMode = 5,
DryingInProgress = 6,
Upgrading = 7,
InsufficientPowerNeedPluginPower = 8,
FilamentAtAmsOutletManualUnload = 10,
};
struct DrySettings
{
std::string dry_filament;
int dry_temp = -1; // -1 means invalid
int dry_hour = -1; // -1 means invalid, hours
};
public:
@@ -193,11 +252,20 @@ public:
int GetHumidityLevel() const { return m_humidity_level; }
int GetHumidityPercent() const { return m_humidity_percent; }
// Only N3F/N3S dry. Written explicitly (not `> AMS_LITE`) so the new AMS_LITE_MIXED (N9) is
// excluded; identical to the old expression for every pre-existing type.
bool SupportDrying() const { return (m_ams_type == N3F) || (m_ams_type == N3S); }
bool SupportDrying() const { return m_ams_type == DevAmsType::N3F || m_ams_type == DevAmsType::N3S; }
int GetLeftDryTime() const { return m_left_dry_time; }
// remote drying control
bool IsSupportRemoteDry(const MachineObject* obj) const;
std::optional<DryStatus> GetDryStatus() const { return m_dry_status; };
std::optional<DrySubStatus> GetDrySubStatus() const { return m_dry_sub_status; }
std::optional<DryFanStatus> GetFan1Status() const { return m_dry_fan1_status; }
std::optional<DryFanStatus> GetFan2Status() const { return m_dry_fan2_status; }
std::optional<std::vector<CannotDryReason>> GetCannotDryReason() const { return m_dry_cannot_reasons; }
std::optional<DrySettings> GetDrySettings() const { return m_dry_settings; };
bool AmsIsDrying();
private:
AmsType m_ams_type = AmsType::AMS;
std::string m_ams_id;
@@ -218,6 +286,14 @@ private:
int m_humidity_level = 5; // AmsType::AMS
int m_humidity_percent = -1; // N3F N3S, the percentage, -1 means invalid. eg. 100 means 100%
int m_left_dry_time = 0;
// see is_support_remote_dry
std::optional<DryStatus> m_dry_status;
std::optional<DrySubStatus> m_dry_sub_status;
std::optional<DryFanStatus> m_dry_fan1_status;
std::optional<DryFanStatus> m_dry_fan2_status;
std::optional<std::vector<CannotDryReason>> m_dry_cannot_reasons;
std::optional<DrySettings> m_dry_settings;
};
/**
@@ -299,7 +375,11 @@ public:
public:
// ctrls
int CtrlAmsReset() const;
// crtl
int CtrlAmsStartDryingHour(int ams_id, std::string filament_type, int tag_temp, int tag_duration_hour, bool rotate_tray, int cooling_temp, bool close_power_conflict = false) const;
int CtrlAmsStopDrying(int ams_id) const;
public:
static bool IsBBL_Filament(std::string tag_uid);
@@ -339,4 +419,18 @@ public:
static void ParseAgentFilament(const json& data, MachineObject* obj, DevFilaSystem* system);
};
struct DevFilamentDryingPreset
{
std::string filament_id;
std::unordered_set<DevAmsType> ams_limitations; // only use ams types in the set
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_time_on_idle; // hour
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_temperature_on_idle;
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_time_on_print; // hour
std::unordered_map<DevAmsType, float> filament_dev_ams_drying_temperature_on_print;
float filament_dev_drying_cooling_temperature = 0.0f;
float filament_dev_drying_softening_temperature = 0.0f;
float filament_dev_ams_drying_heat_distortion_temperature = 0.0f;
};
}// namespace Slic3r
@@ -16,4 +16,44 @@ int DevFilaSystem::CtrlAmsReset() const
return m_owner->publish_json(jj_command);
}
int DevFilaSystem::CtrlAmsStartDryingHour(int ams_id,
std::string filament_type,
int tag_temp,
int tag_duration_hour,
bool rotate_tray,
int cooling_temp,
bool close_power_conflict) const
{
json jj_command;
jj_command["print"]["command"] = "ams_filament_drying";
jj_command["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
jj_command["print"]["ams_id"] = ams_id;
jj_command["print"]["mode"] = static_cast<int>(DevAms::DryCtrlMode::OnTime);
jj_command["print"]["filament"] = filament_type;
jj_command["print"]["temp"] = tag_temp;
jj_command["print"]["duration"] = tag_duration_hour;
jj_command["print"]["humidity"] = 0;
jj_command["print"]["rotate_tray"] = rotate_tray;
jj_command["print"]["cooling_temp"] = cooling_temp;
jj_command["print"]["close_power_conflict"] = close_power_conflict;
return m_owner->publish_json(jj_command);
}
int DevFilaSystem::CtrlAmsStopDrying(int ams_id) const
{
json jj_command;
jj_command["print"]["command"] = "ams_filament_drying";
jj_command["print"]["sequence_id"] = std::to_string(MachineObject::m_sequence_id++);
jj_command["print"]["ams_id"] = ams_id;
jj_command["print"]["mode"] = static_cast<int>(DevAms::DryCtrlMode::Off);
jj_command["print"]["filament"] = "";
jj_command["print"]["temp"] = 0;
jj_command["print"]["duration"] = 0;
jj_command["print"]["humidity"] = 0;
jj_command["print"]["rotate_tray"] = false;
jj_command["print"]["cooling_temp"] = 0;
jj_command["print"]["close_power_conflict"] = false;
return m_owner->publish_json(jj_command);
}
}
+1 -1
View File
@@ -199,7 +199,7 @@ namespace Slic3r
}
}
FilamentInfo info;
_parse_tray_info(atoi(tray.id.c_str()), 0, DevAms::DUMMY, tray, info);
_parse_tray_info(atoi(tray.id.c_str()), 0, DevAms::EXT_SPOOL, tray, info);
tray_filaments.emplace(std::make_pair(info.tray_id, info));
}
}
@@ -1,7 +1,11 @@
#include "DevUtilBackend.h"
#include "slic3r/GUI/BackgroundSlicingProcess.hpp"
#include "slic3r/GUI/Plater.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include <boost/log/trivial.hpp>
namespace Slic3r
{
@@ -15,4 +19,68 @@ std::shared_ptr<MultiNozzleUtils::NozzleGroupResultBase> DevUtilBackend::GetNozz
return nullptr;
}
static std::unordered_map<std::string, DevAmsType> s_ams_type_map = {
{"0", DevAmsType::N3F},
{"1", DevAmsType::N3S},
};
std::optional<Slic3r::DevFilamentDryingPreset> DevUtilBackend::GetFilamentDryingPreset(const std::string& fila_id)
{
if (fila_id.empty() || !GUI::wxGetApp().preset_bundle) {
return std::nullopt;
}
for (auto iter = GUI::wxGetApp().preset_bundle->filaments.begin(); iter != GUI::wxGetApp().preset_bundle->filaments.end(); ++iter) {
const Preset& filament_preset = *iter;
const auto& config = filament_preset.config;
if (filament_preset.filament_id == fila_id) {
DevFilamentDryingPreset info;
info.filament_id = fila_id;
try {
if (config.has("filament_dev_ams_drying_ams_limitations")) {
std::vector<std::string> types = config.option<ConfigOptionStrings>("filament_dev_ams_drying_ams_limitations")->values;
for (auto type : types) {
if (s_ams_type_map.count(type) == 0) {
continue;
}
info.ams_limitations.insert(s_ams_type_map[type]);
}
}
if (config.has("filament_dev_ams_drying_temperature")) {
info.filament_dev_ams_drying_temperature_on_idle[DevAmsType::N3F] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature")->get_at(0);
info.filament_dev_ams_drying_temperature_on_idle[DevAmsType::N3S] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature")->get_at(1);
info.filament_dev_ams_drying_temperature_on_print[DevAmsType::N3F] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature")->get_at(2);
info.filament_dev_ams_drying_temperature_on_print[DevAmsType::N3S] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_temperature")->get_at(3);
}
if (config.has("filament_dev_ams_drying_time")) {
info.filament_dev_ams_drying_time_on_idle[DevAmsType::N3F] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_time")->get_at(0);
info.filament_dev_ams_drying_time_on_idle[DevAmsType::N3S] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_time")->get_at(1);
info.filament_dev_ams_drying_time_on_print[DevAmsType::N3F] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_time")->get_at(2);
info.filament_dev_ams_drying_time_on_print[DevAmsType::N3S] = config.option<ConfigOptionFloats>("filament_dev_ams_drying_time")->get_at(3);
}
if (config.has("filament_dev_drying_softening_temperature")) {
info.filament_dev_drying_softening_temperature = config.option<ConfigOptionFloats>("filament_dev_drying_softening_temperature")->get_at(0);
}
if (config.has("filament_dev_ams_drying_heat_distortion_temperature")) {
info.filament_dev_ams_drying_heat_distortion_temperature = config.option<ConfigOptionFloats>("filament_dev_ams_drying_heat_distortion_temperature")->get_at(0);
}
if (config.has("filament_dev_drying_cooling_temperature")) {
info.filament_dev_drying_cooling_temperature = config.option<ConfigOptionFloats>("filament_dev_drying_cooling_temperature")->get_at(0);
}
return info;
} catch (const std::exception& e) {
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << " exception: " << e.what();
}
}
}
return std::nullopt;
}
}; // namespace Slic3r
+10 -8
View File
@@ -1,18 +1,15 @@
/**
* @file DevUtilBackend.h
* @brief Static helpers bridging the backend (slicer/preset) to the device GUI.
*
* Scope (H2C nozzle rack): exposes only GetNozzleGroupResult — the accessor the print-dispatch
* nozzle-mapping V1 request and result-resolve helpers read. Related helpers (per-nozzle info
* collection via the ExtruderNozzleInfos/NozzleDef type pair, and the drying-preset lookup) are
* not implemented here and left to the consuming code.
* @brief Provides common static utility methods for backend (preset/slicing).
*/
#pragma once
#include "DevDefs.h"
#include "DevFilaSystem.h"
#include "libslic3r/MultiNozzleUtils.hpp"
#include <memory>
#include <optional>
#include <string>
namespace Slic3r
{
@@ -23,10 +20,15 @@ class DevUtilBackend
public:
DevUtilBackend() = delete;
public:
// for rack: the slicer's per-filament -> logical-nozzle grouping for the current plate, read off
// the post-slice GCodeProcessorResult (plater->background_process().get_current_gcode_result()).
// Returns nullptr when there is no plater / no current result.
static std::shared_ptr<MultiNozzleUtils::NozzleGroupResultBase> GetNozzleGroupResult(Slic3r::GUI::Plater* plater);
// for filament preset
static std::optional<DevFilamentDryingPreset> GetFilamentDryingPreset(const std::string& fila_id);
};
}; // namespace Slic3r
+3 -4
View File
@@ -568,7 +568,7 @@ MachineObject::MachineObject(DeviceManager* manager, NetworkAgent* agent, std::s
m_extder_system = new DevExtderSystem(this);
m_extension_tool = DevExtensionTool::Create(this);
m_nozzle_system = new DevNozzleSystem(this);
m_fila_system = new DevFilaSystem(this);
m_fila_system = std::make_shared<DevFilaSystem>(this);
m_fila_switch = new DevFilaSwitch(this);
m_hms_system = new DevHMS(this);
m_config = new DevConfig(this);
@@ -617,8 +617,6 @@ MachineObject::~MachineObject()
delete m_ctrl;
m_ctrl = nullptr;
delete m_fila_system;
m_fila_system = nullptr;
delete m_fila_switch;
m_fila_switch = nullptr;
@@ -3770,7 +3768,7 @@ int MachineObject::parse_json(std::string tunnel, std::string payload, bool key_
update_printer_preset_name();
update_filament_list();
if (jj.contains("ams")) {
DevFilaSystemParser::ParseV1_0(jj, this, m_fila_system, key_field_only);
DevFilaSystemParser::ParseV1_0(jj, this, m_fila_system.get(), key_field_only);
}
/* vitrual tray*/
@@ -5095,6 +5093,7 @@ void MachineObject::parse_new_info(json print)
// fun2 may have infinite length, use get_flag_bits_no_border
if (!fun2.empty()) {
is_support_print_with_emmc = get_flag_bits_no_border(fun2, 0) == 1;
is_support_remote_dry = (get_flag_bits_no_border(fun2, 5) == 1);
is_support_check_track_switch_match_slice_printer = get_flag_bits_no_border(fun2, 19) == 1;
}
+3 -2
View File
@@ -117,7 +117,7 @@ private:
std::shared_ptr<DevExtensionTool> m_extension_tool;
DevExtderSystem* m_extder_system;
DevNozzleSystem* m_nozzle_system;
DevFilaSystem* m_fila_system;
std::shared_ptr<DevFilaSystem> m_fila_system;
DevFilaSwitch* m_fila_switch;
DevFan* m_fan;
DevBed * m_bed;
@@ -342,7 +342,7 @@ public:
std::shared_ptr<DevNozzleMappingCtrl> get_nozzle_mapping_result() const { return m_nozzle_mapping_ptr; }
void clear_auto_nozzle_mapping();// defined in DevMappingNozzle.cpp
DevFilaSystem* GetFilaSystem() const { return m_fila_system;}
std::shared_ptr<DevFilaSystem> GetFilaSystem() const { return m_fila_system;}
DevFilaSwitch* GetFilaSwitch() const { return m_fila_switch;}
bool HasAms() const;
@@ -635,6 +635,7 @@ public:
// fun2
bool is_support_print_with_emmc{false};
bool is_support_remote_dry = false;
bool is_support_check_track_switch_match_slice_printer{false};
bool installed_upgrade_kit{false};
+2 -2
View File
@@ -445,7 +445,7 @@ void GCodeViewer::SequentialView::Marker::render_position_window(const libvgcode
add_row(_u8L("Flow rate"), buff);
sprintf(buff, "%.0f %%", vertex.fan_speed);
add_row(_u8L("Fan speed"), buff);
sprintf(buff, ("%.0f " + _u8L("°C")).c_str(), vertex.temperature);
sprintf(buff, ("%.0f " + _u8L("\u2103" /* °C */)).c_str(), vertex.temperature);
add_row(_u8L("Temperature"), buff);
sprintf(buff, "%.4f", vertex.pressure_advance);
add_row(_u8L("Pressure Advance"), buff);
@@ -3711,7 +3711,7 @@ void GCodeViewer::render_legend(float &legend_height, int canvas_width, int canv
break;
}
case libvgcode::EViewType::FanSpeed: { imgui.title(_u8L("Fan speed (%)")); break; }
case libvgcode::EViewType::Temperature: { imgui.title(_u8L("Temperature (°C)")); break; }
case libvgcode::EViewType::Temperature: { imgui.title(_u8L("Temperature (℃)")); break; }
// ORCA: Add Pressure Advance visualization support
case libvgcode::EViewType::PressureAdvance:{ imgui.title(_u8L("Pressure Advance")); break; }
case libvgcode::EViewType::VolumetricFlowRate:
+20 -15
View File
@@ -2338,11 +2338,6 @@ void GLCanvas3D::remove_curr_plate_all()
m_dirty = true;
}
void GLCanvas3D::update_plate_thumbnails()
{
_update_imgui_select_plate_toolbar();
}
void GLCanvas3D::select_all()
{
if (!m_gizmos.is_allow_select_all()) {
@@ -3228,7 +3223,6 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
// BBS
//m_dirty |= wxGetApp().plater()->get_view_toolbar().update_items_state();
m_dirty |= wxGetApp().plater()->get_collapse_toolbar().update_items_state();
_update_imgui_select_plate_toolbar();
bool mouse3d_controller_applied = wxGetApp().plater()->get_mouse3d_controller().apply(wxGetApp().plater()->get_camera());
m_dirty |= mouse3d_controller_applied;
m_dirty |= wxGetApp().plater()->get_notification_manager()->update_notifications(*this);
@@ -4838,11 +4832,6 @@ void GLCanvas3D::force_set_focus() {
void GLCanvas3D::on_set_focus(wxFocusEvent& evt)
{
m_tooltip_enabled = false;
if (m_canvas_type == ECanvasType::CanvasPreview) {
// update thumbnails and update plate toolbar
wxGetApp().plater()->update_all_plate_thumbnails();
_update_imgui_select_plate_toolbar();
}
_refresh_if_shown_on_screen();
m_tooltip_enabled = true;
m_is_touchpad_navigation = wxGetApp().app_config->get_bool("camera_navigation_style");
@@ -6925,13 +6914,28 @@ void GLCanvas3D::_update_select_plate_toolbar_stats_item(bool force_selected) {
bool GLCanvas3D::_update_imgui_select_plate_toolbar()
{
bool result = true;
if (!m_sel_plate_toolbar.is_enabled() || m_sel_plate_toolbar.is_render_finish) return false;
if (!m_sel_plate_toolbar.is_enabled()) {
return false;
}
const auto& p_plater = wxGetApp().plater();
if (!p_plater) {
return false;
}
if (!p_plater->is_plate_toolbar_image_dirty()) {
return false;
}
if (!p_plater->is_gcode_3mf()) {
p_plater->update_all_plate_thumbnails(true);
}
_update_select_plate_toolbar_stats_item();
m_sel_plate_toolbar.del_all_item();
PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list();
PartPlateList& plate_list = p_plater->get_partplate_list();
for (int i = 0; i < plate_list.get_plate_count(); i++) {
IMToolbarItem* item = new IMToolbarItem();
PartPlate* plate = plate_list.get_plate(i);
@@ -6944,7 +6948,7 @@ bool GLCanvas3D::_update_imgui_select_plate_toolbar()
}
m_sel_plate_toolbar.m_items.push_back(item);
}
p_plater->clear_plate_toolbar_image_dirty();
m_sel_plate_toolbar.is_display_scrollbar = false;
return result;
}
@@ -8802,6 +8806,8 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
return;
}
_update_imgui_select_plate_toolbar();
IMToolbarItem* all_plates_stats_item = m_sel_plate_toolbar.m_all_plates_stats_item;
PartPlateList& plate_list = wxGetApp().plater()->get_partplate_list();
@@ -9218,7 +9224,6 @@ void GLCanvas3D::_render_imgui_select_plate_toolbar()
m_sel_plate_toolbar.is_display_scrollbar = is_win_hovered;
imgui.end();
m_sel_plate_toolbar.is_render_finish = true;
}
//BBS: GUI refactor: GLToolbar adjust
-1
View File
@@ -997,7 +997,6 @@ public:
void select_curr_plate_all();
void select_object_from_idx(std::vector<int>& object_idxs);
void remove_curr_plate_all();
void update_plate_thumbnails();
void select_all();
void deselect_all();
+25 -15
View File
@@ -4775,7 +4775,7 @@ void GUI_App::request_user_logout(const std::string& provider/* = ORCA_CLOUD_PRO
remove_user_presets();
enable_user_preset_folder(false);
Slic3r::PluginManager::instance().unload_cloud_plugins();
Slic3r::PluginManager::instance().clear_cloud_plugin_catalog();
Slic3r::PluginManager::instance().clear_cloud_plugin_metadata();
Slic3r::PluginManager::instance().set_cloud_user("");
preset_bundle->load_user_presets(DEFAULT_USER_FOLDER_NAME, ForwardCompatibilitySubstitutionRule::Enable);
mainframe->update_side_preset_ui();
@@ -8255,22 +8255,32 @@ void GUI_App::open_plugins_dialog(size_t open_on_tab, const std::string& highlig
void GUI_App::open_terminal_dialog()
{
if (m_terminal_dlg) {
// Reached from the plugins dialog's webview ("open_terminal" command), i.e. from
// inside the webview script-message callback, which GTK/macOS deliver synchronously
// (see ui_create_window in PluginHostUi.cpp). TerminalDialog hosts a webview of its
// own, so creating or presenting it on that stack is the same class as the Linux
// gtk_window_present crash — defer all window work to a clean main-loop iteration.
CallAfter([this]() {
if (m_terminal_dlg) {
// Re-front the existing window; guard Show() per #13657 (GTK re-enters
// layout when showing an already-visible window).
if (!m_terminal_dlg->IsShown())
m_terminal_dlg->Show();
m_terminal_dlg->Raise();
return;
}
m_terminal_dlg = new TerminalDialog(mainframe, wxID_ANY, _L("Plugin Terminal"),
wxDefaultPosition, wxSize(820, 600));
m_terminal_dlg->Bind(wxEVT_DESTROY, [this](wxWindowDestroyEvent& event) {
if (event.GetEventObject() == m_terminal_dlg)
m_terminal_dlg = nullptr;
event.Skip();
});
// Show() alone activates and fronts a freshly created window on every platform.
m_terminal_dlg->Show();
m_terminal_dlg->Raise();
return;
}
m_terminal_dlg = new TerminalDialog(mainframe, wxID_ANY, _L("Plugin Terminal"),
wxDefaultPosition, wxSize(820, 600));
m_terminal_dlg->Bind(wxEVT_DESTROY, [this](wxWindowDestroyEvent& event) {
if (event.GetEventObject() == m_terminal_dlg)
m_terminal_dlg = nullptr;
event.Skip();
});
m_terminal_dlg->Show();
m_terminal_dlg->Raise();
}
void GUI_App::open_exportpresetbundledialog(size_t open_on_tab, const std::string& highlight_option)
-2
View File
@@ -61,8 +61,6 @@ void IMToolbar::del_stats_item()
void IMToolbar::set_enabled(bool enable)
{
m_enabled = enable;
if (!m_enabled)
is_render_finish = false;
}
bool IMReturnToolbar::init()
-1
View File
@@ -51,7 +51,6 @@ public:
float icon_height;
bool is_display_scrollbar;
bool show_stats_item{ false };
bool is_render_finish{false};
IMToolbar() {
icon_width = DEFAULT_TOOLBAR_BUTTON_WIDTH;
icon_height = DEFAULT_TOOLBAR_BUTTON_HEIGHT;
+4
View File
@@ -3158,6 +3158,9 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
shader->set_uniform("Texture", 0);
shader->set_uniform("ProjMtx", ortho_projection);
const uint8_t stage = 0;
shader->set_uniform("s_texture", stage);
// Will project scissor/clipping rectangles into framebuffer space
const ImVec2 clip_off = draw_data->DisplayPos; // (0,0) unless using multi-viewports
const ImVec2 clip_scale = draw_data->FramebufferScale; // (1,1) unless using retina display which are often (2,2)
@@ -3222,6 +3225,7 @@ void ImGuiWrapper::render_draw_data(ImDrawData *draw_data)
glsafe(::glScissor((int)clip_min.x, (int)(fb_height - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)));
// Bind texture, Draw
glsafe(::glActiveTexture(GL_TEXTURE0 + stage));
glsafe(::glBindTexture(GL_TEXTURE_2D, (GLuint)(intptr_t)pcmd->GetTexID()));
glsafe(::glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, (void*)(intptr_t)(pcmd->IdxOffset * sizeof(ImDrawIdx))));
}
+2
View File
@@ -348,6 +348,8 @@ void FillBedJob::finalize(bool canceled, std::exception_ptr &eptr)
}
m_plater->update();
}
m_plater->mark_plate_toolbar_image_dirty();
}
}} // namespace Slic3r::GUI
+6 -1
View File
@@ -266,7 +266,12 @@ bool OpenGLManager::init_gl(bool popup_error)
else
s_compressed_textures_supported = false;
if (GLAD_GL_ARB_framebuffer_object) {
if (s_gl_info.is_version_greater_or_equal_to(3, 0)) {
// ARB framebuffer became a mandatory part of core OpenGL 3.0
s_framebuffers_type = EFramebufferType::Arb;
BOOST_LOG_TRIVIAL(info) << "Opengl version >= 30, FrameBuffer Type ARB." << std::endl;
}
else if (GLAD_GL_ARB_framebuffer_object) {
s_framebuffers_type = EFramebufferType::Arb;
BOOST_LOG_TRIVIAL(info) << "Found Framebuffer Type ARB."<< std::endl;
}
+11
View File
@@ -2433,6 +2433,9 @@ void PartPlate::set_pos_and_size(Vec3d& origin, int width, int depth, int height
m_depth = depth;
m_height = height;
if (with_instance_move && m_plater)
m_plater->mark_plate_toolbar_image_dirty();
return;
}
@@ -2780,6 +2783,8 @@ int PartPlate::add_instance(int obj_id, int instance_id, bool move_position, Bou
}
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": plate %1% , m_ready_for_slice changes to %2%") % m_plate_index %m_ready_for_slice;
if (m_plater)
m_plater->mark_plate_toolbar_image_dirty();
return 0;
}
@@ -5344,6 +5349,9 @@ int PartPlateList::notify_instance_removed(int obj_id, int instance_id)
unprintable_plate.update_object_index(obj_id, m_model->objects.size());
}
if (m_plater)
m_plater->mark_plate_toolbar_image_dirty();
return 0;
}
@@ -6265,6 +6273,9 @@ int PartPlateList::rebuild_plates_after_arrangement(bool recycle_plates, bool ex
}
#endif
if (m_plater)
m_plater->mark_plate_toolbar_image_dirty();
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":after rebuild, plates count %1%") % m_plate_list.size();
return ret;
}
+31 -10
View File
@@ -290,6 +290,21 @@ void Plater::show_illegal_characters_warning(wxWindow* parent)
show_error(parent, _L("Invalid name, the following characters are not allowed:") + " <>:/\\|?*\"");
}
void Plater::mark_plate_toolbar_image_dirty()
{
m_b_plate_toolbar_image_dirty = true;
}
bool Plater::is_plate_toolbar_image_dirty() const
{
return m_b_plate_toolbar_image_dirty;
}
void Plater::clear_plate_toolbar_image_dirty()
{
m_b_plate_toolbar_image_dirty = false;
}
static std::map<BedType, std::string> bed_type_thumbnails = {
{BedType::btPC, "bed_cool" },
{BedType::btEP, "bed_engineering" },
@@ -6348,10 +6363,8 @@ void Plater::priv::update(unsigned int flags)
//BBS assemble view
this->assemble_view->reload_scene(false, flags);
if (current_panel && is_preview_shown()) {
q->force_update_all_plate_thumbnails();
//update_fff_scene_only_shells(true);
}
// todo: better to mark thumbnail dirty here
q->mark_plate_toolbar_image_dirty();
if (force_background_processing_restart)
this->restart_background_process(update_status);
@@ -7906,6 +7919,7 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
}
}
q->schedule_background_process(true);
q->mark_plate_toolbar_image_dirty();
return obj_idxs;
}
@@ -8285,6 +8299,8 @@ void Plater::priv::object_list_changed()
main_frame->update_slice_print_status(MainFrame::eEventObjectUpdate, can_slice);
wxGetApp().params_panel()->notify_object_config_changed();
q->mark_plate_toolbar_image_dirty();
}
void Plater::priv::select_curr_plate_all()
@@ -9188,6 +9204,8 @@ void Plater::priv::update_fff_scene()
view3D->reload_scene(true);
//BBS: add assemble view related logic
assemble_view->reload_scene(true);
q->mark_plate_toolbar_image_dirty();
}
//BBS: add print project related logic
@@ -10096,9 +10114,6 @@ void Plater::priv::set_current_panel(wxPanel* panel, bool no_slice)
preview->get_canvas3d()->enable_select_plate_toolbar(true);
}
}
else {
preview->get_canvas3d()->enable_select_plate_toolbar(false);
}
if (current_panel == panel)
{
@@ -10957,6 +10972,7 @@ void Plater::priv::on_process_completed(SlicingProcessCompletedEvent &evt)
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(":finished, reload print soon");
m_is_slicing = false;
this->preview->reload_print(false);
q->mark_plate_toolbar_image_dirty();
/* BBS if in publishing progress */
if (m_is_publishing) {
if (m_publish_dlg && !m_publish_dlg->was_cancelled()) {
@@ -13940,8 +13956,13 @@ void adjust_settings_for_flowrate_calib(ModelObjectPtrs& objects, bool linear, i
_obj->config.set_key_value("seam_slope_type", new ConfigOptionEnum<SeamScarfType>(SeamScarfType::None));
_obj->config.set_key_value("gap_fill_target", new ConfigOptionEnum<GapFillTarget>(GapFillTarget::gftNowhere));
print_config->set_key_value("max_volumetric_extrusion_rate_slope", new ConfigOptionFloat(0));
// ORCA: print the top surface spiral from the center outwards, so the tiles are comparable.
_obj->config.set_key_value("top_surface_fill_order", new ConfigOptionEnum<SurfaceFillOrder>(SurfaceFillOrder::Outward));
// ORCA: request the calibration's special toolpath order (chords first, center spiral
// last and inside-out) so opposing directions collide into the tactile lip the test
// reads. The special order only applies while the fill order is Default, so reset the
// profile's fill order on the calibration objects; changing the setting on the object
// afterwards deliberately overrides the special order.
_obj->config.set_key_value("calib_flowrate_topinfill_special_order", new ConfigOptionBool(true));
_obj->config.set_key_value("top_surface_fill_order", new ConfigOptionEnum<SurfaceFillOrder>(SurfaceFillOrder::Default));
// extract flowrate from name, filename format: flowrate_xxx
std::string obj_name = _obj->name;
@@ -14678,6 +14699,7 @@ void Plater::invalid_all_plate_thumbnails()
plate->thumbnail_data.reset();
plate->no_light_thumbnail_data.reset();
}
mark_plate_toolbar_image_dirty();
}
void Plater::force_update_all_plate_thumbnails()
@@ -14688,7 +14710,6 @@ void Plater::force_update_all_plate_thumbnails()
invalid_all_plate_thumbnails();
update_all_plate_thumbnails(true);
}
get_preview_canvas3D()->update_plate_thumbnails();
}
// BBS: backup
+5
View File
@@ -955,6 +955,10 @@ public:
bool is_loading_project() const { return m_loading_project; }
void mark_plate_toolbar_image_dirty();
bool is_plate_toolbar_image_dirty() const;
void clear_plate_toolbar_image_dirty();
private:
struct priv;
std::unique_ptr<priv> p;
@@ -975,6 +979,7 @@ private:
std::string m_preview_only_filename;
int m_valid_plates_count { 0 };
int m_check_status = 0; // 0 not check, 1 check success, 2 check failed
bool m_b_plate_toolbar_image_dirty{ true };
void suppress_snapshots();
void allow_snapshots();
-8
View File
@@ -163,14 +163,6 @@ PluginWebDialog* PluginWebDialog::create_modeless_dialog(wxWindow* parent,
std::move(on_destroyed));
}
void PluginWebDialog::show_modeless_dialog(PluginWebDialog* dialog)
{
if (dialog == nullptr)
return;
dialog->Show();
dialog->Raise();
}
void PluginWebDialog::post_message(PluginWebDialog* dialog, const nlohmann::json& data)
{
if (dialog != nullptr && dialog->is_open())
-1
View File
@@ -52,7 +52,6 @@ public:
MessageHandler on_message,
CloseHandler on_close,
CloseHandler on_destroyed);
static void show_modeless_dialog(PluginWebDialog* dialog);
static void post_message(PluginWebDialog* dialog, const nlohmann::json& data);
static void request_close(PluginWebDialog* dialog);
+51 -29
View File
@@ -116,8 +116,8 @@ struct PluginDialogItem
PluginAvailableActions available_actions;
};
constexpr bool kFetchCloudCatalog = true;
constexpr bool kUseCurrentCloudCatalog = false;
constexpr bool kFetchCloudMeta = true;
constexpr bool kUseCurrentCloudMeta = false;
// The type of a package's first loaded capability. A package that is not loaded has no type.
PluginCapabilityType primary_capability_type_of(PluginManager& manager, const std::string& plugin_key)
@@ -126,7 +126,7 @@ PluginCapabilityType primary_capability_type_of(PluginManager& manager, const st
return capabilities.empty() ? PluginCapabilityType::Unknown : capabilities.front()->type();
}
std::vector<PluginDescriptor> current_cloud_catalog_snapshot()
std::vector<PluginDescriptor> current_cloud_metadata_snapshot()
{
std::vector<PluginDescriptor> cloud_entries;
for (const PluginDescriptor& entry : PluginManager::instance().get_plugin_descriptors(/*include_invalid=*/true))
@@ -147,20 +147,18 @@ PluginDescriptor as_cloud_only_descriptor(PluginDescriptor descriptor)
return descriptor;
}
// rescan_plugins() clears the whole catalog and rediscovers only local packages, so when no fresh cloud
// data is needed, restore the current cloud rows afterwards or cloud-only rows would disappear.
void refresh_plugin_catalog_blocking(bool fetch_cloud)
void refresh_plugin_metadata_blocking(bool fetch_cloud)
{
PluginManager& manager = PluginManager::instance();
std::vector<std::string> not_found, unauthorized;
const std::vector<PluginDescriptor> current_cloud_catalog = fetch_cloud ? std::vector<PluginDescriptor>{} :
current_cloud_catalog_snapshot();
const std::vector<PluginDescriptor> current_cloud_metadata = fetch_cloud ? std::vector<PluginDescriptor>{} :
current_cloud_metadata_snapshot();
manager.rescan_plugins();
if (!fetch_cloud) {
manager.update_cloud_catalog(current_cloud_catalog);
manager.update_cloud_metadata(current_cloud_metadata);
return;
}
@@ -450,7 +448,7 @@ void PluginsDialog::set_open_terminal_dlg_fn()
void PluginsDialog::update_plugin_dialog_ui()
{
// Called after the shared catalog is already updated, for example from the
// Called after the any metadata is already updated, for example from the
// cloud-plugin state callback. Do not fetch here or the callback can re-enter.
send_plugins();
resolve_pending_activation();
@@ -482,10 +480,21 @@ void PluginsDialog::on_script_message(const nlohmann::json& payload)
if (handle_common_script_command(payload))
return;
// Defer command handling out of the webview script-message callback: GTK and macOS
// deliver it synchronously inside the native webview callback (see ui_create_window
// in PluginHostUi.cpp), and window work on that stack is the crash class fixed in
// b779a7bfed/f2ccbfc8b5. Deferring at this single entry point keeps every command
// handler, current and future, off that stack by construction.
wxGetApp().CallAfter([this, alive = m_alive, payload]() {
if (alive->load(std::memory_order_acquire))
handle_web_command(payload);
});
}
void PluginsDialog::handle_web_command(const nlohmann::json& payload)
{
const std::string command = payload.value("command", "");
if (command == "request_plugins") {
// Discovery already runs at startup and on login, so the shared catalog is up to date by the
// time the dialog opens: render it without a blocking fetch. Refresh is what rediscovers.
send_plugins();
} else if (command == "refresh_plugins") {
refresh_plugins();
@@ -498,8 +507,8 @@ void PluginsDialog::on_script_message(const nlohmann::json& payload)
install_plugin_from_file();
} else if (command == "plugin_menu_action") {
handle_plugin_menu_action(payload.value("plugin_key", ""), payload.value("action", ""));
} else if (command == "run_script_plugin") {
run_script_plugin(payload.value("plugin_key", ""), payload.value("capability_name", ""));
} else if (command == "run_script_plugin_capability") {
run_script_plugin_capability(payload.value("plugin_key", ""), payload.value("capability_name", ""));
} else if (command == "open_terminal") {
m_open_terminal_dlg_fn();
} else if (command == "update_plugin") {
@@ -575,16 +584,16 @@ bool PluginsDialog::get_descriptor(const std::string& plugin_key, PluginDescript
return manager.try_get_plugin_descriptor(plugin_key, descriptor) && descriptor.is_invalid_package();
}
void PluginsDialog::refresh_plugin_catalog_async(const wxString& title, const wxString& message, bool fetch_cloud)
void PluginsDialog::refresh_plugin_metadata_async(const wxString& title, const wxString& message, bool fetch_cloud)
{
run_with_dialog([fetch_cloud]() { refresh_plugin_catalog_blocking(fetch_cloud); }, [this]() { send_plugins(); }, title, message);
run_with_dialog([fetch_cloud]() { refresh_plugin_metadata_blocking(fetch_cloud); }, [this]() { send_plugins(); }, title, message);
}
void PluginsDialog::refresh_plugins()
{
BOOST_LOG_TRIVIAL(info) << "Refreshing plugins from Plugins dialog";
refresh_plugin_catalog_async(_L("Refreshing"), _L("Refreshing plugins data"), kFetchCloudCatalog);
refresh_plugin_metadata_async(_L("Refreshing"), _L("Refreshing plugins data"), kFetchCloudMeta);
}
void PluginsDialog::toggle_plugin(const std::string& plugin_key, bool enabled)
@@ -596,7 +605,6 @@ void PluginsDialog::toggle_plugin(const std::string& plugin_key, bool enabled)
PluginDescriptor row_data;
if (!get_descriptor(plugin_key, row_data)) {
// The catalog changed under the UI. Toggling is local, so just re-render from it.
send_plugins();
return;
}
@@ -688,7 +696,6 @@ void PluginsDialog::toggle_plugin_capability(const std::string& plugin_key,
PluginDescriptor row_data;
if (!get_descriptor(plugin_key, row_data)) {
// The catalog changed under the UI. Toggling is local, so just re-render from it.
send_plugins();
return;
}
@@ -741,12 +748,24 @@ void PluginsDialog::handle_plugin_menu_action(const std::string& plugin_key, con
}
}
void PluginsDialog::restore_z_order()
{
// Deferred so it runs on a clean stack after the modal has fully torn down; the
// alive guard covers the dialog being destroyed while the CallAfter is queued.
wxGetApp().CallAfter([this, alive = m_alive]() {
if (alive->load(std::memory_order_acquire) && IsShown())
Raise();
});
}
void PluginsDialog::install_plugin_from_file()
{
wxFileDialog dialog(this, _L("Select plugin package"), wxEmptyString, wxEmptyString, _L("Plugin files (*.py;*.whl)|*.py;*.whl"),
wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (dialog.ShowModal() != wxID_OK)
const int rc = dialog.ShowModal();
restore_z_order();
if (rc != wxID_OK)
return;
if (!install_plugin_package(dialog.GetPath().ToUTF8().data())) {
@@ -799,7 +818,9 @@ bool PluginsDialog::install_plugin_package(const std::string& package_path)
plugin_name),
kOverwritePluginTitle, wxOK | wxCANCEL | wxCANCEL_DEFAULT | wxICON_WARNING);
dialog.SetOKCancelLabels(_L("Overwrite"), _L("Cancel"));
if (dialog.ShowModal() != wxID_OK) {
const int overwrite_rc = dialog.ShowModal();
restore_z_order();
if (overwrite_rc != wxID_OK) {
BOOST_LOG_TRIVIAL(info) << "Plugin package installation cancelled before overwrite. package=" << package_path
<< " plugin=" << plugin_descriptor.name;
return false;
@@ -827,7 +848,7 @@ bool PluginsDialog::install_plugin_package(const std::string& package_path)
BOOST_LOG_TRIVIAL(info) << "Plugin package installed successfully from " << package_path;
const wxString installed_name = from_u8(plugin_descriptor.name.empty() ? package_file.filename().string() : plugin_descriptor.name);
show_status(wxString::Format(_L("Installed \"%s\"."), installed_name), "success");
refresh_plugin_catalog_async(_L("Refreshing"), _L("Refreshing plugins data"), kUseCurrentCloudCatalog);
refresh_plugin_metadata_async(_L("Refreshing"), _L("Refreshing plugins data"), kUseCurrentCloudMeta);
return true;
}
@@ -910,7 +931,7 @@ void PluginsDialog::restore_capability_config(const PluginCapabilityId& id)
show_status(_L("Default configuration restored."), "success");
}
void PluginsDialog::run_script_plugin(const std::string& plugin_key, const std::string& capability_name)
void PluginsDialog::run_script_plugin_capability(const std::string& plugin_key, const std::string& capability_name)
{
PluginManager& manager = PluginManager::instance();
@@ -1046,16 +1067,17 @@ void PluginsDialog::delete_local_plugin(const PluginDescriptor& plugin)
const wxString plugin_name = from_u8(plugin.name);
const int rc = wxMessageBox(wxString::Format(_L("Delete plugin \"%s\"?\n\nThis permanently removes the plugin folder."), plugin_name),
kDeletePluginTitle, wxYES_NO | wxNO_DEFAULT | wxICON_WARNING, this);
restore_z_order();
if (rc != wxYES)
return;
auto state = std::make_shared<PluginOperationState>();
run_with_dialog(
[plugin_key = plugin.plugin_key, refresh_catalog = plugin.is_cloud_plugin(), state]() {
[plugin_key = plugin.plugin_key, should_refresh = plugin.is_cloud_plugin(), state]() {
std::string error;
const bool succeeded = PluginManager::instance().delete_plugin(plugin_key, error);
if (succeeded && refresh_catalog)
refresh_plugin_catalog_blocking(kFetchCloudCatalog);
if (succeeded && should_refresh)
refresh_plugin_metadata_blocking(kFetchCloudMeta);
store_plugin_operation_result(state, succeeded, std::move(error));
},
[this, state, plugin_name]() {
@@ -1078,6 +1100,7 @@ void PluginsDialog::unsubscribe_cloud_plugin(const PluginDescriptor& plugin)
wxString::Format(_L("Unsubscribe plugin \"%s\"?\n\nThis will stop tracking the plugin and delete any local plugin files."),
plugin_name),
kUnsubscribeTitle, wxYES_NO | wxNO_DEFAULT | wxICON_WARNING, this);
restore_z_order();
if (rc != wxYES)
return;
@@ -1159,7 +1182,7 @@ void PluginsDialog::reinstall_cloud_plugin(const PluginDescriptor& plugin)
return;
}
manager.update_cloud_catalog(std::vector<PluginDescriptor>{as_cloud_only_descriptor(plugin)});
manager.update_cloud_metadata(std::vector<PluginDescriptor>{as_cloud_only_descriptor(plugin)});
}
if (!install_cloud_plugin(plugin_key, plugin.version, from_u8(plugin.name))) {
@@ -1207,6 +1230,7 @@ void PluginsDialog::delete_mine_local_and_cloud_plugin(const std::string& plugin
"deletes the plugin from the cloud. This action cannot be undone."),
plugin_name),
kDeletePluginTitle, wxYES_NO | wxNO_DEFAULT | wxICON_WARNING, this);
restore_z_order();
if (rc != wxYES)
return;
@@ -1216,8 +1240,6 @@ void PluginsDialog::delete_mine_local_and_cloud_plugin(const std::string& plugin
return;
}
// delete_mine_local_and_cloud_plugin already updated the in-memory catalog (see
// finalize_cloud_plugin_removal), so a UI refresh is sufficient here.
send_plugins();
show_status(wxString::Format(_L("Deleted \"%s\"."), plugin_name), "success");
}
+16 -6
View File
@@ -53,6 +53,13 @@ private:
void open_plugin_on_cloud(const std::string& sharing_token);
void open_plugin_hub();
void on_script_message(const nlohmann::json& payload) override;
// Runs one web command on a clean main-loop stack; see on_script_message.
void handle_web_command(const nlohmann::json& payload);
// Re-raises this dialog after a transient modal it opened (file dialog, message box,
// progress dialog). Native macOS panels end by re-activating the app's main window
// (the mainframe) instead of this webview-hosting dialog, burying it; wx only
// compensates for generic wxDialog modals (wxDialog::EndModal raises the parent).
void restore_z_order();
void send_plugins();
void set_plugin_sort(const std::string& sort_key, const std::string& sort_order);
@@ -60,7 +67,7 @@ private:
bool get_descriptor(const std::string& plugin_key, Slic3r::PluginDescriptor& descriptor) const;
void refresh_plugin_catalog_async(const wxString& title, const wxString& message, bool fetch_cloud);
void refresh_plugin_metadata_async(const wxString& title, const wxString& message, bool fetch_cloud);
void refresh_plugins();
void toggle_plugin(const std::string& plugin_key, bool enabled);
void toggle_plugin_capability(const std::string& plugin_key, PluginCapabilityType type, const std::string& capability_name, bool enabled);
@@ -69,7 +76,7 @@ private:
void install_plugin_from_file();
bool install_plugin_package(const std::string& package_path);
bool install_cloud_plugin(const std::string& uuid, const std::string& version, const wxString& name);
void run_script_plugin(const std::string& plugin_key, const std::string& capability_name);
void run_script_plugin_capability(const std::string& plugin_key, const std::string& capability_name);
// Config tab. Both are scoped to the full capability ID: a request naming a
// capability that is gone or not configurable is refused rather than served from, or written
// to, some other entry.
@@ -114,7 +121,8 @@ private:
timer->Start(100);
std::thread([alive,
std::thread([this,
alive,
progress,
timer,
run = std::forward<Run>(run),
@@ -131,7 +139,8 @@ private:
if (wxTheApp == nullptr)
return;
wxTheApp->CallAfter([alive,
wxTheApp->CallAfter([this,
alive,
progress,
timer,
on_finish = std::move(on_finish),
@@ -141,6 +150,7 @@ private:
if (alive->load(std::memory_order_acquire)) {
progress->Destroy();
restore_z_order();
on_finish();
} else if (finish_after_dialog_destroyed) {
on_finish();
@@ -240,9 +250,9 @@ private:
PluginSortKey m_plugin_sort_key = PluginSortKey::None;
PluginSortOrder m_plugin_sort_order = PluginSortOrder::Asc;
// Serializes run_script_plugin. With main-thread execution a plugin's orca.host.ui modal
// Serializes run_script_plugin_capability. With main-thread execution a plugin's orca.host.ui modal
// (message/show_dialog) or the result message box pumps a nested event loop, which could
// re-dispatch the web "run_script_plugin" command and start a second, overlapping run.
// re-dispatch the web "run_script_plugin_capability" command and start a second, overlapping run.
bool m_script_running = false;
// Plugin whose asynchronous activation is in flight, awaited by resolve_pending_activation().
+104
View File
@@ -521,6 +521,14 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater)
//m_change_filament_times_sizer->Add(m_img_change_filament_times, 0, wxTOP, FromDIP(2));
m_change_filament_times_sizer->Add(m_txt_change_filament_times, 0, wxTOP, 0);
m_warn_when_drying_sizer = new wxBoxSizer(wxHORIZONTAL);
m_txt_warn_when_drying = new Label(m_scroll_area, wxEmptyString);
m_txt_warn_when_drying->SetFont(::Label::Body_13);
m_txt_warn_when_drying->SetForegroundColour(wxColour("#F09A17"));
m_txt_warn_when_drying->SetBackgroundColour(*wxWHITE);
m_txt_warn_when_drying->SetLabel(_L("To ensure print quality, the drying temperature will be lowered during printing."));
m_warn_when_drying_sizer->Add(m_txt_warn_when_drying, 0, wxTOP, FromDIP(2));
/*Advanced Options*/
wxBoxSizer* sizer_split_options = new wxBoxSizer(wxHORIZONTAL);
auto m_split_options_line = new wxPanel(m_scroll_area, wxID_ANY);
@@ -735,6 +743,8 @@ SelectMachineDialog::SelectMachineDialog(Plater *plater)
m_scroll_sizer->Add(m_change_filament_times_sizer, 0,wxLEFT|wxRIGHT, FromDIP(15));
// m_scroll_sizer->Add(m_link_edit_nozzle, 0, wxLEFT|wxRIGHT, FromDIP(15));
m_scroll_sizer->Add(suggestion_sizer, 0, wxLEFT|wxRIGHT|wxEXPAND, FromDIP(15));
m_scroll_sizer->Add(0, 0, 0, wxTOP, FromDIP(10));
m_scroll_sizer->Add(m_warn_when_drying_sizer, 0, wxLEFT|wxRIGHT, FromDIP(15));
m_scroll_sizer->Add(sizer_split_options, 1, wxEXPAND|wxLEFT|wxRIGHT, FromDIP(15));
m_scroll_sizer->Add(0, 0, 0, wxTOP, FromDIP(10));
m_scroll_sizer->Add(m_options_other, 0, wxEXPAND|wxLEFT|wxRIGHT, FromDIP(15));
@@ -1734,6 +1744,47 @@ bool SelectMachineDialog::CheckErrorSyncNozzleMappingResultV0(MachineObject* obj
return true;
}
bool SelectMachineDialog::is_ams_drying(MachineObject* obj)
{
const auto& ams_list = obj->GetFilaSystem()->GetAmsList();
for (auto ams = ams_list.begin(); ams != ams_list.end(); ams++) {
if (ams->second->AmsIsDrying()) {
return true;
}
}
return false;
}
bool SelectMachineDialog::is_selected_ams_drying(MachineObject* obj)
{
if (!obj) return false;
// If a UI material is selected, only when that material is mapped to an AMS
// and that AMS is currently drying.
for (const auto &kv : m_materialList) {
Material *mat = kv.second;
if (!mat || !mat->item) continue;
if (!mat->item->m_selected) continue;
// find mapping entry for this material id
for (const FilamentInfo &f : m_ams_mapping_result) {
if (f.id != mat->id) continue;
if (f.ams_id.empty()) return false;
auto fila_system = obj->GetFilaSystem();
if (!fila_system) return false;
DevAms* dev_ams = fila_system->GetAmsById(f.ams_id);
return (dev_ams && dev_ams->AmsIsDrying());
}
return false;
}
return false;
}
void SelectMachineDialog::prepare(int print_plate_idx)
{
m_print_plate_idx = print_plate_idx;
@@ -3888,6 +3939,16 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
m_check_ext_change_assist->Enable(false);
}
{
const bool show_warn_when_drying = is_selected_ams_drying(obj_);
const bool is_currently_shown = (m_txt_warn_when_drying != nullptr) ? m_txt_warn_when_drying->IsShown() : false;
if (is_currently_shown != show_warn_when_drying) {
m_warn_when_drying_sizer->Show(show_warn_when_drying);
Layout();
Fit();
}
}
/*reading done*/
if (wxGetApp().app_config) {
if (obj_->upgrade_force_upgrade) {
@@ -4404,6 +4465,7 @@ void SelectMachineDialog::set_default()
m_mapping_sugs_sizer->Show(false);
m_change_filament_times_sizer->Show(false);
m_txt_change_filament_times->Show(false);
m_warn_when_drying_sizer->Show(false);
// rset status bar
m_status_bar->reset();
@@ -4513,6 +4575,10 @@ void SelectMachineDialog::reset_and_sync_ams_list()
m_filaments_map = wxGetApp().plater()->get_partplate_list().get_curr_plate()->get_real_filament_maps(project_config);
}
bool selected_any = false;
MaterialItem *first_enabled = nullptr;
int first_enabled_id = -1;
for (auto i = 0; i < extruders.size(); i++) {
auto extruder = extruders[i] - 1;
auto colour = wxGetApp().preset_bundle->project_config.opt_string("filament_colour", (unsigned int) extruder);
@@ -4542,7 +4608,20 @@ void SelectMachineDialog::reset_and_sync_ams_list()
item = new MaterialItem(m_filament_panel, colour_rgb, _L(display_materials[extruder]));
m_sizer_ams_mapping->Add(item, 0, wxALL, FromDIP(5));
}
if (!item) continue;
item->SetToolTip(m_ams_tooltip);
if (!selected_any && extruder == m_current_filament_id && item->m_enable) {
item->on_selected();
selected_any = true;
}
if (!first_enabled && item->m_enable) {
first_enabled = item;
first_enabled_id = extruder;
}
item->Bind(wxEVT_LEFT_UP, [this, item, materials, extruder](wxMouseEvent &e) {});
item->Bind(wxEVT_LEFT_DOWN, [this, item, materials, extruder](wxMouseEvent &e) {
if (!item->m_enable) {return;}
@@ -4621,6 +4700,11 @@ void SelectMachineDialog::reset_and_sync_ams_list()
}
}
if (!selected_any && first_enabled) {
m_current_filament_id = first_enabled_id;
first_enabled->on_selected();
}
if (use_double_extruder)
{
m_filament_left_panel->Show();
@@ -5031,6 +5115,10 @@ void SelectMachineDialog::set_default_from_sdcard()
m_materialList.clear();
m_filaments.clear();
bool selected_any = false;
MaterialItem *first_enabled = nullptr;
int first_enabled_id = -1;
for (auto i = 0; i < m_required_data_plate_data_list[m_print_plate_idx]->slice_filaments_info.size(); i++) {
FilamentInfo fo = m_required_data_plate_data_list[m_print_plate_idx]->slice_filaments_info[i];
@@ -5053,6 +5141,17 @@ void SelectMachineDialog::set_default_from_sdcard()
m_sizer_ams_mapping->Add(item, 0, wxALL, FromDIP(5));
}
if (!item) continue;
if (!selected_any && fo.id == m_current_filament_id && item->m_enable) {
item->on_selected();
selected_any = true;
}
if (!first_enabled && item->m_enable) {
first_enabled = item;
first_enabled_id = fo.id;
}
item->Bind(wxEVT_LEFT_UP, [this, item, materials](wxMouseEvent& e) {});
item->Bind(wxEVT_LEFT_DOWN, [this, obj_, item, materials, diameters_count, fo](wxMouseEvent& e) {
if (!item->m_enable) {return;}
@@ -5129,6 +5228,11 @@ void SelectMachineDialog::set_default_from_sdcard()
wxSize screenSize = wxGetDisplaySize();
auto dialogSize = this->GetSize();
if (!selected_any && first_enabled) {
m_current_filament_id = first_enabled_id;
first_enabled->on_selected();
}
reset_ams_material();
// basic info
+7
View File
@@ -28,6 +28,7 @@
#include "boost/bimap/bimap.hpp"
#include "AmsMappingPopup.hpp"
#include "GUI_ObjectLayers.hpp"
#include "ReleaseNote.hpp"
#include "GUI_Utils.hpp"
#include "wxExtensions.hpp"
@@ -354,6 +355,7 @@ protected:
wxBoxSizer* m_sizer_autorefill{ nullptr };
wxBoxSizer* m_mapping_sugs_sizer{ nullptr };
wxBoxSizer* m_change_filament_times_sizer{ nullptr };
wxBoxSizer* m_warn_when_drying_sizer{ nullptr };
Button* m_button_ensure{ nullptr };
wxStaticBitmap * m_rename_button{nullptr};
wxStaticBitmap* m_staticbitmap{ nullptr };
@@ -387,6 +389,8 @@ protected:
CheckBox* m_check_ext_change_assist{ nullptr };
Label* m_label_ext_change_assist{ nullptr };
Label* m_txt_warn_when_drying{ nullptr };
PrinterInfoBox* m_printer_box { nullptr};
PrinterMsgPanel * m_text_printer_msg{nullptr};
Label* m_text_printer_msg_tips{ nullptr };
@@ -542,6 +546,9 @@ public:
bool CheckErrorDynamicSwitchNozzle(MachineObject* obj_);
void on_flow_cali_option_changed();
bool is_ams_drying(MachineObject* obj);
bool is_selected_ams_drying(MachineObject* obj);
PrintFromType get_print_type() {return m_print_type;};
wxString format_steel_name(NozzleType type);
PrintDialogStatus get_status() { return m_print_status; }
+1
View File
@@ -3392,6 +3392,7 @@ void StatusPanel::update_ams(MachineObject *obj)
// must select a current can
m_ams_control->UpdateAms(obj->get_printer_series_str(), obj->printer_type, ams_info, ext_info, *obj->GetExtderSystem(), obj->get_dev_id(), false);
m_ams_control->UpdateAmsDryControl(obj);
last_tray_exist_bits = obj->tray_exist_bits;
last_ams_exist_bits = obj->ams_exist_bits;
+1 -1
View File
@@ -7917,7 +7917,7 @@ bool Tab::validate_filament_temperature_pairs()
if (delta <= rule.max_delta)
continue;
const wxString deg_c = wxString::FromUTF8("°C");
const wxString deg_c = wxString::FromUTF8("℃");
const wxString bullet = wxString::FromUTF8("•");
invalid_pairs += wxString::Format(_L(" - %s:\n %s first layer %d %s, other layers %d %s\n %s max delta %d %s, current delta %d %s\n"),
rule.label, bullet, first_temp, deg_c, other_temp, deg_c, bullet, rule.max_delta, deg_c, delta, deg_c);
+46 -4
View File
@@ -31,6 +31,7 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons
, m_Humidity_tip_popup(AmsHumidityTipPopup(this))
, m_percent_humidity_dry_popup(new uiAmsPercentHumidityDryPopup(this))
, m_ams_introduce_popup(AmsIntroducePopup(this))
, m_ams_dry_ctr_win(new AMSDryCtrWin(this))
{
Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
if (dev) {
@@ -252,6 +253,12 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons
uiAmsHumidityInfo *info = (uiAmsHumidityInfo *) evt.GetClientData();
if (info)
{
Slic3r::DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
MachineObject *obj = nullptr;
if (dev) {
obj = dev->get_selected_machine();
}
if (info->ams_type == AMSModel::GENERIC_AMS)
{
wxPoint img_pos = ClientToScreen(wxPoint(0, 0));
@@ -261,9 +268,14 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons
int humidity_value = info->humidity_display_idx;
if (humidity_value > 0 && humidity_value <= 5) { m_Humidity_tip_popup.set_humidity_level(humidity_value); }
m_Humidity_tip_popup.Popup();
}
else
{
} else if (obj && obj->is_support_remote_dry && (info->ams_type == AMSModel::N3F_AMS || info->ams_type == AMSModel::N3S_AMS)){
m_ams_dry_ctr_win->set_ams_id(info->ams_id);
wxPoint img_pos = ClientToScreen(wxPoint(0, 0));
wxPoint popup_pos(img_pos.x - m_ams_dry_ctr_win->GetSize().GetWidth() + FromDIP(150), img_pos.y - FromDIP(80));
m_ams_dry_ctr_win->Move(popup_pos);
m_ams_dry_ctr_win->ShowModal();
} else {
m_percent_humidity_dry_popup->Update(info);
wxPoint img_pos = ClientToScreen(wxPoint(0, 0));
@@ -283,7 +295,12 @@ void AMSControl::on_retry()
post_event(wxCommandEvent(EVT_AMS_RETRY));
}
AMSControl::~AMSControl() {}
AMSControl::~AMSControl()
{
if (m_ams_dry_ctr_win) {
delete m_ams_dry_ctr_win;
}
}
std::string AMSControl::GetCurentAms() {
return m_current_ams;
@@ -501,6 +518,10 @@ void AMSControl::msw_rescale()
m_percent_humidity_dry_popup->msw_rescale();
}
if (m_ams_dry_ctr_win) {
m_ams_dry_ctr_win->msw_rescale();
}
m_Humidity_tip_popup.msw_rescale();
Layout();
@@ -824,6 +845,27 @@ void AMSControl::show_vams_kn_value(bool show)
//m_vams_lib->show_kn_value(show);
}
void AMSControl::UpdateAmsDryControl(MachineObject* obj)
{
if (!m_ams_dry_ctr_win->IsShown()) {
return;
}
if (!obj || !obj->GetFilaSystem()) {
m_ams_dry_ctr_win->Close();
return;
}
std::weak_ptr<DevFilaSystem> weak_fila_system = obj->GetFilaSystem();
if (auto locaked_fila_system = weak_fila_system.lock()) {
m_ams_dry_ctr_win->update(locaked_fila_system, obj);
} else {
m_ams_dry_ctr_win->Close();
return;
}
}
std::vector<AMSinfo> AMSControl::GenerateSimulateData() {
auto caninfo0_0 = Caninfo{ "0", (""), *wxRED, AMSCanType::AMS_CAN_TYPE_VIRTUAL };
auto caninfo0_1 = Caninfo{ "1", (""), *wxGREEN, AMSCanType::AMS_CAN_TYPE_VIRTUAL };
+3
View File
@@ -16,6 +16,7 @@
#include <tuple>
#include "slic3r/GUI/DeviceCore/DevExtruderSystem.h"
#include "slic3r/GUI/AMSDryControl.hpp"
namespace Slic3r { namespace GUI {
@@ -127,6 +128,7 @@ protected:
AmsHumidityTipPopup m_Humidity_tip_popup;
uiAmsPercentHumidityDryPopup* m_percent_humidity_dry_popup;
AMSDryCtrWin* m_ams_dry_ctr_win;
std::string m_last_ams_id = "";
std::string m_last_tray_id = "";
@@ -170,6 +172,7 @@ public:
void CreateAmsDoubleNozzle(const std::string &series_name, const std::string& printer_type);
void CreateAmsSingleNozzle(const std::string &series_name, const std::string &printer_type);
void ClearAms();
void UpdateAmsDryControl(MachineObject* obj);
void UpdateAms(const std::string &series_name,
const std::string &printer_type,
std::vector<AMSinfo> ams_info,