mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-06-22 03:36:36 +00:00
Implement deleted state for mixed filaments: Add a 'deleted' flag to the MixedFilament structure and update related parsing, serialization, and management functions to handle the visibility of mixed filaments in the UI. Adjust logic in the MixedFilamentManager to ensure proper handling of enabled states based on the deleted flag.
This commit is contained in:
79
CHANGELOG_v0.9.md
Normal file
79
CHANGELOG_v0.9.md
Normal file
@@ -0,0 +1,79 @@
|
||||
## v0.9 Pre-release
|
||||
|
||||
EXPERIMENTAL BUILD - LIMITED TESTING
|
||||
Based on Snapmaker Orca v2.2.4
|
||||
|
||||
v0.9 full spectrum pre-release focuses on mixed-filament workflow UX and stability.
|
||||
|
||||
### What's New in v0.9
|
||||
|
||||
#### Mixed Filaments UI/UX Overhaul (v0.9)
|
||||
- Replaced the blocking mixed-filament popup with an inline expand/retract editor.
|
||||
- Added row hover feedback and click-anywhere row activation for custom mixed filaments.
|
||||
- Added dynamic mixed-filament panel resizing with an expansion cap sized for up to two expanded rows.
|
||||
- Simplified editor flow to `Simple` mode only (mode selector removed from the inline editor).
|
||||
- Moved gradient selector inline with filament selectors for faster editing.
|
||||
- Reworked filament selectors into compact color swatch pickers with `F1/F2/...` labels.
|
||||
- Simplified pattern editing:
|
||||
- removed insert dropdown/button flow,
|
||||
- kept direct filament buttons for appending pattern tokens.
|
||||
- Moved preview labels into the preview bar itself (`Preview` + ratio overlay), with outlined text for readability.
|
||||
|
||||
#### Mixed Filaments Behavior and Reliability (v0.9)
|
||||
- Automatic mixed filaments are now read-only in the inline settings editor.
|
||||
- Automatic mixed filaments can now be deleted from the UI.
|
||||
- Added persistent deleted-state storage for mixed filament rows so deleted auto rows stay deleted after refresh/restart.
|
||||
- Excluded deleted rows from enabled/displayed virtual filament mapping.
|
||||
- Improved change propagation so mixed-filament edits correctly mark config/project dirty states.
|
||||
- Addressed mixed-filament editor collapse/refresh stability issues.
|
||||
|
||||
#### Local Z Dithering and Prime Tower Handling (v0.9)
|
||||
- Enhanced Local-Z phase-b tool change handling when wipe/prime tower is enabled.
|
||||
- Added an unplanned Local-Z tool-change path in wipe tower integration to emit proper tool-change/wipe G-code outside the preplanned per-layer sequence.
|
||||
- Enabled Local-Z phase-b execution with wipe tower active (still blocked when wiping overrides are active).
|
||||
- Restored pre-pass extruder state after Local-Z phase-b so subsequent wipe/prime tower planning remains synchronized.
|
||||
- Improved Local-Z + wipe tower diagnostics/fallback logging for troubleshooting.
|
||||
|
||||
#### Dark Mode and Visual Consistency (v0.9)
|
||||
- Added dark-mode-aware styling to mixed-filament rows and inline editor controls.
|
||||
- Fixed dark-mode text contrast for mixed-filament row labels and controls.
|
||||
- Updated gradient/preview border handling for better dark-mode contrast.
|
||||
|
||||
### Installation
|
||||
|
||||
#### Windows
|
||||
1. Download `Snapmaker_Orca.zip`.
|
||||
2. Extract to a folder.
|
||||
3. Run the executable.
|
||||
|
||||
#### macOS
|
||||
1. Download the macOS build (`arm64` for Apple Silicon or `x86_64` for Intel).
|
||||
2. If the release asset is a `.zip`, unzip it first.
|
||||
3. Open the `.dmg`.
|
||||
4. Drag `Snapmaker_Orca.app` into `Applications`.
|
||||
5. Launch the app from `Applications`.
|
||||
|
||||
#### Linux (AppImage)
|
||||
1. Download `Snapmaker_Orca_Linux_V2.2.4.AppImage`.
|
||||
2. Run `chmod +x Snapmaker_Orca_Linux_V2.2.4.AppImage`.
|
||||
3. Run `./Snapmaker_Orca_Linux_V2.2.4.AppImage`.
|
||||
|
||||
### Warning
|
||||
- Use at your own risk.
|
||||
- May produce incorrect G-code in edge cases.
|
||||
- Mixed-filament behavior is still experimental in some scenarios.
|
||||
- This release has had limited real-printer validation.
|
||||
|
||||
### Features Not Yet Fully Tested
|
||||
1. Mixed-filament editor behavior on all platform/theme combinations (Windows/macOS/Linux).
|
||||
2. Dark-mode visual consistency across all desktop environments.
|
||||
3. Mixed-filament preview/readability with all localization strings and scaling factors.
|
||||
|
||||
### Known Issues
|
||||
- On-screen color blend preview may not exactly match physical print results.
|
||||
- Some UI spacing/alignment may vary by OS and system font rendering.
|
||||
- Older Linux distributions may fail to run this AppImage due to glibc mismatch.
|
||||
|
||||
### Credits
|
||||
- FilamentMixer color blending integration is powered by the FilamentMixer library by [justinh-rahb](https://github.com/justinh-rahb).
|
||||
- Library repository: [https://github.com/justinh-rahb/filament-mixer](https://github.com/justinh-rahb/filament-mixer).
|
||||
@@ -308,7 +308,8 @@ static bool parse_row_definition(const std::string &row,
|
||||
std::string &gradient_component_ids,
|
||||
std::string &gradient_component_weights,
|
||||
std::string &manual_pattern,
|
||||
int &distribution_mode)
|
||||
int &distribution_mode,
|
||||
bool &deleted)
|
||||
{
|
||||
auto trim_copy = [](const std::string &s) {
|
||||
size_t lo = 0;
|
||||
@@ -373,6 +374,7 @@ static bool parse_row_definition(const std::string &row,
|
||||
gradient_component_weights.clear();
|
||||
manual_pattern.clear();
|
||||
distribution_mode = int(MixedFilament::Simple);
|
||||
deleted = false;
|
||||
|
||||
size_t token_idx = 5;
|
||||
if (tokens.size() >= 6) {
|
||||
@@ -410,6 +412,12 @@ static bool parse_row_definition(const std::string &row,
|
||||
distribution_mode = clamp_int(parsed_mode, int(MixedFilament::LayerCycle), int(MixedFilament::Simple));
|
||||
continue;
|
||||
}
|
||||
if (tok[0] == 'd' || tok[0] == 'D') {
|
||||
int parsed_deleted = deleted ? 1 : 0;
|
||||
if (parse_int_token(tok.substr(1), parsed_deleted))
|
||||
deleted = parsed_deleted != 0;
|
||||
continue;
|
||||
}
|
||||
manual_pattern = tok;
|
||||
}
|
||||
|
||||
@@ -686,6 +694,7 @@ void MixedFilamentManager::auto_generate(const std::vector<std::string> &filamen
|
||||
mf.ratio_b = 1;
|
||||
mf.mix_b_percent = 50;
|
||||
mf.enabled = true;
|
||||
mf.deleted = false;
|
||||
mf.custom = false;
|
||||
|
||||
// Try to preserve previous settings.
|
||||
@@ -694,6 +703,9 @@ void MixedFilamentManager::auto_generate(const std::vector<std::string> &filamen
|
||||
prev.component_a == mf.component_a &&
|
||||
prev.component_b == mf.component_b) {
|
||||
mf.enabled = prev.enabled;
|
||||
mf.deleted = prev.deleted;
|
||||
if (mf.deleted)
|
||||
mf.enabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -755,6 +767,7 @@ void MixedFilamentManager::add_custom_filament(unsigned int component_a,
|
||||
mf.pointillism_all_filaments = false;
|
||||
mf.distribution_mode = int(MixedFilament::Simple);
|
||||
mf.enabled = true;
|
||||
mf.deleted = false;
|
||||
mf.custom = true;
|
||||
m_mixed.push_back(std::move(mf));
|
||||
refresh_display_colors(filament_colours);
|
||||
@@ -823,7 +836,8 @@ std::string MixedFilamentManager::serialize_custom_entries() const
|
||||
<< (mf.pointillism_all_filaments ? 1 : 0) << ','
|
||||
<< 'g' << normalized_ids << ','
|
||||
<< 'w' << normalized_weights << ','
|
||||
<< 'm' << clamp_int(mf.distribution_mode, int(MixedFilament::LayerCycle), int(MixedFilament::Simple));
|
||||
<< 'm' << clamp_int(mf.distribution_mode, int(MixedFilament::LayerCycle), int(MixedFilament::Simple)) << ','
|
||||
<< 'd' << (mf.deleted ? 1 : 0);
|
||||
const std::string normalized_pattern = normalize_manual_pattern(mf.manual_pattern);
|
||||
if (!normalized_pattern.empty())
|
||||
ss << ',' << normalized_pattern;
|
||||
@@ -862,8 +876,9 @@ void MixedFilamentManager::load_custom_entries(const std::string &serialized, co
|
||||
std::string gradient_component_weights;
|
||||
std::string manual_pattern;
|
||||
int distribution_mode = int(MixedFilament::Simple);
|
||||
bool deleted = false;
|
||||
if (!parse_row_definition(row, a, b, enabled, custom, mix, pointillism_all_filaments,
|
||||
gradient_component_ids, gradient_component_weights, manual_pattern, distribution_mode)) {
|
||||
gradient_component_ids, gradient_component_weights, manual_pattern, distribution_mode, deleted)) {
|
||||
++skipped_rows;
|
||||
BOOST_LOG_TRIVIAL(warning) << "MixedFilamentManager::load_custom_entries invalid row format: " << row;
|
||||
continue;
|
||||
@@ -891,6 +906,9 @@ void MixedFilamentManager::load_custom_entries(const std::string &serialized, co
|
||||
it_auto->manual_pattern = normalize_manual_pattern(manual_pattern);
|
||||
it_auto->distribution_mode = clamp_int(distribution_mode, int(MixedFilament::LayerCycle), int(MixedFilament::Simple));
|
||||
it_auto->mix_b_percent = it_auto->manual_pattern.empty() ? mix : mix_percent_from_normalized_pattern(it_auto->manual_pattern);
|
||||
it_auto->deleted = deleted;
|
||||
if (it_auto->deleted)
|
||||
it_auto->enabled = false;
|
||||
++updated_auto;
|
||||
continue;
|
||||
}
|
||||
@@ -911,6 +929,9 @@ void MixedFilamentManager::load_custom_entries(const std::string &serialized, co
|
||||
if (!mf.manual_pattern.empty())
|
||||
mf.mix_b_percent = mix_percent_from_normalized_pattern(mf.manual_pattern);
|
||||
mf.enabled = enabled;
|
||||
mf.deleted = deleted;
|
||||
if (mf.deleted)
|
||||
mf.enabled = false;
|
||||
mf.custom = custom;
|
||||
m_mixed.push_back(std::move(mf));
|
||||
++loaded_rows;
|
||||
@@ -1005,7 +1026,7 @@ int MixedFilamentManager::mixed_index_from_filament_id(unsigned int filament_id,
|
||||
const size_t enabled_virtual_idx = size_t(filament_id - num_physical - 1);
|
||||
size_t enabled_seen = 0;
|
||||
for (size_t i = 0; i < m_mixed.size(); ++i) {
|
||||
if (!m_mixed[i].enabled)
|
||||
if (!m_mixed[i].enabled || m_mixed[i].deleted)
|
||||
continue;
|
||||
if (enabled_seen == enabled_virtual_idx)
|
||||
return int(i);
|
||||
@@ -1145,7 +1166,7 @@ size_t MixedFilamentManager::enabled_count() const
|
||||
{
|
||||
size_t count = 0;
|
||||
for (const auto &mf : m_mixed)
|
||||
if (mf.enabled)
|
||||
if (mf.enabled && !mf.deleted)
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
@@ -1154,7 +1175,7 @@ std::vector<std::string> MixedFilamentManager::display_colors() const
|
||||
{
|
||||
std::vector<std::string> colors;
|
||||
for (const auto &mf : m_mixed)
|
||||
if (mf.enabled)
|
||||
if (mf.enabled && !mf.deleted)
|
||||
colors.push_back(mf.display_color);
|
||||
return colors;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,9 @@ struct MixedFilament
|
||||
// Whether this mixed filament is enabled (available for assignment).
|
||||
bool enabled = true;
|
||||
|
||||
// True when this mixed filament row was deleted from UI and should stay hidden.
|
||||
bool deleted = false;
|
||||
|
||||
// True when this row was user-created (custom) instead of auto-generated.
|
||||
bool custom = false;
|
||||
|
||||
@@ -78,6 +81,7 @@ struct MixedFilament
|
||||
pointillism_all_filaments == rhs.pointillism_all_filaments &&
|
||||
distribution_mode == rhs.distribution_mode &&
|
||||
enabled == rhs.enabled &&
|
||||
deleted == rhs.deleted &&
|
||||
custom == rhs.custom;
|
||||
}
|
||||
bool operator!=(const MixedFilament &rhs) const { return !(*this == rhs); }
|
||||
|
||||
@@ -1219,14 +1219,22 @@ void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* con
|
||||
if (filamemts_opt == nullptr)
|
||||
return;
|
||||
|
||||
size_t colors_count = (size_t) filamemts_opt->values.size();
|
||||
if (colors_count == 0)
|
||||
std::vector<std::string> filament_colors = filamemts_opt->values;
|
||||
if (filament_colors.empty())
|
||||
return;
|
||||
colors.resize(colors_count);
|
||||
|
||||
for (unsigned int i = 0; i < colors_count; ++i) {
|
||||
// Include enabled mixed (virtual) filament colors so volume extruder IDs
|
||||
// assigned to mixed rows render correctly in Prepare view.
|
||||
if (GUI::wxGetApp().preset_bundle != nullptr) {
|
||||
const auto mixed_colors = GUI::wxGetApp().preset_bundle->mixed_filaments.display_colors();
|
||||
filament_colors.insert(filament_colors.end(), mixed_colors.begin(), mixed_colors.end());
|
||||
}
|
||||
|
||||
colors.resize(filament_colors.size());
|
||||
|
||||
for (size_t i = 0; i < filament_colors.size(); ++i) {
|
||||
ColorRGBA rgba;
|
||||
const std::string& fil_color = config->opt_string("filament_colour", i);
|
||||
const std::string& fil_color = filament_colors[i];
|
||||
if (decode_color(fil_color, rgba))
|
||||
colors[i] = {fil_color, rgba};
|
||||
}
|
||||
|
||||
@@ -36,9 +36,41 @@ static PrinterTechnology printer_technology()
|
||||
return wxGetApp().preset_bundle->printers.get_selected_preset().printer_technology();
|
||||
}
|
||||
|
||||
static int physical_filaments_count()
|
||||
{
|
||||
return std::max(wxGetApp().filaments_cnt(), 0);
|
||||
}
|
||||
|
||||
static int filaments_count()
|
||||
{
|
||||
return wxGetApp().filaments_cnt();
|
||||
if (wxGetApp().preset_bundle == nullptr)
|
||||
return 0;
|
||||
const int physical = physical_filaments_count();
|
||||
const auto &mixed_mgr = wxGetApp().preset_bundle->mixed_filaments;
|
||||
return static_cast<int>(mixed_mgr.total_filaments(size_t(physical)));
|
||||
}
|
||||
|
||||
static wxString filament_menu_item_name(const int filament_id_1based)
|
||||
{
|
||||
if (filament_id_1based <= 0)
|
||||
return _L("Default");
|
||||
|
||||
if (wxGetApp().preset_bundle == nullptr)
|
||||
return wxString::Format(_L("Filament %d"), filament_id_1based);
|
||||
|
||||
const int physical = physical_filaments_count();
|
||||
if (filament_id_1based <= physical) {
|
||||
const size_t preset_idx = size_t(filament_id_1based - 1);
|
||||
const auto &filament_presets = wxGetApp().preset_bundle->filament_presets;
|
||||
if (preset_idx < filament_presets.size()) {
|
||||
auto preset = wxGetApp().preset_bundle->filaments.find_preset(filament_presets[preset_idx]);
|
||||
if (preset != nullptr)
|
||||
return from_u8(preset->label(false));
|
||||
}
|
||||
return wxString::Format(_L("Filament %d"), filament_id_1based);
|
||||
}
|
||||
|
||||
return wxString::Format(_L("Mixed Filament %d"), filament_id_1based);
|
||||
}
|
||||
|
||||
static bool is_improper_category(const std::string& category, const int filaments_cnt, const bool is_object_settings = true)
|
||||
@@ -905,16 +937,7 @@ void MenuFactory::append_menu_item_change_extruder(wxMenu* menu)
|
||||
bool is_active_extruder = i == initial_extruder;
|
||||
int icon_idx = i == 0 ? 0 : i - 1;
|
||||
|
||||
wxString item_name = _L("Default");
|
||||
|
||||
if (i > 0) {
|
||||
auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i - 1]);
|
||||
if (preset == nullptr) {
|
||||
item_name = wxString::Format(_L("Filament %d"), i);
|
||||
} else {
|
||||
item_name = from_u8(preset->label(false));
|
||||
}
|
||||
}
|
||||
wxString item_name = filament_menu_item_name(i);
|
||||
|
||||
if (is_active_extruder) {
|
||||
item_name << " (" + _L("current") + ")";
|
||||
@@ -1994,16 +2017,7 @@ void MenuFactory::append_menu_item_change_filament(wxMenu* menu)
|
||||
//bool is_active_extruder = i == initial_extruder;
|
||||
bool is_active_extruder = false;
|
||||
|
||||
wxString item_name = _L("Default");
|
||||
|
||||
if (i > 0) {
|
||||
auto preset = wxGetApp().preset_bundle->filaments.find_preset(wxGetApp().preset_bundle->filament_presets[i - 1]);
|
||||
if (preset == nullptr) {
|
||||
item_name = wxString::Format(_L("Filament %d"), i);
|
||||
} else {
|
||||
item_name = from_u8(preset->label(false));
|
||||
}
|
||||
}
|
||||
wxString item_name = filament_menu_item_name(i);
|
||||
|
||||
if (is_active_extruder) {
|
||||
item_name << " (" + _L("current") + ")";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user