Merge remote-tracking branch 'upstream/main' into dev/cut-keep-paint
This commit is contained in:
@@ -1505,6 +1505,9 @@ bool CalibrationPresetPage::is_filaments_compatiable(const std::map<int, Preset*
|
||||
|
||||
bed_temp = 0;
|
||||
std::vector<std::string> filament_types;
|
||||
std::vector<int> nozzle_temperatures;
|
||||
std::vector<int> nozzle_temperature_range_lows;
|
||||
std::vector<int> nozzle_temperature_range_highs;
|
||||
for (auto &item : prests) {
|
||||
const auto& item_preset = item.second;
|
||||
if (!item_preset)
|
||||
@@ -1533,13 +1536,38 @@ bool CalibrationPresetPage::is_filaments_compatiable(const std::map<int, Preset*
|
||||
std::string display_filament_type;
|
||||
filament_types.push_back(item_preset->config.get_filament_type(display_filament_type, 0));
|
||||
|
||||
int nozzle_temperature = 0;
|
||||
int nozzle_temperature_range_low = 0;
|
||||
int nozzle_temperature_range_high = 0;
|
||||
if (const auto* opt_nozzle_temp = item_preset->config.option<ConfigOptionInts>("nozzle_temperature"))
|
||||
nozzle_temperature = opt_nozzle_temp->get_at(0);
|
||||
if (const auto* opt_nozzle_temp_low = item_preset->config.option<ConfigOptionInts>("nozzle_temperature_range_low"))
|
||||
nozzle_temperature_range_low = opt_nozzle_temp_low->get_at(0);
|
||||
if (const auto* opt_nozzle_temp_high = item_preset->config.option<ConfigOptionInts>("nozzle_temperature_range_high"))
|
||||
nozzle_temperature_range_high = opt_nozzle_temp_high->get_at(0);
|
||||
|
||||
nozzle_temperatures.push_back(nozzle_temperature);
|
||||
nozzle_temperature_range_lows.push_back(nozzle_temperature_range_low);
|
||||
nozzle_temperature_range_highs.push_back(nozzle_temperature_range_high);
|
||||
|
||||
// check is it in the filament blacklist
|
||||
if (!is_filament_in_blacklist(item.first, item_preset, error_tips))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Print::check_multi_filaments_compatibility(filament_types) == FilamentCompatibilityType::HighLowMixed) {
|
||||
error_tips = _u8L("Cannot print multiple filaments which have large difference of temperature together. Otherwise, the extruder and nozzle may be blocked or damaged during printing");
|
||||
auto compatibility = Print::check_multi_filaments_compatibility(
|
||||
filament_types,
|
||||
nozzle_temperatures,
|
||||
nozzle_temperature_range_lows,
|
||||
nozzle_temperature_range_highs);
|
||||
|
||||
if (compatibility == FilamentCompatibilityType::InvalidTemperatureRange) {
|
||||
error_tips = _u8L("Invalid recommended nozzle temperature range. The lower bound must be lower than the upper bound.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (compatibility == FilamentCompatibilityType::HighLowMixed) {
|
||||
error_tips = _u8L("Selected nozzle temperatures are incompatible. For multi-material printing, each filament's nozzle temperature must be within the recommended nozzle temperature range of the other filaments. Otherwise, nozzle clogging or printer damage may occur.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "DevConfigUtil.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
|
||||
#include <wx/dir.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
@@ -246,4 +249,49 @@ std::map<std::string, std::vector<std::string>> DevPrinterConfigUtil::get_all_su
|
||||
return subseries;
|
||||
}
|
||||
|
||||
};
|
||||
std::string DevPrinterConfigUtil::get_toolhead_display_name(
|
||||
const std::string& type_str,
|
||||
int ext_id,
|
||||
ToolHeadComponent component,
|
||||
ToolHeadNameCase name_case,
|
||||
bool short_name)
|
||||
{
|
||||
static const std::map<ToolHeadComponent, std::string> comp_keys = {
|
||||
{ ToolHeadComponent::Extruder, "extruder" },
|
||||
{ ToolHeadComponent::Nozzle, "nozzle" },
|
||||
{ ToolHeadComponent::Hotend, "hotend" }
|
||||
};
|
||||
|
||||
const int case_index = static_cast<int>(name_case);
|
||||
const std::string role_key = std::to_string(ext_id);
|
||||
const std::string& comp_key = comp_keys.at(component);
|
||||
|
||||
std::string result;
|
||||
auto names_json = get_value_from_config<json>(type_str, "tool_head_display_names");
|
||||
if (!names_json.is_null() && names_json.contains(role_key) && names_json[role_key].contains(comp_key)) {
|
||||
auto& arr = names_json[role_key][comp_key];
|
||||
if (arr.is_array() && case_index < static_cast<int>(arr.size()))
|
||||
result = arr[case_index].get<std::string>();
|
||||
}
|
||||
|
||||
if (result.empty()) {
|
||||
const std::string side = ext_id == DEPUTY_EXTRUDER_ID ? "Left" : "Right";
|
||||
const std::string component_name = component == ToolHeadComponent::Extruder ? "Extruder" :
|
||||
component == ToolHeadComponent::Hotend ? "Hotend" : "Nozzle";
|
||||
result = side + " " + component_name;
|
||||
if (name_case == ToolHeadNameCase::SentenceCase && result.size() > side.size() + 1)
|
||||
result[side.size() + 1] = static_cast<char>(std::tolower(static_cast<unsigned char>(result[side.size() + 1])));
|
||||
else if (name_case == ToolHeadNameCase::LowerCase)
|
||||
std::transform(result.begin(), result.end(), result.begin(), [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
|
||||
}
|
||||
|
||||
if (short_name) {
|
||||
auto sp = result.find(' ');
|
||||
if (sp != std::string::npos)
|
||||
result = result.substr(0, sp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -30,6 +30,17 @@ public:
|
||||
~dePrinterConfigFactory() = default;
|
||||
};
|
||||
|
||||
enum class ToolHeadComponent {
|
||||
Extruder,
|
||||
Nozzle,
|
||||
Hotend
|
||||
};
|
||||
|
||||
enum class ToolHeadNameCase {
|
||||
TitleCase = 0,
|
||||
SentenceCase = 1,
|
||||
LowerCase = 2
|
||||
};
|
||||
|
||||
class DevPrinterConfigUtil
|
||||
{
|
||||
@@ -70,6 +81,12 @@ public:
|
||||
|
||||
/*extruder*/
|
||||
static bool get_printer_can_set_nozzle(std::string type_str) { return get_value_from_config<bool>(type_str, "enable_set_nozzle_info"); }// can set nozzle from studio
|
||||
static std::string get_toolhead_display_name(
|
||||
const std::string& type_str,
|
||||
int ext_id,
|
||||
ToolHeadComponent component,
|
||||
ToolHeadNameCase name_case = ToolHeadNameCase::TitleCase,
|
||||
bool short_name = false);
|
||||
|
||||
/*print job*/
|
||||
static bool support_ams_ext_mix_print(std::string type_str) { return get_value_from_config<bool>(type_str, "print", "support_ams_ext_mix_print"); }
|
||||
@@ -200,4 +217,4 @@ static std::string _parse_printer_type(const std::string& type_str)
|
||||
return type_str;
|
||||
}
|
||||
|
||||
};// namespace Slic3r
|
||||
};// namespace Slic3r
|
||||
|
||||
@@ -354,6 +354,27 @@ namespace Slic3r
|
||||
}
|
||||
}
|
||||
|
||||
// Orca: special cases that no AMS available, we select ext slot automatically because we don't have other choice anyway
|
||||
if (tray_filaments.size() == 1 && devPrinterUtil::IsVirtualSlot(tray_filaments.begin()->first)) {
|
||||
auto ext_tray = tray_filaments.begin();
|
||||
for (auto & r : result) {
|
||||
if (r.tray_id < 0) {
|
||||
r.tray_id = ext_tray->first;
|
||||
|
||||
r.color = ext_tray->second.color;
|
||||
r.type = ext_tray->second.type;
|
||||
r.distance = ext_tray->second.distance;
|
||||
r.filament_id = ext_tray->second.filament_id;
|
||||
r.ctype = ext_tray->second.ctype;
|
||||
r.colors = ext_tray->second.colors;
|
||||
|
||||
/*for new ams mapping*/
|
||||
r.ams_id = ext_tray->second.ams_id;
|
||||
r.slot_id = ext_tray->second.slot_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//check ams mapping result
|
||||
if (DevMappingUtil::is_valid_mapping_result(obj, result, true))
|
||||
{
|
||||
|
||||
@@ -240,7 +240,14 @@ wxString DeviceErrorDialog::show_error_code(int error_code)
|
||||
Show();
|
||||
Raise();
|
||||
|
||||
#ifndef __linux__
|
||||
// On Linux (especially Wayland) RequestUserAttention(wxUSER_ATTENTION_ERROR) maps to
|
||||
// gtk_window_set_urgency_hint(TRUE) which can leave the window in an urgent-but-unfocused
|
||||
// state — clicks no longer reach any widget in the app and the user has to kill the
|
||||
// process to recover. Same root cause as #9874, where SecondaryCheckDialog had its
|
||||
// RequestUserAttention call removed for the identical reason.
|
||||
this->RequestUserAttention(wxUSER_ATTENTION_ERROR);
|
||||
#endif
|
||||
|
||||
return error_msg;
|
||||
}
|
||||
|
||||
@@ -291,7 +291,6 @@ public:
|
||||
|
||||
bool is_target_slot_unload() const;
|
||||
bool can_unload_filament();
|
||||
bool is_support_amx_ext_mix_mapping() const { return true;}
|
||||
|
||||
void get_ams_colors(std::vector<wxColour>& ams_colors);
|
||||
|
||||
|
||||
@@ -1920,6 +1920,14 @@ void GLCanvas3D::render(bool only_init)
|
||||
|
||||
if (!is_initialized() && !init())
|
||||
return;
|
||||
|
||||
// If a scene reload was postponed while the canvas was hidden, consume it on first visible render.
|
||||
if (m_reload_delayed) {
|
||||
reload_scene(true);
|
||||
if (m_reload_delayed)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_canvas_type == ECanvasType::CanvasView3D && m_gizmos.get_current_type() == GLGizmosManager::Undefined) {
|
||||
enable_return_toolbar(false);
|
||||
}
|
||||
@@ -2398,10 +2406,11 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
if (m_canvas == nullptr || m_config == nullptr || m_model == nullptr)
|
||||
return;
|
||||
|
||||
if (!m_initialized)
|
||||
if (!m_initialized || !_set_current()) {
|
||||
m_reload_delayed = true;
|
||||
set_as_dirty();
|
||||
return;
|
||||
|
||||
_set_current();
|
||||
}
|
||||
|
||||
m_hover_volume_idxs.clear();
|
||||
|
||||
@@ -2456,6 +2465,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
auto model_volume_state_lower = [](const ModelVolumeState& m1, const ModelVolumeState& m2) { return m1.geometry_id < m2.geometry_id; };
|
||||
|
||||
m_reload_delayed = !m_canvas->IsShown() && !refresh_immediately && !force_full_scene_refresh;
|
||||
if (m_reload_delayed) {
|
||||
set_as_dirty();
|
||||
return;
|
||||
}
|
||||
|
||||
PrinterTechnology printer_technology = current_printer_technology();
|
||||
|
||||
@@ -2617,9 +2630,6 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re
|
||||
//BBS clean hover_volume_idxs
|
||||
m_hover_volume_idxs.clear();
|
||||
|
||||
if (m_reload_delayed)
|
||||
return;
|
||||
|
||||
// BBS: do not check wipe tower changes
|
||||
bool update_object_list = false;
|
||||
if (deleted_volumes.size() != deleted_wipe_towers.size())
|
||||
@@ -3897,7 +3907,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt)
|
||||
if (m_gizmos.on_mouse_wheel(evt))
|
||||
return;
|
||||
|
||||
if (m_canvas_type == CanvasAssembleView && (evt.AltDown() || evt.CmdDown())) {
|
||||
if (m_canvas_type == CanvasAssembleView && (evt.AltDown() || evt.CmdDown()) && m_gizmos.m_assemble_view_data != nullptr) {
|
||||
float rotation = (float)evt.GetWheelRotation() / (float)evt.GetWheelDelta();
|
||||
if (evt.AltDown()) {
|
||||
auto clp_dist = m_gizmos.m_assemble_view_data->model_objects_clipper()->get_position();
|
||||
@@ -8915,6 +8925,9 @@ float GLCanvas3D::_render_assembly_tooltip_button(ImGuiWrapper* imgui_wrapper) c
|
||||
//BBS
|
||||
void GLCanvas3D::_render_assemble_control()
|
||||
{
|
||||
if(m_gizmos.m_assemble_view_data == nullptr)
|
||||
return;
|
||||
|
||||
if (m_canvas_type != ECanvasType::CanvasAssembleView) {
|
||||
GLVolume::explosion_ratio = m_explosion_ratio = 1.0;
|
||||
return;
|
||||
|
||||
@@ -4469,6 +4469,21 @@ std::string GUI_App::handle_web_request(std::string cmd)
|
||||
boost::optional<std::string> command = root.get_optional<std::string>("command");
|
||||
if (command.has_value()) {
|
||||
std::string command_str = command.value();
|
||||
static const std::unordered_set<std::string> stealth_blocked_commands = {
|
||||
"get_login_info",
|
||||
"get_orca_login_info",
|
||||
"get_bambu_login_info",
|
||||
"homepage_login_or_register",
|
||||
"homepage_orca_login_or_register",
|
||||
"homepage_bambu_login_or_register",
|
||||
};
|
||||
if (app_config->get_stealth_mode() && stealth_blocked_commands.count(command_str)) {
|
||||
CallAfter([this] {
|
||||
if (mainframe && mainframe->m_webview)
|
||||
mainframe->m_webview->SendCloudProvidersInfo();
|
||||
});
|
||||
return "";
|
||||
}
|
||||
if (command_str.compare("request_project_download") == 0) {
|
||||
if (root.get_child_optional("data") != boost::none) {
|
||||
pt::ptree data_node = root.get_child("data");
|
||||
@@ -5792,12 +5807,16 @@ bool GUI_App::maybe_migrate_user_presets_on_login()
|
||||
{
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
BOOST_LOG_TRIVIAL(info) << "Migrate user presets to the OrcaCloud user folder if needed.";
|
||||
|
||||
if (!m_agent || !m_agent->is_user_login())
|
||||
return false;
|
||||
|
||||
std::string new_user_id = m_agent->get_user_id();
|
||||
if (new_user_id.empty())
|
||||
if (new_user_id.empty()) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "Failed to get user ID, skipping migration.";
|
||||
return false;
|
||||
}
|
||||
|
||||
fs::path user_base = fs::path(data_dir()) / PRESET_USER_DIR;
|
||||
fs::path target_dir = user_base / new_user_id;
|
||||
@@ -6731,6 +6750,16 @@ void GUI_App::stop_sync_user_preset()
|
||||
}
|
||||
}
|
||||
|
||||
void GUI_App::on_stealth_mode_enter()
|
||||
{
|
||||
stop_sync_user_preset();
|
||||
request_user_logout(ORCA_CLOUD_PROVIDER);
|
||||
request_user_logout(BBL_CLOUD_PROVIDER);
|
||||
if (mainframe && mainframe->m_webview) {
|
||||
mainframe->m_webview->SendCloudProvidersInfo();
|
||||
}
|
||||
}
|
||||
|
||||
void GUI_App::start_http_server(const std::string& provider)
|
||||
{
|
||||
m_http_server.set_request_handler([provider](const std::string& url) {
|
||||
|
||||
@@ -530,6 +530,7 @@ public:
|
||||
void sync_preset(Preset* preset);
|
||||
void start_sync_user_preset(bool with_progress_dlg = false);
|
||||
void stop_sync_user_preset();
|
||||
void on_stealth_mode_enter();
|
||||
|
||||
// Bundle subscription sync
|
||||
void check_bundle_updates();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "GUI_ObjectList.hpp"
|
||||
#include "ParamsPanel.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "Tab.hpp"
|
||||
#include "libslic3r/Config.hpp"
|
||||
#include "format.hpp"
|
||||
|
||||
@@ -111,6 +112,21 @@ namespace {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Orca: Resolve the type of a validation option based on its key
|
||||
Preset::Type resolve_validation_option_type(const std::string& opt_key)
|
||||
{
|
||||
if (opt_key.empty())
|
||||
return Preset::TYPE_PRINT;
|
||||
|
||||
if (wxGetApp().get_tab(Preset::TYPE_PRINTER)->get_config()->def()->has(opt_key))
|
||||
return Preset::TYPE_PRINTER;
|
||||
|
||||
if (wxGetApp().get_tab(Preset::TYPE_FILAMENT)->get_config()->def()->has(opt_key))
|
||||
return Preset::TYPE_FILAMENT;
|
||||
|
||||
return Preset::TYPE_PRINT;
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
@@ -1917,9 +1933,12 @@ void NotificationManager::push_validate_error_notification(StringObjectException
|
||||
}
|
||||
|
||||
if (!opt.empty()) {
|
||||
if ((!is_inst && id.id) || (is_inst && parent_id.id)) // if object found
|
||||
const Preset::Type opt_type = resolve_validation_option_type(opt);
|
||||
|
||||
if (opt_type == Preset::TYPE_PRINT && ((!is_inst && id.id) || (is_inst && parent_id.id))) // if object found and it's a print preset option, switch to object first
|
||||
wxGetApp().params_panel()->switch_to_object();
|
||||
wxGetApp().sidebar().jump_to_option(opt, Preset::TYPE_PRINT, L"");
|
||||
|
||||
wxGetApp().sidebar().jump_to_option(opt, opt_type, L"");
|
||||
}
|
||||
else {
|
||||
wxGetApp().mainframe->select_tab(MainFrame::tp3DEditor);
|
||||
|
||||
@@ -51,6 +51,14 @@ ParamsDialog::ParamsDialog(wxWindow * parent)
|
||||
Hide();
|
||||
}
|
||||
#else
|
||||
auto tab = dynamic_cast<Tab *>(m_panel->get_current_tab());
|
||||
// ORCA: Validate filament temperature pairs before closing the material settings dialog.
|
||||
if (tab && !tab->validate_filament_temperature_pairs()) {
|
||||
if (event.CanVeto())
|
||||
event.Veto();
|
||||
return;
|
||||
}
|
||||
|
||||
Hide();
|
||||
if (!m_editing_filament_id.empty()) {
|
||||
Filamentinformation *filament_info = new Filamentinformation();
|
||||
|
||||
@@ -3414,12 +3414,13 @@ int PartPlate::load_gcode_from_file(const std::string& filename)
|
||||
int ret = 0;
|
||||
|
||||
// process gcode
|
||||
DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config();
|
||||
std::vector<int> filament_maps = this->get_filament_maps();
|
||||
DynamicPrintConfig full_config = wxGetApp().preset_bundle->full_config(false, filament_maps);
|
||||
full_config.apply(m_config, true);
|
||||
m_print->apply(*m_model, full_config);
|
||||
m_print->apply(*m_model, full_config, false);
|
||||
//BBS: need to apply two times, for after the first apply, the m_print got its object,
|
||||
//which will affect the config when new_full_config.normalize_fdm(used_filaments);
|
||||
m_print->apply(*m_model, full_config);
|
||||
m_print->apply(*m_model, full_config, false);
|
||||
|
||||
// BBS: use backup path to save temp gcode
|
||||
// auto path = get_tmp_gcode_path();
|
||||
@@ -6102,6 +6103,9 @@ int PartPlateList::store_to_3mf_structure(PlateDataPtrs& plate_data_list, bool w
|
||||
plate_data_item->is_label_object_enabled = m_plate_list[i]->m_gcode_result->label_object_enabled;
|
||||
plate_data_item->limit_filament_maps = m_plate_list[i]->m_gcode_result->limit_filament_maps;
|
||||
plate_data_item->layer_filaments = m_plate_list[i]->m_gcode_result->layer_filaments;
|
||||
plate_data_item->filament_change_sequence = m_plate_list[i]->m_gcode_result->filament_change_sequence;
|
||||
plate_data_item->nozzle_change_sequence = m_plate_list[i]->m_gcode_result->nozzle_change_sequence;
|
||||
plate_data_item->optimal_assignment = m_plate_list[i]->m_gcode_result->optimal_assignment;
|
||||
plate_data_item->first_layer_time = std::to_string(m_plate_list[i]->cali_bboxes_data.first_layer_time);
|
||||
Print *print = nullptr;
|
||||
m_plate_list[i]->get_print((PrintBase **) &print, nullptr, nullptr);
|
||||
@@ -6177,6 +6181,9 @@ int PartPlateList::load_from_3mf_structure(PlateDataPtrs& plate_data_list, int f
|
||||
gcode_result->label_object_enabled = plate_data_list[i]->is_label_object_enabled;
|
||||
gcode_result->timelapse_warning_code = plate_data_list[i]->timelapse_warning_code;
|
||||
m_plate_list[index]->set_timelapse_warning_code(plate_data_list[i]->timelapse_warning_code);
|
||||
gcode_result->filament_change_sequence = plate_data_list[i]->filament_change_sequence;
|
||||
gcode_result->nozzle_change_sequence = plate_data_list[i]->nozzle_change_sequence;
|
||||
gcode_result->optimal_assignment = plate_data_list[i]->optimal_assignment;
|
||||
m_plate_list[index]->slice_filaments_info = plate_data_list[i]->slice_filaments_info;
|
||||
gcode_result->warnings = plate_data_list[i]->warnings;
|
||||
gcode_result->filament_maps = plate_data_list[i]->filament_maps;
|
||||
|
||||
@@ -169,6 +169,8 @@
|
||||
|
||||
#include "DeviceCore/DevFilaSystem.h"
|
||||
#include "DeviceCore/DevManager.h"
|
||||
#include "DeviceCore/DevConfigUtil.h"
|
||||
#include "DeviceCore/DevDefs.h"
|
||||
|
||||
using boost::optional;
|
||||
namespace fs = boost::filesystem;
|
||||
@@ -443,6 +445,7 @@ struct ExtruderGroup : StaticGroup
|
||||
}
|
||||
|
||||
void update_ams();
|
||||
void SetTitle(const wxString& title);
|
||||
|
||||
void sync_ams(MachineObject const *obj, std::vector<DevAms *> const &ams4, std::vector<DevAms *> const &ams1);
|
||||
|
||||
@@ -1263,6 +1266,16 @@ void ExtruderGroup::sync_ams(MachineObject const *obj, std::vector<DevAms *> con
|
||||
update_ams();
|
||||
}
|
||||
|
||||
void ExtruderGroup::SetTitle(const wxString& title)
|
||||
{
|
||||
m_label = title;
|
||||
int tW, tH, descent, externalLeading;
|
||||
GetTextExtent(m_label.IsEmpty() ? "Orca" : m_label, &tW, &tH, &descent, &externalLeading, &m_font);
|
||||
m_label_height = tH - externalLeading;
|
||||
m_label_width = tW;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
bool Sidebar::priv::switch_diameter(bool single)
|
||||
{
|
||||
wxString diameter;
|
||||
@@ -1272,13 +1285,16 @@ bool Sidebar::priv::switch_diameter(bool single)
|
||||
auto diameter_left = left_extruder->combo_diameter->GetValue();
|
||||
auto diameter_right = right_extruder->combo_diameter->GetValue();
|
||||
if (diameter_left != diameter_right) {
|
||||
std::string printer_type = wxGetApp().preset_bundle->printers.get_edited_preset().get_printer_type(wxGetApp().preset_bundle);
|
||||
auto left_name = _L(DevPrinterConfigUtil::get_toolhead_display_name(printer_type, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::SentenceCase));
|
||||
auto right_name = _L(DevPrinterConfigUtil::get_toolhead_display_name(printer_type, MAIN_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::SentenceCase));
|
||||
MessageDialog dlg(this->plater,
|
||||
_L("The software does not support using different diameter of nozzles for one print. "
|
||||
"If the left and right nozzles are inconsistent, we can only proceed with single-head printing. "
|
||||
"Please confirm which nozzle you would like to use for this project."),
|
||||
_L("Switch diameter"), wxYES_NO | wxNO_DEFAULT);
|
||||
dlg.SetButtonLabel(wxID_YES, wxString::Format(_L("Left nozzle: %smm"), diameter_left));
|
||||
dlg.SetButtonLabel(wxID_NO, wxString::Format(_L("Right nozzle: %smm"), diameter_right));
|
||||
dlg.SetButtonLabel(wxID_YES, wxString::Format("%s: %smm", left_name, diameter_left));
|
||||
dlg.SetButtonLabel(wxID_NO, wxString::Format("%s: %smm", right_name, diameter_right));
|
||||
int result = dlg.ShowModal();
|
||||
if (result == wxID_YES)
|
||||
diameter = diameter_left;
|
||||
@@ -2661,6 +2677,9 @@ void Sidebar::update_presets(Preset::Type preset_type)
|
||||
};
|
||||
auto image_path = get_cur_select_bed_image();
|
||||
if (is_dual_extruder) {
|
||||
std::string printer_type = printer_preset.get_printer_type(wxGetApp().preset_bundle);
|
||||
p->left_extruder->SetTitle(_L(DevPrinterConfigUtil::get_toolhead_display_name(printer_type, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::TitleCase)));
|
||||
p->right_extruder->SetTitle(_L(DevPrinterConfigUtil::get_toolhead_display_name(printer_type, MAIN_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::TitleCase)));
|
||||
AMSCountPopupWindow::UpdateAMSCount(0, p->left_extruder);
|
||||
AMSCountPopupWindow::UpdateAMSCount(1, p->right_extruder);
|
||||
//if (!p->is_switching_diameter) {
|
||||
@@ -6923,6 +6942,12 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
||||
}
|
||||
|
||||
if (load_model) {
|
||||
if (!q->m_exported_file && view3D != nullptr) {
|
||||
// Force a 3D scene refresh after view/plate selection to avoid losing the first load
|
||||
// on platforms where the GL canvas mapping lags behind model loading.
|
||||
view3D->reload_scene(true);
|
||||
view3D->set_as_dirty();
|
||||
}
|
||||
if (!silence) wxGetApp().app_config->update_skein_dir(input_files[input_files.size() - 1].parent_path().make_preferred().string());
|
||||
// XXX: Plater.pm had @loaded_files, but didn't seem to fill them with the filenames...
|
||||
}
|
||||
@@ -9150,6 +9175,20 @@ void Plater::priv::set_current_panel(wxPanel* panel, bool no_slice)
|
||||
|
||||
if (current_panel == panel)
|
||||
{
|
||||
if (panel == view3D) {
|
||||
if (view3D->is_reload_delayed()) {
|
||||
// Delayed loading of the 3D scene when caller requests the already active tab.
|
||||
if (printer_technology == ptSLA)
|
||||
update_restart_background_process(true, false);
|
||||
else
|
||||
view3D->reload_scene(true);
|
||||
}
|
||||
|
||||
view3D->set_as_dirty();
|
||||
view3D->get_canvas3d()->reset_old_size();
|
||||
if (notification_manager != nullptr)
|
||||
notification_manager->set_in_preview(false);
|
||||
}
|
||||
//BBS: add slice logic when switch to preview page
|
||||
//BBS: add only gcode mode
|
||||
if (!q->only_gcode_mode() && (current_panel == preview) && (wxGetApp().is_editor())) {
|
||||
|
||||
@@ -53,6 +53,7 @@ std::string PrePrintChecker::get_print_status_info(PrintDialogStatus status)
|
||||
case PrintStatusFilamentWarningHighChamberTempCloseDoor: return "PrintStatusFilamentWarningHighChamberTempCloseDoor";
|
||||
case PrintStatusFilamentWarningHighChamberTempSoft: return "PrintStatusFilamentWarningHighChamberTempSoft";
|
||||
case PrintStatusFilamentWarningUnknownHighChamberTempSoft: return "PrintStatusFilamentWarningUnknownHighChamberTempSoft";
|
||||
case PrintStatusWarningExtFilamentNotMatch: return "PrintStatusWarningExtFilamentNotMatch";
|
||||
case PrintStatusReadingFinished: return "PrintStatusReadingFinished";
|
||||
case PrintStatusSendingCanceled: return "PrintStatusSendingCanceled";
|
||||
case PrintStatusAmsMappingSuccess: return "PrintStatusAmsMappingSuccess";
|
||||
@@ -92,6 +93,7 @@ wxString PrePrintChecker::get_pre_state_msg(PrintDialogStatus status)
|
||||
case PrintStatusWarningKvalueNotUsed: return _L("Set dynamic flow calibration to 'OFF' to enable custom dynamic flow value.");
|
||||
case PrintStatusNotSupportedPrintAll: return _L("This printer does not support printing all plates.");
|
||||
case PrintStatusColorQuantityExceed: return _L("The current firmware supports a maximum of 16 materials. You can either reduce the number of materials to 16 or fewer on the Preparation Page, or try updating the firmware. If you are still restricted after the update, please wait for subsequent firmware support.");
|
||||
case PrintStatusWarningExtFilamentNotMatch: return _L("The type of external filament is unknown or does not match with the filament type in the slicing file. Please make sure you have installed the correct filament in the external spool.");
|
||||
}
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ enum PrintDialogStatus : unsigned int {
|
||||
PrintStatusFilamentWarningHighChamberTempCloseDoor,
|
||||
PrintStatusFilamentWarningHighChamberTempSoft,
|
||||
PrintStatusFilamentWarningUnknownHighChamberTempSoft,
|
||||
PrintStatusWarningExtFilamentNotMatch,
|
||||
PrintStatusFilamentWarningEnd,
|
||||
|
||||
PrintStatusWarningEnd,//->end error<-
|
||||
|
||||
@@ -924,6 +924,8 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too
|
||||
checkbox->SetValue(app_config->get_bool(param));
|
||||
checkbox->SetToolTip(tip);
|
||||
|
||||
if (param == "sync_user_preset") { m_sync_user_preset_checkbox = checkbox; }
|
||||
|
||||
m_sizer_checkbox->Add(checkbox_title, 0, wxALIGN_CENTER | wxTOP | wxBOTTOM, FromDIP(3));
|
||||
m_sizer_checkbox->Add(checkbox , 0, wxALIGN_CENTER | wxRIGHT | wxLEFT, FromDIP(5));
|
||||
|
||||
@@ -955,6 +957,12 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << " sync_user_preset: " << (sync ? "true" : "false");
|
||||
}
|
||||
else if (param == "stealth_mode") {
|
||||
bool enabled = app_config->get_stealth_mode();
|
||||
if (enabled) wxGetApp().on_stealth_mode_enter();
|
||||
if (m_sync_user_preset_checkbox) m_sync_user_preset_checkbox->Enable(!enabled);
|
||||
if (m_bambu_cloud_checkbox) m_bambu_cloud_checkbox->Enable(!enabled);
|
||||
}
|
||||
|
||||
#ifdef __WXMSW__
|
||||
if (param == "associate_3mf") {
|
||||
@@ -1528,7 +1536,7 @@ void PreferencesDialog::create_items()
|
||||
auto item_region = create_item_region_combobox(_L("Login region"), "");
|
||||
g_sizer->Add(item_region);
|
||||
|
||||
auto item_stealth_mode = create_item_checkbox(_L("Stealth mode"), _L("This stops the transmission of data to Bambu's cloud services. Users who don't use BBL machines or use LAN mode only can safely turn on this function."), "stealth_mode");
|
||||
auto item_stealth_mode = create_item_checkbox(_L("Stealth mode"), _L("This disables all cloud services e.g. Orca Cloud and Bambu Cloud. This stops the transmission of data to Bambu's cloud services too. Users who don't use BBL machines or use LAN mode only can safely turn on this function."), "stealth_mode");
|
||||
g_sizer->Add(item_stealth_mode);
|
||||
|
||||
auto item_network_test = create_item_button(_L("Network test"), _L("Test") + " " + dots, "", _L("Open Network Test"), []() {
|
||||
@@ -1552,6 +1560,7 @@ void PreferencesDialog::create_items()
|
||||
text->Wrap(DESIGN_TITLE_SIZE.x);
|
||||
|
||||
auto cb = new ::CheckBox(m_parent);
|
||||
m_bambu_cloud_checkbox = cb;
|
||||
cb->SetValue(app_config->has_cloud_provider(BBL_CLOUD_PROVIDER));
|
||||
cb->SetToolTip(text->GetToolTipText());
|
||||
|
||||
@@ -1585,6 +1594,11 @@ void PreferencesDialog::create_items()
|
||||
auto item_user_sync = create_item_checkbox(_L("Auto sync user presets (Printer/Filament/Process)"), "", "sync_user_preset");
|
||||
g_sizer->Add(item_user_sync);
|
||||
|
||||
if (app_config->get_stealth_mode()) {
|
||||
if (m_bambu_cloud_checkbox) m_bambu_cloud_checkbox->Enable(false);
|
||||
if (m_sync_user_preset_checkbox) m_sync_user_preset_checkbox->Enable(false);
|
||||
}
|
||||
|
||||
auto item_system_sync = create_item_checkbox(_L("Update built-in Presets automatically."), "", "sync_system_preset");
|
||||
g_sizer->Add(item_system_sync);
|
||||
|
||||
|
||||
@@ -71,6 +71,8 @@ public:
|
||||
::CheckBox * m_developer_mode_ckeckbox = {nullptr};
|
||||
::CheckBox * m_internal_developer_mode_ckeckbox = {nullptr};
|
||||
::CheckBox * m_dark_mode_ckeckbox = {nullptr};
|
||||
::CheckBox * m_sync_user_preset_checkbox = {nullptr};
|
||||
::CheckBox * m_bambu_cloud_checkbox = {nullptr};
|
||||
::TextInput *m_backup_interval_textinput = {nullptr};
|
||||
::ComboBox * m_network_version_combo = {nullptr};
|
||||
wxBoxSizer * m_network_version_sizer = {nullptr};
|
||||
|
||||
@@ -243,24 +243,23 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent)
|
||||
auto m_line_top = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxSize(-1, 1));
|
||||
m_line_top->SetBackgroundColour(wxColour(166, 169, 170));
|
||||
|
||||
wxBoxSizer *m_sizer_top = new wxBoxSizer(wxHORIZONTAL);
|
||||
wxBoxSizer *m_sizer_desc = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
wxBoxSizer *m_sizer_body = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
|
||||
|
||||
auto sm = create_scaled_bitmap("OrcaSlicer", nullptr, 70);
|
||||
m_brand = new wxStaticBitmap(this, wxID_ANY, sm, wxDefaultPosition, wxSize(FromDIP(70), FromDIP(70)));
|
||||
|
||||
|
||||
|
||||
wxBoxSizer *m_sizer_right = new wxBoxSizer(wxVERTICAL);
|
||||
auto sm = create_scaled_bitmap("OrcaSlicer", nullptr, 64);
|
||||
m_brand = new wxStaticBitmap(this, wxID_ANY, sm, wxDefaultPosition, FromDIP(wxSize(64, 64)));
|
||||
|
||||
m_text_up_info = new Label(this, Label::Head_14, wxEmptyString, LB_AUTO_WRAP);
|
||||
m_text_up_info->SetForegroundColour(wxColour(0x26, 0x2E, 0x30));
|
||||
|
||||
m_simplebook_release_note = new wxSimplebook(this);
|
||||
m_simplebook_release_note->SetSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
m_simplebook_release_note->SetMinSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
auto github_link = new HyperLink(this, _L("Check on Github"), "", LB_AUTO_WRAP);
|
||||
github_link->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &e) {
|
||||
EndModal(wxID_YES);
|
||||
});
|
||||
|
||||
m_simplebook_release_note = new wxSimplebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSIMPLE_BORDER);
|
||||
//m_simplebook_release_note->SetSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
m_simplebook_release_note->SetMinSize(FromDIP(wxSize(640,420)));
|
||||
m_simplebook_release_note->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8));
|
||||
|
||||
m_scrollwindows_release_note = new wxScrolledWindow(m_simplebook_release_note, wxID_ANY, wxDefaultPosition, wxSize(FromDIP(560), FromDIP(430)), wxVSCROLL);
|
||||
@@ -269,8 +268,9 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent)
|
||||
|
||||
//webview
|
||||
m_vebview_release_note = CreateTipView(m_simplebook_release_note);
|
||||
m_vebview_release_note->SetSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
m_vebview_release_note->SetMinSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
m_vebview_release_note->SetBackgroundColour(wxColour(0xF8, 0xF8, 0xF8));
|
||||
//m_vebview_release_note->SetSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
//m_vebview_release_note->SetMinSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
//m_vebview_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
if (wxGetApp().app_config->get_bool("developer_mode"))
|
||||
m_vebview_release_note->EnableAccessToDevTools();
|
||||
@@ -300,8 +300,6 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent)
|
||||
m_simplebook_release_note->AddPage(m_scrollwindows_release_note, wxEmptyString, false);
|
||||
m_simplebook_release_note->AddPage(m_vebview_release_note, wxEmptyString, false);
|
||||
|
||||
|
||||
|
||||
auto sizer_button = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
m_button_download = new Button(this, _L("Download"));
|
||||
@@ -327,8 +325,6 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent)
|
||||
});
|
||||
|
||||
auto stable_only_label = new Label(this, _L("Check for stable updates only"));
|
||||
stable_only_label->SetFont(Label::Body_13);
|
||||
stable_only_label->SetForegroundColour(wxColour(38, 46, 48));
|
||||
stable_only_label->SetFont(Label::Body_12);
|
||||
|
||||
m_button_cancel = new Button(this, _L("Cancel"));
|
||||
@@ -338,25 +334,27 @@ UpdateVersionDialog::UpdateVersionDialog(wxWindow *parent)
|
||||
EndModal(wxID_NO);
|
||||
});
|
||||
|
||||
m_sizer_main->Add(m_line_top, 0, wxEXPAND | wxBOTTOM, 0);
|
||||
|
||||
//sizer_button->Add(m_remind_choice, 0, wxALL | wxEXPAND, FromDIP(5));
|
||||
|
||||
sizer_button->Add(m_cb_stable_only , 0, wxALIGN_CENTER);
|
||||
sizer_button->Add(stable_only_label , 0, wxALIGN_CENTER | wxLEFT, FromDIP(5));
|
||||
sizer_button->AddStretchSpacer();
|
||||
sizer_button->Add(stable_only_label, 0, wxALIGN_CENTER | wxLEFT, FromDIP(7));
|
||||
sizer_button->Add(m_cb_stable_only, 0, wxALIGN_CENTER | wxLEFT, FromDIP(5));
|
||||
sizer_button->Add(m_button_download, 0, wxALL, FromDIP(5));
|
||||
sizer_button->Add(m_button_skip_version, 0, wxALL, FromDIP(5));
|
||||
sizer_button->Add(m_button_cancel, 0, wxALL, FromDIP(5));
|
||||
sizer_button->Add(m_button_download , 0, wxLEFT, FromDIP(10));
|
||||
sizer_button->Add(m_button_skip_version, 0, wxLEFT, FromDIP(10));
|
||||
sizer_button->Add(m_button_cancel , 0, wxLEFT, FromDIP(10));
|
||||
|
||||
m_sizer_right->Add(m_text_up_info, 0, wxEXPAND | wxBOTTOM | wxTOP, FromDIP(15));
|
||||
m_sizer_right->Add(m_simplebook_release_note, 1, wxEXPAND | wxRIGHT, 0);
|
||||
m_sizer_right->Add(sizer_button, 0, wxEXPAND | wxRIGHT, FromDIP(20));
|
||||
m_sizer_desc->AddStretchSpacer();
|
||||
m_sizer_desc->Add(m_text_up_info, 0, wxEXPAND | wxBOTTOM, FromDIP(5));
|
||||
m_sizer_desc->Add(github_link);
|
||||
m_sizer_desc->AddStretchSpacer();
|
||||
|
||||
m_sizer_body->Add(m_brand, 0, wxTOP|wxRIGHT|wxLEFT, FromDIP(15));
|
||||
m_sizer_body->Add(0, 0, 0, wxRIGHT, 0);
|
||||
m_sizer_body->Add(m_sizer_right, 1, wxBOTTOM | wxEXPAND, FromDIP(8));
|
||||
m_sizer_main->Add(m_sizer_body, 1, wxEXPAND, 0);
|
||||
m_sizer_main->Add(0, 0, 0, wxBOTTOM, 10);
|
||||
m_sizer_top->Add(m_brand , 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, FromDIP(15));
|
||||
m_sizer_top->Add(m_sizer_desc, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
m_sizer_main->Add(m_line_top , 0, wxEXPAND);
|
||||
m_sizer_main->Add(m_sizer_top , 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(15));
|
||||
m_sizer_main->Add(m_simplebook_release_note, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, FromDIP(15));
|
||||
m_sizer_main->Add(sizer_button , 0, wxEXPAND | wxALL , FromDIP(15));
|
||||
|
||||
SetSizer(m_sizer_main);
|
||||
Layout();
|
||||
@@ -479,14 +477,17 @@ void UpdateVersionDialog::update_version_info(wxString release_note, wxString ve
|
||||
// m_vebview_release_note->LoadURL(from_u8(url_line));
|
||||
// }
|
||||
// else {
|
||||
m_simplebook_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
//m_simplebook_release_note->SetMaxSize(wxSize(FromDIP(560), FromDIP(430)));
|
||||
m_simplebook_release_note->SetSelection(1);
|
||||
m_text_up_info->SetLabel(wxString::Format(_L("Click to download new version in default browser: %s"), version));
|
||||
auto data_buf_in = release_note.utf8_str();
|
||||
auto bg_color = StateColor::darkModeColorFor(*wxWHITE).GetAsString();
|
||||
auto fg_color = StateColor::darkModeColorFor(*wxBLACK).GetAsString();
|
||||
html_source = (boost::format("<html><head><style>body { color: %1%; background-color: %2%; font-family: sans-serif; } a { color: #1E90FF }</style></head><body>")
|
||||
% fg_color % bg_color).str();
|
||||
auto bg_color = StateColor::darkModeColorFor(wxColour("#FFFFFF")).GetAsString();
|
||||
auto fg_color = StateColor::darkModeColorFor(wxColour("#262E30")).GetAsString();
|
||||
auto style = "body {color:" + fg_color + "; background-color:" + bg_color + "; font-family:sans-serif}"
|
||||
+ "a {color: #009688}" // matches hyperlink colors
|
||||
+ "img {max-width:100%; height:auto}" // fixes overflowing images
|
||||
+ "ul {padding-inline-start: 20px}"; // reduce left padding on list items
|
||||
html_source = (boost::format("<html><head><style>%1%</style></head><body>") % style).str();
|
||||
md_html(data_buf_in.data(), data_buf_in.length(), [](const MD_CHAR* text, MD_SIZE size, void* userdata) {
|
||||
std::string* out_buf = (std::string*)userdata;
|
||||
out_buf->append(text, size);
|
||||
|
||||
@@ -1092,23 +1092,13 @@ bool SelectMachineDialog::do_ams_mapping(MachineObject *obj_,bool use_ams)
|
||||
|
||||
//single nozzle
|
||||
else {
|
||||
if (obj_->is_support_amx_ext_mix_mapping()){
|
||||
map_opt = { false, true, false, false }; //four values: use_left_ams, use_right_ams, use_left_ext, use_right_ext
|
||||
if (!use_ams) {
|
||||
map_opt[1] = false;
|
||||
map_opt[3] = true;
|
||||
}
|
||||
filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt);
|
||||
//auto_supply_with_ext(obj_->vt_slot);
|
||||
}
|
||||
else {
|
||||
map_opt = { false, true, false, false };
|
||||
if (!use_ams) {
|
||||
map_opt[1] = false;
|
||||
map_opt[3] = true;
|
||||
}
|
||||
filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt);
|
||||
map_opt = { false, true, false, false }; //four values: use_left_ams, use_right_ams, use_left_ext, use_right_ext
|
||||
if (!use_ams) {
|
||||
map_opt[1] = false;
|
||||
map_opt[3] = true;
|
||||
}
|
||||
filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt);
|
||||
//auto_supply_with_ext(obj_->vt_slot);
|
||||
}
|
||||
|
||||
if (filament_result == 0) {
|
||||
@@ -1147,7 +1137,7 @@ bool SelectMachineDialog::do_ams_mapping(MachineObject *obj_,bool use_ams)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, std::string& mapping_array_str2, std::string &ams_mapping_info)
|
||||
bool SelectMachineDialog::get_ams_mapping_result(std::string &mapping_array_str, std::string& mapping_array_str2, std::string &ams_mapping_info) const
|
||||
{
|
||||
if (m_ams_mapping_result.empty())
|
||||
return false;
|
||||
@@ -1438,7 +1428,7 @@ bool SelectMachineDialog::is_nozzle_type_match(DevExtderSystem data, wxString& e
|
||||
return true;
|
||||
}
|
||||
|
||||
int SelectMachineDialog::convert_filament_map_nozzle_id_to_task_nozzle_id(int nozzle_id)
|
||||
int SelectMachineDialog::convert_filament_map_nozzle_id_to_task_nozzle_id(int nozzle_id) const
|
||||
{
|
||||
if (nozzle_id == (int)FilamentMapNozzleId::NOZZLE_LEFT) {
|
||||
return (int)CloudTaskNozzleId::NOZZLE_LEFT;
|
||||
@@ -1691,6 +1681,9 @@ void SelectMachineDialog::show_status(PrintDialogStatus status, std::vector<wxSt
|
||||
} else if (status == PrintDialogStatus::PrintStatusFilamentWarningHighChamberTempSoft || status == PrintDialogStatus::PrintStatusFilamentWarningUnknownHighChamberTempSoft) {
|
||||
Enable_Refresh_Button(true);
|
||||
Enable_Send_Button(true);
|
||||
} else if (status == PrintStatusWarningExtFilamentNotMatch) {
|
||||
Enable_Refresh_Button(true);
|
||||
Enable_Send_Button(true);
|
||||
}
|
||||
|
||||
/*enter perpare mode*/
|
||||
@@ -3458,7 +3451,7 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
|
||||
std::string filament_type = boost::to_upper_copy(m_ams_mapping_result[i].type);
|
||||
std::string filament_brand;
|
||||
|
||||
for (auto fs : m_filaments) {
|
||||
for (auto& fs : m_filaments) {
|
||||
if (fs.id == m_ams_mapping_result[i].id) { filament_brand = m_filaments[i].brand; }
|
||||
}
|
||||
|
||||
@@ -3520,6 +3513,19 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
|
||||
}
|
||||
}
|
||||
|
||||
// Orca: show warning if external filament does not match
|
||||
for (auto& m : m_ams_mapping_result) {
|
||||
if (devPrinterUtil::IsVirtualSlot(m.ams_id)) {
|
||||
for (auto& fs : m_filaments) {
|
||||
if (fs.id == m.id && m.type != fs.type) {
|
||||
show_status(PrintDialogStatus::PrintStatusWarningExtFilamentNotMatch);
|
||||
goto ext_mismatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ext_mismatch:
|
||||
|
||||
/*STUDIO-10970 check the k value and flow cali option*/
|
||||
if (m_checkbox_list["flow_cali"]->IsShown() && m_checkbox_list["flow_cali"]->getValue() == "auto") {
|
||||
const auto ¬_default_ams_names = _check_kval_not_default(obj_, m_ams_mapping_result);
|
||||
@@ -5147,7 +5153,7 @@ void PrinterInfoBox::UpdatePlate(const std::string& plate_name)
|
||||
name = _L("Textured PEI Plate");
|
||||
m_bed_image->SetBitmap(create_scaled_bitmap("bed_pei", this, 40));
|
||||
}
|
||||
else if (plate_name == "SuperTack Plate") {
|
||||
else if (plate_name == "Supertack Plate" || plate_name == "SuperTack Plate") {
|
||||
name = _L("Cool Plate (SuperTack)");
|
||||
m_bed_image->SetBitmap(create_scaled_bitmap("bed_cool_supertack", this, 40));
|
||||
}
|
||||
|
||||
@@ -500,12 +500,12 @@ public:
|
||||
bool Show(bool show);
|
||||
void show_init();
|
||||
bool do_ams_mapping(MachineObject *obj_,bool use_ams);
|
||||
bool get_ams_mapping_result(std::string& mapping_array_str, std::string& mapping_array_str2, std::string& ams_mapping_info);
|
||||
bool get_ams_mapping_result(std::string& mapping_array_str, std::string& mapping_array_str2, std::string& ams_mapping_info) const;
|
||||
bool build_nozzles_info(std::string& nozzles_info);
|
||||
bool can_hybrid_mapping(DevExtderSystem data);
|
||||
void auto_supply_with_ext(std::vector<DevAmsTray> slots);
|
||||
bool is_nozzle_type_match(DevExtderSystem data, wxString& error_message) const;
|
||||
int convert_filament_map_nozzle_id_to_task_nozzle_id(int nozzle_id);
|
||||
int convert_filament_map_nozzle_id_to_task_nozzle_id(int nozzle_id) const;
|
||||
|
||||
PrintFromType get_print_type() {return m_print_type;};
|
||||
wxString format_steel_name(NozzleType type);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "PrePrintChecker.hpp"
|
||||
|
||||
#include "DeviceCore/DevConfig.h"
|
||||
#include "DeviceCore/DevConfigUtil.h"
|
||||
#include "DeviceCore/DevFilaSystem.h"
|
||||
#include "DeviceCore/DevManager.h"
|
||||
#include "DeviceCore/DevMapping.h"
|
||||
@@ -1261,15 +1262,10 @@ bool SyncAmsInfoDialog::do_ams_mapping(MachineObject *obj_)
|
||||
}
|
||||
// single nozzle
|
||||
else {
|
||||
if (obj_->is_support_amx_ext_mix_mapping()) {
|
||||
map_opt = {false, true, false, true}; // four values: use_left_ams, use_right_ams, use_left_ext, use_right_ext
|
||||
filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt, std::vector<int>(),
|
||||
wxGetApp().app_config->get_bool("ams_sync_match_full_use_color_dist") ? false : true);
|
||||
// auto_supply_with_ext(obj_->vt_slot);
|
||||
} else {
|
||||
map_opt = {false, true, false, false};
|
||||
filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt);
|
||||
}
|
||||
map_opt = {false, true, false, true}; // four values: use_left_ams, use_right_ams, use_left_ext, use_right_ext
|
||||
filament_result = DevMappingUtil::ams_filament_mapping(obj_, m_filaments, m_ams_mapping_result, map_opt, std::vector<int>(),
|
||||
wxGetApp().app_config->get_bool("ams_sync_match_full_use_color_dist") ? false : true);
|
||||
// auto_supply_with_ext(obj_->vt_slot);
|
||||
}
|
||||
|
||||
if (filament_result == 0) {
|
||||
@@ -1577,10 +1573,11 @@ bool SyncAmsInfoDialog::is_nozzle_type_match(DevExtderSystem data, wxString &err
|
||||
if (target_machine_nozzle_id < flow_type_of_machine.size()) {
|
||||
if (flow_type_of_machine[target_machine_nozzle_id] != used_extruders_flow[it->first]) {
|
||||
wxString pos;
|
||||
auto sai_nz_pt = wxGetApp().preset_bundle->printers.get_edited_preset().get_printer_type(wxGetApp().preset_bundle);
|
||||
if (target_machine_nozzle_id == DEPUTY_EXTRUDER_ID) {
|
||||
pos = _L("left nozzle");
|
||||
pos = _L(DevPrinterConfigUtil::get_toolhead_display_name(sai_nz_pt, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::LowerCase));
|
||||
} else if ((target_machine_nozzle_id == MAIN_EXTRUDER_ID)) {
|
||||
pos = _L("right nozzle");
|
||||
pos = _L(DevPrinterConfigUtil::get_toolhead_display_name(sai_nz_pt, MAIN_EXTRUDER_ID, ToolHeadComponent::Nozzle, ToolHeadNameCase::LowerCase));
|
||||
}
|
||||
|
||||
error_message = wxString::Format(_L("The nozzle flow setting of %s(%s) doesn't match with the slicing file(%s). "
|
||||
|
||||
@@ -61,6 +61,8 @@
|
||||
#endif // WIN32
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -499,6 +501,22 @@ void Tab::create_preset_tab()
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dynamic_cast<TabFilament *>(this)) {
|
||||
m_variant_combo = new MultiSwitchButton(panel);
|
||||
m_variant_combo->Bind(wxCUSTOMEVT_MULTISWITCH_SELECTION, [this](auto &evt) {
|
||||
evt.Skip();
|
||||
switch_excluder(evt.GetInt());
|
||||
reload_config();
|
||||
update_changed_ui();
|
||||
toggle_options();
|
||||
if (m_active_page)
|
||||
m_active_page->update_visibility(m_mode, true);
|
||||
m_page_view->GetParent()->Layout();
|
||||
});
|
||||
m_variant_combo->Hide();
|
||||
m_main_sizer->Add(m_variant_combo, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, m_em_unit);
|
||||
}
|
||||
|
||||
this->SetSizer(m_main_sizer);
|
||||
//this->Layout();
|
||||
m_page_view = m_parent->get_paged_view();
|
||||
@@ -1241,6 +1259,8 @@ void Tab::reload_config()
|
||||
{
|
||||
if (m_active_page)
|
||||
m_active_page->reload_config();
|
||||
if (m_type == Preset::TYPE_PRINT && m_config != nullptr)
|
||||
m_last_sparse_infill_rotate_template_value = m_config->opt_string("sparse_infill_rotate_template");
|
||||
}
|
||||
|
||||
void Tab::update_mode()
|
||||
@@ -1293,6 +1313,8 @@ void Tab::msw_rescale()
|
||||
{
|
||||
m_mode_view->Rescale();
|
||||
}
|
||||
if (m_variant_combo)
|
||||
m_variant_combo->Rescale();
|
||||
|
||||
if (m_detach_preset_btn)
|
||||
m_detach_preset_btn->msw_rescale();
|
||||
@@ -1358,6 +1380,8 @@ void Tab::sys_color_changed()
|
||||
m_active_page->sys_color_changed();
|
||||
if (m_extruder_switch)
|
||||
m_extruder_switch->Rescale();
|
||||
if (m_variant_combo)
|
||||
m_variant_combo->Rescale();
|
||||
|
||||
//BBS: GUI refactor
|
||||
//Layout();
|
||||
@@ -1744,8 +1768,9 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
|
||||
auto new_value = boost::any_cast<std::string>(value);
|
||||
is_safe_to_rotate = is_safe_to_rotate || new_value.empty();
|
||||
const bool had_previous_value = !m_last_sparse_infill_rotate_template_value.empty();
|
||||
|
||||
if (!is_safe_to_rotate) {
|
||||
if (!is_safe_to_rotate && !had_previous_value) {
|
||||
wxString msg_text = _(
|
||||
L("Infill patterns are typically designed to handle rotation automatically to ensure proper printing and achieve their "
|
||||
"intended effects (e.g., Gyroid, Cubic). Rotating the current sparse infill pattern may lead to insufficient support. "
|
||||
@@ -1762,6 +1787,8 @@ void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
wxGetApp().plater()->update();
|
||||
}
|
||||
}
|
||||
|
||||
m_last_sparse_infill_rotate_template_value = m_config->opt_string("sparse_infill_rotate_template");
|
||||
}
|
||||
|
||||
if(opt_key=="layer_height"){
|
||||
@@ -3742,7 +3769,7 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print
|
||||
// "filament_seam_gap"
|
||||
};
|
||||
|
||||
const int selection = 0; //m_variant_combo->GetSelection(); // TODO: Orca hack
|
||||
const int selection = m_variant_combo ? m_variant_combo->GetSelection() : 0;
|
||||
auto opt = dynamic_cast<ConfigOptionVectorBase *>(m_config->option("filament_retraction_length"));
|
||||
const int extruder_idx = selection < 0 || selection >= static_cast<int>(opt->size()) ? 0 : selection;
|
||||
|
||||
@@ -4272,9 +4299,11 @@ void TabFilament::toggle_options()
|
||||
|
||||
toggle_line("activate_chamber_temp_control", printer_cfg.opt_bool("support_chamber_temp_control"));
|
||||
|
||||
std::string volumetric_speed_cos = m_config->opt_string("volumetric_speed_coefficients", 0u);
|
||||
const int selection = m_variant_combo ? m_variant_combo->GetSelection() : 0;
|
||||
const unsigned int variant_idx = (unsigned int) std::max(selection, 0);
|
||||
std::string volumetric_speed_cos = m_config->opt_string("volumetric_speed_coefficients", variant_idx);
|
||||
bool enable_fit = volumetric_speed_cos != "0 0 0 0 0 0";
|
||||
toggle_option("filament_adaptive_volumetric_speed", enable_fit, 256 + 0u);
|
||||
toggle_option("filament_adaptive_volumetric_speed", enable_fit, 256 + variant_idx);
|
||||
}
|
||||
|
||||
if (m_active_page->title() == L("Setting Overrides"))
|
||||
@@ -4292,7 +4321,8 @@ void TabFilament::toggle_options()
|
||||
toggle_option("filament_multitool_ramming_flow", multitool_ramming);
|
||||
|
||||
bool is_BBL_multi_extruder = is_BBL_printer && printer_cfg.option<ConfigOptionFloats>("nozzle_diameter")->size() > 1;
|
||||
const int extruder_idx = 0; // m_variant_combo->GetSelection(); // TODO: Orca hack
|
||||
const int selection = m_variant_combo ? m_variant_combo->GetSelection() : 0;
|
||||
const int extruder_idx = std::max(selection, 0);
|
||||
toggle_line("long_retractions_when_ec", is_BBL_multi_extruder, 256 + extruder_idx);
|
||||
toggle_line("retraction_distances_when_ec", is_BBL_multi_extruder && m_config->opt_bool("long_retractions_when_ec", extruder_idx), 256 + extruder_idx);
|
||||
}
|
||||
@@ -6301,6 +6331,9 @@ bool Tab::tree_sel_change_delayed(wxCommandEvent& event)
|
||||
if (m_extruder_switch) {
|
||||
m_main_sizer->Show(m_extruder_switch, !m_active_page->m_opt_id_map.empty());
|
||||
GetParent()->Layout();
|
||||
} else if (m_variant_combo) {
|
||||
m_main_sizer->Show(m_variant_combo, m_variant_combo->IsEnabled() && !m_active_page->m_opt_id_map.empty());
|
||||
GetParent()->Layout();
|
||||
}
|
||||
|
||||
auto throw_if_canceled = std::function<void()>([this](){
|
||||
@@ -6398,6 +6431,10 @@ void Tab::transfer_options(const std::string &name_from, const std::string &name
|
||||
//BBS: add project embedded preset relate logic
|
||||
void Tab::save_preset(std::string name /*= ""*/, bool detach, bool save_to_project, bool from_input, std::string input_name )
|
||||
{
|
||||
// ORCA: Validate before opening any save-name UI for filament presets.
|
||||
if (!validate_filament_temperature_pairs())
|
||||
return;
|
||||
|
||||
// since buttons(and choices too) don't get focus on Mac, we set focus manually
|
||||
// to the treectrl so that the EVT_* events are fired for the input field having
|
||||
// focus currently.is there anything better than this ?
|
||||
@@ -6952,6 +6989,104 @@ bool Tab::validate_custom_gcodes()
|
||||
return valid;
|
||||
}
|
||||
|
||||
// ORCA: Session-only suppression keys for temperature-pair safety warnings.
|
||||
static std::unordered_set<std::string> s_filament_temp_pair_warning_suppressed_for_session;
|
||||
|
||||
// ORCA: Validate that first-layer and other-layer temperature pairs are within safety limits, and warn the user if not.
|
||||
bool Tab::validate_filament_temperature_pairs()
|
||||
{
|
||||
if (m_type != Preset::TYPE_FILAMENT || m_presets == nullptr)
|
||||
return true;
|
||||
|
||||
// Warn only for newly edited state, not for unchanged presets.
|
||||
if (!m_presets->current_is_dirty())
|
||||
return true;
|
||||
|
||||
Preset& edited_preset = m_presets->get_edited_preset();
|
||||
DynamicPrintConfig& config = edited_preset.config;
|
||||
const std::string suppress_key = edited_preset.name;
|
||||
// User opted out for this preset during current app session.
|
||||
if (!suppress_key.empty() && s_filament_temp_pair_warning_suppressed_for_session.count(suppress_key) > 0)
|
||||
return true;
|
||||
|
||||
struct TempPairRule
|
||||
{
|
||||
wxString label;
|
||||
std::string first_layer_key;
|
||||
std::string other_layer_key;
|
||||
int max_delta;
|
||||
};
|
||||
|
||||
std::vector<TempPairRule> temp_pair_rules;
|
||||
temp_pair_rules.push_back({_L("Nozzle"), "nozzle_temperature_initial_layer", "nozzle_temperature", 30});
|
||||
|
||||
// Derive bed labels/keys from curr_bed_type metadata (BedType order excludes btDefault).
|
||||
if (const ConfigOptionDef* bed_type_def = print_config_def.get("curr_bed_type");
|
||||
bed_type_def != nullptr) {
|
||||
for (int bt = static_cast<int>(btPC); bt < static_cast<int>(btCount); ++bt) {
|
||||
const BedType bed_type = static_cast<BedType>(bt);
|
||||
const size_t label_idx = static_cast<size_t>(bt - static_cast<int>(btPC));
|
||||
const std::string first_key = get_bed_temp_1st_layer_key(bed_type);
|
||||
const std::string other_key = get_bed_temp_key(bed_type);
|
||||
if (first_key.empty() || other_key.empty())
|
||||
continue;
|
||||
|
||||
wxString label = _(bed_type_def->enum_labels[label_idx]);
|
||||
temp_pair_rules.push_back({label, first_key, other_key, 15});
|
||||
}
|
||||
}
|
||||
|
||||
wxString invalid_pairs;
|
||||
int invalid_count = 0;
|
||||
|
||||
for (const TempPairRule& rule : temp_pair_rules) {
|
||||
if (!config.has(rule.first_layer_key) || !config.has(rule.other_layer_key))
|
||||
continue;
|
||||
|
||||
const ConfigOptionInts* first_opt = config.option<ConfigOptionInts>(rule.first_layer_key);
|
||||
const ConfigOptionInts* other_opt = config.option<ConfigOptionInts>(rule.other_layer_key);
|
||||
if (first_opt == nullptr || other_opt == nullptr || first_opt->values.empty() || other_opt->values.empty())
|
||||
continue;
|
||||
|
||||
const int first_temp = first_opt->get_at(0);
|
||||
const int other_temp = other_opt->get_at(0);
|
||||
|
||||
// Keep existing semantics: 0 means unsupported/off for these temperatures.
|
||||
if (first_temp <= 0 || other_temp <= 0)
|
||||
continue;
|
||||
|
||||
const int delta = std::abs(first_temp - other_temp);
|
||||
if (delta <= rule.max_delta)
|
||||
continue;
|
||||
|
||||
const wxString deg_c = wxString::FromUTF8("°C");
|
||||
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);
|
||||
++invalid_count;
|
||||
}
|
||||
|
||||
if (invalid_count == 0)
|
||||
return true;
|
||||
|
||||
wxString msg_text = _L("Some first-layer and other-layer temperature pairs exceed safety limits.\n");
|
||||
msg_text += _L("\nInvalid pairs:\n");
|
||||
msg_text += invalid_pairs;
|
||||
msg_text += _L("\nYou can go back to edit values, or continue if this is intentional.");
|
||||
msg_text += _L("\n\nContinue anyway?");
|
||||
|
||||
RichMessageDialog dialog(parent(), msg_text, _L("Temperature Safety Check"), wxYES | wxNO | wxICON_WARNING);
|
||||
dialog.SetButtonLabel(wxID_YES, _L("Continue"), true);
|
||||
dialog.SetButtonLabel(wxID_NO, _L("Back"));
|
||||
dialog.ShowCheckBox(_L("Don't warn again for this preset"));
|
||||
const int answer = dialog.ShowModal();
|
||||
// Session-only suppression (does not modify/save filament preset data).
|
||||
if (dialog.IsCheckBoxChecked() && !suppress_key.empty())
|
||||
s_filament_temp_pair_warning_suppressed_for_session.insert(suppress_key);
|
||||
|
||||
return answer == wxID_YES;
|
||||
}
|
||||
|
||||
void Tab::set_just_edit(bool just_edit)
|
||||
{
|
||||
m_just_edit = just_edit;
|
||||
@@ -6971,6 +7106,41 @@ void Tab::set_just_edit(bool just_edit)
|
||||
/// </summary>
|
||||
/// <param name="extruder_id"></param>
|
||||
|
||||
std::vector<wxString> Tab::generate_extruder_options()
|
||||
{
|
||||
std::vector<wxString> options;
|
||||
if (m_type != Preset::TYPE_FILAMENT)
|
||||
return options;
|
||||
|
||||
auto *variants = m_config->option<ConfigOptionStrings>("filament_extruder_variant");
|
||||
if (!variants)
|
||||
return options;
|
||||
|
||||
const std::vector<std::string> known_nozzle_types = {
|
||||
get_nozzle_volume_type_string(NozzleVolumeType::nvtHighFlow),
|
||||
get_nozzle_volume_type_string(NozzleVolumeType::nvtStandard),
|
||||
};
|
||||
|
||||
for (const std::string &variant : variants->values) {
|
||||
std::string drive;
|
||||
std::string nozzle;
|
||||
|
||||
for (const std::string &nozzle_type : known_nozzle_types) {
|
||||
if (variant.size() > nozzle_type.size() &&
|
||||
variant.substr(variant.size() - nozzle_type.size()) == nozzle_type &&
|
||||
variant[variant.size() - nozzle_type.size() - 1] == ' ') {
|
||||
drive = variant.substr(0, variant.size() - nozzle_type.size() - 1);
|
||||
nozzle = nozzle_type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
options.push_back(nozzle.empty() ? from_u8(variant) : wxString::Format(wxT("%s: %s"), from_u8(drive), from_u8(nozzle)));
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
void Tab::update_extruder_variants(int extruder_id)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << extruder_id;
|
||||
@@ -6995,11 +7165,26 @@ void Tab::update_extruder_variants(int extruder_id)
|
||||
GetParent()->Layout();
|
||||
return;
|
||||
}
|
||||
} else if (m_variant_combo) {
|
||||
if (extruder_id >= 0)
|
||||
return;
|
||||
|
||||
const int selection = m_variant_combo->GetSelection();
|
||||
auto options = generate_extruder_options();
|
||||
m_variant_combo->SetOptions(options);
|
||||
|
||||
if (!options.empty())
|
||||
m_variant_combo->SetSelection(selection < 0 || selection >= (int) options.size() ? 0 : selection);
|
||||
|
||||
m_variant_combo->Enable(options.size() > 1);
|
||||
}
|
||||
switch_excluder(extruder_id);
|
||||
if (m_extruder_switch) {
|
||||
m_main_sizer->Show(m_extruder_switch, m_active_page && !m_active_page->m_opt_id_map.empty());
|
||||
GetParent()->Layout();
|
||||
} else if (m_variant_combo) {
|
||||
m_main_sizer->Show(m_variant_combo, m_variant_combo->IsEnabled() && m_active_page && !m_active_page->m_opt_id_map.empty());
|
||||
GetParent()->Layout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7013,7 +7198,7 @@ void Tab::switch_excluder(int extruder_id)
|
||||
{}, {"", "filament_extruder_variant"}, // Preset::TYPE_FILAMENT filament don't use id anymore
|
||||
{}, {"printer_extruder_id", "printer_extruder_variant"}, // Preset::TYPE_PRINTER
|
||||
};
|
||||
if (extruder_id >= nozzle_volumes->size() || extruder_id >= extruders->size())
|
||||
if (!m_variant_combo && (extruder_id >= nozzle_volumes->size() || extruder_id >= extruders->size()))
|
||||
extruder_id = 0;
|
||||
if (m_extruder_switch && m_type != Preset::TYPE_PRINTER) {
|
||||
int current_extruder = m_extruder_switch->GetValue() ? 1 : 0;
|
||||
@@ -7021,15 +7206,25 @@ void Tab::switch_excluder(int extruder_id)
|
||||
extruder_id = current_extruder;
|
||||
else if (extruder_id != current_extruder)
|
||||
return;
|
||||
} else if (m_variant_combo) {
|
||||
int current_variant = m_variant_combo->GetSelection();
|
||||
if (current_variant < 0)
|
||||
current_variant = 0;
|
||||
if (extruder_id == -1)
|
||||
extruder_id = current_variant;
|
||||
else if (extruder_id != current_variant)
|
||||
return;
|
||||
}
|
||||
auto get_index_for_extruder =
|
||||
[this, &extruders, &nozzle_volumes, variant_keys = variant_keys[m_type >= Preset::TYPE_COUNT ? Preset::TYPE_PRINT : m_type]](int extruder_id, int stride = 1) {
|
||||
return m_config->get_index_for_extruder(extruder_id + 1, variant_keys.first,
|
||||
ExtruderType(extruders->values[extruder_id]), NozzleVolumeType(nozzle_volumes->values[extruder_id]), variant_keys.second, stride);
|
||||
};
|
||||
auto index = get_index_for_extruder(extruder_id == -1 ? 0 : extruder_id);
|
||||
auto index = m_variant_combo ? extruder_id : get_index_for_extruder(extruder_id == -1 ? 0 : extruder_id);
|
||||
if (index < 0)
|
||||
return;
|
||||
if (m_variant_combo)
|
||||
m_variant_combo->SetClientData(reinterpret_cast<void *>(static_cast<std::uintptr_t>(index)));
|
||||
for (auto page : m_pages) {
|
||||
bool is_extruder = false;
|
||||
if (m_type == Preset::TYPE_PRINTER) {
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
class TabCtrl;
|
||||
class ModeSwitchButton;
|
||||
class SwitchButton;
|
||||
class MultiSwitchButton;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
@@ -305,6 +306,7 @@ public:
|
||||
|
||||
ModeSwitchButton *m_mode_view = nullptr;
|
||||
SwitchButton *m_extruder_switch = nullptr;
|
||||
MultiSwitchButton *m_variant_combo = nullptr;
|
||||
|
||||
public:
|
||||
// BBS
|
||||
@@ -417,6 +419,7 @@ public:
|
||||
|
||||
static bool validate_custom_gcode(const wxString& title, const std::string& gcode);
|
||||
bool validate_custom_gcodes();
|
||||
bool validate_filament_temperature_pairs();
|
||||
bool validate_custom_gcodes_was_shown{ false };
|
||||
void set_just_edit(bool just_edit);
|
||||
|
||||
@@ -426,6 +429,7 @@ public:
|
||||
|
||||
void update_extruder_variants(int extruder_id = -1);
|
||||
void switch_excluder(int extruder_id = -1);
|
||||
std::vector<wxString> generate_extruder_options();
|
||||
|
||||
protected:
|
||||
void create_line_with_widget(ConfigOptionsGroup* optgroup, const std::string& opt_key, const std::string& path, widget_t widget);
|
||||
@@ -445,6 +449,7 @@ protected:
|
||||
void filter_diff_option(std::vector<std::string> &options);
|
||||
|
||||
ConfigManipulation m_config_manipulation;
|
||||
std::string m_last_sparse_infill_rotate_template_value;
|
||||
ConfigManipulation get_config_manipulation();
|
||||
friend class EditGCodeDialog;
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "Widgets/RoundedRectangle.hpp"
|
||||
#include "Widgets/CheckBox.hpp"
|
||||
#include "Widgets/DialogButtons.hpp"
|
||||
#include "Widgets/HyperLink.hpp"
|
||||
|
||||
using boost::optional;
|
||||
|
||||
@@ -959,6 +960,11 @@ void UnsavedChangesDialog::build(Preset::Type type, PresetCollection *dependent_
|
||||
m_sizer_button->Add(checkbox_sizer, 0, wxLEFT, FromDIP(22));
|
||||
checkbox_sizer->Show(bool(m_buttons & REMEMBER_CHOISE));
|
||||
|
||||
if (dependent_presets != nullptr) {
|
||||
auto wiki = new HyperLink(this, _L("Help"), "https://www.orcaslicer.com/wiki/transfer_discard_changes");
|
||||
m_sizer_button->Add(wiki, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(22));
|
||||
}
|
||||
|
||||
m_sizer_button->Add(0, 0, 1, 0, 0);
|
||||
|
||||
// Add Buttons
|
||||
|
||||
@@ -418,8 +418,9 @@ void WebViewPanel::OnFreshLoginStatus(wxTimerEvent &event)
|
||||
{
|
||||
auto mainframe = Slic3r::GUI::wxGetApp().mainframe;
|
||||
if (mainframe && mainframe->m_webview == this) {
|
||||
Slic3r::GUI::wxGetApp().get_login_info(ORCA_CLOUD_PROVIDER);
|
||||
auto* app_config = Slic3r::GUI::wxGetApp().app_config;
|
||||
if (app_config && app_config->get_stealth_mode()) return;
|
||||
Slic3r::GUI::wxGetApp().get_login_info(ORCA_CLOUD_PROVIDER);
|
||||
if (app_config && app_config->has_cloud_provider(BBL_CLOUD_PROVIDER)) {
|
||||
Slic3r::GUI::wxGetApp().get_login_info(BBL_CLOUD_PROVIDER);
|
||||
}
|
||||
@@ -520,14 +521,18 @@ void WebViewPanel::SendCloudProvidersInfo()
|
||||
if (!app_config)
|
||||
return;
|
||||
|
||||
auto providers = app_config->get_cloud_providers();
|
||||
json j;
|
||||
j["command"] = "cloud_providers_info";
|
||||
json data;
|
||||
json provider_array = json::array();
|
||||
for (const auto& p : providers) {
|
||||
provider_array.push_back(p);
|
||||
|
||||
if (!app_config->get_stealth_mode()) {
|
||||
auto providers = app_config->get_cloud_providers();
|
||||
for (const auto& p : providers) {
|
||||
provider_array.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
data["providers"] = provider_array;
|
||||
j["data"] = data;
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "SwitchButton.hpp"
|
||||
#include "Button.hpp"
|
||||
#include "Label.hpp"
|
||||
#include "StaticBox.hpp"
|
||||
|
||||
@@ -19,7 +20,10 @@
|
||||
#include <wx/dcclient.h>
|
||||
#include <wx/dcgraph.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
wxDEFINE_EVENT(wxCUSTOMEVT_SWITCH_POS, wxCommandEvent);
|
||||
wxDEFINE_EVENT(wxCUSTOMEVT_MULTISWITCH_SELECTION, wxCommandEvent);
|
||||
|
||||
SwitchButton::SwitchButton(wxWindow* parent, wxWindowID id)
|
||||
: wxBitmapToggleButton(parent, id, wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE | wxBU_EXACTFIT)
|
||||
@@ -391,6 +395,192 @@ void ModeSwitchButton::update_tooltip()
|
||||
SetToolTip(m_tooltips[m_selection]);
|
||||
}
|
||||
|
||||
MultiSwitchButton::MultiSwitchButton(wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long style)
|
||||
: StaticBox(parent, id, pos, size, style)
|
||||
, m_bg_color(StateColor(
|
||||
std::make_pair(0xE8E8E8, (int) StateColor::NotChecked),
|
||||
std::make_pair(0x009688, (int) StateColor::Normal)))
|
||||
, m_text_color(StateColor(
|
||||
std::make_pair(0x6B6B6B, (int) StateColor::NotChecked),
|
||||
std::make_pair(0xFFFFFE, (int) StateColor::Normal)))
|
||||
, m_button_radius(10.0)
|
||||
, m_button_padding(10, 6)
|
||||
{
|
||||
SetCornerRadius(m_button_radius);
|
||||
SetBorderWidth(0);
|
||||
|
||||
sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
auto *hsizer = new wxBoxSizer(wxVERTICAL);
|
||||
hsizer->Add(sizer, 1, wxEXPAND);
|
||||
SetSizer(hsizer);
|
||||
SetMinSize(wxSize(-1, 20));
|
||||
|
||||
Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MultiSwitchButton::button_clicked, this);
|
||||
SetFont(Label::Body_12);
|
||||
}
|
||||
|
||||
MultiSwitchButton::~MultiSwitchButton()
|
||||
{
|
||||
DeleteAllOptions();
|
||||
}
|
||||
|
||||
int MultiSwitchButton::AppendOption(const wxString &option, void *clientData)
|
||||
{
|
||||
Button *btn = new Button();
|
||||
btn->Create(this, option, "", wxBORDER_NONE);
|
||||
btn->SetFont(GetFont());
|
||||
btn->SetBackgroundColor(m_bg_color);
|
||||
btn->SetTextColor(m_text_color);
|
||||
btn->SetCornerRadius(m_button_radius);
|
||||
btn->SetPaddingSize(m_button_padding);
|
||||
btn->SetClientData(clientData);
|
||||
|
||||
btns.push_back(btn);
|
||||
sizer->Add(btn, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
wxSize text_size = btn->GetTextExtent(option);
|
||||
btn->SetMinSize(wxSize(text_size.x + m_button_padding.x * 2 + 6, -1));
|
||||
|
||||
return int(btns.size()) - 1;
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetOptions(const std::vector<wxString> &options)
|
||||
{
|
||||
DeleteAllOptions();
|
||||
for (const auto &option : options)
|
||||
AppendOption(option);
|
||||
|
||||
Layout();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::DeleteAllOptions()
|
||||
{
|
||||
sel = -1;
|
||||
for (auto *btn : btns) {
|
||||
if (btn)
|
||||
btn->Destroy();
|
||||
}
|
||||
btns.clear();
|
||||
if (sizer)
|
||||
sizer->Clear();
|
||||
}
|
||||
|
||||
unsigned int MultiSwitchButton::GetCount() const
|
||||
{
|
||||
return (unsigned int) btns.size();
|
||||
}
|
||||
|
||||
int MultiSwitchButton::GetSelection() const
|
||||
{
|
||||
return sel;
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetSelection(int index)
|
||||
{
|
||||
if (index < 0 || index >= (int) btns.size() || index == sel)
|
||||
return;
|
||||
|
||||
sel = index;
|
||||
update_button_styles();
|
||||
send_selection_event();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
wxString MultiSwitchButton::GetSelectedText() const
|
||||
{
|
||||
return sel >= 0 && sel < (int) btns.size() ? btns[sel]->GetLabel() : wxString();
|
||||
}
|
||||
|
||||
wxString MultiSwitchButton::GetOptionText(unsigned int index) const
|
||||
{
|
||||
return index < btns.size() ? btns[index]->GetLabel() : wxString();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetOptionText(unsigned int index, const wxString &text)
|
||||
{
|
||||
if (index >= btns.size())
|
||||
return;
|
||||
btns[index]->SetLabel(text);
|
||||
}
|
||||
|
||||
void *MultiSwitchButton::GetOptionData(unsigned int index) const
|
||||
{
|
||||
return index < btns.size() ? btns[index]->GetClientData() : nullptr;
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetOptionData(unsigned int index, void *clientData)
|
||||
{
|
||||
if (index >= btns.size())
|
||||
return;
|
||||
btns[index]->SetClientData(clientData);
|
||||
}
|
||||
|
||||
void MultiSwitchButton::update_button_styles()
|
||||
{
|
||||
for (int i = 0; i < (int) btns.size(); ++i) {
|
||||
btns[i]->SetValue(i == sel);
|
||||
btns[i]->SetBackgroundColor(m_bg_color);
|
||||
btns[i]->SetTextColor(m_text_color);
|
||||
btns[i]->Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetBackgroundColor(const StateColor &color)
|
||||
{
|
||||
m_bg_color = color;
|
||||
update_button_styles();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetTextColor(const StateColor &color)
|
||||
{
|
||||
m_text_color = color;
|
||||
update_button_styles();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetButtonCornerRadius(double radius)
|
||||
{
|
||||
m_button_radius = radius;
|
||||
SetCornerRadius(radius);
|
||||
for (auto *btn : btns)
|
||||
btn->SetCornerRadius(radius);
|
||||
Layout();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::SetButtonPadding(const wxSize &padding)
|
||||
{
|
||||
m_button_padding = padding;
|
||||
for (auto *btn : btns)
|
||||
btn->SetPaddingSize(padding);
|
||||
Layout();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::Rescale()
|
||||
{
|
||||
for (auto *btn : btns)
|
||||
btn->Rescale();
|
||||
}
|
||||
|
||||
void MultiSwitchButton::button_clicked(wxCommandEvent &event)
|
||||
{
|
||||
SetFocus();
|
||||
auto *btn = event.GetEventObject();
|
||||
auto iter = std::find(btns.begin(), btns.end(), btn);
|
||||
SetSelection(iter == btns.end() ? -1 : int(iter - btns.begin()));
|
||||
}
|
||||
|
||||
bool MultiSwitchButton::send_selection_event()
|
||||
{
|
||||
wxCommandEvent evt(wxCUSTOMEVT_MULTISWITCH_SELECTION, GetId());
|
||||
evt.SetEventObject(this);
|
||||
evt.SetInt(sel);
|
||||
evt.SetString(GetSelectedText());
|
||||
GetEventHandler()->ProcessEvent(evt);
|
||||
return true;
|
||||
}
|
||||
|
||||
SwitchBoard::SwitchBoard(wxWindow *parent, wxString leftL, wxString right, wxSize size)
|
||||
: wxWindow(parent, wxID_ANY, wxDefaultPosition, size)
|
||||
{
|
||||
@@ -554,4 +744,4 @@ bool SwitchBoard::Enable(bool enable /* = true */)
|
||||
is_enable = enable;
|
||||
Refresh();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,14 @@
|
||||
#include "StateColor.hpp"
|
||||
#include "StaticBox.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/tglbtn.h>
|
||||
|
||||
wxDECLARE_EVENT(wxCUSTOMEVT_SWITCH_POS, wxCommandEvent);
|
||||
wxDECLARE_EVENT(wxCUSTOMEVT_MULTISWITCH_SELECTION, wxCommandEvent);
|
||||
|
||||
class Button;
|
||||
|
||||
class SwitchButton : public wxBitmapToggleButton
|
||||
{
|
||||
@@ -76,6 +81,53 @@ private:
|
||||
wxString m_tooltips[3];
|
||||
};
|
||||
|
||||
class MultiSwitchButton : public StaticBox
|
||||
{
|
||||
public:
|
||||
MultiSwitchButton(wxWindow *parent = nullptr, wxWindowID id = wxID_ANY, const wxPoint &pos = wxDefaultPosition,
|
||||
const wxSize &size = wxDefaultSize, long style = 0);
|
||||
~MultiSwitchButton();
|
||||
|
||||
int AppendOption(const wxString &option, void *clientData = nullptr);
|
||||
void SetOptions(const std::vector<wxString> &options);
|
||||
void DeleteAllOptions();
|
||||
|
||||
unsigned int GetCount() const;
|
||||
|
||||
int GetSelection() const;
|
||||
void SetSelection(int index);
|
||||
wxString GetSelectedText() const;
|
||||
|
||||
wxString GetOptionText(unsigned int index) const;
|
||||
void SetOptionText(unsigned int index, const wxString &text);
|
||||
|
||||
void *GetOptionData(unsigned int index) const;
|
||||
void SetOptionData(unsigned int index, void *clientData);
|
||||
|
||||
void SetBackgroundColor(const StateColor &color);
|
||||
void SetTextColor(const StateColor &color);
|
||||
void SetButtonCornerRadius(double radius);
|
||||
void SetButtonPadding(const wxSize &padding);
|
||||
|
||||
void Rescale();
|
||||
|
||||
protected:
|
||||
void button_clicked(wxCommandEvent &event);
|
||||
void update_button_styles();
|
||||
|
||||
bool send_selection_event();
|
||||
|
||||
private:
|
||||
std::vector<Button *> btns;
|
||||
wxBoxSizer *sizer = nullptr;
|
||||
int sel = -1;
|
||||
|
||||
StateColor m_bg_color;
|
||||
StateColor m_text_color;
|
||||
double m_button_radius;
|
||||
wxSize m_button_padding;
|
||||
};
|
||||
|
||||
class SwitchBoard : public wxWindow
|
||||
{
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user