mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-16 13:32:44 +00:00
feat: Filament Track Switch (H2-series O2L-FTS) support
The Filament Track Switch (H2-series accessory, product code O2L-FTS) feeds every AMS to both extruders through a two-track switch. Port full support across the device layer, project config, and GUI. Device / config: - Model the switch-aware AMS binding (the set of extruders an AMS can feed and which input track A/B feeds it), switch readiness, the O2L-FTS firmware module, and the fun2 capability bit for checking a slice against installed hardware. - Register has_filament_switcher and enable_filament_dynamic_map as project config that persists with the project and restores from a saved 3mf, and force both back to false on every project/printer/CLI load path. Live device sync is the only thing that sets them true. GUI: - Sidebar sync activates the switch from live device state, attributes each AMS to the extruder its input track feeds, shows a floating status icon (ready / not-calibrated), and surfaces a one-time tip / not-calibrated warning. - Send dialog gains a non-blocking slice-vs-hardware mismatch warning and a blocking error when a slice needs dynamic nozzle mapping but the switch is missing or not set up. - AMS load/unload guards, AMS-view routing glyph + un-calibrated banner + hidden external-spool road, and mapping-popup external-spool lockout. - Filament pickers collapse the per-extruder split into a single deduplicated "AMS filaments" group with a smart-assign toggle when the switch is ready. - Firmware-upgrade panel lists the O2L-FTS accessory and its version. - Device-provided filament-change steps (ams.cfs) drive the change-step display when firmware sends them, including the three switch steps. - "Load current filament" asks which extruder to feed via a FeedDirectionDialog when the switch is calibrated. Inert without the accessory: every path is gated on the switch being installed (MQTT aux bit 29, default off) or ready, both project flags default false, and the per-extruder AMS attribution is byte-identical, so AMS state, the send/load UI, and sliced g-code are unchanged for every printer that does not report a Filament Track Switch.
This commit is contained in:
@@ -18656,3 +18656,69 @@ msgstr ""
|
|||||||
#, possible-c-format, possible-boost-format
|
#, possible-c-format, possible-boost-format
|
||||||
msgid "The current nozzle mapping may produce an extra %0.2f g of waste."
|
msgid "The current nozzle mapping may produce an extra %0.2f g of waste."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Filament switcher detected. All AMS filaments are now available for both "
|
||||||
|
"extruders. The slicer will auto-assign for optimal printing. "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"A filament switcher is detected but not calibrated and thus currently "
|
||||||
|
"unavailable. Please calibrate it on the printer and synchronize before use. "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"The Filament Track Switch installed on the printer does not match the slicing "
|
||||||
|
"file. Please re-slice to avoid print quality issues."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "This print requires a Filament Track Switch. Please install it first."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "The Filament Track Switch has not been setup. Please setup it first."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "\"Load\" or \"Unload\" is not supported for external spool while using Filament Track Switch."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "The Filament Track Switch has not been setup. Please setup on printer."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Load %s to "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AMS filaments"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Fila Saving"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Filament Track Switch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "AMS has not been initialized. Please initialize it before use."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "External spools is not supported since Filament Track Switch has been installed. If you want to use external spool, please uninstall it."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Switch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "hotend"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Wait for AMS cooling"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Switch current filament at Filament Track Switch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Pull back current filament at Filament Track Switch"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Switch track at Filament Track Switch"
|
||||||
|
msgstr ""
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
<svg width="17" height="9" viewBox="0 0 17 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_iiii_6472_20428)">
|
||||||
|
<rect x="0.0527344" y="0.0527344" width="16" height="8.42105" rx="0.842105" fill="#808080"/>
|
||||||
|
</g>
|
||||||
|
<rect x="0.0527344" y="0.0527344" width="16" height="8.42105" rx="0.842105" stroke="#C2C2C2" stroke-width="0.105263"/>
|
||||||
|
<path d="M10.7006 2.79037H10.5244L10.426 2.792C9.41175 2.82502 8.47921 3.36695 7.94928 4.23755C7.46947 5.02578 6.61347 5.50693 5.69069 5.50693H5.51452V4.94947C5.51452 4.80429 5.35736 4.71355 5.23163 4.78614L3.94526 5.52882C3.81952 5.60141 3.81952 5.78289 3.94526 5.85548L5.23163 6.59816C5.35736 6.67075 5.51452 6.58001 5.51452 6.43483V5.87736H5.69069C6.74276 5.87736 7.71879 5.32886 8.26581 4.43018C8.73063 3.66656 9.54849 3.1912 10.4381 3.16225L10.5244 3.1608H10.7006V3.71826C10.7006 3.86344 10.8577 3.95418 10.9835 3.88159L12.2698 3.13891C12.3956 3.06632 12.3956 2.88485 12.2698 2.81225L10.9835 2.06958C10.8577 1.99699 10.7006 2.08773 10.7006 2.23291V2.79037Z" fill="#EEEEEE"/>
|
||||||
|
<path d="M5.51452 2.79037H5.69069L5.78908 2.792C6.80334 2.82502 7.73588 3.36695 8.26581 4.23755C8.74562 5.02578 9.60161 5.50693 10.5244 5.50693H10.7006V4.94947C10.7006 4.80429 10.8577 4.71355 10.9835 4.78614L12.2698 5.52882C12.3956 5.60141 12.3956 5.78289 12.2698 5.85548L10.9835 6.59816C10.8577 6.67075 10.7006 6.58001 10.7006 6.43483V5.87736H10.5244C9.47233 5.87736 8.4963 5.32886 7.94928 4.43018C7.48446 3.66656 6.6666 3.1912 5.77697 3.16225L5.69069 3.1608H5.51452V3.71826C5.51452 3.86344 5.35735 3.95418 5.23162 3.88159L3.94525 3.13891C3.81952 3.06632 3.81952 2.88485 3.94525 2.81225L5.23162 2.06958C5.35735 1.99699 5.51452 2.08773 5.51452 2.23291V2.79037Z" fill="#EEEEEE"/>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_iiii_6472_20428" x="-1" y="-1" width="18.1055" height="10.5264" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="-1"/>
|
||||||
|
<feGaussianBlur stdDeviation="0.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_6472_20428"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dx="-1"/>
|
||||||
|
<feGaussianBlur stdDeviation="0.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="effect1_innerShadow_6472_20428" result="effect2_innerShadow_6472_20428"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="1"/>
|
||||||
|
<feGaussianBlur stdDeviation="0.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="effect2_innerShadow_6472_20428" result="effect3_innerShadow_6472_20428"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dx="1"/>
|
||||||
|
<feGaussianBlur stdDeviation="0.5"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="effect3_innerShadow_6472_20428" result="effect4_innerShadow_6472_20428"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,38 @@
|
|||||||
|
<svg width="33" height="18" viewBox="0 0 33 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g filter="url(#filter0_iiii_6472_20289)">
|
||||||
|
<rect x="0.105469" y="0.105469" width="32" height="16.8421" rx="1.68421" fill="#EA3D23"/>
|
||||||
|
</g>
|
||||||
|
<rect x="0.105469" y="0.105469" width="32" height="16.8421" rx="1.68421" stroke="#C2C2C2" stroke-width="0.210526"/>
|
||||||
|
<path d="M21.4011 5.57976H21.0488L20.852 5.58301C18.8235 5.64906 16.9584 6.73293 15.8986 8.47412C14.9389 10.0506 13.2269 11.0129 11.3814 11.0129H11.029V9.89796C11.029 9.6076 10.7147 9.42613 10.4633 9.57131L7.89051 11.0567C7.63905 11.2018 7.63905 11.5648 7.89051 11.71L10.4633 13.1953C10.7147 13.3405 11.029 13.159 11.029 12.8687V11.7538H11.3814C13.4855 11.7538 15.4376 10.6567 16.5316 8.85939C17.4613 7.33213 19.097 6.38143 20.8762 6.32352L21.0488 6.32062H21.4011V7.43555C21.4011 7.72591 21.7155 7.90739 21.9669 7.76221L24.5397 6.27685C24.7911 6.13167 24.7911 5.76871 24.5397 5.62353L21.9669 4.13818C21.7155 3.993 21.4011 4.17447 21.4011 4.46484V5.57976Z" fill="#EEEEEE"/>
|
||||||
|
<path d="M11.029 5.57976H11.3814L11.5782 5.58301C13.6067 5.64906 15.4718 6.73293 16.5316 8.47412C17.4912 10.0506 19.2032 11.0129 21.0488 11.0129H21.4011V9.89796C21.4011 9.6076 21.7155 9.42613 21.9669 9.57131L24.5397 11.0567C24.7911 11.2018 24.7911 11.5648 24.5397 11.71L21.9669 13.1953C21.7155 13.3405 21.4011 13.159 21.4011 12.8687V11.7538H21.0488C18.9447 11.7538 16.9926 10.6567 15.8986 8.85939C14.9689 7.33213 13.3332 6.38143 11.5539 6.32352L11.3814 6.32062H11.029V7.43555C11.029 7.72591 10.7147 7.90739 10.4632 7.76221L7.8905 6.27685C7.63904 6.13167 7.63904 5.76871 7.8905 5.62353L10.4632 4.13818C10.7147 3.993 11.029 4.17447 11.029 4.46484V5.57976Z" fill="#EEEEEE"/>
|
||||||
|
<defs>
|
||||||
|
<filter id="filter0_iiii_6472_20289" x="-2" y="-2" width="36.2109" height="21.0527" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||||
|
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||||
|
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="-2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_6472_20289"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dx="-2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="effect1_innerShadow_6472_20289" result="effect2_innerShadow_6472_20289"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dy="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="effect2_innerShadow_6472_20289" result="effect3_innerShadow_6472_20289"/>
|
||||||
|
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||||
|
<feOffset dx="2"/>
|
||||||
|
<feGaussianBlur stdDeviation="1"/>
|
||||||
|
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||||
|
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.25 0"/>
|
||||||
|
<feBlend mode="normal" in2="effect3_innerShadow_6472_20289" result="effect4_innerShadow_6472_20289"/>
|
||||||
|
</filter>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
@@ -1326,6 +1326,14 @@ int CLI::run(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
set_temporary_dir(temp_path);
|
set_temporary_dir(temp_path);
|
||||||
|
|
||||||
|
// The Filament Track Switch flags are live-device state with no meaning in headless slicing;
|
||||||
|
// default both off unless explicitly provided on the command line, so an old 3MF that had
|
||||||
|
// them enabled still slices without the switch behavior.
|
||||||
|
if (!m_extra_config.has("has_filament_switcher"))
|
||||||
|
m_extra_config.set_key_value("has_filament_switcher", new ConfigOptionBool(false));
|
||||||
|
if (!m_extra_config.has("enable_filament_dynamic_map"))
|
||||||
|
m_extra_config.set_key_value("enable_filament_dynamic_map", new ConfigOptionBool(false));
|
||||||
|
|
||||||
m_extra_config.apply(m_config, true);
|
m_extra_config.apply(m_config, true);
|
||||||
m_extra_config.normalize_fdm();
|
m_extra_config.normalize_fdm();
|
||||||
|
|
||||||
|
|||||||
@@ -304,6 +304,10 @@ void AppConfig::set_defaults()
|
|||||||
if (get("show_3d_navigator").empty())
|
if (get("show_3d_navigator").empty())
|
||||||
set_bool("show_3d_navigator", true);
|
set_bool("show_3d_navigator", true);
|
||||||
|
|
||||||
|
// Show the one-time "Filament Track Switch is ready" tip until it has been seen once.
|
||||||
|
if (get("show_fila_switch_tips").empty())
|
||||||
|
set_bool("show_fila_switch_tips", true);
|
||||||
|
|
||||||
if (get("show_plate_gridlines").empty())
|
if (get("show_plate_gridlines").empty())
|
||||||
set_bool("show_plate_gridlines", true);
|
set_bool("show_plate_gridlines", true);
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,12 @@ static std::vector<std::string> s_project_options {
|
|||||||
"prime_volume_mode",
|
"prime_volume_mode",
|
||||||
"nozzle_volume_type",
|
"nozzle_volume_type",
|
||||||
"filament_map_mode",
|
"filament_map_mode",
|
||||||
"filament_map"
|
"filament_map",
|
||||||
|
// Filament Track Switch device state: whether the switch is installed and ready, and
|
||||||
|
// whether dynamic per-nozzle filament mapping is active. Persisted with the project and
|
||||||
|
// restored from a saved 3mf; reset to false on load and set true only by live device sync.
|
||||||
|
"has_filament_switcher",
|
||||||
|
"enable_filament_dynamic_map"
|
||||||
};
|
};
|
||||||
|
|
||||||
//Orca: add custom as default
|
//Orca: add custom as default
|
||||||
@@ -4323,6 +4328,10 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
|||||||
};
|
};
|
||||||
clear_compatible_printers(config);
|
clear_compatible_printers(config);
|
||||||
|
|
||||||
|
// Dynamic per-nozzle filament mapping reflects live device state, not a stored setting;
|
||||||
|
// drop it from any imported config so it only comes from the connected printer.
|
||||||
|
config.erase("enable_filament_dynamic_map");
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
size_t num_extruders = (printer_technology == ptFFF) ?
|
size_t num_extruders = (printer_technology == ptFFF) ?
|
||||||
std::min(config.option<ConfigOptionFloats>("nozzle_diameter" )->values.size(),
|
std::min(config.option<ConfigOptionFloats>("nozzle_diameter" )->values.size(),
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "Plater.hpp"
|
#include "Plater.hpp"
|
||||||
#include "BitmapCache.hpp"
|
#include "BitmapCache.hpp"
|
||||||
#include "BindDialog.hpp"
|
#include "BindDialog.hpp"
|
||||||
|
#include "slic3r/GUI/DeviceCore/DevFilaSwitch.h"
|
||||||
|
|
||||||
#include "DeviceCore/DevFilaSystem.h"
|
#include "DeviceCore/DevFilaSystem.h"
|
||||||
#include "DeviceCore/DevNozzleRack.h"
|
#include "DeviceCore/DevNozzleRack.h"
|
||||||
@@ -974,6 +975,8 @@ void AmsMapingPopup::on_left_down(wxMouseEvent &evt)
|
|||||||
auto left = item->GetSize();
|
auto left = item->GetSize();
|
||||||
|
|
||||||
if (pos.x > p_rect.x && pos.y > p_rect.y && pos.x < (p_rect.x + item->GetSize().x) && pos.y < (p_rect.y + item->GetSize().y)) {
|
if (pos.x > p_rect.x && pos.y > p_rect.y && pos.x < (p_rect.x + item->GetSize().x) && pos.y < (p_rect.y + item->GetSize().y)) {
|
||||||
|
// Orca: the external spool is un-pickable while a Filament Track Switch is installed (Apple hit-tests here).
|
||||||
|
if (m_fila_switch_installed && (item->m_ams_id == VIRTUAL_TRAY_MAIN_ID || item->m_ams_id == VIRTUAL_TRAY_DEPUTY_ID)) { return; }
|
||||||
if (item->m_tray_data.type == TrayType::NORMAL) {
|
if (item->m_tray_data.type == TrayType::NORMAL) {
|
||||||
if (!m_ext_mapping_filatype_check && (item->m_ams_id == VIRTUAL_TRAY_MAIN_ID || item->m_ams_id == VIRTUAL_TRAY_DEPUTY_ID)) {
|
if (!m_ext_mapping_filatype_check && (item->m_ams_id == VIRTUAL_TRAY_MAIN_ID || item->m_ams_id == VIRTUAL_TRAY_DEPUTY_ID)) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
@@ -1169,6 +1172,11 @@ void AmsMapingPopup::update(MachineObject* obj, const std::vector<FilamentInfo>&
|
|||||||
if (!obj) {return;}
|
if (!obj) {return;}
|
||||||
m_ams_remain_detect_flag = obj->GetFilaSystem()->IsDetectRemainEnabled();
|
m_ams_remain_detect_flag = obj->GetFilaSystem()->IsDetectRemainEnabled();
|
||||||
|
|
||||||
|
// Orca: with a Filament Track Switch installed, filament routes through the switch and the external
|
||||||
|
// spool cannot be used, so its mapping slots are rendered greyed-out and un-pickable. Inert (false)
|
||||||
|
// on any printer without a switch — GetFilaSwitch()->IsInstalled() defaults to false.
|
||||||
|
m_fila_switch_installed = obj->GetFilaSwitch()->IsInstalled();
|
||||||
|
|
||||||
for (auto& ams_container : m_amsmapping_container_list) {
|
for (auto& ams_container : m_amsmapping_container_list) {
|
||||||
ams_container->Destroy();
|
ams_container->Destroy();
|
||||||
}
|
}
|
||||||
@@ -1546,6 +1554,20 @@ void AmsMapingPopup::add_ext_ams_mapping(TrayData tray_data, MappingItem* item)
|
|||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
m_mapping_item_list.push_back(item);
|
m_mapping_item_list.push_back(item);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Orca: a Filament Track Switch cannot route the external spool, so grey the ext slot out and make it
|
||||||
|
// un-pickable, with a tooltip explaining why (the click below is disabled; on_left_down also skips it).
|
||||||
|
if (m_fila_switch_installed) {
|
||||||
|
const wxString disp_name = (tray_data.type == THIRD) ? wxString("?")
|
||||||
|
: (tray_data.type == EMPTY) ? wxString("-")
|
||||||
|
: wxString(tray_data.name);
|
||||||
|
item->set_data(m_tag_material, wxColour(0xEE, 0xEE, 0xEE), disp_name, false, tray_data, true);
|
||||||
|
item->SetToolTip(_L("External spools is not supported since Filament Track Switch has been installed. If you want to use external spool, please uninstall it."));
|
||||||
|
item->Bind(wxEVT_LEFT_DOWN, [](wxMouseEvent&) { /* un-pickable while the switch is installed */ });
|
||||||
|
item->set_tray_index(_L("Ext"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// set button
|
// set button
|
||||||
if (tray_data.type == NORMAL) {
|
if (tray_data.type == NORMAL) {
|
||||||
if (is_match_material(tray_data.filament_type)) {
|
if (is_match_material(tray_data.filament_type)) {
|
||||||
|
|||||||
@@ -244,6 +244,9 @@ public:
|
|||||||
bool m_has_unmatch_filament {false};
|
bool m_has_unmatch_filament {false};
|
||||||
int m_current_filament_id;
|
int m_current_filament_id;
|
||||||
ShowType m_show_type{ShowType::RIGHT};
|
ShowType m_show_type{ShowType::RIGHT};
|
||||||
|
// Orca: set from update() — true when a Filament Track Switch is installed, which makes the
|
||||||
|
// external-spool slots un-pickable (false on any printer without a switch, so behavior is unchanged).
|
||||||
|
bool m_fila_switch_installed{false};
|
||||||
std::string m_tag_material;
|
std::string m_tag_material;
|
||||||
wxBoxSizer *m_sizer_main{nullptr};
|
wxBoxSizer *m_sizer_main{nullptr};
|
||||||
wxBoxSizer *m_sizer_ams{nullptr};
|
wxBoxSizer *m_sizer_ams{nullptr};
|
||||||
|
|||||||
@@ -41,6 +41,31 @@ enum AmsStatusMain
|
|||||||
AMS_STATUS_MAIN_UNKNOWN = 0xFF,
|
AMS_STATUS_MAIN_UNKNOWN = 0xFF,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// STEP_CHECK_POSITION and STEP_CONFIRM_EXTRUDED share code 0x08 by device design.
|
||||||
|
enum DevFilamentStep
|
||||||
|
{
|
||||||
|
STEP_IDLE = 0x00,
|
||||||
|
STEP_PAUSE = 0x01,
|
||||||
|
STEP_HEAT_NOZZLE = 0x02,
|
||||||
|
STEP_CUT_FILAMENT = 0x03,
|
||||||
|
STEP_PULL_CURR_FILAMENT = 0x04,
|
||||||
|
STEP_PUSH_NEW_FILAMENT = 0x05,
|
||||||
|
STEP_GRAB_NEW_FILAMENT = 0x06,
|
||||||
|
STEP_PURGE_OLD_FILAMENT = 0x07,
|
||||||
|
STEP_CHECK_POSITION = 0x08,
|
||||||
|
STEP_SWITCH_EXTRUDER = 0x09,
|
||||||
|
STEP_SWITCH_HOTEND = 0x0A,
|
||||||
|
STEP_AMS_FILA_COOLING = 0x0B,
|
||||||
|
STEP_PUSH_SWITCHER_FILA = 0x0C,
|
||||||
|
STEP_PULL_SWITCHER_FILA = 0x0D,
|
||||||
|
STEP_SWITCHER_SWITCH = 0x0E,
|
||||||
|
STEP_CONFIRM_EXTRUDED = 0x08,
|
||||||
|
STEP_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
// Slots and Tray
|
// Slots and Tray
|
||||||
#define VIRTUAL_TRAY_MAIN_ID 255
|
#define VIRTUAL_TRAY_MAIN_ID 255
|
||||||
#define VIRTUAL_TRAY_DEPUTY_ID 254
|
#define VIRTUAL_TRAY_DEPUTY_ID 254
|
||||||
|
|||||||
@@ -9,6 +9,19 @@ namespace Slic3r {
|
|||||||
|
|
||||||
DevFilaSwitch::DevFilaSwitch(MachineObject *owner) { m_owner = owner; }
|
DevFilaSwitch::DevFilaSwitch(MachineObject *owner) { m_owner = owner; }
|
||||||
|
|
||||||
|
bool DevFilaSwitch::IsReady() const
|
||||||
|
{
|
||||||
|
if (!m_is_installed) { return false; }
|
||||||
|
|
||||||
|
const auto& ams_list = m_owner->GetFilaSystem()->GetAmsList();
|
||||||
|
for (const auto& ams_item : ams_list) {
|
||||||
|
if (ams_item.second->GetBindedExtruderSet().empty()) { return false; }
|
||||||
|
if (!ams_item.second->GetSwitcherPos().has_value()) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void DevFilaSwitch::Reset()
|
void DevFilaSwitch::Reset()
|
||||||
{
|
{
|
||||||
m_is_installed = false;
|
m_is_installed = false;
|
||||||
|
|||||||
@@ -49,6 +49,11 @@ public:
|
|||||||
public:
|
public:
|
||||||
bool IsInstalled() const { return m_is_installed; };
|
bool IsInstalled() const { return m_is_installed; };
|
||||||
|
|
||||||
|
// Ready once installed and every AMS has resolved both its extruder binding and its
|
||||||
|
// switcher track position from the device. The send dialog and sidebar sync UX only
|
||||||
|
// treat the switch as usable when this is true.
|
||||||
|
bool IsReady() const;
|
||||||
|
|
||||||
std::optional<bool> IsInA_HasFilament() const { return m_in_a_has_filament; };
|
std::optional<bool> IsInA_HasFilament() const { return m_in_a_has_filament; };
|
||||||
std::optional<bool> IsInB_HasFilament() const { return m_in_b_has_filament; };
|
std::optional<bool> IsInB_HasFilament() const { return m_in_b_has_filament; };
|
||||||
|
|
||||||
@@ -67,12 +72,6 @@ public:
|
|||||||
void Reset();
|
void Reset();
|
||||||
void ParseFilaSwitchInfo(const nlohmann::json& print_jj);
|
void ParseFilaSwitchInfo(const nlohmann::json& print_jj);
|
||||||
|
|
||||||
// NOTE: an IsReady() accessor is intentionally omitted. It would walk
|
|
||||||
// GetFilaSystem()->GetAmsList() calling GetBindedExtruderSet()/GetSwitcherPos(),
|
|
||||||
// AMS filament-switch binding accessors Orca's DevFilaSystem does not yet carry.
|
|
||||||
// It is unused by the filament blacklist; port it alongside the filament-switch
|
|
||||||
// device-sync UI that needs those accessors.
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MachineObject* m_owner;
|
MachineObject* m_owner;
|
||||||
|
|
||||||
|
|||||||
@@ -346,6 +346,15 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS
|
|||||||
|
|
||||||
if (!key_field_only)
|
if (!key_field_only)
|
||||||
{
|
{
|
||||||
|
// Newer firmware sends the exact filament-change step sequence in ams.cfs, so the
|
||||||
|
// client no longer hardcodes the steps per model. Absent on current firmware, which
|
||||||
|
// keeps the list empty and the legacy hardcoded/ams_status_sub step path in effect.
|
||||||
|
if (jj["ams"].contains("cfs")) {
|
||||||
|
system->m_filament_change_steps = DevJsonValParser::GetVal<std::vector<DevFilamentStep>>(jj["ams"], "cfs");
|
||||||
|
} else {
|
||||||
|
system->m_filament_change_steps.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (jj["ams"].contains("tray_read_done_bits"))
|
if (jj["ams"].contains("tray_read_done_bits"))
|
||||||
{
|
{
|
||||||
obj->tray_read_done_bits = stol(jj["ams"]["tray_read_done_bits"].get<std::string>(), nullptr, 16);
|
obj->tray_read_done_bits = stol(jj["ams"]["tray_read_done_bits"].get<std::string>(), nullptr, 16);
|
||||||
@@ -403,17 +412,43 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS
|
|||||||
int type_id = 1; // 0:dummy 1:ams 2:ams-lite 3:n3f 4:n3s
|
int type_id = 1; // 0:dummy 1:ams 2:ams-lite 3:n3f 4:n3s
|
||||||
|
|
||||||
/*ams info*/
|
/*ams info*/
|
||||||
|
std::set<int> binded_extruder_set;
|
||||||
|
std::optional<DevFilaSwitch::SwitchPos> binded_switcher_pos;
|
||||||
if (it->contains("info")) {
|
if (it->contains("info")) {
|
||||||
const std::string& info = (*it)["info"].get<std::string>();
|
const std::string& info = (*it)["info"].get<std::string>();
|
||||||
type_id = DevUtil::get_flag_bits(info, 0, 4);
|
type_id = DevUtil::get_flag_bits(info, 0, 4);
|
||||||
extuder_id = DevUtil::get_flag_bits(info, 8, 4);
|
extuder_id = DevUtil::get_flag_bits(info, 8, 4);
|
||||||
|
if (extuder_id == 0xE && obj->GetFilaSwitch()->IsInstalled()) {
|
||||||
|
int bind_switch_in = DevUtil::get_flag_bits(info, 24, 4);
|
||||||
|
if (bind_switch_in == 0 || bind_switch_in == 1) {
|
||||||
|
binded_extruder_set = { MAIN_EXTRUDER_ID, DEPUTY_EXTRUDER_ID };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bind_switch_in == 0) {
|
||||||
|
binded_switcher_pos = DevFilaSwitch::SwitchPos::POS_IN_B;
|
||||||
|
} else if (bind_switch_in == 1) {
|
||||||
|
binded_switcher_pos = DevFilaSwitch::SwitchPos::POS_IN_A;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Orca: the switch feeds every AMS to both extruders; pin a deterministic
|
||||||
|
// single-extruder id so legacy GetExtruderId() consumers keep a valid value
|
||||||
|
// while switch-aware code reads the binding set instead.
|
||||||
|
extuder_id = MAIN_EXTRUDER_ID;
|
||||||
|
} else if (extuder_id != 0xE) {
|
||||||
|
binded_extruder_set = { extuder_id };
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!obj->is_enable_ams_np && obj->get_printer_ams_type() == "f1") {
|
if (!obj->is_enable_ams_np && obj->get_printer_ams_type() == "f1") {
|
||||||
type_id = DevAms::AMS_LITE;
|
type_id = DevAms::AMS_LITE;
|
||||||
}
|
}
|
||||||
|
binded_extruder_set = { MAIN_EXTRUDER_ID };
|
||||||
}
|
}
|
||||||
|
|
||||||
/*AMS without initialization*/
|
/*AMS without initialization*/
|
||||||
|
// Orca: an AMS reporting extruder 0xE without a Filament Track Switch installed has
|
||||||
|
// no usable extruder binding; drop it, preserving the existing display for
|
||||||
|
// half-initialized printers. With the switch installed the 0xE case is remapped
|
||||||
|
// above to both extruders and falls through to normal handling.
|
||||||
if (extuder_id == 0xE)
|
if (extuder_id == 0xE)
|
||||||
{
|
{
|
||||||
ams_id_set.erase(ams_id);
|
ams_id_set.erase(ams_id);
|
||||||
@@ -445,6 +480,13 @@ void DevFilaSystemParser::ParseV1_0(const json& jj, MachineObject* obj, DevFilaS
|
|||||||
/*set ams type flag*/
|
/*set ams type flag*/
|
||||||
curr_ams->SetAmsType(type_id);
|
curr_ams->SetAmsType(type_id);
|
||||||
|
|
||||||
|
// Refresh the switch-aware extruder binding on every push (both create and
|
||||||
|
// update paths) so it can't go stale after an AMS is re-homed to another
|
||||||
|
// extruder. Without the switch the set holds the single bound extruder and
|
||||||
|
// the track position stays empty.
|
||||||
|
curr_ams->m_binded_extruder_set = binded_extruder_set;
|
||||||
|
curr_ams->m_binded_switcher_pos = binded_switcher_pos;
|
||||||
|
|
||||||
|
|
||||||
/*set ams exist flag*/
|
/*set ams exist flag*/
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -4,9 +4,12 @@
|
|||||||
|
|
||||||
#include "DevDefs.h"
|
#include "DevDefs.h"
|
||||||
#include "DevFilaAmsSetting.h"
|
#include "DevFilaAmsSetting.h"
|
||||||
|
#include "DevFilaSwitch.h"
|
||||||
#include "DevUtil.h"
|
#include "DevUtil.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <wx/string.h>
|
#include <wx/string.h>
|
||||||
@@ -169,6 +172,20 @@ public:
|
|||||||
// installed on the extruder
|
// installed on the extruder
|
||||||
int GetExtruderId() const { return m_ext_id; }
|
int GetExtruderId() const { return m_ext_id; }
|
||||||
|
|
||||||
|
// Extruders this AMS can currently feed. Without a Filament Track Switch installed this
|
||||||
|
// is the single {m_ext_id}; with the switch installed the device binds it to both extruders.
|
||||||
|
const std::set<int>& GetBindedExtruderSet() const { return m_binded_extruder_set; }
|
||||||
|
|
||||||
|
// The bound extruder when exactly one is bound, empty otherwise. Used to attribute an AMS
|
||||||
|
// to a single extruder on printers without the switch.
|
||||||
|
std::optional<int> GetUniqueBindedExtruderId() const
|
||||||
|
{
|
||||||
|
return m_binded_extruder_set.size() == 1 ? std::optional<int>(*m_binded_extruder_set.begin()) : std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Which switch input track (A/B) feeds this AMS, set only when a Filament Track Switch is installed.
|
||||||
|
std::optional<DevFilaSwitch::SwitchPos> GetSwitcherPos() const { return m_binded_switcher_pos; }
|
||||||
|
|
||||||
// temperature and humidity
|
// temperature and humidity
|
||||||
float GetCurrentTemperature() const { return m_current_temperature; }
|
float GetCurrentTemperature() const { return m_current_temperature; }
|
||||||
|
|
||||||
@@ -185,6 +202,12 @@ private:
|
|||||||
AmsType m_ams_type = AmsType::AMS;
|
AmsType m_ams_type = AmsType::AMS;
|
||||||
std::string m_ams_id;
|
std::string m_ams_id;
|
||||||
int m_ext_id;//extruder id
|
int m_ext_id;//extruder id
|
||||||
|
// Orca: keeps the legacy single m_ext_id for existing consumers and carries the
|
||||||
|
// switch-aware binding alongside it (BambuStudio stores only the set). Without a Filament
|
||||||
|
// Track Switch the set is {m_ext_id}; with one installed the device binds both extruders and
|
||||||
|
// records which input track (A/B) feeds this AMS.
|
||||||
|
std::set<int> m_binded_extruder_set;
|
||||||
|
std::optional<DevFilaSwitch::SwitchPos> m_binded_switcher_pos;
|
||||||
bool m_exist = false;
|
bool m_exist = false;
|
||||||
|
|
||||||
// slots and trays
|
// slots and trays
|
||||||
@@ -268,6 +291,11 @@ public:
|
|||||||
|
|
||||||
std::weak_ptr<DevAmsSystemFirmwareSwitch> GetAmsFirmwareSwitch() const { return m_ams_firmware_switch;}
|
std::weak_ptr<DevAmsSystemFirmwareSwitch> GetAmsFirmwareSwitch() const { return m_ams_firmware_switch;}
|
||||||
|
|
||||||
|
// filament change steps
|
||||||
|
// The exact change-step sequence reported by the AMS (ams.cfs). Empty on current firmware,
|
||||||
|
// which leaves the legacy hardcoded/ams_status_sub step handling in effect.
|
||||||
|
const std::vector<DevFilamentStep>& GetFilamentChangeSteps() const { return m_filament_change_steps; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// ctrls
|
// ctrls
|
||||||
int CtrlAmsReset() const;
|
int CtrlAmsReset() const;
|
||||||
@@ -281,6 +309,9 @@ private:
|
|||||||
/* ams properties */
|
/* ams properties */
|
||||||
int m_ams_cali_stat = 0;
|
int m_ams_cali_stat = 0;
|
||||||
|
|
||||||
|
// Change-step sequence reported by the AMS (ams.cfs); empty when firmware doesn't send it.
|
||||||
|
std::vector<DevFilamentStep> m_filament_change_steps;
|
||||||
|
|
||||||
std::map<std::string, DevAms*, NumericStrCompare> amsList;// key: ams[id], start with 0
|
std::map<std::string, DevAms*, NumericStrCompare> amsList;// key: ams[id], start with 0
|
||||||
|
|
||||||
DevAmsSystemSetting m_ams_system_setting{ this };
|
DevAmsSystemSetting m_ams_system_setting{ this };
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ public:
|
|||||||
bool isCuttingModule() const { return product_name.Contains("Cutting Module"); }
|
bool isCuttingModule() const { return product_name.Contains("Cutting Module"); }
|
||||||
bool isExtinguishSystem() const { return product_name.Contains("Extinguishing System"); }
|
bool isExtinguishSystem() const { return product_name.Contains("Extinguishing System"); }
|
||||||
bool isWTM() const { return name.find("wtm") != std::string::npos; } // nozzle (rack hotend) module firmware
|
bool isWTM() const { return name.find("wtm") != std::string::npos; } // nozzle (rack hotend) module firmware
|
||||||
|
bool isFilaTrackSwitch() const { return product_name.Contains("Filament Track"); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -869,6 +869,7 @@ void MachineObject::clear_version_info()
|
|||||||
laser_version_info = DevFirmwareVersionInfo();
|
laser_version_info = DevFirmwareVersionInfo();
|
||||||
cutting_module_version_info = DevFirmwareVersionInfo();
|
cutting_module_version_info = DevFirmwareVersionInfo();
|
||||||
extinguish_version_info = DevFirmwareVersionInfo();
|
extinguish_version_info = DevFirmwareVersionInfo();
|
||||||
|
filatrack_version_info = DevFirmwareVersionInfo();
|
||||||
module_vers.clear();
|
module_vers.clear();
|
||||||
// Drop cached rack-hotend (WTM) firmware alongside the module list.
|
// Drop cached rack-hotend (WTM) firmware alongside the module list.
|
||||||
// Inert for non-rack printers (rack firmware map is empty).
|
// Inert for non-rack printers (rack firmware map is empty).
|
||||||
@@ -890,6 +891,8 @@ void MachineObject::store_version_info(const DevFirmwareVersionInfo& info)
|
|||||||
// the rack upgrade UI can read per-nozzle versions. isWTM() is false for every non-rack
|
// the rack upgrade UI can read per-nozzle versions. isWTM() is false for every non-rack
|
||||||
// printer's modules, so this branch never fires outside H2C.
|
// printer's modules, so this branch never fires outside H2C.
|
||||||
m_nozzle_system->AddFirmwareInfoWTM(info);
|
m_nozzle_system->AddFirmwareInfoWTM(info);
|
||||||
|
} else if (info.isFilaTrackSwitch()) {
|
||||||
|
filatrack_version_info = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
module_vers.emplace(info.name, info);
|
module_vers.emplace(info.name, info);
|
||||||
@@ -1572,7 +1575,7 @@ int MachineObject::check_resume_condition()
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int MachineObject::command_ams_change_filament(bool load, std::string ams_id, std::string slot_id, int old_temp, int new_temp)
|
int MachineObject::command_ams_change_filament(bool load, std::string ams_id, std::string slot_id, int old_temp, int new_temp, std::optional<int> extruder_id)
|
||||||
{
|
{
|
||||||
json j;
|
json j;
|
||||||
try {
|
try {
|
||||||
@@ -1604,6 +1607,13 @@ int MachineObject::command_ams_change_filament(bool load, std::string ams_id, st
|
|||||||
j["print"]["slot_id"] = atoi(slot_id.c_str());
|
j["print"]["slot_id"] = atoi(slot_id.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filament Track Switch: route the load to the chosen extruder. Only present when the
|
||||||
|
// caller supplied a value (FTS-installed+ready path), so every other caller is unchanged.
|
||||||
|
if (extruder_id.has_value())
|
||||||
|
{
|
||||||
|
j["print"]["extruder_id"] = *extruder_id;
|
||||||
|
}
|
||||||
|
|
||||||
} catch (const std::exception &) {}
|
} catch (const std::exception &) {}
|
||||||
return this->publish_json(j);
|
return this->publish_json(j);
|
||||||
}
|
}
|
||||||
@@ -5085,6 +5095,7 @@ void MachineObject::parse_new_info(json print)
|
|||||||
// fun2 may have infinite length, use get_flag_bits_no_border
|
// fun2 may have infinite length, use get_flag_bits_no_border
|
||||||
if (!fun2.empty()) {
|
if (!fun2.empty()) {
|
||||||
is_support_print_with_emmc = get_flag_bits_no_border(fun2, 0) == 1;
|
is_support_print_with_emmc = get_flag_bits_no_border(fun2, 0) == 1;
|
||||||
|
is_support_check_track_switch_match_slice_printer = get_flag_bits_no_border(fun2, 19) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*aux*/
|
/*aux*/
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
#include <optional>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
#include <boost/nowide/fstream.hpp>
|
#include <boost/nowide/fstream.hpp>
|
||||||
#include "nlohmann/json.hpp"
|
#include "nlohmann/json.hpp"
|
||||||
@@ -378,6 +379,7 @@ public:
|
|||||||
DevFirmwareVersionInfo laser_version_info;
|
DevFirmwareVersionInfo laser_version_info;
|
||||||
DevFirmwareVersionInfo cutting_module_version_info;
|
DevFirmwareVersionInfo cutting_module_version_info;
|
||||||
DevFirmwareVersionInfo extinguish_version_info;
|
DevFirmwareVersionInfo extinguish_version_info;
|
||||||
|
DevFirmwareVersionInfo filatrack_version_info;
|
||||||
std::map<std::string, DevFirmwareVersionInfo> module_vers;
|
std::map<std::string, DevFirmwareVersionInfo> module_vers;
|
||||||
std::map<std::string, DevFirmwareVersionInfo> new_ver_list;
|
std::map<std::string, DevFirmwareVersionInfo> new_ver_list;
|
||||||
bool m_new_ver_list_exist = false;
|
bool m_new_ver_list_exist = false;
|
||||||
@@ -633,6 +635,7 @@ public:
|
|||||||
|
|
||||||
// fun2
|
// fun2
|
||||||
bool is_support_print_with_emmc{false};
|
bool is_support_print_with_emmc{false};
|
||||||
|
bool is_support_check_track_switch_match_slice_printer{false};
|
||||||
|
|
||||||
bool installed_upgrade_kit{false};
|
bool installed_upgrade_kit{false};
|
||||||
int bed_temperature_limit = -1;
|
int bed_temperature_limit = -1;
|
||||||
@@ -746,7 +749,7 @@ public:
|
|||||||
int check_resume_condition();
|
int check_resume_condition();
|
||||||
// ams controls
|
// ams controls
|
||||||
//int command_ams_switch(int tray_index, int old_temp = 210, int new_temp = 210);
|
//int command_ams_switch(int tray_index, int old_temp = 210, int new_temp = 210);
|
||||||
int command_ams_change_filament(bool load, std::string ams_id, std::string slot_id, int old_temp = 210, int new_temp = 210);
|
int command_ams_change_filament(bool load, std::string ams_id, std::string slot_id, int old_temp = 210, int new_temp = 210, std::optional<int> extruder_id = std::nullopt);
|
||||||
int command_ams_user_settings(bool start_read_opt, bool tray_read_opt, bool remain_flag = false);
|
int command_ams_user_settings(bool start_read_opt, bool tray_read_opt, bool remain_flag = false);
|
||||||
int command_ams_switch_filament(bool switch_filament);
|
int command_ams_switch_filament(bool switch_filament);
|
||||||
int command_ams_air_print_detect(bool air_print_detect);
|
int command_ams_air_print_detect(bool air_print_detect);
|
||||||
|
|||||||
@@ -174,6 +174,9 @@ FilamentGroupPopup::FilamentGroupPopup(wxWindow *parent) : PopupWindow(parent, w
|
|||||||
button_labels[idx]->Bind(wxEVT_LEAVE_WINDOW, [this](auto &) { UpdateButtonStatus(); });
|
button_labels[idx]->Bind(wxEVT_LEAVE_WINDOW, [this](auto &) { UpdateButtonStatus(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Smart filament assign section
|
||||||
|
MakeSmartFilamentSection(top_sizer, horizontal_margin, vertical_padding);
|
||||||
|
|
||||||
{
|
{
|
||||||
wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxBoxSizer *button_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
// ORCA Unified hyperlinks
|
// ORCA Unified hyperlinks
|
||||||
@@ -257,6 +260,7 @@ void FilamentGroupPopup::Init()
|
|||||||
SetFilamentMapMode(m_mode);
|
SetFilamentMapMode(m_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateSmartFilamentSection();
|
||||||
UpdateButtonStatus();
|
UpdateButtonStatus();
|
||||||
GUI::wxGetApp().UpdateDarkUIWin(this);
|
GUI::wxGetApp().UpdateDarkUIWin(this);
|
||||||
}
|
}
|
||||||
@@ -408,4 +412,65 @@ void FilamentGroupPopup::UpdateButtonStatus(int hover_idx)
|
|||||||
Fit();
|
Fit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FilamentGroupPopup::MakeSmartFilamentSection(wxSizer *top_sizer, int horizontal_margin, int vertical_padding)
|
||||||
|
{
|
||||||
|
m_smart_filament_panel = new StaticBox(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0);
|
||||||
|
m_smart_filament_panel->SetCornerRadius(FromDIP(4));
|
||||||
|
m_smart_filament_panel->SetBorderWidth(FromDIP(1));
|
||||||
|
m_smart_filament_panel->SetBorderColor(wxColour("#CECECE"));
|
||||||
|
m_smart_filament_panel->SetBackgroundColor(StateColor(std::pair<wxColour, int>(wxColour("#F8F8F8"), StateColor::Normal)));
|
||||||
|
|
||||||
|
auto *label = new Label(m_smart_filament_panel, _L("Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings"));
|
||||||
|
label->SetFont(Label::Body_12);
|
||||||
|
label->SetForegroundColour(GreyColor);
|
||||||
|
label->SetBackgroundColour(wxColour("#F8F8F8"));
|
||||||
|
label->Wrap(FromDIP(240));
|
||||||
|
|
||||||
|
m_smart_filament_switch = new SwitchButton(m_smart_filament_panel);
|
||||||
|
m_smart_filament_switch->Bind(wxEVT_TOGGLEBUTTON, &FilamentGroupPopup::OnSmartFilamentToggle, this);
|
||||||
|
#ifdef __WXOSX__
|
||||||
|
// wxEVT_TOGGLEBUTTON event not handled well by PopupWindow on MacOS
|
||||||
|
// we bind a wxEVT_LEFT_DOWN event as a workaround
|
||||||
|
m_smart_filament_switch->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent &) {
|
||||||
|
wxCommandEvent evt(wxEVT_TOGGLEBUTTON);
|
||||||
|
evt.SetInt(!m_smart_filament_switch->GetValue());
|
||||||
|
m_smart_filament_switch->Command(evt);
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto *panel_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
panel_sizer->Add(label, 1, wxALIGN_CENTER_VERTICAL | wxALL, FromDIP(10));
|
||||||
|
panel_sizer->Add(m_smart_filament_switch, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, FromDIP(10));
|
||||||
|
m_smart_filament_panel->SetSizer(panel_sizer);
|
||||||
|
|
||||||
|
top_sizer->Add(m_smart_filament_panel, 0, wxEXPAND | wxLEFT | wxRIGHT, horizontal_margin);
|
||||||
|
m_smart_filament_spacer = top_sizer->AddSpacer(vertical_padding);
|
||||||
|
|
||||||
|
// Hidden by default; shown in Init() when the filament track switch is ready
|
||||||
|
m_smart_filament_panel->Show(false);
|
||||||
|
m_smart_filament_spacer->Show(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilamentGroupPopup::OnSmartFilamentToggle(wxCommandEvent &event)
|
||||||
|
{
|
||||||
|
auto &config = wxGetApp().preset_bundle->project_config;
|
||||||
|
auto *dynamic_filament = dynamic_cast<ConfigOptionBool *>(config.option("enable_filament_dynamic_map"));
|
||||||
|
if (dynamic_filament) { dynamic_filament->value = m_smart_filament_switch->GetValue(); }
|
||||||
|
plater_ref->update();
|
||||||
|
event.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilamentGroupPopup::UpdateSmartFilamentSection()
|
||||||
|
{
|
||||||
|
bool show = wxGetApp().sidebar().is_fila_switch_ready();
|
||||||
|
m_smart_filament_panel->Show(show);
|
||||||
|
m_smart_filament_spacer->Show(show);
|
||||||
|
|
||||||
|
if (show) {
|
||||||
|
auto &config = wxGetApp().preset_bundle->project_config;
|
||||||
|
auto *dynamic_filament = dynamic_cast<ConfigOptionBool *>(config.option("enable_filament_dynamic_map"));
|
||||||
|
if (dynamic_filament) { m_smart_filament_switch->SetValue(dynamic_filament->value); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace Slic3r::GUI
|
}} // namespace Slic3r::GUI
|
||||||
@@ -3,10 +3,13 @@
|
|||||||
|
|
||||||
#include <wx/bitmap.h>
|
#include <wx/bitmap.h>
|
||||||
#include <wx/bmpbuttn.h>
|
#include <wx/bmpbuttn.h>
|
||||||
|
#include <wx/sizer.h>
|
||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
#include "libslic3r/PrintConfig.hpp"
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
#include "Widgets/PopupWindow.hpp"
|
#include "Widgets/PopupWindow.hpp"
|
||||||
#include "Widgets/Label.hpp"
|
#include "Widgets/Label.hpp"
|
||||||
|
#include "Widgets/SwitchButton.hpp"
|
||||||
|
#include "Widgets/StaticBox.hpp"
|
||||||
|
|
||||||
namespace Slic3r { namespace GUI {
|
namespace Slic3r { namespace GUI {
|
||||||
|
|
||||||
@@ -42,6 +45,10 @@ private:
|
|||||||
void Init();
|
void Init();
|
||||||
void UpdateButtonStatus(int hover_idx = -1);
|
void UpdateButtonStatus(int hover_idx = -1);
|
||||||
void DrawRoundedCorner(int radius);
|
void DrawRoundedCorner(int radius);
|
||||||
|
|
||||||
|
void MakeSmartFilamentSection(wxSizer *top_sizer, int horizontal_margin, int vertical_padding);
|
||||||
|
void UpdateSmartFilamentSection();
|
||||||
|
void OnSmartFilamentToggle(wxCommandEvent &event);
|
||||||
private:
|
private:
|
||||||
FilamentMapMode GetFilamentMapMode() const;
|
FilamentMapMode GetFilamentMapMode() const;
|
||||||
void SetFilamentMapMode(const FilamentMapMode mode);
|
void SetFilamentMapMode(const FilamentMapMode mode);
|
||||||
@@ -75,6 +82,10 @@ private:
|
|||||||
wxStaticText *wiki_link;
|
wxStaticText *wiki_link;
|
||||||
wxStaticText *video_link;
|
wxStaticText *video_link;
|
||||||
|
|
||||||
|
StaticBox *m_smart_filament_panel{nullptr};
|
||||||
|
wxSizerItem *m_smart_filament_spacer{nullptr};
|
||||||
|
SwitchButton *m_smart_filament_switch{nullptr};
|
||||||
|
|
||||||
PartPlate* partplate_ref{ nullptr };
|
PartPlate* partplate_ref{ nullptr };
|
||||||
Plater* plater_ref{ nullptr };
|
Plater* plater_ref{ nullptr };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,6 +39,68 @@ static std::vector<int> get_applied_map(DynamicConfig& proj_config, const Plater
|
|||||||
extern std::string& get_left_extruder_unprintable_text();
|
extern std::string& get_left_extruder_unprintable_text();
|
||||||
extern std::string& get_right_extruder_unprintable_text();
|
extern std::string& get_right_extruder_unprintable_text();
|
||||||
|
|
||||||
|
// Orca: minimal smart-filament toggle. When a filament track switch is ready every AMS filament is
|
||||||
|
// reachable from both nozzles, so one filament can be assigned to multiple nozzles to maximize
|
||||||
|
// savings. The checkbox drives the enable_filament_dynamic_map project flag.
|
||||||
|
class SmartFilamentPanel : public wxPanel
|
||||||
|
{
|
||||||
|
static constexpr int spacing = 20;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SmartFilamentPanel(wxWindow *parent) : wxPanel(parent)
|
||||||
|
{
|
||||||
|
SetBackgroundColour(*wxWHITE);
|
||||||
|
wxBoxSizer *main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
|
main_sizer->AddSpacer(FromDIP(spacing));
|
||||||
|
|
||||||
|
auto *separator = new wxPanel(this);
|
||||||
|
separator->SetBackgroundColour(wxColour("#EEEEEE"));
|
||||||
|
main_sizer->Add(separator, 0, wxEXPAND | wxLEFT | wxRIGHT, FromDIP(15));
|
||||||
|
|
||||||
|
main_sizer->AddSpacer(FromDIP(spacing));
|
||||||
|
|
||||||
|
m_smart_filament_checkbox = new CheckBox(this);
|
||||||
|
if (auto *opt = enable_filament_dynamic_map())
|
||||||
|
m_smart_filament_checkbox->SetValue(opt->value);
|
||||||
|
m_smart_filament_checkbox->Bind(wxEVT_TOGGLEBUTTON, &SmartFilamentPanel::on_smart_filament_checkbox, this);
|
||||||
|
|
||||||
|
auto *label = new Label(this, _L("Enable smart filament assign: Assign one filament to multiple nozzles to maximize savings"));
|
||||||
|
label->SetFont(Label::Body_12);
|
||||||
|
|
||||||
|
// Orca: dropped the vendor "Learn more" tracking link (no Orca help page for this feature).
|
||||||
|
|
||||||
|
auto *smart_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
smart_sizer->Add(m_smart_filament_checkbox, 0, wxALIGN_CENTER_VERTICAL);
|
||||||
|
smart_sizer->Add(label, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, FromDIP(3));
|
||||||
|
|
||||||
|
main_sizer->Add(smart_sizer, 0, wxLEFT | wxRIGHT | wxBOTTOM, FromDIP(15));
|
||||||
|
|
||||||
|
SetSizer(main_sizer);
|
||||||
|
Layout();
|
||||||
|
Fit();
|
||||||
|
wxGetApp().UpdateDarkUIWin(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static ConfigOptionBool *enable_filament_dynamic_map()
|
||||||
|
{
|
||||||
|
auto &config = wxGetApp().preset_bundle->project_config;
|
||||||
|
return dynamic_cast<ConfigOptionBool *>(config.option("enable_filament_dynamic_map"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_smart_filament_checkbox(wxCommandEvent &event)
|
||||||
|
{
|
||||||
|
if (auto *opt = enable_filament_dynamic_map())
|
||||||
|
opt->value = m_smart_filament_checkbox->GetValue();
|
||||||
|
wxGetApp().plater()->update();
|
||||||
|
event.Skip();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CheckBox *m_smart_filament_checkbox{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
bool try_pop_up_before_slice(bool is_slice_all, Plater* plater_ref, PartPlate* partplate_ref, bool force_pop_up)
|
bool try_pop_up_before_slice(bool is_slice_all, Plater* plater_ref, PartPlate* partplate_ref, bool force_pop_up)
|
||||||
{
|
{
|
||||||
@@ -136,6 +198,14 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
|
|||||||
SetMinSize(wxSize(FromDIP(580), -1));
|
SetMinSize(wxSize(FromDIP(580), -1));
|
||||||
SetMaxSize(wxSize(FromDIP(580), -1));
|
SetMaxSize(wxSize(FromDIP(580), -1));
|
||||||
|
|
||||||
|
// Orca: when a filament track switch is ready, every AMS filament reaches both nozzles, so the
|
||||||
|
// Match/Convenience sub-mode is dropped and Auto is presented purely as a filament-saving mode.
|
||||||
|
// Orca has no fmmAutoForQuality, so "only saving" collapses to "switch ready" and the remaining
|
||||||
|
// auto mode set is { fmmAutoForFlush }.
|
||||||
|
m_fila_switch_ready = wxGetApp().sidebar().is_fila_switch_ready();
|
||||||
|
const bool only_saving_mode = m_fila_switch_ready;
|
||||||
|
const bool auto_match_available = machine_synced && !m_fila_switch_ready;
|
||||||
|
|
||||||
if (mode < fmmManual)
|
if (mode < fmmManual)
|
||||||
m_page_type = PageType::ptAuto;
|
m_page_type = PageType::ptAuto;
|
||||||
else if (mode == fmmManual || mode == fmmNozzleManual)
|
else if (mode == fmmManual || mode == fmmNozzleManual)
|
||||||
@@ -149,7 +219,7 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
|
|||||||
|
|
||||||
wxBoxSizer *mode_sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxBoxSizer *mode_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
|
||||||
m_auto_btn = new CapsuleButton(this, PageType::ptAuto, _L("Auto"), false);
|
m_auto_btn = new CapsuleButton(this, PageType::ptAuto, only_saving_mode ? _L("Fila Saving") : _L("Auto"), false);
|
||||||
m_manual_btn = new CapsuleButton(this, PageType::ptManual, _L("Custom"), false);
|
m_manual_btn = new CapsuleButton(this, PageType::ptManual, _L("Custom"), false);
|
||||||
if (show_default)
|
if (show_default)
|
||||||
m_default_btn = new CapsuleButton(this, PageType::ptDefault, _L("Same as Global"), true);
|
m_default_btn = new CapsuleButton(this, PageType::ptDefault, _L("Same as Global"), true);
|
||||||
@@ -168,12 +238,14 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
|
|||||||
|
|
||||||
auto panel_sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto panel_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
|
||||||
|
// Orca: fall back to the saving mode whenever Match is unavailable, which now also covers the
|
||||||
|
// filament-track-switch-ready case (auto_match_available folds in !m_fila_switch_ready).
|
||||||
FilamentMapMode default_auto_mode = mode >= fmmManual ? fmmAutoForFlush :
|
FilamentMapMode default_auto_mode = mode >= fmmManual ? fmmAutoForFlush :
|
||||||
mode == fmmAutoForMatch && !machine_synced ? fmmAutoForFlush :
|
mode == fmmAutoForMatch && !auto_match_available ? fmmAutoForFlush :
|
||||||
mode;
|
mode;
|
||||||
|
|
||||||
m_manual_map_panel = new FilamentMapManualPanel(this, m_filament_color, m_filament_type, filaments, filament_map);
|
m_manual_map_panel = new FilamentMapManualPanel(this, m_filament_color, m_filament_type, filaments, filament_map);
|
||||||
m_auto_map_panel = new FilamentMapAutoPanel(this, default_auto_mode, machine_synced);
|
m_auto_map_panel = new FilamentMapAutoPanel(this, default_auto_mode, auto_match_available);
|
||||||
if (show_default)
|
if (show_default)
|
||||||
m_default_map_panel = new FilamentMapDefaultPanel(this);
|
m_default_map_panel = new FilamentMapDefaultPanel(this);
|
||||||
else
|
else
|
||||||
@@ -184,6 +256,13 @@ FilamentMapDialog::FilamentMapDialog(wxWindow *parent,
|
|||||||
if (show_default) panel_sizer->Add(m_default_map_panel, 0, wxEXPAND);
|
if (show_default) panel_sizer->Add(m_default_map_panel, 0, wxEXPAND);
|
||||||
main_sizer->Add(panel_sizer, 0, wxEXPAND);
|
main_sizer->Add(panel_sizer, 0, wxEXPAND);
|
||||||
|
|
||||||
|
// Smart filament section, shown only in filament-saving (flush) mode when the switch is ready.
|
||||||
|
if (m_fila_switch_ready) {
|
||||||
|
m_smart_filament = new SmartFilamentPanel(this);
|
||||||
|
m_smart_filament->Show(get_mode() == fmmAutoForFlush);
|
||||||
|
main_sizer->Add(m_smart_filament, 0, wxEXPAND);
|
||||||
|
}
|
||||||
|
|
||||||
wxPanel* bottom_panel = new wxPanel(this);
|
wxPanel* bottom_panel = new wxPanel(this);
|
||||||
bottom_panel->SetBackgroundColour(*wxWHITE);
|
bottom_panel->SetBackgroundColour(*wxWHITE);
|
||||||
wxBoxSizer *bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
|
wxBoxSizer *bottom_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
@@ -319,6 +398,9 @@ void FilamentMapDialog::update_panel_status(PageType page)
|
|||||||
m_auto_map_panel->Show();
|
m_auto_map_panel->Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_smart_filament)
|
||||||
|
m_smart_filament->Show(get_mode() == fmmAutoForFlush);
|
||||||
|
|
||||||
Layout();
|
Layout();
|
||||||
Fit();
|
Fit();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace GUI {
|
|||||||
class DragDropPanel;
|
class DragDropPanel;
|
||||||
class Plater;
|
class Plater;
|
||||||
class PartPlate;
|
class PartPlate;
|
||||||
|
class SmartFilamentPanel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Try to pop up the filament map dialog before slicing.
|
* @brief Try to pop up the filament map dialog before slicing.
|
||||||
@@ -78,6 +79,9 @@ private:
|
|||||||
Button* m_ok_btn;
|
Button* m_ok_btn;
|
||||||
Button* m_cancel_btn;
|
Button* m_cancel_btn;
|
||||||
CheckBox* m_checkbox;
|
CheckBox* m_checkbox;
|
||||||
|
SmartFilamentPanel* m_smart_filament{nullptr};
|
||||||
|
|
||||||
|
bool m_fila_switch_ready{false};
|
||||||
|
|
||||||
PageType m_page_type;
|
PageType m_page_type;
|
||||||
|
|
||||||
|
|||||||
+264
-16
@@ -564,6 +564,9 @@ struct Sidebar::priv
|
|||||||
ScalableButton* m_printer_setting = nullptr;
|
ScalableButton* m_printer_setting = nullptr;
|
||||||
wxStaticText * m_text_printer_settings = nullptr;
|
wxStaticText * m_text_printer_settings = nullptr;
|
||||||
wxPanel* m_panel_printer_content = nullptr;
|
wxPanel* m_panel_printer_content = nullptr;
|
||||||
|
// Filament Track Switch status overlay: an icon floated over the left/single extruder AMS area,
|
||||||
|
// shown only when the switch is installed (green when ready, red when not calibrated).
|
||||||
|
wxStaticBitmap* extruder_separator_icon = nullptr;
|
||||||
|
|
||||||
ObjectList *m_object_list{ nullptr };
|
ObjectList *m_object_list{ nullptr };
|
||||||
ObjectSettings *object_settings{ nullptr };
|
ObjectSettings *object_settings{ nullptr };
|
||||||
@@ -594,6 +597,19 @@ struct Sidebar::priv
|
|||||||
bool switch_diameter(bool single);
|
bool switch_diameter(bool single);
|
||||||
void update_sync_status(const MachineObject* obj);
|
void update_sync_status(const MachineObject* obj);
|
||||||
|
|
||||||
|
// Filament Track Switch (H2-family accessory): true only when the connected printer is the
|
||||||
|
// selected one, online, and reports the switch installed and calibrated.
|
||||||
|
bool is_fila_switch_ready();
|
||||||
|
// One-time info tip when the switch is ready, and a not-calibrated warning otherwise.
|
||||||
|
void show_filament_switcher_dialog(bool is_ready, bool is_manual);
|
||||||
|
void show_fila_switch_msg(bool ready);
|
||||||
|
bool fila_switch_warning_shown = false;
|
||||||
|
// Show/hide and reposition the switcher status icon; caches the last state to avoid churn.
|
||||||
|
void update_extruder_separator_icon(bool show, bool ready);
|
||||||
|
// Orca: BBS resets the switcher UI from DeviceManager::OnSelectedMachineChanged, which Orca lacks.
|
||||||
|
// Track the last-synced device id here so update_sync_status can detect a machine change.
|
||||||
|
std::string last_sync_dev_id;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
wxString btn_reslice_tip;
|
wxString btn_reslice_tip;
|
||||||
void show_rich_tip(const wxString& tooltip, wxButton* btn);
|
void show_rich_tip(const wxString& tooltip, wxButton* btn);
|
||||||
@@ -642,6 +658,18 @@ void Sidebar::priv::layout_printer(bool isBBL, bool isDual)
|
|||||||
extruder_dual_sizer->AddSpacer(FromDIP(4));
|
extruder_dual_sizer->AddSpacer(FromDIP(4));
|
||||||
extruder_dual_sizer->Add(right_extruder->sizer, 1, wxEXPAND, 0);
|
extruder_dual_sizer->Add(right_extruder->sizer, 1, wxEXPAND, 0);
|
||||||
|
|
||||||
|
// Filament Track Switch status icon, floated over the extruder AMS area (positioned in
|
||||||
|
// update_extruder_separator_icon). Created hidden; a click re-shows the ready/not-ready tip.
|
||||||
|
if (!extruder_separator_icon) {
|
||||||
|
auto bitmap = ScalableBitmap(m_panel_printer_content, "fila_switch", 10);
|
||||||
|
extruder_separator_icon = new wxStaticBitmap(m_panel_printer_content, wxID_ANY, bitmap.bmp(), wxDefaultPosition, bitmap.GetBmpSize());
|
||||||
|
extruder_separator_icon->Hide();
|
||||||
|
extruder_separator_icon->Bind(wxEVT_LEFT_DOWN, [this](wxMouseEvent& evt) {
|
||||||
|
show_fila_switch_msg(is_fila_switch_ready());
|
||||||
|
evt.Skip();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// single
|
// single
|
||||||
extruder_single_sizer = single_extruder->sizer;
|
extruder_single_sizer = single_extruder->sizer;
|
||||||
wxBoxSizer * extruder_sizer = new wxBoxSizer(wxVERTICAL);
|
wxBoxSizer * extruder_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
@@ -1610,6 +1638,105 @@ std::optional<NozzleOption> Sidebar::priv::get_nozzle_options(MachineObject* obj
|
|||||||
return nozzle_option;
|
return nozzle_option;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sidebar::priv::is_fila_switch_ready()
|
||||||
|
{
|
||||||
|
if (!wxGetApp().plater()->is_same_printer_for_connected_and_selected(false))
|
||||||
|
return false;
|
||||||
|
auto device_manager = wxGetApp().getDeviceManager();
|
||||||
|
if (device_manager == nullptr)
|
||||||
|
return false;
|
||||||
|
auto obj = device_manager->get_selected_machine();
|
||||||
|
if (obj == nullptr || !obj->is_online())
|
||||||
|
return false;
|
||||||
|
auto fila_switch = obj->GetFilaSwitch();
|
||||||
|
if (fila_switch == nullptr)
|
||||||
|
return false;
|
||||||
|
return fila_switch->IsInstalled() && fila_switch->IsReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sidebar::priv::show_fila_switch_msg(bool ready)
|
||||||
|
{
|
||||||
|
wxString msg = ready ? _L("Filament switcher detected. All AMS filaments are now available for both extruders. "
|
||||||
|
"The slicer will auto-assign for optimal printing. ") :
|
||||||
|
_L("A filament switcher is detected but not calibrated and thus currently unavailable. "
|
||||||
|
"Please calibrate it on the printer and synchronize before use. ");
|
||||||
|
|
||||||
|
long style = ready ? (wxICON_INFORMATION | wxOK) : (wxICON_WARNING | wxOK);
|
||||||
|
// Orca: drop the vendor "Learn more" tracking link; there is no Orca help page for the switch yet.
|
||||||
|
MessageDialog dlg(static_cast<wxWindow *>(wxGetApp().mainframe), msg, _L("Tips"), style);
|
||||||
|
dlg.CenterOnParent();
|
||||||
|
dlg.ShowModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sidebar::priv::show_filament_switcher_dialog(bool is_ready, bool is_manual)
|
||||||
|
{
|
||||||
|
if (is_ready) {
|
||||||
|
// Show the "switch is ready" tip only once, ever.
|
||||||
|
if (wxGetApp().app_config->get("show_fila_switch_tips") == "true") {
|
||||||
|
wxGetApp().app_config->set("show_fila_switch_tips", "false");
|
||||||
|
show_fila_switch_msg(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// A manual sync always warns; an automatic update warns once per session.
|
||||||
|
if (is_manual || !fila_switch_warning_shown) {
|
||||||
|
fila_switch_warning_shown = true;
|
||||||
|
show_fila_switch_msg(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sidebar::priv::update_extruder_separator_icon(bool show, bool ready)
|
||||||
|
{
|
||||||
|
if (!extruder_separator_icon)
|
||||||
|
return;
|
||||||
|
static bool last_show = false;
|
||||||
|
static bool last_ready = false;
|
||||||
|
static bool first_call = true;
|
||||||
|
|
||||||
|
if (!first_call && last_show == show && last_ready == ready)
|
||||||
|
return;
|
||||||
|
first_call = false;
|
||||||
|
last_show = show;
|
||||||
|
last_ready = ready;
|
||||||
|
|
||||||
|
// Never overlay the icon when the connected printer is not the selected preset.
|
||||||
|
if (!wxGetApp().plater()->is_same_printer_for_connected_and_selected(false)) {
|
||||||
|
extruder_separator_icon->Hide();
|
||||||
|
if (m_panel_printer_content)
|
||||||
|
m_panel_printer_content->Refresh();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show && left_extruder && left_extruder->hsizer_ams && left_extruder->sizer) {
|
||||||
|
// Orca: center the icon over the seam between the two extruder cards, vertically aligned with
|
||||||
|
// the AMS row. left_extruder and the icon share m_panel_printer_content as parent, so
|
||||||
|
// left_extruder->GetPosition() and the icon position live in the same coordinate space.
|
||||||
|
wxPoint left_box_pos = left_extruder->GetPosition();
|
||||||
|
wxPoint ams_local_pos = left_extruder->hsizer_ams->GetPosition();
|
||||||
|
wxSize left_size = left_extruder->sizer->GetSize();
|
||||||
|
wxSize ams_size = left_extruder->hsizer_ams->GetSize();
|
||||||
|
wxSize icon_size = extruder_separator_icon->GetSize();
|
||||||
|
int ams_abs_y = left_box_pos.y + ams_local_pos.y + FromDIP(4);
|
||||||
|
int center_x = left_size.GetWidth() + FromDIP(6);
|
||||||
|
int center_y = ams_abs_y + (ams_size.GetHeight() - icon_size.GetHeight()) / 2;
|
||||||
|
center_x -= icon_size.GetWidth() / 2;
|
||||||
|
center_y -= icon_size.GetHeight() / 2;
|
||||||
|
extruder_separator_icon->SetPosition(wxPoint(center_x, center_y));
|
||||||
|
|
||||||
|
auto normal_bitmap = ScalableBitmap(m_panel_printer_content, "fila_switch", 10);
|
||||||
|
auto error_bitmap = ScalableBitmap(m_panel_printer_content, "fila_switch_error", 10);
|
||||||
|
extruder_separator_icon->SetBitmap(ready ? normal_bitmap.bmp() : error_bitmap.bmp());
|
||||||
|
|
||||||
|
extruder_separator_icon->Show();
|
||||||
|
extruder_separator_icon->Raise();
|
||||||
|
} else {
|
||||||
|
extruder_separator_icon->Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_panel_printer_content)
|
||||||
|
m_panel_printer_content->Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
bool Sidebar::priv::sync_extruder_list(bool &only_external_material, bool is_manual)
|
bool Sidebar::priv::sync_extruder_list(bool &only_external_material, bool is_manual)
|
||||||
{
|
{
|
||||||
MachineObject *obj = wxGetApp().getDeviceManager()->get_selected_machine();
|
MachineObject *obj = wxGetApp().getDeviceManager()->get_selected_machine();
|
||||||
@@ -1728,18 +1855,29 @@ bool Sidebar::priv::sync_extruder_list(bool &only_external_material, bool is_man
|
|||||||
}
|
}
|
||||||
|
|
||||||
int deputy_4 = 0, main_4 = 0, deputy_1 = 0, main_1 = 0;
|
int deputy_4 = 0, main_4 = 0, deputy_1 = 0, main_1 = 0;
|
||||||
|
const bool switch_ready = is_fila_switch_ready();
|
||||||
for (auto ams : obj->GetFilaSystem()->GetAmsList()) {
|
for (auto ams : obj->GetFilaSystem()->GetAmsList()) {
|
||||||
// Main (first) extruder at right
|
for (int extruder_id : ams.second->GetBindedExtruderSet()) {
|
||||||
if (ams.second->GetExtruderId() == 0) {
|
// With the switch installed every AMS binds to both extruders; once it is ready, attribute
|
||||||
if (ams.second->GetAmsType() == DevAms::N3S) // N3S
|
// each to the extruder its input track feeds so the per-extruder counts stay correct. Without
|
||||||
++main_1;
|
// a switch the binding set is the single extruder and the filter is skipped, matching the
|
||||||
else
|
// pre-switch counts.
|
||||||
++main_4;
|
if (switch_ready) {
|
||||||
} else if (ams.second->GetExtruderId() == 1) {
|
auto switcher_pos = ams.second->GetSwitcherPos();
|
||||||
if (ams.second->GetAmsType() == DevAms::N3S) // N3S
|
if (!switcher_pos)
|
||||||
++deputy_1;
|
continue;
|
||||||
else
|
int switcher_id = obj->is_main_extruder_on_left() ? (1 - static_cast<int>(switcher_pos.value()))
|
||||||
++deputy_4;
|
: static_cast<int>(switcher_pos.value());
|
||||||
|
if (extruder_id != switcher_id)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const bool is_n3s = ams.second->GetAmsType() == DevAms::N3S;
|
||||||
|
// Main (first) extruder is id 0, deputy is id 1.
|
||||||
|
if (extruder_id == 0) {
|
||||||
|
if (is_n3s) ++main_1; else ++main_4;
|
||||||
|
} else if (extruder_id == 1) {
|
||||||
|
if (is_n3s) ++deputy_1; else ++deputy_4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
only_external_material = !obj->GetFilaSystem()->HasAms();
|
only_external_material = !obj->GetFilaSystem()->HasAms();
|
||||||
@@ -1774,6 +1912,22 @@ bool Sidebar::priv::sync_extruder_list(bool &only_external_material, bool is_man
|
|||||||
printer_tab->set_extruder_volume_type(idx, target_types[idx]);
|
printer_tab->set_extruder_volume_type(idx, target_types[idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (extruder_nums > 1) {
|
||||||
|
auto fila_switch = obj->GetFilaSwitch();
|
||||||
|
if (fila_switch->IsInstalled())
|
||||||
|
show_filament_switcher_dialog(fila_switch->IsReady(), is_manual);
|
||||||
|
else
|
||||||
|
fila_switch_warning_shown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the live switch state into the project so slicing and the send dialog honor it. Both
|
||||||
|
// resolve to false unless the switch is installed and calibrated, so nothing changes without one.
|
||||||
|
auto &project_config = wxGetApp().preset_bundle->project_config;
|
||||||
|
if (auto *dynamic_filament = project_config.opt<ConfigOptionBool>("enable_filament_dynamic_map"))
|
||||||
|
dynamic_filament->value = is_fila_switch_ready();
|
||||||
|
if (auto *has_switcher = project_config.opt<ConfigOptionBool>("has_filament_switcher"))
|
||||||
|
has_switcher->value = is_fila_switch_ready();
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " finish sync_extruder_list";
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << __LINE__ << " finish sync_extruder_list";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1791,6 +1945,7 @@ void Sidebar::priv::update_sync_status(const MachineObject *obj)
|
|||||||
right_extruder->sync_ams(nullptr, {}, {});
|
right_extruder->sync_ams(nullptr, {}, {});
|
||||||
single_extruder->ShowBadge(false);
|
single_extruder->ShowBadge(false);
|
||||||
single_extruder->sync_ams(nullptr, {}, {});
|
single_extruder->sync_ams(nullptr, {}, {});
|
||||||
|
update_extruder_separator_icon(false, false);
|
||||||
//btn_sync_printer->SetBorderColor(not_synced_colour);
|
//btn_sync_printer->SetBorderColor(not_synced_colour);
|
||||||
//btn_sync_printer->SetIcon("printer_sync");
|
//btn_sync_printer->SetIcon("printer_sync");
|
||||||
m_printer_bbl_sync->SetBitmap_("printer_sync_not");
|
m_printer_bbl_sync->SetBitmap_("printer_sync_not");
|
||||||
@@ -1801,6 +1956,16 @@ void Sidebar::priv::update_sync_status(const MachineObject *obj)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Orca: replaces BBS's reset_fila_switch hook on DeviceManager::OnSelectedMachineChanged (absent
|
||||||
|
// in Orca). Selection/MQTT updates all funnel through here, so a change of the selected device id
|
||||||
|
// resets the switcher icon and the once-per-session not-ready warning for the new printer.
|
||||||
|
const std::string cur_dev_id = obj->get_dev_id();
|
||||||
|
if (cur_dev_id != last_sync_dev_id) {
|
||||||
|
last_sync_dev_id = cur_dev_id;
|
||||||
|
update_extruder_separator_icon(false, false);
|
||||||
|
fila_switch_warning_shown = false;
|
||||||
|
}
|
||||||
|
|
||||||
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
|
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
|
||||||
if (!preset_bundle) {
|
if (!preset_bundle) {
|
||||||
clear_all_sync_status();
|
clear_all_sync_status();
|
||||||
@@ -1852,6 +2017,21 @@ void Sidebar::priv::update_sync_status(const MachineObject *obj)
|
|||||||
if (extruder_nums != obj->GetExtderSystem()->GetTotalExtderCount())
|
if (extruder_nums != obj->GetExtderSystem()->GetTotalExtderCount())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Filament Track Switch: only ever surfaced on multi-extruder machines. When installed, tip/warn
|
||||||
|
// and show the status icon (green ready / red not-calibrated); when absent the icon stays hidden.
|
||||||
|
// Inert on any printer without a switch: GetFilaSwitch()->IsInstalled() is false.
|
||||||
|
const bool fila_switch_flag = is_fila_switch_ready();
|
||||||
|
if (extruder_nums > 1) {
|
||||||
|
auto fila_switch = obj->GetFilaSwitch();
|
||||||
|
if (fila_switch->IsInstalled()) {
|
||||||
|
show_filament_switcher_dialog(fila_switch->IsReady(), false);
|
||||||
|
update_extruder_separator_icon(true, fila_switch->IsReady());
|
||||||
|
} else {
|
||||||
|
update_extruder_separator_icon(false, false);
|
||||||
|
fila_switch_warning_shown = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<ExtruderInfo> extruder_infos(extruder_nums);
|
std::vector<ExtruderInfo> extruder_infos(extruder_nums);
|
||||||
std::vector<int> nozzle_volume_types = wxGetApp().preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
|
std::vector<int> nozzle_volume_types = wxGetApp().preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values;
|
||||||
//for (size_t i = 0; i < nozzle_volume_types.size(); ++i) {
|
//for (size_t i = 0; i < nozzle_volume_types.size(); ++i) {
|
||||||
@@ -1893,16 +2073,34 @@ void Sidebar::priv::update_sync_status(const MachineObject *obj)
|
|||||||
machine_extruder_infos[extruder.GetExtId()].diameter = extruder.GetNozzleDiameter();
|
machine_extruder_infos[extruder.GetExtId()].diameter = extruder.GetNozzleDiameter();
|
||||||
}
|
}
|
||||||
for (auto &item : obj->GetFilaSystem()->GetAmsList()) {
|
for (auto &item : obj->GetFilaSystem()->GetAmsList()) {
|
||||||
if (item.second->GetExtruderId() >= machine_extruder_infos.size())
|
int extruder_id;
|
||||||
|
// With the switch ready every AMS feeds both extruders, so attribute each to the extruder its
|
||||||
|
// input track feeds. Without a switch the binding is a single extruder
|
||||||
|
// (GetUniqueBindedExtruderId() == GetExtruderId()) and the switcher position is empty, so this
|
||||||
|
// yields the same attribution as before.
|
||||||
|
if (fila_switch_flag) {
|
||||||
|
auto switcher_pos = item.second->GetSwitcherPos();
|
||||||
|
if (!switcher_pos)
|
||||||
|
continue;
|
||||||
|
extruder_id = obj->is_main_extruder_on_left() ? (1 - static_cast<int>(switcher_pos.value()))
|
||||||
|
: static_cast<int>(switcher_pos.value());
|
||||||
|
} else {
|
||||||
|
const auto &uniq_extruder_id = item.second->GetUniqueBindedExtruderId();
|
||||||
|
if (!uniq_extruder_id)
|
||||||
|
continue;
|
||||||
|
extruder_id = uniq_extruder_id.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extruder_id >= machine_extruder_infos.size())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (item.second->GetAmsType() == DevAms::N3S)
|
if (item.second->GetAmsType() == DevAms::N3S)
|
||||||
{ // N3S
|
{ // N3S
|
||||||
machine_extruder_infos[item.second->GetExtruderId()].ams_1++;
|
machine_extruder_infos[extruder_id].ams_1++;
|
||||||
machine_extruder_infos[item.second->GetExtruderId()].ams_v1.push_back(item.second);
|
machine_extruder_infos[extruder_id].ams_v1.push_back(item.second);
|
||||||
} else {
|
} else {
|
||||||
machine_extruder_infos[item.second->GetExtruderId()].ams_4++;
|
machine_extruder_infos[extruder_id].ams_4++;
|
||||||
machine_extruder_infos[item.second->GetExtruderId()].ams_v4.push_back(item.second);
|
machine_extruder_infos[extruder_id].ams_v4.push_back(item.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1956,6 +2154,20 @@ void Sidebar::priv::update_sync_status(const MachineObject *obj)
|
|||||||
// btn_sync_printer->SetIcon("printer_sync");
|
// btn_sync_printer->SetIcon("printer_sync");
|
||||||
m_printer_bbl_sync->SetBitmap_("printer_sync_not");
|
m_printer_bbl_sync->SetBitmap_("printer_sync_not");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When the switch is ready every AMS filament is available to both extruders; refresh the
|
||||||
|
// filament combos whenever the AMS list changes so both extruders pick up the full set.
|
||||||
|
if (fila_switch_flag) {
|
||||||
|
static std::map<int, DynamicPrintConfig> last_filament_ams_list;
|
||||||
|
bool is_same_ams_list = last_filament_ams_list == wxGetApp().preset_bundle->filament_ams_list;
|
||||||
|
if (!is_same_ams_list)
|
||||||
|
last_filament_ams_list = wxGetApp().preset_bundle->filament_ams_list;
|
||||||
|
const auto print_tech = wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology();
|
||||||
|
if (print_tech == ptFFF && !is_same_ams_list) {
|
||||||
|
for (PlaterPresetComboBox *cb : combos_filament)
|
||||||
|
cb->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sidebar::update_sync_ams_btn_enable(wxUpdateUIEvent &e)
|
void Sidebar::update_sync_ams_btn_enable(wxUpdateUIEvent &e)
|
||||||
@@ -2408,6 +2620,24 @@ Sidebar::Sidebar(Plater *parent)
|
|||||||
p->left_extruder = new ExtruderGroup(p->m_panel_printer_content, 0, _L("Left Nozzle"));
|
p->left_extruder = new ExtruderGroup(p->m_panel_printer_content, 0, _L("Left Nozzle"));
|
||||||
p->right_extruder = new ExtruderGroup(p->m_panel_printer_content, 1, _L("Right Nozzle"));
|
p->right_extruder = new ExtruderGroup(p->m_panel_printer_content, 1, _L("Right Nozzle"));
|
||||||
p->single_extruder = new ExtruderGroup(p->m_panel_printer_content, -1, _L("Nozzle"));
|
p->single_extruder = new ExtruderGroup(p->m_panel_printer_content, -1, _L("Nozzle"));
|
||||||
|
// Orca: keep the floating switcher icon aligned with the left extruder's AMS row when the
|
||||||
|
// extruder card is resized (the overlay is absolutely positioned, not managed by a sizer).
|
||||||
|
p->left_extruder->Bind(wxEVT_SIZE, [this](wxSizeEvent &evt) {
|
||||||
|
if (p->extruder_separator_icon && p->extruder_separator_icon->IsShown()) {
|
||||||
|
wxPoint left_box_pos = p->left_extruder->GetPosition();
|
||||||
|
wxPoint ams_local_pos = p->left_extruder->hsizer_ams->GetPosition();
|
||||||
|
wxSize left_size = p->left_extruder->sizer->GetSize();
|
||||||
|
wxSize ams_size = p->left_extruder->hsizer_ams->GetSize();
|
||||||
|
wxSize icon_size = p->extruder_separator_icon->GetSize();
|
||||||
|
int ams_abs_y = left_box_pos.y + ams_local_pos.y + FromDIP(4);
|
||||||
|
int center_x = left_size.GetWidth() + FromDIP(6) - icon_size.GetWidth() / 2;
|
||||||
|
int center_y = ams_abs_y + (ams_size.GetHeight() - icon_size.GetHeight()) / 2 - icon_size.GetHeight() / 2;
|
||||||
|
p->extruder_separator_icon->SetPosition(wxPoint(center_x, center_y));
|
||||||
|
if (p->m_panel_printer_content)
|
||||||
|
p->m_panel_printer_content->Refresh();
|
||||||
|
}
|
||||||
|
evt.Skip();
|
||||||
|
});
|
||||||
auto switch_diameter = [this](wxCommandEvent & evt) {
|
auto switch_diameter = [this](wxCommandEvent & evt) {
|
||||||
auto extruder = dynamic_cast<ExtruderGroup *>(dynamic_cast<ComboBox *>(evt.GetEventObject())->GetParent());
|
auto extruder = dynamic_cast<ExtruderGroup *>(dynamic_cast<ComboBox *>(evt.GetEventObject())->GetParent());
|
||||||
p->is_switching_diameter = true;
|
p->is_switching_diameter = true;
|
||||||
@@ -3821,6 +4051,16 @@ bool Sidebar::sync_extruder_list()
|
|||||||
return p->sync_extruder_list(only_external_material);
|
return p->sync_extruder_list(only_external_material);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Sidebar::is_fila_switch_ready()
|
||||||
|
{
|
||||||
|
return p->is_fila_switch_ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Sidebar::reset_fila_switch()
|
||||||
|
{
|
||||||
|
p->update_extruder_separator_icon(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
bool Sidebar::need_auto_sync_extruder_list_after_connect_priner(const MachineObject *obj)
|
bool Sidebar::need_auto_sync_extruder_list_after_connect_priner(const MachineObject *obj)
|
||||||
{
|
{
|
||||||
if(!obj)
|
if(!obj)
|
||||||
@@ -6947,6 +7187,14 @@ std::vector<size_t> Plater::priv::load_files(const std::vector<fs::path>& input_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filament Track Switch state is derived live from the connected
|
||||||
|
// printer; a loaded project must not carry a stale installed/active
|
||||||
|
// flag, so clear both and let device sync re-derive them.
|
||||||
|
if (auto* has_switcher = proj_cfg.opt<ConfigOptionBool>("has_filament_switcher"))
|
||||||
|
has_switcher->value = false;
|
||||||
|
if (auto* dynamic_map = proj_cfg.opt<ConfigOptionBool>("enable_filament_dynamic_map"))
|
||||||
|
dynamic_map->value = false;
|
||||||
}
|
}
|
||||||
// Update filament combobox after loading config
|
// Update filament combobox after loading config
|
||||||
wxGetApp().plater()->sidebar().update_presets(Preset::TYPE_FILAMENT);
|
wxGetApp().plater()->sidebar().update_presets(Preset::TYPE_FILAMENT);
|
||||||
|
|||||||
@@ -196,6 +196,8 @@ public:
|
|||||||
std::map<int, DynamicPrintConfig> build_filament_ams_list(MachineObject* obj);
|
std::map<int, DynamicPrintConfig> build_filament_ams_list(MachineObject* obj);
|
||||||
void sync_ams_list(bool is_from_big_sync_btn = false);
|
void sync_ams_list(bool is_from_big_sync_btn = false);
|
||||||
bool sync_extruder_list();
|
bool sync_extruder_list();
|
||||||
|
bool is_fila_switch_ready();
|
||||||
|
void reset_fila_switch();
|
||||||
bool need_auto_sync_extruder_list_after_connect_priner(const MachineObject* obj);
|
bool need_auto_sync_extruder_list_after_connect_priner(const MachineObject* obj);
|
||||||
void update_sync_status(const MachineObject* obj);
|
void update_sync_status(const MachineObject* obj);
|
||||||
int get_sidebar_pos_right_x();
|
int get_sidebar_pos_right_x();
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ std::string PrePrintChecker::get_print_status_info(PrintDialogStatus status)
|
|||||||
case PrintStatusUnsupportedPrinter: return "PrintStatusUnsupportedPrinter";
|
case PrintStatusUnsupportedPrinter: return "PrintStatusUnsupportedPrinter";
|
||||||
case PrintStatusRackNozzleMappingWaiting: return "PrintStatusRackNozzleMappingWaiting";
|
case PrintStatusRackNozzleMappingWaiting: return "PrintStatusRackNozzleMappingWaiting";
|
||||||
case PrintStatusRackNozzleMappingError: return "PrintStatusRackNozzleMappingError";
|
case PrintStatusRackNozzleMappingError: return "PrintStatusRackNozzleMappingError";
|
||||||
|
case PrintStatusFilaSwitcherError: return "PrintStatusFilaSwitcherError";
|
||||||
case PrintStatusColorQuantityExceed: return "PrintStatusColorQuantityExceed";
|
case PrintStatusColorQuantityExceed: return "PrintStatusColorQuantityExceed";
|
||||||
// Handle filament errors
|
// Handle filament errors
|
||||||
case PrintStatusAmsOnSettingup: return "PrintStatusAmsOnSettingup";
|
case PrintStatusAmsOnSettingup: return "PrintStatusAmsOnSettingup";
|
||||||
@@ -50,6 +51,7 @@ std::string PrePrintChecker::get_print_status_info(PrintDialogStatus status)
|
|||||||
case PrintStatusTimelapseWarning: return "PrintStatusTimelapseWarning";
|
case PrintStatusTimelapseWarning: return "PrintStatusTimelapseWarning";
|
||||||
case PrintStatusMixAmsAndVtSlotWarning: return "PrintStatusMixAmsAndVtSlotWarning";
|
case PrintStatusMixAmsAndVtSlotWarning: return "PrintStatusMixAmsAndVtSlotWarning";
|
||||||
case PrintStatusRackNozzleMappingWarning: return "PrintStatusRackNozzleMappingWarning";
|
case PrintStatusRackNozzleMappingWarning: return "PrintStatusRackNozzleMappingWarning";
|
||||||
|
case PrintStatusFilaSwitcherSlicingNotMatch: return "PrintStatusFilaSwitcherSlicingNotMatch";
|
||||||
case PrintStatusWarningKvalueNotUsed: return "PrintStatusWarningKvalueNotUsed";
|
case PrintStatusWarningKvalueNotUsed: return "PrintStatusWarningKvalueNotUsed";
|
||||||
case PrintStatusHasFilamentInBlackListWarning: return "PrintStatusHasFilamentInBlackListWarning";
|
case PrintStatusHasFilamentInBlackListWarning: return "PrintStatusHasFilamentInBlackListWarning";
|
||||||
case PrintStatusFilamentWarningHighChamberTemp: return "PrintStatusFilamentWarningHighChamberTemp";
|
case PrintStatusFilamentWarningHighChamberTemp: return "PrintStatusFilamentWarningHighChamberTemp";
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ enum PrintDialogStatus : unsigned int {
|
|||||||
PrintStatusUnsupportedPrinter,
|
PrintStatusUnsupportedPrinter,
|
||||||
PrintStatusRackNozzleMappingWaiting,
|
PrintStatusRackNozzleMappingWaiting,
|
||||||
PrintStatusRackNozzleMappingError,
|
PrintStatusRackNozzleMappingError,
|
||||||
|
PrintStatusFilaSwitcherError,
|
||||||
PrintStatusPrinterErrorEnd,
|
PrintStatusPrinterErrorEnd,
|
||||||
|
|
||||||
// Errors for filament, Block Print
|
// Errors for filament, Block Print
|
||||||
@@ -92,6 +93,7 @@ enum PrintDialogStatus : unsigned int {
|
|||||||
PrintStatusMixAmsAndVtSlotWarning,
|
PrintStatusMixAmsAndVtSlotWarning,
|
||||||
PrintStatusToolHeadCoolingFanWarning,
|
PrintStatusToolHeadCoolingFanWarning,
|
||||||
PrintStatusRackNozzleMappingWarning,
|
PrintStatusRackNozzleMappingWarning,
|
||||||
|
PrintStatusFilaSwitcherSlicingNotMatch,
|
||||||
PrintStatusPrinterWarningEnd,
|
PrintStatusPrinterWarningEnd,
|
||||||
|
|
||||||
// Warnings for filament
|
// Warnings for filament
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
#include <utility>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
|
||||||
@@ -510,7 +512,13 @@ bool PresetComboBox::add_ams_filaments(std::string selected, bool alias_name)
|
|||||||
bool selected_in_ams = false;
|
bool selected_in_ams = false;
|
||||||
bool is_bbl_vendor_preset = m_preset_bundle->is_bbl_vendor();
|
bool is_bbl_vendor_preset = m_preset_bundle->is_bbl_vendor();
|
||||||
if (is_bbl_vendor_preset && !m_preset_bundle->filament_ams_list.empty()) {
|
if (is_bbl_vendor_preset && !m_preset_bundle->filament_ams_list.empty()) {
|
||||||
|
// When a filament track switch is installed and calibrated, every AMS filament is reachable
|
||||||
|
// from both extruders, so present one deduplicated group instead of the Left/Right split.
|
||||||
|
bool fila_switch_ready = wxGetApp().sidebar().is_fila_switch_ready();
|
||||||
bool dual_extruder = (m_preset_bundle->filament_ams_list.begin()->first & 0x10000) == 0;
|
bool dual_extruder = (m_preset_bundle->filament_ams_list.begin()->first & 0x10000) == 0;
|
||||||
|
if (fila_switch_ready)
|
||||||
|
set_label_marker(Append(_L("AMS filaments"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM));
|
||||||
|
else
|
||||||
set_label_marker(Append(dual_extruder ? _L("Left filaments") : _L("AMS filament"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM));
|
set_label_marker(Append(dual_extruder ? _L("Left filaments") : _L("AMS filament"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM));
|
||||||
m_first_ams_filament = GetCount();
|
m_first_ams_filament = GetCount();
|
||||||
auto &filaments = m_collection->get_presets();
|
auto &filaments = m_collection->get_presets();
|
||||||
@@ -523,8 +531,12 @@ bool PresetComboBox::add_ams_filaments(std::string selected, bool alias_name)
|
|||||||
icon_width = 32;
|
icon_width = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deduplicate by (tray_name, filament_id) so a filament shared by both extruders is
|
||||||
|
// listed once when the switch is ready. Uses Orca's tray naming/lookup, not BBS's.
|
||||||
|
std::set<std::pair<std::string, std::string>> added_filaments;
|
||||||
|
|
||||||
for (auto &entry : m_preset_bundle->filament_ams_list) {
|
for (auto &entry : m_preset_bundle->filament_ams_list) {
|
||||||
if (dual_extruder && (entry.first & 0x10000)) {
|
if (!fila_switch_ready && dual_extruder && (entry.first & 0x10000)) {
|
||||||
dual_extruder = false;
|
dual_extruder = false;
|
||||||
set_label_marker(Append(_L("Right filaments"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM));
|
set_label_marker(Append(_L("Right filaments"), wxNullBitmap, DD_ITEM_STYLE_SPLIT_ITEM));
|
||||||
}
|
}
|
||||||
@@ -535,6 +547,13 @@ bool PresetComboBox::add_ams_filaments(std::string selected, bool alias_name)
|
|||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": %1% 's filament_id is empty.") % name;
|
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": %1% 's filament_id is empty.") % name;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (fila_switch_ready) {
|
||||||
|
// skip the external spool and collapse duplicates shared across both extruders
|
||||||
|
if (name == "Ext")
|
||||||
|
continue;
|
||||||
|
if (!added_filaments.insert(std::make_pair(name, filament_id)).second)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
auto iter = std::find_if(filaments.begin(), filaments.end(),
|
auto iter = std::find_if(filaments.begin(), filaments.end(),
|
||||||
[&filament_id, this](auto &f) { return f.is_compatible && m_collection->get_preset_base(f) == &f && f.filament_id == filament_id; });
|
[&filament_id, this](auto &f) { return f.is_compatible && m_collection->get_preset_base(f) == &f && f.filament_id == filament_id; });
|
||||||
if (iter == filaments.end()) {
|
if (iter == filaments.end()) {
|
||||||
|
|||||||
@@ -1593,6 +1593,58 @@ bool SelectMachineDialog::use_dynamic_nozzle_map() const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SelectMachineDialog::slicing_with_fila_switch() const
|
||||||
|
{
|
||||||
|
if (use_dynamic_nozzle_map())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (m_print_type == FROM_NORMAL) {
|
||||||
|
auto has_filament_switcher = wxGetApp().preset_bundle->project_config.option<ConfigOptionBool>("has_filament_switcher");
|
||||||
|
if (has_filament_switcher)
|
||||||
|
return has_filament_switcher->value;
|
||||||
|
} else if (m_print_type == FROM_SDCARD_VIEW) {
|
||||||
|
if (m_required_data_plate_data_list.size() > (size_t) m_print_plate_idx) {
|
||||||
|
auto has_filament_switcher = m_required_data_plate_data_list[m_print_plate_idx]->config.option<ConfigOptionBool>("has_filament_switcher");
|
||||||
|
if (has_filament_switcher)
|
||||||
|
return has_filament_switcher->value;
|
||||||
|
}
|
||||||
|
auto has_filament_switcher = m_required_data_config.option<ConfigOptionBool>("has_filament_switcher");
|
||||||
|
if (has_filament_switcher)
|
||||||
|
return has_filament_switcher->value;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SelectMachineDialog::CheckErrorDynamicSwitchNozzle(MachineObject* obj_)
|
||||||
|
{
|
||||||
|
if (!obj_)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Advisory only (does not block Send): the file was sliced for a switch state that doesn't
|
||||||
|
// match the installed hardware, so grouping/flush may be suboptimal. Only on firmware that
|
||||||
|
// reports it can check this.
|
||||||
|
if (obj_->is_support_check_track_switch_match_slice_printer && slicing_with_fila_switch() != obj_->GetFilaSwitch()->IsInstalled()) {
|
||||||
|
show_status(PrintDialogStatus::PrintStatusFilaSwitcherSlicingNotMatch,
|
||||||
|
{_L("The Filament Track Switch installed on the printer does not match the slicing file. Please re-slice to avoid print quality issues.")});
|
||||||
|
}
|
||||||
|
|
||||||
|
// The blocking checks below only matter for dynamic nozzle mapping, which requires a switch.
|
||||||
|
if (!use_dynamic_nozzle_map())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!obj_->GetFilaSwitch()->IsInstalled()) {
|
||||||
|
show_status(PrintDialogStatus::PrintStatusFilaSwitcherError, {_L("This print requires a Filament Track Switch. Please install it first.")});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!obj_->GetFilaSwitch()->IsReady()) {
|
||||||
|
show_status(PrintDialogStatus::PrintStatusFilaSwitcherError, {_L("The Filament Track Switch has not been setup. Please setup it first.")});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void SelectMachineDialog::clear_nozzle_mapping()
|
void SelectMachineDialog::clear_nozzle_mapping()
|
||||||
{
|
{
|
||||||
m_nozzle_mapping_result.clear();
|
m_nozzle_mapping_result.clear();
|
||||||
@@ -2010,6 +2062,14 @@ void SelectMachineDialog::show_status(PrintDialogStatus status, std::vector<wxSt
|
|||||||
// Extra-waste warning: allow Send.
|
// Extra-waste warning: allow Send.
|
||||||
Enable_Refresh_Button(true);
|
Enable_Refresh_Button(true);
|
||||||
Enable_Send_Button(true);
|
Enable_Send_Button(true);
|
||||||
|
} else if (status == PrintDialogStatus::PrintStatusFilaSwitcherError) {
|
||||||
|
// Missing or un-set-up switch required by the slice: block Send.
|
||||||
|
Enable_Refresh_Button(true);
|
||||||
|
Enable_Send_Button(false);
|
||||||
|
} else if (status == PrintDialogStatus::PrintStatusFilaSwitcherSlicingNotMatch) {
|
||||||
|
// Advisory slicing/hardware mismatch: allow Send.
|
||||||
|
Enable_Refresh_Button(true);
|
||||||
|
Enable_Send_Button(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*enter perpare mode*/
|
/*enter perpare mode*/
|
||||||
@@ -3795,6 +3855,10 @@ void SelectMachineDialog::update_show_status(MachineObject* obj_)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filament Track Switch: warn on a slicing/hardware mismatch, and block Send when dynamic
|
||||||
|
// nozzle mapping needs a switch that isn't installed or set up. No-op for printers without one.
|
||||||
|
if (!CheckErrorDynamicSwitchNozzle(obj_)) return;
|
||||||
|
|
||||||
// Rack print-dispatch nozzle mapping (dynamic V1): request/await the printer's mapping and block
|
// Rack print-dispatch nozzle mapping (dynamic V1): request/await the printer's mapping and block
|
||||||
// Send while it computes. No-op for non-rack printers.
|
// Send while it computes. No-op for non-rack printers.
|
||||||
if (!CheckErrorSyncNozzleMappingResultV1(obj_)) return;
|
if (!CheckErrorSyncNozzleMappingResultV1(obj_)) return;
|
||||||
|
|||||||
@@ -526,6 +526,12 @@ public:
|
|||||||
bool CheckErrorSyncNozzleMappingResultV0(MachineObject* obj_);
|
bool CheckErrorSyncNozzleMappingResultV0(MachineObject* obj_);
|
||||||
void clear_nozzle_mapping();
|
void clear_nozzle_mapping();
|
||||||
bool use_dynamic_nozzle_map() const;
|
bool use_dynamic_nozzle_map() const;
|
||||||
|
|
||||||
|
// Filament Track Switch: warn when the sliced switch state doesn't match the installed
|
||||||
|
// hardware, and (for dynamic nozzle mapping) block Send when the switch is missing or not
|
||||||
|
// set up. slicing_with_fila_switch() reports whether the file was sliced assuming a switch.
|
||||||
|
bool slicing_with_fila_switch() const;
|
||||||
|
bool CheckErrorDynamicSwitchNozzle(MachineObject* obj_);
|
||||||
void on_flow_cali_option_changed();
|
void on_flow_cali_option_changed();
|
||||||
|
|
||||||
PrintFromType get_print_type() {return m_print_type;};
|
PrintFromType get_print_type() {return m_print_type;};
|
||||||
|
|||||||
@@ -2258,7 +2258,7 @@ void StatusBasePanel::show_filament_load_group(bool show)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto cur_ext = obj->GetExtderSystem()->GetCurrentExtder();
|
auto cur_ext = obj->GetExtderSystem()->GetCurrentExtder();
|
||||||
m_filament_step->SetupSteps(cur_ext ? cur_ext->HasFilamentInExt() : false);
|
m_filament_step->SetupSteps(obj, cur_ext ? cur_ext->HasFilamentInExt() : false);
|
||||||
|
|
||||||
Layout();
|
Layout();
|
||||||
Fit();
|
Fit();
|
||||||
@@ -3526,6 +3526,14 @@ void StatusPanel::update_ams_control_state(std::string ams_id, std::string slot_
|
|||||||
if (ams_id.empty() || slot_id.empty()) {
|
if (ams_id.empty() || slot_id.empty()) {
|
||||||
load_error_info = _L("Choose an AMS slot then press \"Load\" or \"Unload\" button to automatically load or unload filament.");
|
load_error_info = _L("Choose an AMS slot then press \"Load\" or \"Unload\" button to automatically load or unload filament.");
|
||||||
unload_error_info = _L("Choose an AMS slot then press \"Load\" or \"Unload\" button to automatically load or unload filament.");
|
unload_error_info = _L("Choose an AMS slot then press \"Load\" or \"Unload\" button to automatically load or unload filament.");
|
||||||
|
} else if (obj->GetFilaSwitch()->IsInstalled() && devPrinterUtil::IsVirtualSlot(ams_id)) {
|
||||||
|
// Orca: with a Filament Track Switch installed the external spool cannot be routed, so both actions are blocked.
|
||||||
|
load_error_info = _L("\"Load\" or \"Unload\" is not supported for external spool while using Filament Track Switch.");
|
||||||
|
unload_error_info = load_error_info;
|
||||||
|
} else if (obj->GetFilaSwitch()->IsInstalled() && !obj->GetFilaSwitch()->IsReady()) {
|
||||||
|
// Orca: an un-calibrated Filament Track Switch cannot route filament to either extruder, so block both actions.
|
||||||
|
load_error_info = _L("The Filament Track Switch has not been setup. Please setup on printer.");
|
||||||
|
unload_error_info = load_error_info;
|
||||||
} else if (ams_id == std::to_string(VIRTUAL_TRAY_MAIN_ID) || ams_id == std::to_string(VIRTUAL_TRAY_DEPUTY_ID)) {
|
} else if (ams_id == std::to_string(VIRTUAL_TRAY_MAIN_ID) || ams_id == std::to_string(VIRTUAL_TRAY_DEPUTY_ID)) {
|
||||||
for (auto ext : obj->GetExtderSystem()->GetExtruders()) {
|
for (auto ext : obj->GetExtderSystem()->GetExtruders()) {
|
||||||
if (ext.GetSlotNow().ams_id == ams_id && ext.GetSlotNow().slot_id == slot_id)
|
if (ext.GetSlotNow().ams_id == ams_id && ext.GetSlotNow().slot_id == slot_id)
|
||||||
@@ -3535,6 +3543,8 @@ void StatusPanel::update_ams_control_state(std::string ams_id, std::string slot_
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (auto ext : obj->GetExtderSystem()->GetExtruders()) {
|
for (auto ext : obj->GetExtderSystem()->GetExtruders()) {
|
||||||
|
// Orca: with a Filament Track Switch installed a slot is not bound to a single extruder, so skip the "already loaded" identity check.
|
||||||
|
if (obj->GetFilaSwitch()->IsInstalled()) { continue; }
|
||||||
if (ext.GetSlotNow().ams_id == ams_id && ext.GetSlotNow().slot_id == slot_id)
|
if (ext.GetSlotNow().ams_id == ams_id && ext.GetSlotNow().slot_id == slot_id)
|
||||||
{
|
{
|
||||||
load_error_info = _L("Current slot has already been loaded.");
|
load_error_info = _L("Current slot has already been loaded.");
|
||||||
@@ -4231,6 +4241,43 @@ void StatusPanel::on_ams_load_curr()
|
|||||||
std::string curr_ams_id = m_ams_control->GetCurentAms();
|
std::string curr_ams_id = m_ams_control->GetCurentAms();
|
||||||
std::string curr_can_id = m_ams_control->GetCurrentCan(curr_ams_id);
|
std::string curr_can_id = m_ams_control->GetCurrentCan(curr_ams_id);
|
||||||
|
|
||||||
|
std::optional<int> extruder_id = std::nullopt;
|
||||||
|
if (obj->GetFilaSwitch() && obj->GetFilaSwitch()->IsInstalled()) {
|
||||||
|
if (!obj->GetFilaSwitch()->IsReady()) {
|
||||||
|
MessageDialog msg_dlg(nullptr, _L("The Filament Track Switch has not been setup. Please setup on printer."), wxEmptyString, wxICON_WARNING | wxOK);
|
||||||
|
msg_dlg.ShowModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filament Track Switch is calibrated: the load can go to either extruder, so ask the
|
||||||
|
// user which. Record each extruder's currently-loaded slot so the dialog can grey out a
|
||||||
|
// side that already holds this filament.
|
||||||
|
std::vector<std::pair<std::string, std::string>> extruderSlots(2, {"", ""});
|
||||||
|
if (auto ext = obj->GetExtderSystem()->GetExtderById(MAIN_EXTRUDER_ID); ext.has_value())
|
||||||
|
{
|
||||||
|
if (ext->HasFilamentInExt())
|
||||||
|
{
|
||||||
|
extruderSlots[MAIN_EXTRUDER_ID] = {ext->GetSlotNow().ams_id, ext->GetSlotNow().slot_id};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (auto ext = obj->GetExtderSystem()->GetExtderById(DEPUTY_EXTRUDER_ID); ext.has_value())
|
||||||
|
{
|
||||||
|
if (ext->HasFilamentInExt())
|
||||||
|
{
|
||||||
|
extruderSlots[DEPUTY_EXTRUDER_ID] = {ext->GetSlotNow().ams_id, ext->GetSlotNow().slot_id};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FeedDirectionDialog dialog(nullptr, 2, obj->printer_type);
|
||||||
|
dialog.SetExtruderMapping(obj, curr_ams_id, curr_can_id, extruderSlots);
|
||||||
|
auto rtn = dialog.ShowModal();
|
||||||
|
|
||||||
|
if (rtn != wxID_OK)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
extruder_id = dialog.GetExtruderID();
|
||||||
|
}
|
||||||
|
|
||||||
update_load_with_temp();
|
update_load_with_temp();
|
||||||
//virtual tray
|
//virtual tray
|
||||||
@@ -4262,11 +4309,11 @@ void StatusPanel::on_ams_load_curr()
|
|||||||
if (obj->is_enable_np || obj->is_enable_ams_np) {
|
if (obj->is_enable_np || obj->is_enable_ams_np) {
|
||||||
try {
|
try {
|
||||||
if (!curr_ams_id.empty() && !curr_can_id.empty()) {
|
if (!curr_ams_id.empty() && !curr_can_id.empty()) {
|
||||||
obj->command_ams_change_filament(true, curr_ams_id, "0", old_temp, new_temp);
|
obj->command_ams_change_filament(true, curr_ams_id, "0", old_temp, new_temp, extruder_id);
|
||||||
}
|
}
|
||||||
} catch (...) {}
|
} catch (...) {}
|
||||||
} else {
|
} else {
|
||||||
obj->command_ams_change_filament(true, "254", "0", old_temp, new_temp);
|
obj->command_ams_change_filament(true, "254", "0", old_temp, new_temp, extruder_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4302,12 +4349,12 @@ void StatusPanel::on_ams_load_curr()
|
|||||||
if (obj->is_enable_np) {
|
if (obj->is_enable_np) {
|
||||||
try {
|
try {
|
||||||
if (!curr_ams_id.empty() && !curr_can_id.empty()) {
|
if (!curr_ams_id.empty() && !curr_can_id.empty()) {
|
||||||
obj->command_ams_change_filament(true, curr_ams_id, curr_can_id, old_temp, new_temp);
|
obj->command_ams_change_filament(true, curr_ams_id, curr_can_id, old_temp, new_temp, extruder_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (...){}
|
catch (...){}
|
||||||
} else {
|
} else {
|
||||||
obj->command_ams_change_filament(true, curr_ams_id, curr_can_id, old_temp, new_temp);
|
obj->command_ams_change_filament(true, curr_ams_id, curr_can_id, old_temp, new_temp, extruder_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5636,6 +5636,18 @@ void TabPrinter::on_preset_loaded()
|
|||||||
if (use_default_nozzle_volume_type) {
|
if (use_default_nozzle_volume_type) {
|
||||||
m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values = current_printer.config.option<ConfigOptionEnumsGeneric>("default_nozzle_volume_type")->values;
|
m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type")->values = current_printer.config.option<ConfigOptionEnumsGeneric>("default_nozzle_volume_type")->values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Changing printer model drops any Filament Track Switch context from the previous
|
||||||
|
// printer; clear both device-derived flags so a switch-less printer never inherits a
|
||||||
|
// stale installed/active state (re-derived by device sync when a printer is connected).
|
||||||
|
if (auto* has_switcher = m_preset_bundle->project_config.opt<ConfigOptionBool>("has_filament_switcher"))
|
||||||
|
has_switcher->value = false;
|
||||||
|
if (auto* dynamic_map = m_preset_bundle->project_config.opt<ConfigOptionBool>("enable_filament_dynamic_map"))
|
||||||
|
dynamic_map->value = false;
|
||||||
|
// Orca: also clear the sidebar switcher status icon on printer-model change (mirrors BBS's
|
||||||
|
// reset_fila_switch on machine change); it re-derives from device sync once a printer connects.
|
||||||
|
if (wxGetApp().plater())
|
||||||
|
wxGetApp().plater()->sidebar().reset_fila_switch();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ static const std::unordered_map<wxString, wxString> ACCESSORY_DISPLAY_STR = {
|
|||||||
{"O2L_ACM", "Active Cutting Module"},
|
{"O2L_ACM", "Active Cutting Module"},
|
||||||
{"O2L_UCM", "Ultrasonic Cutting Module"},
|
{"O2L_UCM", "Ultrasonic Cutting Module"},
|
||||||
{"O2L-AFP", L("Auto Fire Extinguishing System")},
|
{"O2L-AFP", L("Auto Fire Extinguishing System")},
|
||||||
|
{"O2L-FTS", L("Filament Track Switch")},
|
||||||
};
|
};
|
||||||
|
|
||||||
enum FIRMWARE_STASUS
|
enum FIRMWARE_STASUS
|
||||||
@@ -217,6 +218,7 @@ MachineInfoPanel::MachineInfoPanel(wxWindow* parent, wxWindowID id, const wxPoin
|
|||||||
createLaserWidgets(m_main_left_sizer);
|
createLaserWidgets(m_main_left_sizer);
|
||||||
createAirPumpWidgets(m_main_left_sizer);
|
createAirPumpWidgets(m_main_left_sizer);
|
||||||
createExtinguishWidgets(m_main_left_sizer);
|
createExtinguishWidgets(m_main_left_sizer);
|
||||||
|
createFilaTrackSwitchWidgets(m_main_left_sizer);
|
||||||
|
|
||||||
// nozzle rack widgets (H2C induction hotend rack; hidden unless GetNozzleRack()->IsSupported())
|
// nozzle rack widgets (H2C induction hotend rack; hidden unless GetNozzleRack()->IsSupported())
|
||||||
createNozzleRackWidgets(m_main_left_sizer);
|
createNozzleRackWidgets(m_main_left_sizer);
|
||||||
@@ -406,6 +408,27 @@ void MachineInfoPanel::createExtinguishWidgets(wxBoxSizer* main_left_sizer)
|
|||||||
main_left_sizer->Add(m_extinguish_sizer, 0, wxEXPAND, 0);
|
main_left_sizer->Add(m_extinguish_sizer, 0, wxEXPAND, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MachineInfoPanel::createFilaTrackSwitchWidgets(wxBoxSizer* main_left_sizer)
|
||||||
|
{
|
||||||
|
m_filatrack_line_above = new wxStaticLine(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL);
|
||||||
|
m_filatrack_line_above->SetBackgroundColour(wxColour(206, 206, 206));
|
||||||
|
main_left_sizer->Add(m_filatrack_line_above, 0, wxEXPAND | wxLEFT, FromDIP(40));
|
||||||
|
|
||||||
|
m_filatrack_img = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap, wxDefaultPosition, wxSize(FromDIP(200), FromDIP(200)));
|
||||||
|
m_filatrack_img->SetBitmap(m_img_filatrack.bmp());
|
||||||
|
|
||||||
|
wxBoxSizer* content_sizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
content_sizer->Add(0, 40, 0, wxEXPAND, FromDIP(5));
|
||||||
|
m_filatrack_version = new uiDeviceUpdateVersion(this, wxID_ANY);
|
||||||
|
content_sizer->Add(m_filatrack_version, 0, wxEXPAND, 0);
|
||||||
|
|
||||||
|
m_filatrack_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
m_filatrack_sizer->Add(m_filatrack_img, 0, wxALIGN_TOP | wxALL, FromDIP(5));
|
||||||
|
m_filatrack_sizer->Add(content_sizer, 1, wxEXPAND, 0);
|
||||||
|
|
||||||
|
main_left_sizer->Add(m_filatrack_sizer, 0, wxEXPAND, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void MachineInfoPanel::msw_rescale()
|
void MachineInfoPanel::msw_rescale()
|
||||||
{
|
{
|
||||||
rescale_bitmaps();
|
rescale_bitmaps();
|
||||||
@@ -435,6 +458,7 @@ void MachineInfoPanel::init_bitmaps()
|
|||||||
m_img_laser = ScalableBitmap(this, "laser", 160);
|
m_img_laser = ScalableBitmap(this, "laser", 160);
|
||||||
m_img_cutting = ScalableBitmap(this, "cut", 160);
|
m_img_cutting = ScalableBitmap(this, "cut", 160);
|
||||||
m_img_extinguish = ScalableBitmap(this, "extinguish", 160);
|
m_img_extinguish = ScalableBitmap(this, "extinguish", 160);
|
||||||
|
m_img_filatrack = ScalableBitmap(this, "filament_track_switch", 160);
|
||||||
m_img_nozzle_rack = ScalableBitmap(this, "nozzle_rack", 160);
|
m_img_nozzle_rack = ScalableBitmap(this, "nozzle_rack", 160);
|
||||||
|
|
||||||
upgrade_green_icon = ScalableBitmap(this, "monitor_upgrade_online", 5);
|
upgrade_green_icon = ScalableBitmap(this, "monitor_upgrade_online", 5);
|
||||||
@@ -544,6 +568,7 @@ void MachineInfoPanel::update(MachineObject* obj)
|
|||||||
update_cut(obj);
|
update_cut(obj);
|
||||||
update_laszer(obj);
|
update_laszer(obj);
|
||||||
update_extinguish(obj);
|
update_extinguish(obj);
|
||||||
|
update_filatrack(obj);
|
||||||
update_nozzle_rack(obj);
|
update_nozzle_rack(obj);
|
||||||
|
|
||||||
//update progress
|
//update progress
|
||||||
@@ -1129,6 +1154,19 @@ void MachineInfoPanel::update_extinguish(MachineObject* obj)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MachineInfoPanel::update_filatrack(MachineObject* obj)
|
||||||
|
{
|
||||||
|
if (obj && obj->filatrack_version_info.isValid())
|
||||||
|
{
|
||||||
|
m_filatrack_version->UpdateInfo(obj->filatrack_version_info);
|
||||||
|
show_filatrack(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
show_filatrack(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MachineInfoPanel::show_status(int status, std::string upgrade_status_str)
|
void MachineInfoPanel::show_status(int status, std::string upgrade_status_str)
|
||||||
{
|
{
|
||||||
if (last_status == status && last_status_str == upgrade_status_str) return;
|
if (last_status == status && last_status_str == upgrade_status_str) return;
|
||||||
@@ -1263,6 +1301,16 @@ void MachineInfoPanel::show_extinguish(bool show)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MachineInfoPanel::show_filatrack(bool show)
|
||||||
|
{
|
||||||
|
if (m_filatrack_version->IsShown() != show)
|
||||||
|
{
|
||||||
|
m_filatrack_img->Show(show);
|
||||||
|
m_filatrack_line_above->Show(show);
|
||||||
|
m_filatrack_version->Show(show);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MachineInfoPanel::createNozzleRackWidgets(wxBoxSizer *main_left_sizer)
|
void MachineInfoPanel::createNozzleRackWidgets(wxBoxSizer *main_left_sizer)
|
||||||
{
|
{
|
||||||
// horizontal line above
|
// horizontal line above
|
||||||
|
|||||||
@@ -134,6 +134,12 @@ protected:
|
|||||||
wxStaticLine* m_extinguish_line_above = nullptr;;
|
wxStaticLine* m_extinguish_line_above = nullptr;;
|
||||||
uiDeviceUpdateVersion* m_extinguish_version = nullptr;
|
uiDeviceUpdateVersion* m_extinguish_version = nullptr;
|
||||||
|
|
||||||
|
/* filament track switch info*/
|
||||||
|
wxBoxSizer* m_filatrack_sizer = nullptr;
|
||||||
|
wxStaticBitmap* m_filatrack_img = nullptr;
|
||||||
|
wxStaticLine* m_filatrack_line_above = nullptr;
|
||||||
|
uiDeviceUpdateVersion* m_filatrack_version = nullptr;
|
||||||
|
|
||||||
/* nozzle rack (H2C induction hotend rack) — opens wgtDeviceNozzleRackUpgradeDlg */
|
/* nozzle rack (H2C induction hotend rack) — opens wgtDeviceNozzleRackUpgradeDlg */
|
||||||
wxBoxSizer* m_nozzle_rack_sizer = nullptr;
|
wxBoxSizer* m_nozzle_rack_sizer = nullptr;
|
||||||
wxStaticBitmap* m_nozzle_rack_img = nullptr;
|
wxStaticBitmap* m_nozzle_rack_img = nullptr;
|
||||||
@@ -162,6 +168,7 @@ protected:
|
|||||||
ScalableBitmap m_img_cutting;
|
ScalableBitmap m_img_cutting;
|
||||||
ScalableBitmap m_img_laser;
|
ScalableBitmap m_img_laser;
|
||||||
ScalableBitmap m_img_extinguish;
|
ScalableBitmap m_img_extinguish;
|
||||||
|
ScalableBitmap m_img_filatrack;
|
||||||
ScalableBitmap m_img_nozzle_rack;
|
ScalableBitmap m_img_nozzle_rack;
|
||||||
ScalableBitmap upgrade_gray_icon;
|
ScalableBitmap upgrade_gray_icon;
|
||||||
ScalableBitmap upgrade_green_icon;
|
ScalableBitmap upgrade_green_icon;
|
||||||
@@ -220,18 +227,21 @@ private:
|
|||||||
void createCuttingWidgets(wxBoxSizer* main_left_sizer);
|
void createCuttingWidgets(wxBoxSizer* main_left_sizer);
|
||||||
void createLaserWidgets(wxBoxSizer* main_left_sizer);
|
void createLaserWidgets(wxBoxSizer* main_left_sizer);
|
||||||
void createExtinguishWidgets(wxBoxSizer* main_left_sizer);
|
void createExtinguishWidgets(wxBoxSizer* main_left_sizer);
|
||||||
|
void createFilaTrackSwitchWidgets(wxBoxSizer* main_left_sizer);
|
||||||
void createNozzleRackWidgets(wxBoxSizer* main_left_sizer);
|
void createNozzleRackWidgets(wxBoxSizer* main_left_sizer);
|
||||||
|
|
||||||
void update_air_pump(MachineObject* obj);
|
void update_air_pump(MachineObject* obj);
|
||||||
void update_cut(MachineObject* obj);
|
void update_cut(MachineObject* obj);
|
||||||
void update_laszer(MachineObject* obj);
|
void update_laszer(MachineObject* obj);
|
||||||
void update_extinguish(MachineObject* obj);
|
void update_extinguish(MachineObject* obj);
|
||||||
|
void update_filatrack(MachineObject* obj);
|
||||||
void update_nozzle_rack(MachineObject* obj);
|
void update_nozzle_rack(MachineObject* obj);
|
||||||
|
|
||||||
void show_air_pump(bool show = true);
|
void show_air_pump(bool show = true);
|
||||||
void show_cut(bool show = true);
|
void show_cut(bool show = true);
|
||||||
void show_laszer(bool show = true);
|
void show_laszer(bool show = true);
|
||||||
void show_extinguish(bool show = true);
|
void show_extinguish(bool show = true);
|
||||||
|
void show_filatrack(bool show = true);
|
||||||
void show_nozzle_rack(bool show = true);
|
void show_nozzle_rack(bool show = true);
|
||||||
|
|
||||||
void on_nozzle_rack_update(wxCommandEvent& event);
|
void on_nozzle_rack_update(wxCommandEvent& event);
|
||||||
|
|||||||
@@ -9,9 +9,11 @@
|
|||||||
|
|
||||||
#include "slic3r/GUI/DeviceCore/DevManager.h"
|
#include "slic3r/GUI/DeviceCore/DevManager.h"
|
||||||
#include "slic3r/GUI/DeviceCore/DevFilaSystem.h"
|
#include "slic3r/GUI/DeviceCore/DevFilaSystem.h"
|
||||||
|
#include "slic3r/GUI/DeviceCore/DevFilaSwitch.h"
|
||||||
|
|
||||||
#include <wx/simplebook.h>
|
#include <wx/simplebook.h>
|
||||||
#include <wx/dcgraph.h>
|
#include <wx/dcgraph.h>
|
||||||
|
#include <wx/artprov.h>
|
||||||
|
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
|
|
||||||
@@ -39,7 +41,7 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons
|
|||||||
SetBackgroundColour(*wxWHITE);
|
SetBackgroundColour(*wxWHITE);
|
||||||
// normal mode
|
// normal mode
|
||||||
//Freeze();
|
//Freeze();
|
||||||
wxBoxSizer *m_sizer_body = new wxBoxSizer(wxVERTICAL);
|
m_sizer_body = new wxBoxSizer(wxVERTICAL);
|
||||||
m_amswin = new wxWindow(this, wxID_ANY);
|
m_amswin = new wxWindow(this, wxID_ANY);
|
||||||
m_amswin->SetBackgroundColour(*wxWHITE);
|
m_amswin->SetBackgroundColour(*wxWHITE);
|
||||||
m_amswin->SetSize(wxSize(FromDIP(578), -1));
|
m_amswin->SetSize(wxSize(FromDIP(578), -1));
|
||||||
@@ -151,6 +153,12 @@ AMSControl::AMSControl(wxWindow *parent, wxWindowID id, const wxPoint &pos, cons
|
|||||||
m_extruder = new AMSextruder(m_amswin, wxID_ANY, m_total_ext_count, wxDefaultPosition, AMS_EXTRUDER_SIZE);
|
m_extruder = new AMSextruder(m_amswin, wxID_ANY, m_total_ext_count, wxDefaultPosition, AMS_EXTRUDER_SIZE);
|
||||||
m_sizer_option_mid->Add( m_extruder, 0, wxALIGN_CENTER, 0 );
|
m_sizer_option_mid->Add( m_extruder, 0, wxALIGN_CENTER, 0 );
|
||||||
|
|
||||||
|
// Orca: filament-switch routing glyph; hidden by default so it stays inert (zero layout impact)
|
||||||
|
// on any printer without a Filament Track Switch. Shown from UpdateAms only when installed.
|
||||||
|
m_switcher = new SwitcherImage(m_amswin, wxID_ANY, "fila_switch", wxSize(FromDIP(29), FromDIP(16)), wxDefaultPosition);
|
||||||
|
m_switcher->Hide();
|
||||||
|
m_sizer_option_mid->Add(m_switcher, 0, wxALIGN_CENTER | wxLEFT, FromDIP(6));
|
||||||
|
|
||||||
|
|
||||||
/*option right*/
|
/*option right*/
|
||||||
m_button_extruder_feed = new Button(m_panel_option_right, _L("Load"));
|
m_button_extruder_feed = new Button(m_panel_option_right, _L("Load"));
|
||||||
@@ -975,6 +983,32 @@ void AMSControl::UpdateAms(const std::string &series_name,
|
|||||||
{
|
{
|
||||||
m_amswin->Layout();
|
m_amswin->Layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*update switch status*/
|
||||||
|
// Orca: inert on any printer without a Filament Track Switch — install is false, so the banner is
|
||||||
|
// never materialized, the glyph stays hidden, and every ShowRoad(true) below is a no-op.
|
||||||
|
const auto [install, ready] = isFilaSwitchReady();
|
||||||
|
show_switcher_status(install && (!ready));
|
||||||
|
bool isShow = install && m_total_ext_count >= 2;
|
||||||
|
if (m_switcher->IsShown() != isShow)
|
||||||
|
{
|
||||||
|
m_switcher->Show(isShow);
|
||||||
|
m_sizer_body->Layout();
|
||||||
|
m_sizer_body->Fit(this);
|
||||||
|
this->Layout();
|
||||||
|
this->Refresh(true);
|
||||||
|
this->Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*update ext road visibility when fila switch installed*/
|
||||||
|
bool road_visibility_changed = false;
|
||||||
|
for (auto& [ams_id, ams_item] : m_ams_item_list) {
|
||||||
|
if (!ams_item) continue;
|
||||||
|
// Orca: drop the external-spool road (AMSModel::EXT_AMS) while the switch routes all filament.
|
||||||
|
const bool should_show_road = !(install && ams_item->get_ams_model() == AMSModel::EXT_AMS);
|
||||||
|
if (ams_item->ShowRoad(should_show_road)) { road_visibility_changed = true; }
|
||||||
|
}
|
||||||
|
if (road_visibility_changed) { m_amswin->Layout(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
void AMSControl::AddAmsPreview(AMSinfo info, AMSModel type)
|
void AMSControl::AddAmsPreview(AMSinfo info, AMSModel type)
|
||||||
@@ -1596,6 +1630,54 @@ void AMSControl::on_ams_setting_click(wxMouseEvent &event)
|
|||||||
post_event(SimpleEvent(EVT_AMS_SETTINGS));
|
post_event(SimpleEvent(EVT_AMS_SETTINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::tuple<bool, bool> AMSControl::isFilaSwitchReady()
|
||||||
|
{
|
||||||
|
DeviceManager* dev = Slic3r::GUI::wxGetApp().getDeviceManager();
|
||||||
|
if (!dev) return {false, false};
|
||||||
|
MachineObject* obj = dev->get_selected_machine();
|
||||||
|
if (!obj) return {false, false};
|
||||||
|
// Orca: GetFilaSwitch() is a raw non-null accessor (BBS returns a shared_ptr).
|
||||||
|
DevFilaSwitch* fila_switch = obj->GetFilaSwitch();
|
||||||
|
if (fila_switch)
|
||||||
|
{
|
||||||
|
return {fila_switch->IsInstalled(), fila_switch->IsReady()};
|
||||||
|
}
|
||||||
|
return {false, false};
|
||||||
|
}
|
||||||
|
|
||||||
|
void AMSControl::show_switcher_status(bool show)
|
||||||
|
{
|
||||||
|
// Orca: never materialize the banner on printers that never request it, so the AMS control is
|
||||||
|
// byte-identical without a Filament Track Switch (UpdateAms calls this with show=false every refresh).
|
||||||
|
if (!show && tipPanel == nullptr) { return; }
|
||||||
|
|
||||||
|
if (tipPanel == nullptr)
|
||||||
|
{
|
||||||
|
m_sizer_body->Add(0, 0, 1, wxEXPAND | wxTOP, FromDIP(5));
|
||||||
|
tipPanel = new wxPanel(m_amswin);
|
||||||
|
tipPanel->SetBackgroundColour(wxColour(255, 153, 0));
|
||||||
|
tipSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
tipPanel->SetSizer(tipSizer);
|
||||||
|
icon = new wxStaticBitmap(tipPanel, wxID_ANY,
|
||||||
|
wxArtProvider::GetBitmap(wxART_INFORMATION, wxART_MESSAGE_BOX, wxSize(FromDIP(16), FromDIP(16))));
|
||||||
|
tipSizer->Add(icon, 0, wxALL, FromDIP(8));
|
||||||
|
tipText = new wxStaticText(tipPanel, wxID_ANY, _L("AMS has not been initialized. Please initialize it before use."));
|
||||||
|
tipText->SetForegroundColour(wxColour(255, 255, 255));
|
||||||
|
tipText->SetFont(wxFont(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD));
|
||||||
|
tipText->Wrap(-1);
|
||||||
|
tipText->SetMinSize(wxSize(-1, -1));
|
||||||
|
tipSizer->Add(tipText, 0, wxALL | wxALIGN_CENTER_VERTICAL | wxEXPAND, FromDIP(8));
|
||||||
|
m_sizer_body->Add(tipPanel, 1, wxEXPAND, 0);
|
||||||
|
}
|
||||||
|
if (tipPanel->IsShown() == show)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
tipPanel->Show(show);
|
||||||
|
m_amswin->Layout();
|
||||||
|
m_amswin->Fit();
|
||||||
|
}
|
||||||
|
|
||||||
void AMSControl::parse_object(MachineObject* obj) {
|
void AMSControl::parse_object(MachineObject* obj) {
|
||||||
if (!obj || obj->GetFilaSystem()->GetAmsList().size() == 0)
|
if (!obj || obj->GetFilaSystem()->GetAmsList().size() == 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <wx/hyperlink.h>
|
#include <wx/hyperlink.h>
|
||||||
#include <wx/animate.h>
|
#include <wx/animate.h>
|
||||||
#include <wx/dynarray.h>
|
#include <wx/dynarray.h>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include "slic3r/GUI/DeviceCore/DevExtruderSystem.h"
|
#include "slic3r/GUI/DeviceCore/DevExtruderSystem.h"
|
||||||
|
|
||||||
@@ -51,8 +52,16 @@ protected:
|
|||||||
|
|
||||||
int m_total_ext_count = 1;
|
int m_total_ext_count = 1;
|
||||||
AMSextruder *m_extruder{nullptr};
|
AMSextruder *m_extruder{nullptr};
|
||||||
|
SwitcherImage *m_switcher{nullptr}; // Orca: filament-switch routing glyph (hidden unless a switch is installed)
|
||||||
AMSRoadDownPart* m_down_road{ nullptr };
|
AMSRoadDownPart* m_down_road{ nullptr };
|
||||||
|
|
||||||
|
// Orca: "AMS not initialized" warning banner, materialized lazily only when a switch needs it (see show_switcher_status)
|
||||||
|
wxBoxSizer* m_sizer_body{nullptr};
|
||||||
|
wxPanel* tipPanel{nullptr};
|
||||||
|
wxBoxSizer* tipSizer{nullptr};
|
||||||
|
wxStaticBitmap* icon{nullptr};
|
||||||
|
wxStaticText* tipText{nullptr};
|
||||||
|
|
||||||
/*items*/
|
/*items*/
|
||||||
wxBoxSizer* m_sizer_ams_items{nullptr};
|
wxBoxSizer* m_sizer_ams_items{nullptr};
|
||||||
wxScrolledWindow* m_panel_prv_left {nullptr};
|
wxScrolledWindow* m_panel_prv_left {nullptr};
|
||||||
@@ -151,6 +160,11 @@ public:
|
|||||||
void StopRridLoading(wxString amsid, wxString canid);
|
void StopRridLoading(wxString amsid, wxString canid);
|
||||||
void ShowFilamentTip(bool hasams = true);
|
void ShowFilamentTip(bool hasams = true);
|
||||||
|
|
||||||
|
// Orca: Filament Track Switch awareness. isFilaSwitchReady() resolves the selected machine and
|
||||||
|
// returns {installed, ready}; show_switcher_status() toggles the "AMS not initialized" banner.
|
||||||
|
std::tuple<bool, bool> isFilaSwitchReady();
|
||||||
|
void show_switcher_status(bool show);
|
||||||
|
|
||||||
void UpdatePassRoad(string ams_id, AMSPassRoadType type, AMSPassRoadSTEP step);
|
void UpdatePassRoad(string ams_id, AMSPassRoadType type, AMSPassRoadSTEP step);
|
||||||
void CreateAms();
|
void CreateAms();
|
||||||
void CreateAmsDoubleNozzle(const std::string &series_name, const std::string& printer_type);
|
void CreateAmsDoubleNozzle(const std::string &series_name, const std::string& printer_type);
|
||||||
|
|||||||
@@ -742,6 +742,63 @@ void AMSExtImage::doRender(wxDC& dc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Orca: SwitcherImage — routing glyph drawn when a Filament Track Switch is installed.
|
||||||
|
void SwitcherImage::paintEvent(wxPaintEvent &evt)
|
||||||
|
{
|
||||||
|
wxPaintDC dc(this);
|
||||||
|
render(dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherImage::render(wxDC &dc)
|
||||||
|
{
|
||||||
|
#ifdef __WXMSW__
|
||||||
|
wxSize size = GetSize();
|
||||||
|
wxMemoryDC memdc;
|
||||||
|
wxBitmap bmp(size.x, size.y);
|
||||||
|
memdc.SelectObject(bmp);
|
||||||
|
memdc.Blit({0, 0}, size, &dc, {0, 0});
|
||||||
|
|
||||||
|
{
|
||||||
|
wxGCDC dc2(memdc);
|
||||||
|
doRender(dc2);
|
||||||
|
}
|
||||||
|
|
||||||
|
memdc.SelectObject(wxNullBitmap);
|
||||||
|
dc.DrawBitmap(bmp, 0, 0);
|
||||||
|
#else
|
||||||
|
doRender(dc);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void SwitcherImage::doRender(wxDC &dc)
|
||||||
|
{
|
||||||
|
auto size = GetSize();
|
||||||
|
if (m_show_state){
|
||||||
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||||
|
dc.SetBrush(*wxWHITE);
|
||||||
|
dc.DrawBitmap(m_switcher.bmp(), wxPoint((size.x - m_switcher.GetBmpSize().x) / 2, 0));
|
||||||
|
}
|
||||||
|
Layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitcherImage::SwitcherImage(wxWindow *parent, wxWindowID id, string file_name, const wxSize& size, const wxPoint &pos)
|
||||||
|
{
|
||||||
|
wxWindow::Create(parent, id, pos, size);
|
||||||
|
SetBackgroundColour(StateColor::darkModeColorFor(*wxWHITE));
|
||||||
|
m_show_state = true;
|
||||||
|
m_switcher = ScalableBitmap(this, file_name, 16);
|
||||||
|
m_file_name = file_name;
|
||||||
|
SetSize(size);
|
||||||
|
SetMinSize(size);
|
||||||
|
SetMaxSize(size);
|
||||||
|
|
||||||
|
|
||||||
|
Bind(wxEVT_PAINT, &SwitcherImage::paintEvent, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitcherImage::~SwitcherImage() {}
|
||||||
|
|
||||||
|
|
||||||
//DevAms Extruder
|
//DevAms Extruder
|
||||||
AMSextruder::AMSextruder(wxWindow *parent, wxWindowID id, int nozzle_num, const wxPoint &pos, const wxSize &size)
|
AMSextruder::AMSextruder(wxWindow *parent, wxWindowID id, int nozzle_num, const wxPoint &pos, const wxSize &size)
|
||||||
{
|
{
|
||||||
@@ -3577,6 +3634,18 @@ void AmsItem::doRender(wxDC& dc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Orca: toggle the road segment below the item (m_panel_road). Used to drop the external-spool
|
||||||
|
// road when a Filament Track Switch is installed. No-op (returns false) when already in state.
|
||||||
|
bool AmsItem::ShowRoad(bool show)
|
||||||
|
{
|
||||||
|
if (!m_panel_road) return false;
|
||||||
|
if (m_panel_road->IsShown() == show) return false;
|
||||||
|
m_panel_road->Show(show);
|
||||||
|
Layout();
|
||||||
|
Refresh();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void AmsItem::RenderLiteRoad(wxDC& dc, wxSize size) {
|
void AmsItem::RenderLiteRoad(wxDC& dc, wxSize size) {
|
||||||
auto end_top = size.x - FromDIP(3);
|
auto end_top = size.x - FromDIP(3);
|
||||||
if (m_panel_pos == AMSPanelPos::RIGHT_PANEL){
|
if (m_panel_pos == AMSPanelPos::RIGHT_PANEL){
|
||||||
@@ -3706,4 +3775,342 @@ void AmsItem::show_sn_value(bool show)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DevExtruderImage::DevExtruderImage(wxWindow *parent, wxWindowID id, int extruder_num, const wxPoint &pos, const wxSize &size) : wxWindow(parent, id, pos, wxDefaultSize), m_extruder_num(extruder_num)
|
||||||
|
{
|
||||||
|
// wxWindow::Create(parent, id, pos, wxSize(FromDIP(45), FromDIP(112)));
|
||||||
|
SetBackgroundColour(*wxWHITE);
|
||||||
|
SetSize(wxSize(FromDIP(48), FromDIP(112)));
|
||||||
|
SetMinSize(wxSize(FromDIP(48), FromDIP(112)));
|
||||||
|
SetMaxSize(wxSize(FromDIP(48), FromDIP(112)));
|
||||||
|
|
||||||
|
|
||||||
|
m_left_extruder_active_filled = new ScalableBitmap(this, "left_extruder_active_filled", 62);
|
||||||
|
m_left_extruder_active_empty = new ScalableBitmap(this, "left_extruder_active_empty", 62);
|
||||||
|
m_left_extruder_unactive_filled = new ScalableBitmap(this, "left_extruder_unactive_filled", 62);
|
||||||
|
m_left_extruder_unactive_empty = new ScalableBitmap(this, "left_extruder_unactive_empty", 62);
|
||||||
|
m_right_extruder_active_filled = new ScalableBitmap(this, "right_extruder_active_filled", 62);
|
||||||
|
m_right_extruder_active_empty = new ScalableBitmap(this, "right_extruder_active_empty", 62);
|
||||||
|
m_right_extruder_unactive_filled = new ScalableBitmap(this, "right_extruder_unactive_filled", 62);
|
||||||
|
m_right_extruder_unactive_empty = new ScalableBitmap(this, "right_extruder_unactive_empty", 62);
|
||||||
|
|
||||||
|
m_extruder_single_nozzle_empty_load = new ScalableBitmap(this, "monitor_extruder_empty_load", 106);
|
||||||
|
m_extruder_single_nozzle_empty_unload = new ScalableBitmap(this, "monitor_extruder_empty_unload", 106);
|
||||||
|
m_extruder_single_nozzle_filled_load = new ScalableBitmap(this, "monitor_extruder_filled_load", 106);
|
||||||
|
m_extruder_single_nozzle_filled_unload = new ScalableBitmap(this, "monitor_extruder_filled_unload", 106);
|
||||||
|
|
||||||
|
Bind(wxEVT_PAINT, &DevExtruderImage::paintEvent, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevExtruderImage::msw_rescale()
|
||||||
|
{
|
||||||
|
m_left_extruder_active_filled->msw_rescale();
|
||||||
|
m_left_extruder_active_empty->msw_rescale();
|
||||||
|
m_left_extruder_unactive_filled->msw_rescale();
|
||||||
|
m_left_extruder_unactive_empty->msw_rescale();
|
||||||
|
m_right_extruder_active_filled->msw_rescale();
|
||||||
|
m_right_extruder_active_empty->msw_rescale();
|
||||||
|
m_right_extruder_unactive_filled->msw_rescale();
|
||||||
|
m_right_extruder_unactive_empty->msw_rescale();
|
||||||
|
|
||||||
|
m_extruder_single_nozzle_empty_load->msw_rescale();
|
||||||
|
m_extruder_single_nozzle_empty_unload->msw_rescale();
|
||||||
|
m_extruder_single_nozzle_filled_load->msw_rescale();
|
||||||
|
m_extruder_single_nozzle_filled_unload->msw_rescale();
|
||||||
|
Layout();
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevExtruderImage::render(wxDC &dc)
|
||||||
|
{
|
||||||
|
#ifdef __WXMSW__
|
||||||
|
wxSize size = GetSize();
|
||||||
|
wxMemoryDC memdc;
|
||||||
|
wxBitmap bmp(size.x, size.y);
|
||||||
|
memdc.SelectObject(bmp);
|
||||||
|
memdc.Blit({0, 0}, size, &dc, {0, 0});
|
||||||
|
|
||||||
|
{
|
||||||
|
wxGCDC dc2(memdc);
|
||||||
|
doRender(dc2);
|
||||||
|
}
|
||||||
|
|
||||||
|
memdc.SelectObject(wxNullBitmap);
|
||||||
|
dc.DrawBitmap(bmp, 0, 0);
|
||||||
|
#else
|
||||||
|
doRender(dc);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void DevExtruderImage::doRender(wxDC &dc)
|
||||||
|
{
|
||||||
|
auto size = GetSize();
|
||||||
|
auto pot = wxPoint(size.x / 2, (size.y - m_left_extruder_active_filled->GetBmpSize().y) / 2);
|
||||||
|
|
||||||
|
if (m_extruder_num >= 2)
|
||||||
|
{
|
||||||
|
ScalableBitmap *left_extruder_bmp{nullptr};
|
||||||
|
ScalableBitmap *right_extruder_bmp{nullptr};
|
||||||
|
|
||||||
|
switch (m_right_ext_state)
|
||||||
|
{
|
||||||
|
case DevExtruderState::FILLED_LOAD:
|
||||||
|
right_extruder_bmp = current_extruder_loc == "right" ? m_right_extruder_active_filled : m_right_extruder_unactive_filled;
|
||||||
|
break;
|
||||||
|
case DevExtruderState::FILLED_UNLOAD:
|
||||||
|
right_extruder_bmp = current_extruder_loc == "right" ? m_right_extruder_active_filled : m_right_extruder_unactive_filled;
|
||||||
|
break;
|
||||||
|
case DevExtruderState::EMPTY_LOAD:
|
||||||
|
if (current_extruder_loc.empty())
|
||||||
|
{
|
||||||
|
right_extruder_bmp = m_right_extruder_active_empty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
right_extruder_bmp = current_extruder_loc == "right" ? m_right_extruder_active_empty : m_right_extruder_unactive_empty;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DevExtruderState::EMPTY_UNLOAD:
|
||||||
|
right_extruder_bmp = current_extruder_loc == "right" ? m_right_extruder_active_empty : m_right_extruder_unactive_empty;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_left_ext_state)
|
||||||
|
{
|
||||||
|
case DevExtruderState::FILLED_LOAD:
|
||||||
|
left_extruder_bmp = current_extruder_loc == "left" ? m_left_extruder_active_filled : m_left_extruder_unactive_filled;
|
||||||
|
break;
|
||||||
|
case DevExtruderState::FILLED_UNLOAD:
|
||||||
|
left_extruder_bmp = current_extruder_loc == "left" ? m_left_extruder_active_filled : m_left_extruder_unactive_filled;
|
||||||
|
break;
|
||||||
|
case DevExtruderState::EMPTY_LOAD:
|
||||||
|
if (current_extruder_loc.empty())
|
||||||
|
{
|
||||||
|
left_extruder_bmp = m_left_extruder_active_empty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
left_extruder_bmp = current_extruder_loc == "left" ? m_left_extruder_active_empty : m_left_extruder_unactive_empty;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DevExtruderState::EMPTY_UNLOAD:
|
||||||
|
left_extruder_bmp = current_extruder_loc == "left" ? m_left_extruder_active_empty : m_left_extruder_unactive_empty;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left_extruder_bmp) { dc.DrawBitmap(left_extruder_bmp->bmp(), pot.x - left_extruder_bmp->GetBmpWidth(), pot.y); }
|
||||||
|
if (right_extruder_bmp) { dc.DrawBitmap(right_extruder_bmp->bmp(), pot.x, pot.y); }
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScalableBitmap *extruder_bmp = nullptr;
|
||||||
|
switch (m_single_ext_state)
|
||||||
|
{
|
||||||
|
case DevExtruderState::FILLED_LOAD:
|
||||||
|
extruder_bmp = m_extruder_single_nozzle_filled_load;
|
||||||
|
break;
|
||||||
|
case DevExtruderState::FILLED_UNLOAD:
|
||||||
|
extruder_bmp = m_extruder_single_nozzle_filled_unload;
|
||||||
|
break;
|
||||||
|
case DevExtruderState::EMPTY_LOAD:
|
||||||
|
extruder_bmp = m_extruder_single_nozzle_empty_load;
|
||||||
|
break;
|
||||||
|
case DevExtruderState::EMPTY_UNLOAD:
|
||||||
|
extruder_bmp = m_extruder_single_nozzle_empty_unload;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extruder_bmp) { dc.DrawBitmap(extruder_bmp->bmp(), pot.x - extruder_bmp->GetBmpWidth() / 2, (size.y - extruder_bmp->GetBmpHeight()) / 2); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FeedDirectionDialog::FeedDirectionDialog(wxWindow* parent,
|
||||||
|
const int extruderNum,
|
||||||
|
const std::string& printer_type)
|
||||||
|
: wxDialog(parent, wxID_ANY, "", wxDefaultPosition, wxDefaultSize),
|
||||||
|
m_extruder_num(extruderNum),
|
||||||
|
m_printer_type(printer_type)
|
||||||
|
{
|
||||||
|
SetBackgroundColour(wxColour("#FFFFFF"));
|
||||||
|
SetMaxSize(wxSize(FromDIP(360), FromDIP(207)));
|
||||||
|
SetMinSize(wxSize(FromDIP(360), FromDIP(207)));
|
||||||
|
SetSize(wxSize(FromDIP(360), FromDIP(207)));
|
||||||
|
|
||||||
|
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
|
wxGridSizer* topSizer = new wxGridSizer (1, 3, FromDIP(5), 0);
|
||||||
|
|
||||||
|
m_radioHelper = new wxRadioButton(this, wxID_ANY, wxT(""), wxDefaultPosition, wxDefaultSize, wxRB_GROUP);
|
||||||
|
m_leftRadio = new wxRadioButton(this, wxID_ANY,
|
||||||
|
_L(DevPrinterConfigUtil::get_toolhead_display_name(m_printer_type, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Extruder, ToolHeadNameCase::TitleCase, true)));
|
||||||
|
m_rightRadio = new wxRadioButton(this, wxID_ANY,
|
||||||
|
_L(DevPrinterConfigUtil::get_toolhead_display_name(m_printer_type, MAIN_EXTRUDER_ID, ToolHeadComponent::Extruder, ToolHeadNameCase::TitleCase, true)));
|
||||||
|
m_radioHelper->Show(false);
|
||||||
|
m_radioHelper->SetCanFocus(false);
|
||||||
|
|
||||||
|
m_leftRadio->SetForegroundColour(*wxBLACK);
|
||||||
|
m_rightRadio->SetForegroundColour(*wxBLACK);
|
||||||
|
|
||||||
|
topSizer->Add(m_leftRadio, 0, wxALIGN_CENTER | wxALL, FromDIP(20));
|
||||||
|
m_extruderImage = new DevExtruderImage(this, wxID_ANY, m_extruder_num);
|
||||||
|
topSizer->Add(m_extruderImage, 0, wxALIGN_CENTER | wxALL, FromDIP(5));
|
||||||
|
topSizer->Add(m_rightRadio, 0, wxALIGN_CENTER | wxALL, FromDIP(20));
|
||||||
|
|
||||||
|
mainSizer->AddStretchSpacer(1);
|
||||||
|
mainSizer->Add(topSizer, 1, wxEXPAND);
|
||||||
|
mainSizer->AddStretchSpacer(1);
|
||||||
|
|
||||||
|
wxBoxSizer* bottomSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
m_confirmBtn = new Button(this, _L("Confirm"));
|
||||||
|
m_confirmBtn->SetSize(wxSize(FromDIP(80), FromDIP(32)));
|
||||||
|
m_confirmBtn->Enable(false);
|
||||||
|
m_confirmBtn->SetFont(::Label::Body_14);
|
||||||
|
bottomSizer->Add(m_confirmBtn, 0, wxALIGN_RIGHT);
|
||||||
|
|
||||||
|
mainSizer->Add(bottomSizer, 0, wxALIGN_RIGHT | wxBOTTOM | wxRIGHT, FromDIP(10));
|
||||||
|
|
||||||
|
SetSizer(mainSizer);
|
||||||
|
Layout();
|
||||||
|
Centre(wxBOTH);
|
||||||
|
|
||||||
|
m_lastChecked = m_radioHelper;
|
||||||
|
m_confirmBtn->Bind(wxEVT_BUTTON, &FeedDirectionDialog::OnConfirm, this);
|
||||||
|
m_leftRadio->Bind(wxEVT_RADIOBUTTON, &FeedDirectionDialog::OnRadioClicked, this);
|
||||||
|
m_rightRadio->Bind(wxEVT_RADIOBUTTON, &FeedDirectionDialog::OnRadioClicked, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FeedDirectionDialog::OnConfirm(wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
EndModal(wxID_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FeedDirectionDialog::OnRadioClicked(wxCommandEvent& evt)
|
||||||
|
{
|
||||||
|
auto clicked = static_cast<wxRadioButton*>(evt.GetEventObject());
|
||||||
|
m_load_extruder_id = std::nullopt;
|
||||||
|
if (clicked == m_lastChecked)
|
||||||
|
{
|
||||||
|
m_radioHelper->SetValue(true);
|
||||||
|
m_lastChecked = m_radioHelper;
|
||||||
|
m_confirmBtn->Enable(false);
|
||||||
|
m_extruderImage->update(DevExtruderState::EMPTY_LOAD, DevExtruderState::EMPTY_LOAD);
|
||||||
|
m_extruderImage->setExtruderUsed("");
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clicked->SetValue(true);
|
||||||
|
m_lastChecked = clicked;
|
||||||
|
m_confirmBtn->Enable(true);
|
||||||
|
|
||||||
|
if (clicked == m_leftRadio)
|
||||||
|
{
|
||||||
|
m_extruderImage->update(DevExtruderState::FILLED_LOAD, DevExtruderState::EMPTY_LOAD);
|
||||||
|
m_extruderImage->setExtruderUsed("left");
|
||||||
|
m_load_extruder_id = 1;
|
||||||
|
{
|
||||||
|
SetTitle(wxString::Format(_L("Load %s to ") + _L(DevPrinterConfigUtil::get_toolhead_display_name(m_printer_type, DEPUTY_EXTRUDER_ID, ToolHeadComponent::Extruder, ToolHeadNameCase::LowerCase)), m_filament_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (clicked == m_rightRadio)
|
||||||
|
{
|
||||||
|
m_extruderImage->update(DevExtruderState::EMPTY_LOAD, DevExtruderState::FILLED_LOAD);
|
||||||
|
m_extruderImage->setExtruderUsed("right");
|
||||||
|
m_load_extruder_id = 0;
|
||||||
|
{
|
||||||
|
SetTitle(wxString::Format(_L("Load %s to ") + _L(DevPrinterConfigUtil::get_toolhead_display_name(m_printer_type, MAIN_EXTRUDER_ID, ToolHeadComponent::Extruder, ToolHeadNameCase::LowerCase)), m_filament_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_leftRadio->Refresh();
|
||||||
|
m_rightRadio->Refresh();
|
||||||
|
Fit();
|
||||||
|
Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> FeedDirectionDialog::GetExtruderID()
|
||||||
|
{
|
||||||
|
if (m_extruderImage)
|
||||||
|
{
|
||||||
|
return m_load_extruder_id;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxString FeedDirectionDialog::calcTrayName(MachineObject* obj, const std::string& amsID, const std::string& slotID)
|
||||||
|
{
|
||||||
|
if (amsID.empty() || slotID.empty() || !obj)
|
||||||
|
return wxString();
|
||||||
|
|
||||||
|
auto filaSys = obj->GetFilaSystem();
|
||||||
|
if (!filaSys)
|
||||||
|
return wxString();
|
||||||
|
|
||||||
|
DevAms* ams = filaSys->GetAmsById(amsID);
|
||||||
|
if (!ams)
|
||||||
|
return wxString();
|
||||||
|
|
||||||
|
int ams_id_int = std::stoi(amsID);
|
||||||
|
int slot_id_int = std::stoi(slotID);
|
||||||
|
int tray_id = 0;
|
||||||
|
|
||||||
|
// Orca: DevAms::AmsType is the local enum (AMS / AMS_LITE / N3F / N3S); it has no EXT_SPOOL
|
||||||
|
// member, and external/virtual spools are not real DevAms objects (GetAmsById returns nullptr
|
||||||
|
// above), so the EXT_SPOOL branch from upstream is unnecessary here.
|
||||||
|
if (ams->GetAmsType() == DevAms::AMS || ams->GetAmsType() == DevAms::AMS_LITE || ams->GetAmsType() == DevAms::N3F) {
|
||||||
|
tray_id = ams_id_int * 4 + slot_id_int;
|
||||||
|
} else if (ams->GetAmsType() == DevAms::N3S) {
|
||||||
|
tray_id = ams_id_int + slot_id_int;
|
||||||
|
} else {
|
||||||
|
return wxString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return wxGetApp().transition_tridid(tray_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FeedDirectionDialog::SetExtruderMapping(MachineObject* obj,
|
||||||
|
const std::string& currAmsId,
|
||||||
|
const std::string& currSlotId,
|
||||||
|
const std::vector<std::pair<std::string, std::string>>& extruderSlots)
|
||||||
|
{
|
||||||
|
wxString filamentID = calcTrayName(obj, currAmsId, currSlotId);
|
||||||
|
if (filamentID.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_filament_id = filamentID;
|
||||||
|
SetTitle(wxString::Format(_L("Load %s to "), filamentID));
|
||||||
|
|
||||||
|
std::vector<wxString> extruderMapping(extruderSlots.size());
|
||||||
|
for (size_t i = 0; i < extruderSlots.size(); ++i) {
|
||||||
|
if (!extruderSlots[i].first.empty())
|
||||||
|
extruderMapping[i] = calcTrayName(obj, extruderSlots[i].first, extruderSlots[i].second);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extruderMapping.size() > 1 && extruderMapping[1] == filamentID) //left extruder
|
||||||
|
{
|
||||||
|
m_leftRadio->Enable(false);
|
||||||
|
m_confirmBtn->Enable(false);
|
||||||
|
m_extruderImage->update(DevExtruderState::EMPTY_LOAD, DevExtruderState::EMPTY_LOAD);
|
||||||
|
m_extruderImage->setExtruderUsed("right");
|
||||||
|
}
|
||||||
|
else if (!extruderMapping.empty() && extruderMapping[0] == filamentID) //right extruder
|
||||||
|
{
|
||||||
|
m_rightRadio->Enable(false);
|
||||||
|
m_confirmBtn->Enable(false);
|
||||||
|
m_extruderImage->update(DevExtruderState::EMPTY_LOAD, DevExtruderState::EMPTY_LOAD);
|
||||||
|
m_extruderImage->setExtruderUsed("left");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_radioHelper->SetValue(true);
|
||||||
|
m_lastChecked = m_radioHelper;
|
||||||
|
m_confirmBtn->Enable(false);
|
||||||
|
m_extruderImage->update(DevExtruderState::EMPTY_LOAD, DevExtruderState::EMPTY_LOAD);
|
||||||
|
m_extruderImage->setExtruderUsed("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}} // namespace Slic3r::GUI
|
}} // namespace Slic3r::GUI
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include <wx/hyperlink.h>
|
#include <wx/hyperlink.h>
|
||||||
#include <wx/animate.h>
|
#include <wx/animate.h>
|
||||||
#include <wx/dynarray.h>
|
#include <wx/dynarray.h>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
|
||||||
#define AMS_CONTROL_BRAND_COLOUR wxColour(0, 150, 136)
|
#define AMS_CONTROL_BRAND_COLOUR wxColour(0, 150, 136)
|
||||||
@@ -400,6 +401,26 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Orca: routing glyph shown on the AMS control when a Filament Track Switch is installed.
|
||||||
|
class SwitcherImage: public wxWindow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void setShowState(bool show_state) { m_show_state = show_state; };
|
||||||
|
// void msw_rescale();
|
||||||
|
void paintEvent(wxPaintEvent &evt);
|
||||||
|
|
||||||
|
void render(wxDC &dc);
|
||||||
|
bool m_show_state = {false};
|
||||||
|
wxColour m_colour;
|
||||||
|
ScalableBitmap m_switcher;
|
||||||
|
string m_file_name;
|
||||||
|
// bool m_ams_loading{ false };
|
||||||
|
void doRender(wxDC &dc);
|
||||||
|
SwitcherImage(wxWindow *parent, wxWindowID id, string file_name, const wxSize& size, const wxPoint &pos = wxDefaultPosition);
|
||||||
|
~SwitcherImage();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class AMSextruder : public wxWindow
|
class AMSextruder : public wxWindow
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -771,6 +792,9 @@ public:
|
|||||||
void PlayRridLoading(wxString canid);
|
void PlayRridLoading(wxString canid);
|
||||||
void StopRridLoading(wxString canid);
|
void StopRridLoading(wxString canid);
|
||||||
void msw_rescale();
|
void msw_rescale();
|
||||||
|
// Orca: hide/show the road segment below the item; used to drop the external-spool road
|
||||||
|
// when a Filament Track Switch is installed. Returns true if the visibility actually changed.
|
||||||
|
bool ShowRoad(bool show);
|
||||||
void show_sn_value(bool show);
|
void show_sn_value(bool show);
|
||||||
void SetAmsStepExtra(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step);
|
void SetAmsStepExtra(wxString canid, AMSPassRoadType type, AMSPassRoadSTEP step);
|
||||||
void SetAmsStep(std::string amsid, std::string canid, AMSPassRoadType type, AMSPassRoadSTEP step);
|
void SetAmsStep(std::string amsid, std::string canid, AMSPassRoadType type, AMSPassRoadSTEP step);
|
||||||
@@ -849,6 +873,111 @@ wxDECLARE_EVENT(EVT_AMS_UNSELETED_AMS, wxCommandEvent);
|
|||||||
wxDECLARE_EVENT(EVT_VAMS_ON_FILAMENT_EDIT, wxCommandEvent);
|
wxDECLARE_EVENT(EVT_VAMS_ON_FILAMENT_EDIT, wxCommandEvent);
|
||||||
wxDECLARE_EVENT(EVT_AMS_SWITCH, SimpleEvent);
|
wxDECLARE_EVENT(EVT_AMS_SWITCH, SimpleEvent);
|
||||||
|
|
||||||
|
enum class DevExtruderState {
|
||||||
|
FILLED_LOAD,
|
||||||
|
FILLED_UNLOAD,
|
||||||
|
EMPTY_LOAD,
|
||||||
|
EMPTY_UNLOAD
|
||||||
|
};
|
||||||
|
|
||||||
|
class DevExtruderImage : public wxWindow
|
||||||
|
{
|
||||||
|
ScalableBitmap *m_left_extruder_active_filled;
|
||||||
|
ScalableBitmap *m_left_extruder_active_empty;
|
||||||
|
ScalableBitmap *m_left_extruder_unactive_filled;
|
||||||
|
ScalableBitmap *m_left_extruder_unactive_empty;
|
||||||
|
ScalableBitmap *m_right_extruder_active_filled;
|
||||||
|
ScalableBitmap *m_right_extruder_active_empty;
|
||||||
|
ScalableBitmap *m_right_extruder_unactive_filled;
|
||||||
|
ScalableBitmap *m_right_extruder_unactive_empty;
|
||||||
|
|
||||||
|
ScalableBitmap *m_extruder_single_nozzle_empty_load;
|
||||||
|
ScalableBitmap *m_extruder_single_nozzle_empty_unload;
|
||||||
|
ScalableBitmap *m_extruder_single_nozzle_filled_load;
|
||||||
|
ScalableBitmap *m_extruder_single_nozzle_filled_unload;
|
||||||
|
|
||||||
|
DevExtruderState m_left_ext_state = {DevExtruderState::EMPTY_LOAD};
|
||||||
|
DevExtruderState m_right_ext_state = {DevExtruderState::EMPTY_LOAD};
|
||||||
|
DevExtruderState m_single_ext_state = {DevExtruderState::EMPTY_LOAD};
|
||||||
|
|
||||||
|
public:
|
||||||
|
DevExtruderImage(wxWindow *parent, wxWindowID id,
|
||||||
|
int extruder_num,
|
||||||
|
const wxPoint &pos = wxDefaultPosition,
|
||||||
|
const wxSize &size = wxDefaultSize);
|
||||||
|
~DevExtruderImage()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
void update(DevExtruderState single_state)
|
||||||
|
{
|
||||||
|
m_single_ext_state = single_state;
|
||||||
|
}
|
||||||
|
void update(DevExtruderState left_state, DevExtruderState right_state)
|
||||||
|
{
|
||||||
|
m_left_ext_state = left_state;
|
||||||
|
m_right_ext_state = right_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void msw_rescale();
|
||||||
|
void setExtruderCount(int extruder_num)
|
||||||
|
{
|
||||||
|
m_extruder_num = extruder_num;
|
||||||
|
}
|
||||||
|
void setExtruderUsed(const std::string& loc)
|
||||||
|
{
|
||||||
|
if (current_extruder_loc == loc) { return; }
|
||||||
|
current_extruder_loc = loc;
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void paintEvent(wxPaintEvent &evt)
|
||||||
|
{
|
||||||
|
wxPaintDC dc(this);
|
||||||
|
render(dc);
|
||||||
|
}
|
||||||
|
void render(wxDC &dc);
|
||||||
|
void doRender(wxDC &dc);
|
||||||
|
int m_extruder_num = 1;
|
||||||
|
std::string current_extruder_loc = "";
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Filament Track Switch: when the switch is installed and calibrated a filament can be routed to
|
||||||
|
// either extruder, so this dialog lets the user pick. GetExtruderID() returns the chosen extruder
|
||||||
|
// (1 = deputy/left, 0 = main/right) or nullopt if none was picked; that value is passed to
|
||||||
|
// MachineObject::command_ams_change_filament. Only constructed on the FTS-ready path.
|
||||||
|
class FeedDirectionDialog : public wxDialog
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FeedDirectionDialog(wxWindow* parent, const int extruderNum, const std::string& printer_type = "");
|
||||||
|
|
||||||
|
std::optional<int> GetExtruderID();
|
||||||
|
|
||||||
|
void SetExtruderMapping(MachineObject* obj,
|
||||||
|
const std::string& currAmsId,
|
||||||
|
const std::string& currSlotId,
|
||||||
|
const std::vector<std::pair<std::string, std::string>>& extruderSlots);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static wxString calcTrayName(MachineObject* obj, const std::string& amsID, const std::string& slotID);
|
||||||
|
|
||||||
|
int m_extruder_num{};
|
||||||
|
std::string m_printer_type;
|
||||||
|
wxString m_filament_id{};
|
||||||
|
wxRadioButton* m_radioHelper{nullptr};
|
||||||
|
wxRadioButton* m_leftRadio{nullptr};
|
||||||
|
wxRadioButton* m_rightRadio{nullptr};
|
||||||
|
wxRadioButton* m_lastChecked{nullptr};
|
||||||
|
DevExtruderImage* m_extruderImage{nullptr};
|
||||||
|
Button* m_confirmBtn{nullptr};
|
||||||
|
std::optional<int> m_load_extruder_id = std::nullopt;
|
||||||
|
|
||||||
|
void OnConfirm(wxCommandEvent& event);
|
||||||
|
void OnRadioClicked(wxCommandEvent& evt);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
}} // namespace Slic3r::GUI
|
}} // namespace Slic3r::GUI
|
||||||
|
|
||||||
#endif // !slic3r_GUI_amscontrol_hpp_
|
#endif // !slic3r_GUI_amscontrol_hpp_
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "../BitmapCache.hpp"
|
#include "../BitmapCache.hpp"
|
||||||
#include "../I18N.hpp"
|
#include "../I18N.hpp"
|
||||||
#include "../GUI_App.hpp"
|
#include "../GUI_App.hpp"
|
||||||
|
#include "../DeviceCore/DevFilaSystem.h"
|
||||||
|
|
||||||
#include <wx/simplebook.h>
|
#include <wx/simplebook.h>
|
||||||
#include <wx/dcgraph.h>
|
#include <wx/dcgraph.h>
|
||||||
@@ -37,6 +38,28 @@ FilamentLoad::FilamentLoad(wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
|||||||
//FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_FEED_FILAMENT] = _L("Feed Filament");
|
//FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_FEED_FILAMENT] = _L("Feed Filament");
|
||||||
FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_CONFIRM_EXTRUDED] = _L("Confirm extruded");
|
FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_CONFIRM_EXTRUDED] = _L("Confirm extruded");
|
||||||
FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_CHECK_POSITION] = _L("Check filament location");
|
FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_CHECK_POSITION] = _L("Check filament location");
|
||||||
|
|
||||||
|
// Orca: labels for the device-numbered steps carried by the AMS (ams.cfs). Overlapping steps
|
||||||
|
// reuse the wording above so the current-step highlight (driven by the legacy ams_status_sub
|
||||||
|
// path) still text-matches; the switch/hotend/cooling and Filament Track Switch steps are new.
|
||||||
|
// STEP_CHECK_POSITION and STEP_CONFIRM_EXTRUDED share code 0x08, so CONFIRM is assigned first
|
||||||
|
// and CHECK_POSITION last, leaving code 0x08 mapped to "Check filament location" as on device.
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_IDLE] = _L("Idling...");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PAUSE] = _L("Pause");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_HEAT_NOZZLE] = _L("Heat the nozzle");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_CUT_FILAMENT] = _L("Cut filament");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PULL_CURR_FILAMENT] = _L("Pull back the current filament");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PUSH_NEW_FILAMENT] = _L("Push new filament into extruder");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_GRAB_NEW_FILAMENT] = _L("Grab new filament");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PURGE_OLD_FILAMENT] = _L("Purge old filament");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_SWITCH_EXTRUDER] = _L("Switch") + " " + _L("extruder");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_SWITCH_HOTEND] = _L("Switch") + " " + _L("hotend");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_AMS_FILA_COOLING] = _L("Wait for AMS cooling");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PUSH_SWITCHER_FILA] = _L("Switch current filament at Filament Track Switch");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_PULL_SWITCHER_FILA] = _L("Pull back current filament at Filament Track Switch");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_SWITCHER_SWITCH] = _L("Switch track at Filament Track Switch");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_CONFIRM_EXTRUDED] = _L("Confirm extruded");
|
||||||
|
DEV_FILAMENT_CHANGE_STEP_STRING[DevFilamentStep::STEP_CHECK_POSITION] = _L("Check filament location");
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentLoad::SetFilamentStep(FilamentStep item_idx, FilamentStepType f_type)
|
void FilamentLoad::SetFilamentStep(FilamentStep item_idx, FilamentStepType f_type)
|
||||||
@@ -124,11 +147,34 @@ void FilamentLoad::SetFilamentStep(FilamentStep item_idx, FilamentStepType f_typ
|
|||||||
step_control->SetSlotInformation(slot_info);
|
step_control->SetSlotInformation(slot_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentLoad::SetupSteps(bool has_fila_to_switch) {
|
void FilamentLoad::SetupSteps(MachineObject* obj_, bool has_fila_to_switch) {
|
||||||
m_filament_load_steps->DeleteAllItems();
|
m_filament_load_steps->DeleteAllItems();
|
||||||
m_filament_unload_steps->DeleteAllItems();
|
m_filament_unload_steps->DeleteAllItems();
|
||||||
m_filament_vt_load_steps->DeleteAllItems();
|
m_filament_vt_load_steps->DeleteAllItems();
|
||||||
|
|
||||||
|
// Orca: newer firmware sends the exact change-step sequence through the AMS (ams.cfs). When
|
||||||
|
// present, build the visible steps straight from that list and skip the hardcoded per-model
|
||||||
|
// sequences below. Inert on current firmware: the list is empty, so this branch is skipped and
|
||||||
|
// the legacy logic runs unchanged.
|
||||||
|
if (obj_ && obj_->GetFilaSystem() && !obj_->GetFilaSystem()->GetFilamentChangeSteps().empty()) {
|
||||||
|
const auto& steps = obj_->GetFilaSystem()->GetFilamentChangeSteps();
|
||||||
|
for (auto step : steps) {
|
||||||
|
auto iter = DEV_FILAMENT_CHANGE_STEP_STRING.find(step);
|
||||||
|
if (iter == DEV_FILAMENT_CHANGE_STEP_STRING.end()) {
|
||||||
|
BOOST_LOG_TRIVIAL(error) << "Unknown filament change step: " << static_cast<int>(step);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_filament_load_steps->AppendItem(iter->second);
|
||||||
|
m_filament_unload_steps->AppendItem(iter->second);
|
||||||
|
m_filament_vt_load_steps->AppendItem(iter->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout();
|
||||||
|
Fit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_ams_model == AMSModel::GENERIC_AMS || m_ext_model == AMSModel::N3F_AMS || m_ext_model == AMSModel::N3S_AMS) {
|
if (m_ams_model == AMSModel::GENERIC_AMS || m_ext_model == AMSModel::N3F_AMS || m_ext_model == AMSModel::N3S_AMS) {
|
||||||
if (has_fila_to_switch) {
|
if (has_fila_to_switch) {
|
||||||
m_filament_load_steps->AppendItem(FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_HEAT_NOZZLE]);
|
m_filament_load_steps->AppendItem(FILAMENT_CHANGE_STEP_STRING[FilamentStep::STEP_HEAT_NOZZLE]);
|
||||||
|
|||||||
@@ -35,6 +35,10 @@ protected:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
std::map<FilamentStep, wxString> FILAMENT_CHANGE_STEP_STRING;
|
std::map<FilamentStep, wxString> FILAMENT_CHANGE_STEP_STRING;
|
||||||
|
// Labels for the device-numbered steps reported by the AMS (ams.cfs). Keyed by the device
|
||||||
|
// enum, separate from the legacy FilamentStep map above. Only used when the AMS provides a
|
||||||
|
// step list; empty AMS list falls back to the legacy sequences below.
|
||||||
|
std::map<DevFilamentStep, wxString> DEV_FILAMENT_CHANGE_STEP_STRING;
|
||||||
AMSModel m_ams_model{ AMSModel::GENERIC_AMS };
|
AMSModel m_ams_model{ AMSModel::GENERIC_AMS };
|
||||||
AMSModel m_ext_model{ AMSModel::AMS_LITE };
|
AMSModel m_ext_model{ AMSModel::AMS_LITE };
|
||||||
AMSModel m_is_none_ams_mode{ AMSModel::AMS_LITE };
|
AMSModel m_is_none_ams_mode{ AMSModel::AMS_LITE };
|
||||||
@@ -44,7 +48,7 @@ public:
|
|||||||
void SetFilamentStep(FilamentStep item_idx, FilamentStepType f_type);
|
void SetFilamentStep(FilamentStep item_idx, FilamentStepType f_type);
|
||||||
void ShowFilamentTip(bool hasams = true);
|
void ShowFilamentTip(bool hasams = true);
|
||||||
|
|
||||||
void SetupSteps(bool is_extrusion_exist);
|
void SetupSteps(MachineObject* obj_, bool is_extrusion_exist);
|
||||||
|
|
||||||
void show_nofilament_mode(bool show);
|
void show_nofilament_mode(bool show);
|
||||||
void updateID(int ams_id, int slot_id) { m_ams_id = ams_id; m_slot_id = slot_id; };
|
void updateID(int ams_id, int slot_id) { m_ams_id = ams_id; m_slot_id = slot_id; };
|
||||||
|
|||||||
Reference in New Issue
Block a user