This commit is contained in:
Ocraftyone 2026-03-15 12:08:22 -04:00 committed by GitHub
commit cb6eaa3c65
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 779 additions and 219 deletions

View file

@ -74,6 +74,23 @@
#define CLI_GCODE_PATH_IN_UNPRINTABLE_AREA -102
#ifdef _WIN32
#define PUSH_IGNORE_DEPRECATED \
_Pragma("warning(push)") \
_Pragma("warning(disable: 4996)")
#else
#define PUSH_IGNORE_DEPRECATED \
_Pragma("GCC diagnostic push")\
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
#endif
#ifdef _WIN32
#define POP_IGNORE_DEPRECATED \
_Pragma("warning(pop)")
#else
#define PUSH_IGNORE_DEPRECATED \
_Pragma("GCC diagnostic pop")
#endif
namespace boost { namespace filesystem { class directory_entry; }}
namespace Slic3r {

View file

@ -649,6 +649,8 @@ set(SLIC3R_GUI_SOURCES
Utils/WxFontUtils.hpp
Utils/FileTransferUtils.cpp
Utils/FileTransferUtils.hpp
GUI/ToggleExpr.cpp
GUI/ToggleExpr.hpp
)
add_subdirectory(GUI/DeviceCore)

View file

@ -36,22 +36,22 @@ t_config_option_keys const &ConfigManipulation::applying_keys() const
return m_applying_keys;
}
void ConfigManipulation::toggle_field(const std::string &opt_key, const bool toggle, int opt_index /* = -1*/)
void ConfigManipulation::toggle_field(const std::string &opt_key, const ToggleExpr& toggle_expr, int opt_index /* = -1*/)
{
if (local_config) {
if (local_config->option(opt_key) == nullptr) return;
}
cb_toggle_field(opt_key, toggle, opt_index);
cb_toggle_field(opt_key, toggle_expr, opt_index);
}
void ConfigManipulation::toggle_line(const std::string& opt_key, const bool toggle, int opt_index)
void ConfigManipulation::toggle_line(const std::string& opt_key, const ToggleExpr& toggle_expr, int opt_index)
{
if (local_config) {
if (local_config->option(opt_key) == nullptr)
return;
}
if (cb_toggle_line)
cb_toggle_line(opt_key, toggle, opt_index);
cb_toggle_line(opt_key, toggle_expr, opt_index);
}
void ConfigManipulation::check_nozzle_recommended_temperature_range(DynamicPrintConfig *config) {
@ -572,10 +572,11 @@ void ConfigManipulation::apply_null_fff_config(DynamicPrintConfig *config, std::
void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, const bool is_global_config)
{
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
auto is_global_config_te = ToggleExpr(is_global_config, "Editing").set_postfixes("object config", "global config");
auto gcflavor = preset_bundle->printers.get_edited_preset().config.option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
const auto gcflavor = ToggleExpr::FromConfigEnum<GCodeFlavor>(&preset_bundle->printers.get_edited_preset().config, "gcode_flavor");
bool have_volumetric_extrusion_rate_slope = config->option<ConfigOptionFloat>("max_volumetric_extrusion_rate_slope")->value > 0;
auto have_volumetric_extrusion_rate_slope = ToggleExpr::FromConfigFloat(config, "max_volumetric_extrusion_rate_slope") > 0;
float have_volumetric_extrusion_rate_slope_segment_length = config->option<ConfigOptionFloat>("max_volumetric_extrusion_rate_slope_segment_length")->value;
toggle_field("enable_arc_fitting", !have_volumetric_extrusion_rate_slope);
toggle_line("max_volumetric_extrusion_rate_slope_segment_length", have_volumetric_extrusion_rate_slope);
@ -587,66 +588,67 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
apply(config, &new_conf);
}
bool have_perimeters = config->opt_int("wall_loops") > 0;
auto have_perimeters = ToggleExpr::FromConfigInt(config, "wall_loops") > 0;
for (auto el : { "extra_perimeters_on_overhangs", "ensure_vertical_shell_thickness", "detect_thin_wall", "detect_overhang_wall",
"seam_position", "staggered_inner_seams", "wall_sequence", "outer_wall_line_width",
"inner_wall_speed", "outer_wall_speed", "small_perimeter_speed", "small_perimeter_threshold" })
toggle_field(el, have_perimeters);
bool have_infill = config->option<ConfigOptionPercent>("sparse_infill_density")->value > 0;
auto have_infill = ToggleExpr::FromConfigFloat(config, "sparse_infill_density") > 0;
// sparse_infill_filament uses the same logic as in Print::extruders()
for (auto el : { "sparse_infill_pattern", "infill_combination", "fill_multiline","infill_direction",
"minimum_sparse_infill_area", "sparse_infill_filament", "infill_anchor", "infill_anchor_max","infill_shift_step","sparse_infill_rotate_template","symmetric_infill_y_axis"})
toggle_line(el, have_infill);
bool have_combined_infill = config->opt_bool("infill_combination") && have_infill;
auto have_combined_infill = ToggleExpr::FromConfigBool(config, "infill_combination") && have_infill;
toggle_line("infill_combination_max_layer_height", have_combined_infill);
// Infill patterns that support multiline infill.
InfillPattern pattern = config->opt_enum<InfillPattern>("sparse_infill_pattern");
bool have_multiline_infill_pattern = pattern == ipGyroid || pattern == ipGrid || pattern == ipRectilinear || pattern == ipTpmsD || pattern == ipTpmsFK || pattern == ipCrossHatch || pattern == ipHoneycomb || pattern == ipLateralLattice || pattern == ipLateralHoneycomb || pattern == ipConcentric ||
pattern == ipCubic || pattern == ipStars || pattern == ipAlignedRectilinear || pattern == ipLightning || pattern == ip3DHoneycomb || pattern == ipAdaptiveCubic || pattern == ipSupportCubic|| pattern == ipTriangles || pattern == ipQuarterCubic|| pattern == ipArchimedeanChords || pattern == ipHilbertCurve || pattern == ipOctagramSpiral;
auto pattern = ToggleExpr::FromConfigEnum<InfillPattern>(config, "sparse_infill_pattern");
auto pattern_e = config->opt_enum<InfillPattern>("sparse_infill_pattern");
auto non_multiline_infill_pattern = pattern == ipCrossHatch || pattern == ipLine ||
pattern == ipLockedZag || pattern == ipMonotonic || pattern == ipMonotonicLine || pattern == ipZigZag ||
ToggleExpr(pattern_e == ipConcentricInternal || pattern_e == ipSupportBase, "");
// If there is infill, enable/disable fill_multiline according to whether the pattern supports multiline infill.
if (have_infill) {
toggle_field("fill_multiline", have_multiline_infill_pattern);
toggle_field("fill_multiline", !non_multiline_infill_pattern);
// If the infill pattern does not support multiline fill_multiline is changed to 1.
// Necessary when the pattern contains params.multiline (for example, triangles because they belong to the rectilinear class)
if (!have_multiline_infill_pattern) {
if (non_multiline_infill_pattern) {
DynamicPrintConfig new_conf = *config;
new_conf.set_key_value("fill_multiline", new ConfigOptionInt(1));
apply(config, &new_conf);
}
// Hide infill anchor max if sparse_infill_pattern is not line or if sparse_infill_pattern is line but infill_anchor_max is 0.
bool infill_anchor = config->opt_enum<InfillPattern>("sparse_infill_pattern") != ipLine;
auto infill_anchor = ToggleExpr::FromConfigEnum<InfillPattern>(config, "sparse_infill_pattern") != ipLine;
toggle_field("infill_anchor_max", infill_anchor);
// Only allow configuration of open anchors if the anchoring is enabled.
bool has_infill_anchors = infill_anchor && config->option<ConfigOptionFloatOrPercent>("infill_anchor_max")->value > 0;
auto has_infill_anchors = infill_anchor && ToggleExpr::FromConfigFloat(config, "infill_anchor_max", CompareType::GT, 0);
toggle_field("infill_anchor", has_infill_anchors);
}
//cross zag
bool is_cross_zag = config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value == InfillPattern::ipCrossZag;
bool is_locked_zig = config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value == InfillPattern::ipLockedZag;
auto is_cross_zag = ToggleExpr::FromConfigEnum<InfillPattern>(config, "sparse_infill_pattern") == InfillPattern::ipCrossZag;
auto is_locked_zig = ToggleExpr::FromConfigEnum<InfillPattern>(config, "sparse_infill_pattern") == InfillPattern::ipLockedZag;
toggle_line("infill_shift_step", is_cross_zag || is_locked_zig);
for (auto el : { "skeleton_infill_density", "skin_infill_density", "infill_lock_depth", "skin_infill_depth","skin_infill_line_width", "skeleton_infill_line_width" })
toggle_line(el, is_locked_zig);
bool is_zig_zag = config->option<ConfigOptionEnum<InfillPattern>>("sparse_infill_pattern")->value == InfillPattern::ipZigZag;
auto is_zig_zag = ToggleExpr::FromConfigEnum<InfillPattern>(config, "sparse_infill_pattern") == InfillPattern::ipZigZag;
toggle_line("symmetric_infill_y_axis", is_zig_zag || is_cross_zag || is_locked_zig);
bool has_spiral_vase = config->opt_bool("spiral_mode");
auto has_spiral_vase = ToggleExpr::FromConfigBool(config, "spiral_mode");
toggle_line("spiral_mode_smooth", has_spiral_vase);
toggle_line("spiral_mode_max_xy_smoothing", has_spiral_vase && config->opt_bool("spiral_mode_smooth"));
toggle_line("spiral_mode_max_xy_smoothing", has_spiral_vase && ToggleExpr::FromConfigBool(config, "spiral_mode_smooth"));
toggle_line("spiral_starting_flow_ratio", has_spiral_vase);
toggle_line("spiral_finishing_flow_ratio", has_spiral_vase);
bool has_top_shell = config->opt_int("top_shell_layers") > 0 || (has_spiral_vase && config->opt_int("bottom_shell_layers") > 1);
bool has_bottom_shell = config->opt_int("bottom_shell_layers") > 0;
bool has_solid_infill = has_top_shell || has_bottom_shell;
auto has_top_shell = ToggleExpr::FromConfigInt(config, "top_shell_layers") > 0 || (has_spiral_vase && ToggleExpr::FromConfigInt(config, "bottom_shell_layers") > 1);
auto has_bottom_shell = ToggleExpr::FromConfigInt(config, "bottom_shell_layers") > 0;
auto has_solid_infill = has_top_shell || has_bottom_shell;
toggle_field("top_surface_pattern", has_top_shell);
toggle_field("bottom_surface_pattern", has_bottom_shell);
toggle_field("top_surface_density", has_top_shell);
@ -669,68 +671,61 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
for (auto el : { "top_surface_line_width", "top_surface_speed" })
toggle_field(el, has_top_shell);
bool have_default_acceleration = config->opt_float("default_acceleration") > 0;
auto have_default_acceleration = ToggleExpr::FromConfigFloat(config, "default_acceleration") > 0;
for (auto el : {"outer_wall_acceleration", "inner_wall_acceleration", "initial_layer_acceleration",
"top_surface_acceleration", "travel_acceleration", "bridge_acceleration", "sparse_infill_acceleration", "internal_solid_infill_acceleration"})
toggle_field(el, have_default_acceleration);
bool machine_supports_junction_deviation = false;
if (gcflavor == gcfMarlinFirmware) {
auto machine_supports_junction_deviation = gcflavor == gcfMarlinFirmware;
if (machine_supports_junction_deviation) {
if (const auto *machine_jd = preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("machine_max_junction_deviation")) {
machine_supports_junction_deviation = !machine_jd->values.empty() && machine_jd->values.front() > 0.0;
machine_supports_junction_deviation = ToggleExpr(!machine_jd->values.empty(), "machine_max_junction_deviation is not set").disable_postfix() && ToggleExpr(machine_jd->values.front() > 0.0, "machine_max_junction_deviation[0]") > 0;
}
}
toggle_line("default_junction_deviation", gcflavor == gcfMarlinFirmware);
if (machine_supports_junction_deviation) {
toggle_field("default_junction_deviation", true);
toggle_field("default_jerk", false);
for (auto el : { "outer_wall_jerk", "inner_wall_jerk", "initial_layer_jerk", "top_surface_jerk", "travel_jerk", "infill_jerk"})
toggle_line(el, false);
} else {
toggle_field("default_junction_deviation", false);
toggle_field("default_jerk", true);
bool have_default_jerk = config->has("default_jerk") && config->opt_float("default_jerk") > 0;
for (auto el : { "outer_wall_jerk", "inner_wall_jerk", "initial_layer_jerk", "top_surface_jerk", "travel_jerk", "infill_jerk"}) {
toggle_line(el, true);
toggle_field("default_junction_deviation", machine_supports_junction_deviation);
toggle_field("default_jerk", !machine_supports_junction_deviation);
ToggleExpr have_default_jerk = ToggleExpr(config->has("default_jerk") && config->opt_float("default_jerk") > 0, "default_jerk") > "0";
for (auto el : { "outer_wall_jerk", "inner_wall_jerk", "initial_layer_jerk", "top_surface_jerk", "travel_jerk", "infill_jerk"}) {
toggle_line(el, !machine_supports_junction_deviation);
if (machine_supports_junction_deviation)
toggle_field(el, have_default_jerk);
}
}
bool have_skirt = config->opt_int("skirt_loops") > 0;
toggle_field("skirt_height", have_skirt && config->opt_enum<DraftShield>("draft_shield") != dsEnabled);
auto have_skirt = ToggleExpr::FromConfigInt(config, "skirt_loops") > 0;
toggle_field("skirt_height", have_skirt && ToggleExpr::FromConfigEnum<DraftShield>(config, "draft_shield") != dsEnabled);
toggle_line("single_loop_draft_shield", have_skirt); // ORCA: Display one wall if skirt enabled
for (auto el : {"skirt_type", "min_skirt_length", "skirt_distance", "skirt_start_angle", "skirt_speed", "draft_shield"})
toggle_field(el, have_skirt);
bool have_brim = (config->opt_enum<BrimType>("brim_type") != btNoBrim);
auto have_brim = ToggleExpr::FromConfigEnum<BrimType>(config, "brim_type") != btNoBrim;
toggle_field("brim_object_gap", have_brim);
toggle_field("brim_use_efc_outline", have_brim);
bool have_brim_width = (config->opt_enum<BrimType>("brim_type") != btNoBrim) && config->opt_enum<BrimType>("brim_type") != btAutoBrim &&
config->opt_enum<BrimType>("brim_type") != btPainted;
auto have_brim_width = ToggleExpr::FromConfigEnum<BrimType>(config, "brim_type") != btNoBrim && ToggleExpr::FromConfigEnum<BrimType>(config, "brim_type") != btAutoBrim &&
ToggleExpr::FromConfigEnum<BrimType>(config, "brim_type") != btPainted;
toggle_field("brim_width", have_brim_width);
// wall_filament uses the same logic as in Print::extruders()
toggle_field("wall_filament", have_perimeters || have_brim);
bool have_brim_ear = (config->opt_enum<BrimType>("brim_type") == btEar);
const auto brim_width = config->opt_float("brim_width");
auto have_brim_ear = ToggleExpr::FromConfigEnum<BrimType>(config, "brim_type") == btEar;
auto brim_width_valid = ToggleExpr::FromConfigFloat(config, "brim_width") > 0.0f;
// disable brim_ears_max_angle and brim_ears_detection_length if brim_width is 0
toggle_field("brim_ears_max_angle", brim_width > 0.0f);
toggle_field("brim_ears_detection_length", brim_width > 0.0f);
toggle_field("brim_ears_max_angle", brim_width_valid);
toggle_field("brim_ears_detection_length", brim_width_valid);
// hide brim_ears_max_angle and brim_ears_detection_length if brim_ear is not selected
toggle_line("brim_ears_max_angle", have_brim_ear);
toggle_line("brim_ears_detection_length", have_brim_ear);
// Hide Elephant foot compensation layers if elefant_foot_compensation is not enabled
toggle_line("elefant_foot_compensation_layers", config->opt_float("elefant_foot_compensation") > 0);
toggle_line("elefant_foot_compensation_layers", ToggleExpr::FromConfigFloat(config, "elefant_foot_compensation") > 0);
bool have_raft = config->opt_int("raft_layers") > 0;
bool have_support_material = config->opt_bool("enable_support") || have_raft;
auto have_raft = ToggleExpr::FromConfigInt(config, "raft_layers") > 0;
auto have_support_material = ToggleExpr::FromConfigBool(config, "enable_support") || have_raft;
SupportType support_type = config->opt_enum<SupportType>("support_type");
bool have_support_interface = config->opt_int("support_interface_top_layers") > 0 || config->opt_int("support_interface_bottom_layers") > 0;
bool have_support_soluble = have_support_material && config->opt_float("support_top_z_distance") == 0;
auto support_style = config->opt_enum<SupportMaterialStyle>("support_style");
auto have_support_interface = ToggleExpr::FromConfigInt(config, "support_interface_top_layers") > 0 || ToggleExpr::FromConfigInt(config, "support_interface_bottom_layers") > 0;
auto have_support_soluble = have_support_material && ToggleExpr::FromConfigFloat(config, "support_top_z_distance") == 0;
const auto support_style = ToggleExpr::FromConfigEnum<SupportMaterialStyle>(config, "support_style");
for (auto el : { "support_style", "support_base_pattern",
"support_base_pattern_spacing", "support_expansion", "support_angle",
"support_interface_pattern", "support_interface_top_layers", "support_interface_bottom_layers",
@ -738,15 +733,16 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
"support_type", "support_on_build_plate_only", "support_critical_regions_only", "support_interface_not_for_body",
"support_object_xy_distance", "support_object_first_layer_gap", "independent_support_layer_height"})
toggle_field(el, have_support_material);
toggle_field("support_threshold_angle", have_support_material && is_auto(support_type));
toggle_field("support_threshold_overlap", config->opt_int("support_threshold_angle") == 0 && have_support_material && is_auto(support_type));
auto is_auto_tree = ToggleExpr(is_auto(support_type), "Is not auto support type").disable_postfix();
toggle_field("support_threshold_angle", have_support_material && is_auto_tree);
toggle_field("support_threshold_overlap", ToggleExpr::FromConfigInt(config, "support_threshold_angle") == 0 && have_support_material && is_auto_tree);
//toggle_field("support_closing_radius", have_support_material && support_style == smsSnug);
bool support_is_tree = config->opt_bool("enable_support") && is_tree(support_type);
bool support_is_normal_tree = support_is_tree && support_style != smsTreeOrganic &&
auto support_is_tree = ToggleExpr::FromConfigBool(config, "enable_support") && ToggleExpr(is_tree(support_type), "Is not tree support type").disable_postfix();
auto support_is_normal_tree = support_is_tree && support_style != smsTreeOrganic &&
// Orca: use organic as default
support_style != smsDefault;
bool support_is_organic = support_is_tree && !support_is_normal_tree;
auto support_is_organic = support_is_tree && !support_is_normal_tree;
// settings shared by normal and organic trees
for (auto el : {"tree_support_branch_angle", "tree_support_branch_distance", "tree_support_branch_diameter" })
toggle_line(el, support_is_normal_tree);
@ -757,19 +753,19 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
for (auto el : {"tree_support_branch_angle_organic", "tree_support_branch_distance_organic", "tree_support_branch_diameter_organic", "tree_support_angle_slow", "tree_support_tip_diameter", "tree_support_top_rate", "tree_support_branch_diameter_angle"})
toggle_line(el, support_is_organic);
toggle_field("tree_support_brim_width", support_is_tree && !config->opt_bool("tree_support_auto_brim"));
toggle_field("tree_support_brim_width", support_is_tree && !ToggleExpr::FromConfigBool(config, "tree_support_auto_brim"));
// tree support use max_bridge_length instead of bridge_no_support
toggle_line("max_bridge_length", support_is_tree);
toggle_line("bridge_no_support", !support_is_tree);
toggle_line("support_critical_regions_only", is_auto(support_type) && support_is_tree);
toggle_line("support_critical_regions_only", is_auto_tree && support_is_tree);
for (auto el : { "support_interface_filament",
"support_interface_loop_pattern", "support_bottom_interface_spacing" })
toggle_field(el, have_support_material && have_support_interface);
bool can_ironing_support = have_raft || (have_support_material && config->opt_int("support_interface_top_layers") > 0);
auto can_ironing_support = have_raft || (have_support_material && ToggleExpr::FromConfigInt(config, "support_interface_top_layers") > 0);
toggle_field("support_ironing", can_ironing_support);
bool has_support_ironing = can_ironing_support && config->opt_bool("support_ironing");
auto has_support_ironing = can_ironing_support && ToggleExpr::FromConfigBool(config, "support_ironing");
for (auto el : {"support_ironing_pattern", "support_ironing_flow", "support_ironing_spacing" })
toggle_line(el, has_support_ironing);
// Orca: Force solid support interface when using support ironing
@ -793,137 +789,138 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
for (auto el : { "raft_first_layer_expansion", "raft_first_layer_density"})
toggle_field(el, have_support_material && !(support_is_normal_tree && !have_raft));
bool has_ironing = (config->opt_enum<IroningType>("ironing_type") != IroningType::NoIroning);
auto has_ironing = ToggleExpr::FromConfigEnum<IroningType>(config, "ironing_type") != IroningType::NoIroning;
for (auto el : { "ironing_pattern", "ironing_flow", "ironing_spacing", "ironing_angle", "ironing_inset", "ironing_angle_fixed" })
toggle_line(el, has_ironing);
toggle_line("ironing_speed", has_ironing || has_support_ironing);
bool have_sequential_printing = (config->opt_enum<PrintSequence>("print_sequence") == PrintSequence::ByObject);
auto have_sequential_printing = ToggleExpr::FromConfigEnum<PrintSequence>(config, "print_sequence") == PrintSequence::ByObject;
// for (auto el : { "extruder_clearance_radius", "extruder_clearance_height_to_rod", "extruder_clearance_height_to_lid" })
// toggle_field(el, have_sequential_printing);
toggle_field("print_order", !have_sequential_printing);
toggle_field("single_extruder_multi_material", !is_BBL_Printer);
auto is_BBL_printer = ToggleExpr(is_BBL_Printer, "BBL printer").set_prefixes("Isn't", "Is").disable_postfix();
toggle_field("single_extruder_multi_material", !is_BBL_printer);
auto bSEMM = preset_bundle->printers.get_edited_preset().config.opt_bool("single_extruder_multi_material");
auto bSEMM = ToggleExpr::FromConfigBool(&preset_bundle->printers.get_edited_preset().config, "single_extruder_multi_material");
toggle_field("ooze_prevention", !bSEMM);
bool have_ooze_prevention = config->opt_bool("ooze_prevention");
auto have_ooze_prevention = ToggleExpr::FromConfigBool(config, "ooze_prevention");
toggle_line("standby_temperature_delta", have_ooze_prevention);
toggle_line("preheat_time", have_ooze_prevention);
int preheat_steps = config->opt_int("preheat_steps");
const auto preheat_steps = ToggleExpr::FromConfigInt(config, "preheat_steps");
toggle_line("preheat_steps", have_ooze_prevention && (preheat_steps > 0));
bool have_prime_tower = config->opt_bool("enable_prime_tower");
auto have_prime_tower = ToggleExpr::FromConfigBool(config, "enable_prime_tower");
for (auto el : {"prime_tower_width", "prime_tower_brim_width", "prime_tower_skip_points", "wipe_tower_wall_type", "prime_tower_infill_gap","prime_tower_enable_framework", "enable_tower_interface_features"})
toggle_line(el, have_prime_tower);
toggle_line("enable_tower_interface_cooldown_during_tower",
have_prime_tower && config->opt_bool("enable_tower_interface_features"));
have_prime_tower && ToggleExpr::FromConfigBool(config, "enable_tower_interface_features"));
for (auto el : {"wall_filament", "sparse_infill_filament", "solid_infill_filament", "wipe_tower_filament"})
toggle_line(el, !bSEMM);
bool purge_in_primetower = preset_bundle->printers.get_edited_preset().config.opt_bool("purge_in_prime_tower");
auto purge_in_primetower = ToggleExpr::FromConfigBool(&preset_bundle->printers.get_edited_preset().config, "purge_in_prime_tower");
for (auto el : {"wipe_tower_rotation_angle", "wipe_tower_cone_angle",
"wipe_tower_extra_spacing", "wipe_tower_max_purge_speed",
"wipe_tower_bridging", "wipe_tower_extra_flow",
"wipe_tower_no_sparse_layers"})
toggle_line(el, have_prime_tower && !is_BBL_Printer);
toggle_line(el, have_prime_tower && !is_BBL_printer);
WipeTowerWallType wipe_tower_wall_type = config->opt_enum<WipeTowerWallType>("wipe_tower_wall_type");
bool have_rib_wall = (wipe_tower_wall_type == WipeTowerWallType::wtwRib)&&have_prime_tower;
toggle_line("wipe_tower_cone_angle", have_prime_tower && !is_BBL_Printer && wipe_tower_wall_type == WipeTowerWallType::wtwCone);
const auto wipe_tower_wall_type = ToggleExpr::FromConfigEnum<WipeTowerWallType>(config,"wipe_tower_wall_type");
auto have_rib_wall = (wipe_tower_wall_type == WipeTowerWallType::wtwRib)&&have_prime_tower;
toggle_line("wipe_tower_cone_angle", have_prime_tower && !is_BBL_printer && wipe_tower_wall_type == WipeTowerWallType::wtwCone);
toggle_line("wipe_tower_extra_rib_length", have_rib_wall);
toggle_line("wipe_tower_rib_width", have_rib_wall);
toggle_line("wipe_tower_fillet_wall", have_rib_wall);
toggle_field("prime_tower_width", have_prime_tower && !(is_BBL_Printer && have_rib_wall));
toggle_field("prime_tower_width", have_prime_tower && !(is_BBL_printer && have_rib_wall));
toggle_line("single_extruder_multi_material_priming", !bSEMM && have_prime_tower && !is_BBL_Printer);
toggle_line("single_extruder_multi_material_priming", !bSEMM && have_prime_tower && !is_BBL_printer);
toggle_line("prime_volume",have_prime_tower && (!purge_in_primetower || !bSEMM));
for (auto el : {"flush_into_infill", "flush_into_support", "flush_into_objects"})
toggle_field(el, have_prime_tower);
bool have_avoid_crossing_perimeters = config->opt_bool("reduce_crossing_wall");
auto have_avoid_crossing_perimeters = ToggleExpr::FromConfigBool(config, "reduce_crossing_wall");
toggle_line("max_travel_detour_distance", have_avoid_crossing_perimeters);
bool has_set_other_flow_ratios = config->opt_bool("set_other_flow_ratios");
auto has_set_other_flow_ratios = ToggleExpr::FromConfigBool(config, "set_other_flow_ratios");
for (auto el : {"first_layer_flow_ratio", "outer_wall_flow_ratio", "inner_wall_flow_ratio", "overhang_flow_ratio", "sparse_infill_flow_ratio", "internal_solid_infill_flow_ratio", "gap_fill_flow_ratio", "support_flow_ratio", "support_interface_flow_ratio"})
toggle_line(el, has_set_other_flow_ratios);
bool has_overhang_speed = config->opt_bool("enable_overhang_speed");
auto has_overhang_speed = ToggleExpr::FromConfigBool(config, "enable_overhang_speed");
for (auto el : {"overhang_1_4_speed", "overhang_2_4_speed", "overhang_3_4_speed", "overhang_4_4_speed"})
toggle_line(el, has_overhang_speed);
toggle_line("slowdown_for_curled_perimeters", has_overhang_speed);
toggle_line("flush_into_objects", !is_global_config);
toggle_line("flush_into_objects", !is_global_config_te);
toggle_line("support_interface_not_for_body",config->opt_int("support_interface_filament")&&!config->opt_int("support_filament"));
toggle_line("support_interface_not_for_body",ToggleExpr::FromConfigInt(config, "support_interface_filament") != 0 && ToggleExpr::FromConfigInt(config, "support_filament") == 0);
// Get the current fuzzy skin state
bool has_fuzzy_skin = config->opt_enum<FuzzySkinType>("fuzzy_skin") != FuzzySkinType::Disabled_fuzzy;
auto has_fuzzy_skin = ToggleExpr::FromConfigEnum<FuzzySkinType>(config, "fuzzy_skin") != FuzzySkinType::Disabled_fuzzy;
// Show fuzzy skin options when fuzzy skin is not disabled
for (auto el : {"fuzzy_skin_mode", "fuzzy_skin_noise_type", "fuzzy_skin_point_distance", "fuzzy_skin_thickness", "fuzzy_skin_first_layer"})
toggle_line(el, has_fuzzy_skin);
// Show noise type specific options with the same logic
NoiseType fuzzy_skin_noise_type = config->opt_enum<NoiseType>("fuzzy_skin_noise_type");
const auto fuzzy_skin_noise_type = ToggleExpr::FromConfigEnum<NoiseType>(config, "fuzzy_skin_noise_type");
toggle_line("fuzzy_skin_scale", fuzzy_skin_noise_type != NoiseType::Classic && has_fuzzy_skin);
toggle_line("fuzzy_skin_octaves", fuzzy_skin_noise_type != NoiseType::Classic && fuzzy_skin_noise_type != NoiseType::Voronoi && has_fuzzy_skin);
toggle_line("fuzzy_skin_persistence", (fuzzy_skin_noise_type == NoiseType::Perlin || fuzzy_skin_noise_type == NoiseType::Billow) && has_fuzzy_skin);
bool have_arachne = config->opt_enum<PerimeterGeneratorType>("wall_generator") == PerimeterGeneratorType::Arachne;
auto have_arachne = ToggleExpr::FromConfigEnum<PerimeterGeneratorType>(config, "wall_generator") == PerimeterGeneratorType::Arachne;
for (auto el : {"wall_transition_length", "wall_transition_filter_deviation", "wall_transition_angle",
"min_feature_size", "min_length_factor", "min_bead_width", "wall_distribution_count", "initial_layer_min_bead_width"})
toggle_line(el, have_arachne);
toggle_field("detect_thin_wall", !have_arachne);
// Orca
auto is_role_based_wipe_speed = config->opt_bool("role_based_wipe_speed");
auto is_role_based_wipe_speed = ToggleExpr::FromConfigBool(config, "role_based_wipe_speed");
toggle_field("wipe_speed",!is_role_based_wipe_speed);
for (auto el : {"accel_to_decel_enable", "accel_to_decel_factor"})
toggle_line(el, gcflavor == gcfKlipper);
if(gcflavor == gcfKlipper)
toggle_field("accel_to_decel_factor", config->opt_bool("accel_to_decel_enable"));
toggle_field("accel_to_decel_factor", ToggleExpr::FromConfigBool(config, "accel_to_decel_enable"));
bool have_make_overhang_printable = config->opt_bool("make_overhang_printable");
auto have_make_overhang_printable = ToggleExpr::FromConfigBool(config, "make_overhang_printable");
toggle_line("make_overhang_printable_angle", have_make_overhang_printable);
toggle_line("make_overhang_printable_hole_size", have_make_overhang_printable);
toggle_line("min_width_top_surface", config->opt_bool("only_one_wall_top") || ((config->opt_float("min_length_factor") > 0.5f) && have_arachne)); // 0.5 is default value
toggle_line("min_width_top_surface", ToggleExpr::FromConfigBool(config, "only_one_wall_top") || (ToggleExpr::FromConfigFloat(config, "min_length_factor") > 0.5f) && have_arachne); // 0.5 is default value
for (auto el : { "hole_to_polyhole_threshold", "hole_to_polyhole_twisted" })
toggle_line(el, config->opt_bool("hole_to_polyhole"));
toggle_line(el, ToggleExpr::FromConfigBool(config, "hole_to_polyhole"));
bool has_detect_overhang_wall = config->opt_bool("detect_overhang_wall");
bool has_overhang_reverse = config->opt_bool("overhang_reverse");
bool force_wall_direction = config->opt_enum<WallDirection>("wall_direction") != WallDirection::Auto;
bool allow_overhang_reverse = !has_spiral_vase && !force_wall_direction;
auto has_detect_overhang_wall = ToggleExpr::FromConfigBool(config, "detect_overhang_wall");
auto has_overhang_reverse = ToggleExpr::FromConfigBool(config, "overhang_reverse");
auto force_wall_direction = ToggleExpr::FromConfigEnum<WallDirection>(config, "wall_direction") != WallDirection::Auto;
auto allow_overhang_reverse = !has_spiral_vase && !force_wall_direction;
toggle_line("overhang_reverse", allow_overhang_reverse);
toggle_line("overhang_reverse_internal_only", allow_overhang_reverse && has_overhang_reverse);
bool has_overhang_reverse_internal_only = config->opt_bool("overhang_reverse_internal_only");
auto has_overhang_reverse_internal_only = ToggleExpr::FromConfigBool(config, "overhang_reverse_internal_only");
if (has_overhang_reverse_internal_only){
DynamicPrintConfig new_conf = *config;
new_conf.set_key_value("overhang_reverse_threshold", new ConfigOptionFloatOrPercent(0,true));
apply(config, &new_conf);
}
toggle_line("overhang_reverse_threshold", has_detect_overhang_wall && allow_overhang_reverse && has_overhang_reverse && !has_overhang_reverse_internal_only);
toggle_line("timelapse_type", is_BBL_Printer);
toggle_line("timelapse_type", is_BBL_printer);
bool have_small_area_infill_flow_compensation = config->opt_bool("small_area_infill_flow_compensation");
auto have_small_area_infill_flow_compensation = ToggleExpr::FromConfigBool(config, "small_area_infill_flow_compensation");
toggle_line("small_area_infill_flow_compensation_model", have_small_area_infill_flow_compensation);
toggle_field("seam_slope_type", !has_spiral_vase);
bool has_seam_slope = !has_spiral_vase && config->opt_enum<SeamScarfType>("seam_slope_type") != SeamScarfType::None;
auto has_seam_slope = !has_spiral_vase && ToggleExpr::FromConfigEnum<SeamScarfType>(config, "seam_slope_type") != SeamScarfType::None;
toggle_line("seam_slope_conditional", has_seam_slope);
toggle_line("seam_slope_start_height", has_seam_slope);
toggle_line("seam_slope_entire_loop", has_seam_slope);
@ -932,11 +929,11 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_line("seam_slope_inner_walls", has_seam_slope);
toggle_line("scarf_joint_speed", has_seam_slope);
toggle_line("scarf_joint_flow_ratio", has_seam_slope);
toggle_field("seam_slope_min_length", !config->opt_bool("seam_slope_entire_loop"));
toggle_line("scarf_angle_threshold", has_seam_slope && config->opt_bool("seam_slope_conditional"));
toggle_line("scarf_overhang_threshold", has_seam_slope && config->opt_bool("seam_slope_conditional"));
toggle_field("seam_slope_min_length", !ToggleExpr::FromConfigBool(config, "seam_slope_entire_loop"));
toggle_line("scarf_angle_threshold", has_seam_slope && ToggleExpr::FromConfigBool(config, "seam_slope_conditional"));
toggle_line("scarf_overhang_threshold", has_seam_slope && ToggleExpr::FromConfigBool(config, "seam_slope_conditional"));
bool use_beam_interlocking = config->opt_bool("interlocking_beam");
auto use_beam_interlocking = ToggleExpr::FromConfigBool(config, "interlocking_beam");
toggle_line("mmu_segmented_region_interlocking_depth", !use_beam_interlocking);
toggle_line("interlocking_beam_width", use_beam_interlocking);
toggle_line("interlocking_orientation", use_beam_interlocking);
@ -944,22 +941,22 @@ void ConfigManipulation::toggle_print_fff_options(DynamicPrintConfig *config, co
toggle_line("interlocking_depth", use_beam_interlocking);
toggle_line("interlocking_boundary_avoidance", use_beam_interlocking);
bool lattice_options = config->opt_enum<InfillPattern>("sparse_infill_pattern") == InfillPattern::ipLateralLattice;
auto lattice_options = pattern == InfillPattern::ipLateralLattice;
for (auto el : { "lateral_lattice_angle_1", "lateral_lattice_angle_2"})
toggle_line(el, lattice_options);
// Adaptative Cubic and support cubic infill patterns do not support infill rotation.
bool FillAdaptive = (pattern == InfillPattern::ipAdaptiveCubic || pattern == InfillPattern::ipSupportCubic);
auto FillAdaptive = pattern == InfillPattern::ipAdaptiveCubic || pattern == InfillPattern::ipSupportCubic;
//Orca: disable infill_direction/solid_infill_direction if sparse_infill_rotate_template/solid_infill_rotate_template is not empty value and adaptive cubic/support cubic infill pattern is not selected
toggle_field("sparse_infill_rotate_template", !FillAdaptive);
toggle_field("infill_direction", config->opt_string("sparse_infill_rotate_template") == "" && !FillAdaptive);
toggle_field("solid_infill_direction", config->opt_string("solid_infill_rotate_template") == "");
toggle_line("infill_overhang_angle", config->opt_enum<InfillPattern>("sparse_infill_pattern") == InfillPattern::ipLateralHoneycomb);
toggle_field("infill_direction", ToggleExpr::FromConfigString(config, "sparse_infill_rotate_template") == "" && !FillAdaptive);
toggle_field("solid_infill_direction", ToggleExpr::FromConfigString(config, "solid_infill_rotate_template") == "");
toggle_line("infill_overhang_angle", pattern == InfillPattern::ipLateralHoneycomb);
std::string printer_type = wxGetApp().preset_bundle->printers.get_edited_preset().get_printer_type(wxGetApp().preset_bundle);
toggle_line("enable_wrapping_detection", DevPrinterConfigUtil::support_wrapping_detection(printer_type));
toggle_line("enable_wrapping_detection", ToggleExpr(DevPrinterConfigUtil::support_wrapping_detection(printer_type), "Printer does not support wrapping detection").disable_postfix());
}
void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, const bool is_global_config/* = false*/)
@ -998,7 +995,7 @@ void ConfigManipulation::update_print_sla_config(DynamicPrintConfig* config, con
void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config)
{
bool supports_en = config->opt_bool("supports_enable");
auto supports_en = ToggleExpr::FromConfigBool(config, "supports_enable");
toggle_field("support_head_front_diameter", supports_en);
toggle_field("support_head_penetration", supports_en);
@ -1017,7 +1014,7 @@ void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config)
toggle_field("support_points_density_relative", supports_en);
toggle_field("support_points_minimal_distance", supports_en);
bool pad_en = config->opt_bool("pad_enable");
auto pad_en = ToggleExpr::FromConfigBool(config, "pad_enable");
toggle_field("pad_wall_thickness", pad_en);
toggle_field("pad_wall_height", pad_en);
@ -1028,7 +1025,7 @@ void ConfigManipulation::toggle_print_sla_options(DynamicPrintConfig* config)
toggle_field("pad_around_object", pad_en);
toggle_field("pad_around_object_everywhere", pad_en);
bool zero_elev = config->opt_bool("pad_around_object") && pad_en;
auto zero_elev = ToggleExpr::FromConfigBool(config, "pad_around_object") && pad_en;
toggle_field("support_object_elevation", supports_en && !zero_elev);
toggle_field("pad_object_gap", zero_elev);

View file

@ -10,6 +10,7 @@
#include "libslic3r/PrintConfig.hpp"
#include "Field.hpp"
#include "ToggleExpr.hpp"
namespace Slic3r {
@ -27,8 +28,8 @@ class ConfigManipulation
// function to loading of changed configuration
std::function<void()> load_config = nullptr;
std::function<void (const std::string&, bool toggle, int opt_index)> cb_toggle_field = nullptr;
std::function<void(const std::string &, bool toggle, int opt_index)> cb_toggle_line = nullptr;
std::function<void (const std::string&, const ToggleExpr& toggle_expr, int opt_index)> cb_toggle_field = nullptr;
std::function<void(const std::string &, const ToggleExpr& toggle_expr, int opt_index)> cb_toggle_line = nullptr;
// callback to propagation of changed value, if needed
std::function<void(const std::string&, const boost::any&)> cb_value_change = nullptr;
//BBS: change local config to const DynamicPrintConfig
@ -40,8 +41,8 @@ class ConfigManipulation
public:
ConfigManipulation(std::function<void()> load_config,
std::function<void(const std::string&, bool toggle, int opt_index)> cb_toggle_field,
std::function<void(const std::string&, bool toggle, int opt_index)> cb_toggle_line,
std::function<void(const std::string&, const ToggleExpr& toggle_expr, int opt_index)> cb_toggle_field,
std::function<void(const std::string&, const ToggleExpr& toggle_expr, int opt_index)> cb_toggle_line,
std::function<void(const std::string&, const boost::any&)> cb_value_change,
//BBS: change local config to DynamicPrintConfig
const DynamicPrintConfig* local_config = nullptr,
@ -65,8 +66,8 @@ public:
void apply(DynamicPrintConfig* config, DynamicPrintConfig* new_config);
t_config_option_keys const &applying_keys() const;
void toggle_field(const std::string& field_key, const bool toggle, int opt_index = -1);
void toggle_line(const std::string& field_key, const bool toggle, int opt_index = -1);
void toggle_field(const std::string& field_key, const ToggleExpr& toggle_expr, int opt_index = -1);
void toggle_line(const std::string& field_key, const ToggleExpr& toggle_expr, int opt_index = -1);
// FFF print
void update_print_fff_config(DynamicPrintConfig* config, const bool is_global_config = false, const bool is_plate_config = false);

View file

@ -207,6 +207,8 @@ public:
/// Callback function to edit field value
t_back_to_init m_fn_edit_value{ nullptr };
std::set<std::string> disabled_reasons{};
// This is used to avoid recursive invocation of the field change/update by wxWidgets.
bool m_disable_change_event {false};
bool m_is_modified_value {false};
@ -288,7 +290,7 @@ protected:
bool bEnterPressed = false;
wxString m_na_value = _(L("N/A"));
friend class OptionsGroup;
};

View file

@ -379,9 +379,9 @@ void ObjectSettings::update_config_values(ModelConfig* config)
field->toggle(toggle);
};
#else
auto toggle_field = [this](const t_config_option_key & opt_key, bool toggle, int opt_index)
auto toggle_field = [this](const t_config_option_key & opt_key, const ToggleExpr& toggle_expr, int opt_index)
{
m_tab_active->toggle_option(opt_key, toggle, opt_index);
m_tab_active->toggle_option(opt_key, toggle_expr, opt_index);
};
#endif

View file

@ -284,16 +284,16 @@ bool ObjectTableSettings::update_settings_list(bool is_object, bool is_multiple_
m_settings_list_sizer->Add(optgroup->sizer, 0, wxEXPAND | wxALL, 0);
m_og_settings.push_back(optgroup);
auto toggle_field = [this, optgroup](const t_config_option_key & opt_key, bool toggle, int opt_index)
auto toggle_field = [this, optgroup](const t_config_option_key & opt_key, const ToggleExpr& toggle_expr, int opt_index)
{
Field* field = optgroup->get_fieldc(opt_key, opt_index);;
if (field)
field->toggle(toggle);
field->toggle(toggle_expr.get_value());
};
auto toggle_line = [this, optgroup](const t_config_option_key &opt_key, bool toggle, int opt_index)
auto toggle_line = [this, optgroup](const t_config_option_key &opt_key, const ToggleExpr& toggle_expr, int opt_index)
{
Line* line = optgroup->get_line(opt_key);
if (line) line->toggle_visible = toggle;
if (line) line->toggle_visible = toggle_expr.get_value();
};
ConfigManipulation config_manipulation(nullptr, toggle_field, toggle_line, nullptr, &m_current_config);
@ -381,7 +381,7 @@ void ObjectTableSettings::update_config_values(bool is_object, ModelObject* obje
DynamicPrintConfig &main_config = m_current_config;
auto toggle_field = [this](const t_config_option_key & opt_key, bool toggle, int opt_index)
auto toggle_field = [this](const t_config_option_key & opt_key, const ToggleExpr& toggle_expr, int opt_index)
{
Field* field = nullptr;
for (auto og : m_og_settings) {
@ -390,12 +390,12 @@ void ObjectTableSettings::update_config_values(bool is_object, ModelObject* obje
break;
}
if (field)
field->toggle(toggle);
field->toggle(toggle_expr.get_value());
};
auto toggle_line = [this](const t_config_option_key &opt_key, bool toggle, int opt_index) {
auto toggle_line = [this](const t_config_option_key &opt_key, const ToggleExpr& toggle_expr, int opt_index) {
for (auto og : m_og_settings) {
Line *line = og->get_line(opt_key);
if (line) { line->toggle_visible = toggle; break; }
if (line) { line->toggle_visible = toggle_expr.get_value(); break; }
}
};

View file

@ -10,6 +10,7 @@
#include <boost/algorithm/string/split.hpp>
#include "libslic3r/Utils.hpp"
#include "I18N.hpp"
#include "ToggleExpr.hpp"
#include "format.hpp"
#include <slic3r/GUI/Widgets/Label.hpp>
@ -400,6 +401,27 @@ void OG_CustomCtrl::OnMotion(wxMouseEvent& event)
}
if (!tooltip.IsEmpty())
break;
for (auto& ctrl_line : ctrl_lines) {
for (const auto& option : ctrl_line.og_line.get_options()) {
auto field = opt_group->get_field(option.opt_id);
if (!field) continue;
auto win = field->getWindow();
if (!win) continue;
auto tooltips = win->GetToolTip();
auto tip = tooltips ? tooltips->GetTip() : "";
tip += "\n\n";
tip += ToggleExpr::build_reasons_string("Option is disabled.", field->disabled_reasons);
tip.Trim(true);
if (!tip.IsEmpty() && !win->IsEnabled() && is_point_in_rect(pos, win->GetRect())) {
tooltip = tip;
break;
}
}
if (!tooltip.IsEmpty())
break;
}
}
// Set tooltips with information for each icon

View file

@ -1301,6 +1301,14 @@ void ExtruderOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const
OptionsGroup::on_change_OG(opt_id, value);
}
void OptionsGroup::clear_disabled_reasons()
{
for (auto& field : m_fields)
field.second->disabled_reasons.clear();
for (auto& line : m_lines)
line.hidden_reasons.clear();
}
wxString OptionsGroup::get_url(const std::string& path_end)
{
//BBS

View file

@ -57,6 +57,7 @@ public:
std::string label_path;
bool undo_to_sys{false}; // BBS: object config
bool toggle_visible{true}; // BBS: hide some line
std::set<std::string> hidden_reasons; // Why was the visibility toggled
size_t full_width {0};
widget_t widget {nullptr};
@ -240,6 +241,7 @@ protected:
virtual void back_to_sys_value(const std::string& opt_key) {}
public:
void clear_disabled_reasons();
static wxString get_url(const std::string& path_end);
static bool launch_browser(const std::string& path_end);
};

View file

@ -637,13 +637,8 @@ void ParamsPanel::set_active_tab(wxPanel* tab)
}
auto tab_print = dynamic_cast<Tab *>(m_tab_print);
if (cur_tab == m_tab_print) {
if (tab_print)
tab_print->toggle_line("print_flow_ratio", false);
} else {
if (tab_print)
tab_print->toggle_line("print_flow_ratio", false);
}
if (tab_print)
tab_print->toggle_line("print_flow_ratio", ToggleExpr(false, "Disabled"));
}
bool ParamsPanel::is_active_and_shown_tab(wxPanel* tab)

View file

@ -57,6 +57,8 @@
#include <commctrl.h>
#endif // WIN32
#include "ToggleExpr.hpp"
#include <algorithm>
namespace Slic3r {
@ -1429,21 +1431,41 @@ Field* Tab::get_field(const t_config_option_key& opt_key, Page** selected_page,
return field;
}
void Tab::toggle_option(const std::string& opt_key, bool toggle, int opt_index/* = -1*/)
void Tab::toggle_option(const std::string& opt_key, const ToggleExpr& toggle_expr, int opt_index /*= -1*/)
{
if (!m_active_page)
return;
Field* field = m_active_page->get_field(opt_key, opt_index);
if (field)
field->toggle(toggle);
if (field) {
auto [value, reasons] = toggle_expr.get_result();
field->toggle(value);
if (value)
field->disabled_reasons.clear();
else
field->disabled_reasons.merge(reasons);
}
}
void Tab::toggle_line(const std::string &opt_key, bool toggle, int opt_index)
void Tab::toggle_line(const std::string& opt_key, const ToggleExpr& toggle_expr, int opt_index /*= -1*/)
{
if (!m_active_page) return;
Line *line = m_active_page->get_line(opt_key, opt_index);
if (line) line->toggle_visible = toggle;
};
if (line) {
auto [value, reasons] = toggle_expr.get_result();
line->toggle_visible = value;
if (value)
line->hidden_reasons.clear();
else
line->hidden_reasons.merge(reasons);
}
}
void Tab::clear_disabled_reasons()
{
if (!m_active_page) return;
for (auto optgroup : m_active_page->m_optgroups)
optgroup->clear_disabled_reasons();
}
// To be called by custom widgets, load a value into a config,
// update the preset selection boxes (the dirty flags)
@ -2027,6 +2049,16 @@ void Tab::activate_option(const std::string& opt_key, const wxString& category)
evt.SetEventObject(field->getWindow());
wxPostEvent(m_page_view, evt);
}
if (!field->getWindow()->IsShown()) {
Line* line = get_line(opt_key);
if (!line) return;
if (line->toggle_visible) {
show_error(this, std::string("The selected option is hidden by the config mode. ")
.append(line->get_options()[0].opt.mode == comAdvanced ? "Enable advanced mode to use this option" : "Enable developer mode to use this option"));
} else {
show_error(this, ToggleExpr::build_reasons_string("The selected option is hidden.", line->hidden_reasons));
}
}
}
else if (category == "Single extruder MM setup") {
// When we show and hide "Single extruder MM setup" page,
@ -2755,6 +2787,7 @@ void TabPrint::toggle_options()
{
if (!m_active_page) return;
// BBS: whether the preset is Bambu Lab printer
this->clear_disabled_reasons();
if (m_preset_bundle) {
bool is_BBL_printer = wxGetApp().preset_bundle->is_bbl_vendor();
m_config_manipulation.set_is_BBL_Printer(is_BBL_printer);
@ -3755,16 +3788,20 @@ void TabFilament::update_filament_overrides_page(const DynamicPrintConfig* print
if (opt_key == "filament_long_retractions_when_cut") {
int machine_enabled_level = printers_config->option<ConfigOptionInt>(
"enable_long_retraction_when_cut")->value;
bool machine_enabled = machine_enabled_level == LongRectrationLevel::EnableFilament;
toggle_line(opt_key, machine_enabled, extruder_idx + 256);
field->toggle(is_checked && machine_enabled);
auto machine_enabled = ToggleExpr(machine_enabled_level == LongRectrationLevel::EnableFilament,
"enable_long_retraction_when_cut is not enabled for filament")
.disable_postfix();
toggle_line(opt_key, machine_enabled, extruder_idx + 256);
field->toggle(is_checked && machine_enabled.get_value());
} else if (opt_key == "filament_retraction_distances_when_cut") {
int machine_enabled_level = printers_config->option<ConfigOptionInt>(
"enable_long_retraction_when_cut")->value;
bool machine_enabled = machine_enabled_level == LongRectrationLevel::EnableFilament;
bool filament_enabled = m_config->option<ConfigOptionBools>("filament_long_retractions_when_cut")->values[extruder_idx] == 1;
auto machine_enabled = ToggleExpr(machine_enabled_level == LongRectrationLevel::EnableFilament,
"enable_long_retraction_when_cut is not enabled for filament")
.disable_postfix();
auto filament_enabled = ToggleExpr::FromConfigBool(m_config, "filament_long_retractions_when_cut", extruder_idx);
toggle_line(opt_key, filament_enabled && machine_enabled, extruder_idx + 256);
field->toggle(is_checked && filament_enabled && machine_enabled);
field->toggle(is_checked && (filament_enabled && machine_enabled).get_value());
} else {
if (!is_checked) {
const std::string printer_opt_key = opt_key.substr(strlen("filament_"));
@ -4177,34 +4214,37 @@ void TabFilament::toggle_options()
{
if (!m_active_page)
return;
bool is_BBL_printer = false;
this->clear_disabled_reasons();
bool b_is_BBL_printer = false;
if (m_preset_bundle) {
is_BBL_printer =
b_is_BBL_printer =
wxGetApp().preset_bundle->is_bbl_vendor();
}
bool is_multi_extruder = m_preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->size() > 1;
auto is_BBL_printer = ToggleExpr(b_is_BBL_printer, "BBL printer").set_prefixes("Isn't ", "Is ").disable_postfix();
auto is_multi_extruder = ToggleExpr(m_preset_bundle->printers.get_edited_preset().config.option<ConfigOptionFloats>("nozzle_diameter")->size() > 1, "Not multi extruder").disable_postfix();
auto cfg = m_preset_bundle->printers.get_edited_preset().config;
if (m_active_page->title() == L("Cooling")) {
bool has_enable_overhang_bridge_fan = m_config->opt_bool("enable_overhang_bridge_fan", 0);
auto has_enable_overhang_bridge_fan = ToggleExpr::FromConfigBool(m_config, "enable_overhang_bridge_fan", 0);
for (auto el : {"overhang_fan_speed", "overhang_fan_threshold", "internal_bridge_fan_speed"}) // ORCA: Add support for separate internal bridge fan speed control
toggle_option(el, has_enable_overhang_bridge_fan);
toggle_option("additional_cooling_fan_speed", cfg.opt_bool("auxiliary_fan"));
toggle_option("additional_cooling_fan_speed", ToggleExpr::FromConfigBool(&cfg, "auxiliary_fan"));
// Orca: toggle dont slow down for external perimeters if
bool has_slow_down_for_layer_cooling = m_config->opt_bool("slow_down_for_layer_cooling", 0);
auto has_slow_down_for_layer_cooling = ToggleExpr::FromConfigBool(m_config, "slow_down_for_layer_cooling", 0);
toggle_option("dont_slow_down_outer_wall", has_slow_down_for_layer_cooling);
}
if (m_active_page->title() == L("Filament"))
{
bool pa = m_config->opt_bool("enable_pressure_advance", 0);
auto pa = ToggleExpr::FromConfigBool(m_config, "enable_pressure_advance", 0);
toggle_option("pressure_advance", pa);
//Orca: Enable the plates that should be visible when multi bed support is enabled or a BBL printer is selected; otherwise, enable only the plate visible for the selected bed type.
DynamicConfig& proj_cfg = m_preset_bundle->project_config;
std::string bed_temp_1st_layer_key = "";
if (proj_cfg.has("curr_bed_type"))
std::string bed_temp_1st_layer_key;
auto has_bed_type= ToggleExpr(proj_cfg.has("curr_bed_type"), "curr_bed_type").set_postfixes(" not set", " is set");
if (has_bed_type)
{
bed_temp_1st_layer_key = get_bed_temp_1st_layer_key(proj_cfg.opt_enum<BedType>("curr_bed_type"));
}
@ -4213,13 +4253,16 @@ void TabFilament::toggle_options()
"textured_cool_plate_temp_initial_layer", "eng_plate_temp_initial_layer",
"textured_plate_temp_initial_layer", "hot_plate_temp_initial_layer"};
bool support_multi_bed_types = std::find(bed_temp_keys.begin(), bed_temp_keys.end(), bed_temp_1st_layer_key) ==
bed_temp_keys.end() ||
is_BBL_printer || cfg.opt_bool("support_multi_bed_types");
auto current_bed_has_temp = ToggleExpr(std::find(bed_temp_keys.begin(), bed_temp_keys.end(), bed_temp_1st_layer_key) ==
bed_temp_keys.end(),
bed_temp_1st_layer_key).set_postfixes(" not set", " is set");
auto support_multi_bed_types_opt = ToggleExpr::FromConfigBool(&cfg, "support_multi_bed_types");
auto support_multi_bed_types = (has_bed_type && current_bed_has_temp) ||
is_BBL_printer || support_multi_bed_types_opt;
for (const auto& key : bed_temp_keys)
{
toggle_line(key, support_multi_bed_types || bed_temp_1st_layer_key == key);
toggle_line(key, support_multi_bed_types || ToggleExpr(bed_temp_1st_layer_key == key, ""));
}
@ -4229,20 +4272,20 @@ void TabFilament::toggle_options()
// If adaptive PA is not enabled, hide the adaptive PA model section
toggle_option("adaptive_pressure_advance", pa);
toggle_option("adaptive_pressure_advance_overhangs", pa);
bool has_adaptive_pa = m_config->opt_bool("adaptive_pressure_advance", 0);
auto has_adaptive_pa = ToggleExpr::FromConfigBool(m_config, "adaptive_pressure_advance", 0);
toggle_line("adaptive_pressure_advance_overhangs", has_adaptive_pa && pa);
toggle_line("adaptive_pressure_advance_model", has_adaptive_pa && pa);
toggle_line("adaptive_pressure_advance_bridges", has_adaptive_pa && pa);
bool is_pellet_printer = cfg.opt_bool("pellet_modded_printer");
auto is_pellet_printer = ToggleExpr::FromConfigBool(&cfg, "pellet_modded_printer");
toggle_line("pellet_flow_coefficient", is_pellet_printer);
toggle_line("filament_diameter", !is_pellet_printer);
bool support_chamber_temp_control = this->m_preset_bundle->printers.get_edited_preset().config.opt_bool("support_chamber_temp_control");
auto support_chamber_temp_control = ToggleExpr::FromConfigBool(&cfg, "support_chamber_temp_control");
toggle_line("chamber_temperature", support_chamber_temp_control);
std::string volumetric_speed_cos = m_config->opt_string("volumetric_speed_coefficients", 0u);
bool enable_fit = volumetric_speed_cos != "0 0 0 0 0 0";
auto volumetric_speed_cos = ToggleExpr::FromConfigString(m_config, "volumetric_speed_coefficients", 0u);
auto enable_fit = volumetric_speed_cos != "0 0 0 0 0 0";
toggle_option("filament_adaptive_volumetric_speed", enable_fit, 256 + 0u);
}
@ -4256,13 +4299,14 @@ void TabFilament::toggle_options()
"filament_cooling_initial_speed", "filament_cooling_final_speed"})
toggle_option(el, !is_BBL_printer);
bool multitool_ramming = m_config->opt_bool("filament_multitool_ramming", 0);
auto multitool_ramming = ToggleExpr::FromConfigBool(m_config, "filament_multitool_ramming", 0);
toggle_option("filament_multitool_ramming_volume", multitool_ramming);
toggle_option("filament_multitool_ramming_flow", multitool_ramming);
const int extruder_idx = 0; // m_variant_combo->GetSelection(); // TODO: Orca hack
toggle_line("long_retractions_when_ec", is_multi_extruder && is_BBL_printer, 256 + extruder_idx);
toggle_line("retraction_distances_when_ec", is_multi_extruder && is_BBL_printer && m_config->opt_bool("long_retractions_when_ec", extruder_idx), 256 + extruder_idx);
auto long_retractions_ec = ToggleExpr::FromConfigBool(m_config, "long_retractions_when_ec", extruder_idx);
toggle_line("retraction_distances_when_ec", is_multi_extruder && is_BBL_printer && long_retractions_ec, 256 + extruder_idx);
}
}
@ -5189,6 +5233,7 @@ void TabPrinter::toggle_options()
{
if (!m_active_page || m_presets->get_edited_preset().printer_technology() == ptSLA)
return;
this->clear_disabled_reasons();
auto nozzle_volumes = m_preset_bundle->project_config.option<ConfigOptionEnumsGeneric>("nozzle_volume_type");
auto extruders = m_config->option<ConfigOptionEnumsGeneric>("extruder_type");
@ -5199,21 +5244,28 @@ void TabPrinter::toggle_options()
};
//BBS: whether the preset is Bambu Lab printer
bool is_BBL_printer = false;
bool b_is_BBL_printer = false;
if (m_preset_bundle) {
is_BBL_printer = wxGetApp().preset_bundle->is_bbl_vendor();
b_is_BBL_printer = wxGetApp().preset_bundle->is_bbl_vendor();
}
bool is_QIDI_printer = false;
bool b_is_QIDI_printer = false;
if (m_preset_bundle) {
is_QIDI_printer = wxGetApp().preset_bundle->is_qidi_vendor();
b_is_QIDI_printer = wxGetApp().preset_bundle->is_qidi_vendor();
}
bool have_multiple_extruders = true;
auto is_BBL_printer = ToggleExpr(b_is_BBL_printer, "BBL printer").set_prefixes("Isn't ", "Is ").disable_postfix();
auto is_QIDI_printer = ToggleExpr(b_is_QIDI_printer, "QIDI printer").set_prefixes("Isn't ", "Is ").disable_postfix();
// bool have_multiple_extruders = true;
//m_extruders_count > 1;
//if (m_active_page->title() == "Custom G-code") {
// toggle_option("change_filament_gcode", have_multiple_extruders);
//}
auto gcf = ToggleExpr::FromConfigEnum<GCodeFlavor>(m_config, "gcode_flavor");
auto gcf_is_marlin = gcf == gcfMarlinFirmware;
auto gcf_is_marlin_legacy = gcf == gcfMarlinLegacy;
auto gcf_is_klipper = gcf == gcfKlipper;
if (m_active_page->title() == L("Basic information")) {
// SoftFever: hide BBL specific settings
@ -5224,15 +5276,14 @@ void TabPrinter::toggle_options()
for (auto el : {"use_firmware_retraction", "use_relative_e_distances", "support_multi_bed_types", "pellet_modded_printer", "bed_mesh_max", "bed_mesh_min", "bed_mesh_probe_distance", "adaptive_bed_mesh_margin", "thumbnails"})
toggle_line(el, !is_BBL_printer);
auto gcf = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
toggle_line("enable_power_loss_recovery", is_BBL_printer || gcf == gcfMarlinFirmware);
toggle_line("enable_power_loss_recovery", is_BBL_printer || gcf_is_marlin);
}
if (m_active_page->title() == L("Machine G-code")) {
PresetBundle *preset_bundle = wxGetApp().preset_bundle;
std::string printer_type = preset_bundle->printers.get_edited_preset().get_printer_type(preset_bundle);
toggle_line("wrapping_detection_gcode", DevPrinterConfigUtil::support_wrapping_detection(printer_type));
toggle_line("wrapping_detection_gcode", ToggleExpr(DevPrinterConfigUtil::support_wrapping_detection(printer_type), "Doesn't support wrapping detection").disable_postfix());
}
if (m_active_page->title() == L("Multimaterial")) {
@ -5247,8 +5298,8 @@ void TabPrinter::toggle_options()
})
toggle_option(el, !is_BBL_printer && !is_QIDI_printer);
auto bSEMM = m_config->opt_bool("single_extruder_multi_material");
if (!bSEMM && m_config->opt_bool("manual_filament_change")) {
auto bSEMM = ToggleExpr::FromConfigBool(m_config, "single_extruder_multi_material");
if (!bSEMM && ToggleExpr::FromConfigBool(m_config, "manual_filament_change")) {
DynamicPrintConfig new_conf = *m_config;
new_conf.set_key_value("manual_filament_change", new ConfigOptionBool(false));
load_config(new_conf);
@ -5265,15 +5316,17 @@ void TabPrinter::toggle_options()
{
size_t i = size_t(val - 1);
int variant_index = get_index_for_extruder(i);
bool have_retract_length = m_config->opt_float("retraction_length", variant_index) > 0;
auto have_retract_length = ToggleExpr::FromConfigFloat(m_config, "retraction_length", variant_index) > 0;
toggle_option("extruder_printable_area", false, i); // disable
toggle_line("extruder_printable_area", m_preset_bundle->get_printer_extruder_count() == 2, i); //hide
toggle_option("extruder_printable_height", false, i);
toggle_line("extruder_printable_height", m_preset_bundle->get_printer_extruder_count() == 2, i);
auto hardcoded_disabled = ToggleExpr(false, "Disabled").disable_postfix();
auto two_extruders = ToggleExpr(m_preset_bundle->get_printer_extruder_count() == 2, "Printer extruder count") > "2";
toggle_option("extruder_printable_area", hardcoded_disabled, i); // disable
toggle_line("extruder_printable_area", two_extruders, i); //hide
toggle_option("extruder_printable_height", hardcoded_disabled, i);
toggle_line("extruder_printable_height", two_extruders, i);
// when using firmware retraction, firmware decides retraction length
bool use_firmware_retraction = m_config->opt_bool("use_firmware_retraction");
auto use_firmware_retraction = ToggleExpr::FromConfigBool(m_config, "use_firmware_retraction");
toggle_option("retract_length", !use_firmware_retraction, i);
// user can customize travel length if we have retraction length or we"re using
@ -5282,7 +5335,7 @@ void TabPrinter::toggle_options()
// user can customize other retraction options if retraction is enabled
//BBS
bool retraction = have_retract_length || use_firmware_retraction;
auto retraction = have_retract_length || use_firmware_retraction;
std::vector<std::string> vec = {"z_hop", "retract_when_changing_layer"};
for (auto el : vec)
toggle_option(el, retraction, i);
@ -5291,7 +5344,7 @@ void TabPrinter::toggle_options()
vec.resize(0);
vec = {"retract_lift_above", "retract_lift_below", "retract_lift_enforce"};
for (auto el : vec)
toggle_option(el, retraction && (m_config->opt_float("z_hop", i) > 0), i);
toggle_option(el, retraction && ToggleExpr::FromConfigFloat(m_config, "z_hop", i) > 0, i);
// some options only apply when not using firmware retraction
vec.resize(0);
@ -5302,7 +5355,7 @@ void TabPrinter::toggle_options()
//BBS
toggle_option(el, retraction && !use_firmware_retraction, i);
bool wipe = retraction && m_config->opt_bool("wipe", variant_index);
auto wipe = retraction && ToggleExpr::FromConfigBool(m_config, "wipe", variant_index);
toggle_option("retract_before_wipe", wipe, i);
if (use_firmware_retraction && wipe) {
@ -5327,37 +5380,39 @@ void TabPrinter::toggle_options()
// BBS
toggle_option("wipe_distance", wipe, i);
toggle_option("retract_length_toolchange", have_multiple_extruders, i);
// toggle_option("retract_length_toolchange", have_multiple_extruders, i);
bool toolchange_retraction = m_config->opt_float("retract_length_toolchange", variant_index) > 0;
toggle_option("retract_restart_extra_toolchange", have_multiple_extruders && toolchange_retraction, i);
auto toolchange_retraction = ToggleExpr::FromConfigFloat(m_config, "retract_length_toolchange", variant_index) > 0;
toggle_option("retract_restart_extra_toolchange", toolchange_retraction, i);
toggle_option("long_retractions_when_cut", !use_firmware_retraction && m_config->opt_int("enable_long_retraction_when_cut"), i);
toggle_line("retraction_distances_when_cut", m_config->opt_bool("long_retractions_when_cut", variant_index), i);
toggle_option("long_retractions_when_cut",
!use_firmware_retraction && ToggleExpr::FromConfigInt(m_config, "enable_long_retraction_when_cut") != 0, i);
toggle_line("retraction_distances_when_cut", ToggleExpr::FromConfigBool(m_config, "long_retractions_when_cut", variant_index), i);
toggle_option("travel_slope", m_config->opt_enum("z_hop_types", i) != ZHopType::zhtNormal, i);
toggle_option("travel_slope",
ToggleExpr::FromConfigEnum<ZHopType>(m_config, "z_hop_types", i) != ZHopType::zhtNormal,
i);
}
if (m_active_page->title() == L("Motion ability")) {
auto gcf = m_config->option<ConfigOptionEnum<GCodeFlavor>>("gcode_flavor")->value;
bool silent_mode = m_config->opt_bool("silent_mode");
int max_field = silent_mode ? 2 : 1;
for (int i = 0; i < max_field; ++i)
toggle_option("machine_max_acceleration_travel", gcf != gcfMarlinLegacy && gcf != gcfKlipper, i);
toggle_line("machine_max_acceleration_travel", gcf != gcfMarlinLegacy && gcf != gcfKlipper);
toggle_option("machine_max_acceleration_travel", !gcf_is_marlin_legacy && !gcf_is_klipper, i);
toggle_line("machine_max_acceleration_travel", !gcf_is_marlin_legacy && !gcf_is_klipper);
for (int i = 0; i < max_field; ++i)
toggle_option("machine_max_junction_deviation", gcf == gcfMarlinFirmware, i);
toggle_line("machine_max_junction_deviation", gcf == gcfMarlinFirmware);
toggle_option("machine_max_junction_deviation", gcf_is_marlin, i);
toggle_line("machine_max_junction_deviation", gcf_is_marlin);
// Check if junction deviation value is non-zero and firmware is Marlin
bool enable_jerk = gcf != gcfMarlinFirmware;
auto enable_jerk = !gcf_is_marlin;
if (gcf == gcfMarlinFirmware) {
const auto *junction_deviation = m_config->option<ConfigOptionFloats>("machine_max_junction_deviation");
if (junction_deviation != nullptr) {
const auto &values = junction_deviation->values;
enable_jerk = std::all_of(values.begin(), values.end(), [](double val) { return val == 0.0; });
enable_jerk = ToggleExpr(std::all_of(values.begin(), values.end(), [](double val) { return val == 0.0; }), "machine_max_junction_deviation") == "0";
} else {
enable_jerk = true;
enable_jerk = ToggleExpr(true, "");
}
}
for (int i = 0; i < max_field; ++i) {
@ -5367,7 +5422,7 @@ void TabPrinter::toggle_options()
toggle_option("machine_max_jerk_e", enable_jerk, i);
}
bool resonance_avoidance = m_config->opt_bool("resonance_avoidance");
auto resonance_avoidance = ToggleExpr::FromConfigBool(m_config, "resonance_avoidance");
toggle_option("min_resonance_avoidance_speed", resonance_avoidance);
toggle_option("max_resonance_avoidance_speed", resonance_avoidance);
}
@ -7408,8 +7463,9 @@ void TabSLAMaterial::reload_config()
void TabSLAMaterial::toggle_options()
{
this->clear_disabled_reasons();
const Preset &current_printer = m_preset_bundle->printers.get_edited_preset();
std::string model = current_printer.config.opt_string("printer_model");
auto model = ToggleExpr::FromConfigString(&current_printer.config, "printer_model");
m_config_manipulation.toggle_field("material_print_speed", model != "SL1");
}
@ -7563,6 +7619,7 @@ void TabSLAPrint::update_description_lines()
void TabSLAPrint::toggle_options()
{
this->clear_disabled_reasons();
if (m_active_page)
m_config_manipulation.toggle_print_sla_options(m_config);
}
@ -7612,12 +7669,12 @@ ConfigManipulation Tab::get_config_manipulation()
update();
};
auto cb_toggle_field = [this](const t_config_option_key& opt_key, bool toggle, int opt_index) {
return toggle_option(opt_key, toggle, opt_index >= 0 ? opt_index + 256 : opt_index);
auto cb_toggle_field = [this](const t_config_option_key& opt_key, const ToggleExpr& toggle_expr, int opt_index) {
return toggle_option(opt_key, toggle_expr, opt_index >= 0 ? opt_index + 256 : opt_index);
};
auto cb_toggle_line = [this](const t_config_option_key &opt_key, bool toggle, int opt_index) {
return toggle_line(opt_key, toggle, opt_index >= 0 ? opt_index + 256 : opt_index);
auto cb_toggle_line = [this](const t_config_option_key &opt_key, const ToggleExpr& toggle_expr, int opt_index) {
return toggle_line(opt_key, toggle_expr, opt_index >= 0 ? opt_index + 256 : opt_index);
};
auto cb_value_change = [this](const std::string& opt_key, const boost::any& value) {

View file

@ -26,6 +26,7 @@
#include <wx/imaglist.h>
#include <map>
#include <utility>
#include <vector>
#include <memory>
@ -50,6 +51,7 @@ class ModelConfig;
class ObjectBase;
namespace GUI {
class ToggleExpr;
class TabPresetComboBox;
class OG_CustomCtrl;
@ -387,9 +389,12 @@ public:
std::pair<OG_CustomCtrl*, bool*> get_custom_ctrl_with_blinking_ptr(const t_config_option_key& opt_key, int opt_index = -1);
Field* get_field(const t_config_option_key &opt_key, Page** selected_page, int opt_index = -1);
void toggle_option(const std::string &opt_key, bool toggle, int opt_index = -1);
void toggle_line(const std::string &opt_key, bool toggle, int opt_index = -1); // BBS: hide some line
wxSizer* description_line_widget(wxWindow* parent, ogStaticText** StaticText, wxString text = wxEmptyString);
void toggle_option(const std::string& opt_key, const ToggleExpr& toggle_expr, int opt_index = -1);
void toggle_line(const std::string& opt_key, const ToggleExpr& toggle_expr, int opt_index = -1);
void clear_disabled_reasons();
wxSizer* description_line_widget(wxWindow* parent, ogStaticText** StaticText, wxString text = wxEmptyString);
bool current_preset_is_dirty() const;
bool saved_preset_is_dirty() const;
void update_saved_preset_from_current_preset();

View file

@ -0,0 +1,174 @@
#include "ToggleExpr.hpp"
namespace Slic3r { namespace GUI {
std::string ToggleExpr::Leaf::get_reason(const bool inverted) const
{
return get_prefix(inverted) + m_name + get_postfix(inverted);
}
std::string ToggleExpr::Leaf::get_prefix(const bool inverted) const
{
if (!m_has_prefixes)
return "";
std::string p = inverted ? m_inverted_prefix : m_standard_prefix;
if (!p.empty() && p.back() != ' ')
p += " ";
return p;
}
std::string ToggleExpr::Leaf::get_postfix(const bool inverted) const
{
if (m_disable_postfix)
return "";
if (!m_comparison_val.empty() && m_comp_type != CompareType::NO_CT) {
return " " + comparison_type_to_string(m_comp_type, !inverted) + " " + m_comparison_val;
}
std::string p = inverted ? m_inverted_postfix : m_standard_postfix;
if (!p.empty() && p.front() != ' ')
p.insert(p.begin(), ' ');
return p;
}
std::pair<bool, std::set<std::string>> ToggleExpr::Node::evaluate(const bool inverted) const
{
struct EvalVisitor
{
bool inverted;
std::pair<bool, std::set<std::string>> operator()(const And& data_and) const
{
auto [lhs_val, lhs_reasons] = data_and.lhs->evaluate(inverted);
auto [rhs_val, rhs_reasons] = data_and.rhs->evaluate(inverted);
bool result = lhs_val && rhs_val;
// Result was a success, ignore any reason strings
if (result)
return {result, {}};
std::set<std::string> reasons;
if (!lhs_val)
reasons.merge(lhs_reasons);
if (!rhs_val)
reasons.merge(rhs_reasons);
return {result, std::move(reasons)};
}
std::pair<bool, std::set<std::string>> operator()(const Or& data_or) const
{
auto [lhs_val, lhs_reasons] = data_or.lhs->evaluate(inverted);
auto [rhs_val, rhs_reasons] = data_or.rhs->evaluate(inverted);
bool result = lhs_val || rhs_val;
std::set<std::string> reasons;
if (!lhs_val) {
reasons.merge(lhs_reasons);
}
if (!rhs_val)
reasons.merge(rhs_reasons);
return {result, std::move(reasons)};
}
std::pair<bool, std::set<std::string>> operator()(const Not& data_not) const
{
return data_not.child->evaluate(!inverted);
}
std::pair<bool, std::set<std::string>> operator()(const Leaf& data_leaf) const
{
bool value = inverted ? !data_leaf.m_value : data_leaf.m_value;
std::set<std::string> reasons;
if (!value)
reasons = {data_leaf.get_reason(inverted)};
return {value, std::move(reasons)};
}
};
EvalVisitor obj{inverted};
return std::visit(obj, data);
}
std::string ToggleExpr::comparison_type_to_string(const CompareType type, const bool inverted)
{
if (!inverted) {
switch (type) {
case CompareType::GT: return ">";
case CompareType::LT: return "<";
case CompareType::GTE: return ">=";
case CompareType::LTE: return "<=";
case CompareType::EQ: return "==";
case CompareType::NEQ: return "!=";
default: return "";
}
} else {
switch (type) {
case CompareType::GT: return "<=";
case CompareType::LT: return ">=";
case CompareType::GTE: return "<";
case CompareType::LTE: return ">";
case CompareType::EQ: return "!=";
case CompareType::NEQ: return "==";
default: return "";
}
}
}
ToggleExpr ToggleExpr::FromConfigBool(const DynamicPrintConfig* config, const std::string& opt_key, unsigned opt_idx)
{
auto val = opt_idx == -1 ? config->opt_bool(opt_key) : config->opt_bool(opt_key, opt_idx);
return {val, opt_key};
}
ToggleExpr ToggleExpr::FromConfigInt(
const DynamicPrintConfig* config, const std::string& opt_key, CompareType comp_type, int comp_val, unsigned opt_idx)
{
auto val = opt_idx == -1 ? config->opt_int(opt_key) : config->opt_int(opt_key, opt_idx);
return ToggleExpr(compare(val, comp_type, comp_val), opt_key).set_comparison(comp_type, std::to_string(comp_val));
}
ToggleExprFragment<int> ToggleExpr::FromConfigInt(const DynamicPrintConfig* config, const std::string& opt_key, unsigned opt_idx)
{
return {config, opt_key, opt_idx};
}
ToggleExpr ToggleExpr::FromConfigFloat(
const DynamicPrintConfig* config, const std::string& opt_key, CompareType comp_type, double comp_val, unsigned opt_idx)
{
auto val = opt_idx == -1 ? config->opt_float(opt_key) : config->opt_float(opt_key, opt_idx);
return ToggleExpr(compare(val, comp_type, comp_val), opt_key).set_comparison(comp_type, std::to_string(comp_val));
}
ToggleExprFragment<double> ToggleExpr::FromConfigFloat(const DynamicPrintConfig* config, const std::string& opt_key, unsigned opt_idx)
{
return {config, opt_key, opt_idx};
}
ToggleExpr ToggleExpr::FromConfigString(
const DynamicPrintConfig* config, const std::string& opt_key, CompareType comp_type, const std::string& comp_val, unsigned opt_idx)
{
auto val = opt_idx == -1 ? config->opt_string(opt_key) : config->opt_string(opt_key, opt_idx);
return ToggleExpr(compare(val, comp_type, comp_val), opt_key).set_comparison(comp_type, comp_val);
}
ToggleExprFragment<std::string> ToggleExpr::FromConfigString(const DynamicPrintConfig* config, const std::string& opt_key, unsigned opt_idx)
{
return {config, opt_key, opt_idx};
}
std::string ToggleExpr::build_reasons_string(std::string beginning_message, const std::set<std::string>& reasons)
{
if (reasons.empty()) return "";
auto message = std::move(beginning_message);
if (!message.empty()) {
boost::trim(message);
message += " ";
}
message += "Reasons:\n";
for (auto& reason : reasons) {
message += reason;
message += "\n";
}
return message;
}
}} // namespace Slic3r::GUI

View file

@ -0,0 +1,278 @@
#ifndef ORCASLICER_TOGGLEEXPR_HPP
#define ORCASLICER_TOGGLEEXPR_HPP
namespace Slic3r::GUI {
enum class CompareType { NO_CT, GT, LT, GTE, LTE, EQ, NEQ };
template<typename T> class ToggleExprFragment;
class ToggleExpr
{
struct Result
{
bool value;
std::set<std::string> reasons;
};
struct Node;
using NodePtr = std::shared_ptr<Node>;
struct And
{
NodePtr lhs, rhs;
};
struct Or
{
NodePtr lhs, rhs;
};
struct Not
{
NodePtr child;
};
struct Leaf
{
bool m_value;
std::string m_name;
bool m_has_prefixes{};
std::string m_standard_prefix{};
std::string m_inverted_prefix{};
bool m_disable_postfix{};
std::string m_standard_postfix{" disabled"};
std::string m_inverted_postfix{" enabled"};
CompareType m_comp_type{CompareType::NO_CT};
std::string m_comparison_val{};
Leaf(const bool value, std::string name) : m_value(value), m_name(std::move(name)) {}
[[nodiscard]] std::string get_reason(bool inverted) const;
private:
[[nodiscard]] std::string get_prefix(bool inverted) const;
[[nodiscard]] std::string get_postfix(bool inverted) const;
};
struct Node
{
using NodeData = std::variant<And, Or, Not, Leaf>;
NodeData data;
explicit Node(NodeData _data) : data(std::move(_data)) {}
std::pair<bool, std::set<std::string>> evaluate(bool inverted = false) const;
};
template<class... Ts>
struct visitor : Ts... { using Ts::operator()...; };
template<class... Ts>
visitor(Ts...) -> visitor<Ts...>;
NodePtr m_node;
public:
ToggleExpr(const bool value, std::string name)
{
m_node = std::make_shared<Node>(Leaf{value, std::move(name)});
}
ToggleExpr(std::shared_ptr<Node> node) : m_node(std::move(node)) {}
explicit operator bool() const
{
return get_value();
}
friend ToggleExpr operator&&(const ToggleExpr& lhs, const ToggleExpr& rhs)
{
return ToggleExpr(std::make_shared<Node>(And{lhs.m_node, rhs.m_node}));
}
friend ToggleExpr operator||(const ToggleExpr& lhs, const ToggleExpr& rhs)
{
return ToggleExpr(std::make_shared<Node>(Or{lhs.m_node, rhs.m_node}));
}
friend ToggleExpr operator!(const ToggleExpr& rhs)
{
return ToggleExpr(std::make_shared<Node>(Not{rhs.m_node}));
}
// For ToggleExpr objects that can be LHS
friend ToggleExpr& operator==(ToggleExpr& lhs, std::string rhs) { return lhs.set_comparison(CompareType::EQ, std::move(rhs)); }
friend ToggleExpr& operator!=(ToggleExpr& lhs, std::string rhs) { return lhs.set_comparison(CompareType::NEQ, std::move(rhs)); }
friend ToggleExpr& operator>(ToggleExpr& lhs, std::string rhs) { return lhs.set_comparison(CompareType::GT, std::move(rhs)); }
friend ToggleExpr& operator<(ToggleExpr& lhs, std::string rhs) { return lhs.set_comparison(CompareType::LT, std::move(rhs)); }
friend ToggleExpr& operator>=(ToggleExpr& lhs, std::string rhs) { return lhs.set_comparison(CompareType::GTE, std::move(rhs)); }
friend ToggleExpr& operator<=(ToggleExpr& lhs, std::string rhs) { return lhs.set_comparison(CompareType::LTE, std::move(rhs)); }
// For newly created ToggleExpr objects
friend ToggleExpr& operator==(ToggleExpr lhs, std::string rhs) { return lhs.set_comparison(CompareType::EQ, std::move(rhs)); }
friend ToggleExpr& operator!=(ToggleExpr lhs, std::string rhs) { return lhs.set_comparison(CompareType::NEQ, std::move(rhs)); }
friend ToggleExpr& operator>(ToggleExpr lhs, std::string rhs) { return lhs.set_comparison(CompareType::GT, std::move(rhs)); }
friend ToggleExpr& operator<(ToggleExpr lhs, std::string rhs) { return lhs.set_comparison(CompareType::LT, std::move(rhs)); }
friend ToggleExpr& operator>=(ToggleExpr lhs, std::string rhs) { return lhs.set_comparison(CompareType::GTE, std::move(rhs)); }
friend ToggleExpr& operator<=(ToggleExpr lhs, std::string rhs) { return lhs.set_comparison(CompareType::LTE, std::move(rhs)); }
///
/// \param value_false_prefix When the provided value is false, what should the prefix be?
/// \param opposite_prefix When the provided value is false when inverted ('!' operator), what should the prefix be?
/// \return self
ToggleExpr& set_prefixes(std::string value_false_prefix, std::string opposite_prefix)
{
std::visit(visitor{[](auto& data) { static_assert("Calling set_prefixes on a non leaf node"); },
[&](Leaf& leaf) {
leaf.m_standard_prefix = std::move(value_false_prefix);
leaf.m_inverted_prefix = std::move(opposite_prefix);
}},
m_node->data);
return *this;
}
ToggleExpr& disable_postfix()
{
std::visit(visitor{[](auto&) { static_assert("Calling disable_postfix on a non leaf node"); },
[&](Leaf& leaf) { leaf.m_disable_postfix = true; }},
m_node->data);
return *this;
}
ToggleExpr& set_postfixes(std::string value_false_postfix, std::string opposite_postfix)
{
std::visit(visitor{[](auto&) { static_assert("Calling set_postfixes on a non leaf node"); },
[&](Leaf& leaf) {
leaf.m_standard_postfix = std::move(value_false_postfix);
leaf.m_inverted_postfix = std::move(opposite_postfix);
}},
m_node->data);
return *this;
}
/// Set the comparison that is occurring to generate the provided value
/// \return self
ToggleExpr& set_comparison(CompareType comp_type, std::string comparison_val)
{
std::visit(visitor{[](auto& data) { static_assert("Calling set_comparison on a non leaf node"); },
[&](Leaf& leaf) {
leaf.m_comp_type = comp_type;
leaf.m_comparison_val = std::move(comparison_val);
}},
m_node->data);
return *this;
}
[[nodiscard]] bool get_value() const { return m_node->evaluate().first; }
[[nodiscard]] std::set<std::string> get_reasons() const
{
return m_node->evaluate().second;
}
[[nodiscard]] std::pair<bool, std::set<std::string>> get_result() const
{
return m_node->evaluate();
}
template<typename T> static bool compare(T value, CompareType comp_type, T comp_value)
{
switch (comp_type) {
case CompareType::NO_CT: throw std::invalid_argument("ToggleExpr::FromConfig cannot accept a condition type of NO_CT");
case CompareType::GT: return value > comp_value;
case CompareType::LT: return value < comp_value;
case CompareType::GTE: return value >= comp_value;
case CompareType::LTE: return value <= comp_value;
case CompareType::EQ: return value == comp_value;
case CompareType::NEQ: return value != comp_value;
}
return false;
}
static std::string comparison_type_to_string(CompareType type, bool inverted);
static ToggleExpr FromConfigBool(const DynamicPrintConfig* config, const std::string& opt_key, unsigned opt_idx = -1);
static ToggleExpr FromConfigInt(
const DynamicPrintConfig* config, const std::string& opt_key, CompareType comp_type, int comp_val, unsigned opt_idx = -1);
static ToggleExprFragment<int> FromConfigInt(const DynamicPrintConfig* config, const std::string& opt_key, unsigned opt_idx = -1);
template<typename EnumT>
static ToggleExpr FromConfigEnum(
const DynamicPrintConfig* config, const std::string& opt_key, CompareType comp_type, EnumT comp_value, unsigned opt_idx = -1)
{
bool ret_val;
if (opt_idx == -1) {
auto enum_opt = config->option<ConfigOptionEnum<EnumT>>(opt_key);
auto val = enum_opt->value;
ret_val = compare(val, comp_type, comp_value);
} else {
auto enum_opt = config->option<ConfigOptionEnumsGeneric>(opt_key);
auto val = enum_opt->get_at(opt_idx);
ret_val = compare(static_cast<EnumT>(val), comp_type, comp_value);
}
return ToggleExpr(ret_val, opt_key).set_comparison(comp_type, ConfigOptionEnum<EnumT>::get_enum_names().at(static_cast<int>(comp_value)));
}
template<typename EnumT>
static ToggleExprFragment<EnumT> FromConfigEnum(const DynamicPrintConfig* config, const std::string& opt_key, unsigned opt_idx = -1)
{ return {config, opt_key, opt_idx}; }
static ToggleExpr FromConfigFloat(
const DynamicPrintConfig* config, const std::string& opt_key, CompareType comp_type, double comp_val, unsigned opt_idx = -1);
static ToggleExprFragment<double> FromConfigFloat(const DynamicPrintConfig* config, const std::string& opt_key, unsigned opt_idx = -1);
static ToggleExpr FromConfigString(const DynamicPrintConfig* config,
const std::string& opt_key,
CompareType comp_type,
const std::string& comp_val,
unsigned opt_idx = -1);
static ToggleExprFragment<std::string> FromConfigString(const DynamicPrintConfig* config,
const std::string& opt_key,
unsigned opt_idx = -1);
static std::string build_reasons_string(std::string beginning_message, const std::set<std::string>& reasons);
};
template<typename T> class ToggleExprFragment
{
const DynamicPrintConfig* config;
std::string opt_key;
unsigned opt_idx;
ToggleExpr build_expr(CompareType comp_type, T comp_val) const
{
if constexpr (std::is_same_v<T, int>) {
return ToggleExpr::FromConfigInt(config, opt_key, comp_type, comp_val, opt_idx);
} else if constexpr (std::is_same_v<T, double>) {
return ToggleExpr::FromConfigFloat(config, opt_key, comp_type, comp_val, opt_idx);
} else if constexpr (std::is_same_v<T, std::string>) {
return ToggleExpr::FromConfigString(config, opt_key, comp_type, comp_val, opt_idx);
} else if constexpr (std::is_enum_v<T>) {
return ToggleExpr::FromConfigEnum(config, opt_key, comp_type, comp_val, opt_idx);
} else {
// Unsupported
static_assert(false, "The provided type is unsupported by this class");
}
return ToggleExpr(false, "");
}
public:
ToggleExprFragment(const DynamicPrintConfig* config, const std::string& opt_key, unsigned opt_idx)
: config(config), opt_key(opt_key), opt_idx(opt_idx)
{}
friend ToggleExpr operator==(const ToggleExprFragment& lhs, T rhs) { return lhs.build_expr(CompareType::EQ, rhs); }
friend ToggleExpr operator!=(const ToggleExprFragment& lhs, T rhs) { return lhs.build_expr(CompareType::NEQ, rhs); }
friend ToggleExpr operator>(const ToggleExprFragment& lhs, T rhs) { return lhs.build_expr(CompareType::GT, rhs); }
friend ToggleExpr operator<(const ToggleExprFragment& lhs, T rhs) { return lhs.build_expr(CompareType::LT, rhs); }
friend ToggleExpr operator>=(const ToggleExprFragment& lhs, T rhs) { return lhs.build_expr(CompareType::GTE, rhs); }
friend ToggleExpr operator<=(const ToggleExprFragment& lhs, T rhs) { return lhs.build_expr(CompareType::LTE, rhs); }
friend class ToggleExpr;
};
} // namespace Slic3r::GUI
#endif // ORCASLICER_TOGGLEEXPR_HPP