Merge remote-tracking branch 'PRIVATE/master' into ys_cut
@ -46,7 +46,7 @@ BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 78
|
||||
ColumnLimit: 140
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: true
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
|
BIN
resources/profiles/Creality/ENDER5PRO_thumbnail.png
Normal file
After Width: | Height: | Size: 28 KiB |
3
resources/profiles/Rigid3D.idx
Normal file
@ -0,0 +1,3 @@
|
||||
min_slic3r_version = 2.6.0-alpha0
|
||||
1.0.0 Initial Rigid3D bundle
|
||||
|
469
resources/profiles/Rigid3D.ini
Normal file
@ -0,0 +1,469 @@
|
||||
# Print profiles for the Rigid3D printers.
|
||||
|
||||
[vendor]
|
||||
# Vendor name will be shown by the Config Wizard.
|
||||
name = Rigid3D
|
||||
# Configuration version of this file. Config file will only be installed, if the config_version differs.
|
||||
# This means, the server may force the PrusaSlicer configuration to be downgraded.
|
||||
config_version = 1.0.0
|
||||
# Where to get the updates from?
|
||||
config_update_url = https://files.prusa3d.com/wp-content/uploads/repository/PrusaSlicer-settings-master/live/Rigid3D/
|
||||
# changelog_url = https://files.prusa3d.com/?latest=slicer-profiles&lng=%1%
|
||||
|
||||
# The printer models will be shown by the Configuration Wizard in this order,
|
||||
# also the first model installed & the first nozzle installed will be activated after install.
|
||||
# Printer model name will be shown by the installation wizard.
|
||||
|
||||
[printer_model:Zero2]
|
||||
name = Rigid3D Zero2
|
||||
variants = 0.4
|
||||
technology = FFF
|
||||
family = Zero
|
||||
bed_model = zero_bed.stl
|
||||
bed_texture = zero2_bed.png
|
||||
default_materials = Generic PLA @Rigid3D; Generic PETG @Rigid3D; Generic ABS @Rigid3D; Rigid3D PLA @Rigid3D; Generic Nylon @Rigid3D; Generic FLEX @Rigid3D
|
||||
|
||||
[printer_model:Zero3]
|
||||
name = Rigid3D Zero3
|
||||
variants = 0.4
|
||||
technology = FFF
|
||||
family = Zero
|
||||
bed_model = zero_bed.stl
|
||||
bed_texture = zero3_bed.png
|
||||
default_materials =Generic PLA @Rigid3D; Generic PETG @Rigid3D; Generic ABS @Rigid3D; Rigid3D PLA @Rigid3D; Generic Nylon @Rigid3D; Generic FLEX @Rigid3D
|
||||
|
||||
[printer_model:Mucit]
|
||||
name = Rigid3D Mucit
|
||||
variants = 0.4
|
||||
technology = FFF
|
||||
family = Mucit
|
||||
bed_model = mucit_bed.stl
|
||||
bed_texture = mucit_bed.png
|
||||
default_materials = Generic PLA @Rigid3D; Rigid3D PLA @Rigid3D
|
||||
|
||||
[printer_model:Mucit2]
|
||||
name = Rigid3D Mucit2
|
||||
variants = 0.4
|
||||
technology = FFF
|
||||
family = Mucit
|
||||
bed_model = mucit2_bed.stl
|
||||
bed_texture = mucit2_bed.png
|
||||
default_materials = Generic PLA @Rigid3D; Generic PETG @Rigid3D; Generic ABS @Rigid3D; Rigid3D PLA @Rigid3D; Generic Nylon @Rigid3D; Generic FLEX @Rigid3D
|
||||
|
||||
# All presets starting with asterisk, for example *common*, are intermediate and they will
|
||||
# not make it into the user interface.
|
||||
|
||||
# Common print preset
|
||||
[print:*common*]
|
||||
avoid_crossing_perimeters = 0
|
||||
avoid_crossing_perimeters_max_detour = 0
|
||||
bottom_fill_pattern = monotonic
|
||||
bottom_solid_min_thickness = 0.8
|
||||
bridge_acceleration = 0
|
||||
bridge_angle = 0
|
||||
bridge_flow_ratio = 1
|
||||
bridge_speed = 60
|
||||
brim_separation = 0
|
||||
brim_type = no_brim
|
||||
brim_width = 0
|
||||
clip_multipart_objects = 1
|
||||
compatible_printers =
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_RIGID3D.*/
|
||||
complete_objects = 0
|
||||
default_acceleration = 0
|
||||
dont_support_bridges = 1
|
||||
draft_shield = disabled
|
||||
elefant_foot_compensation = 0
|
||||
ensure_vertical_shell_thickness = 0
|
||||
external_perimeter_extrusion_width = 0.45
|
||||
external_perimeter_speed = 50%
|
||||
external_perimeters_first = 1
|
||||
extra_perimeters = 1
|
||||
extruder_clearance_height = 20
|
||||
extruder_clearance_radius = 20
|
||||
extrusion_width = 0.45
|
||||
fill_angle = 45
|
||||
fill_density = 10%
|
||||
fill_pattern = line
|
||||
first_layer_acceleration = 0
|
||||
first_layer_acceleration_over_raft = 0
|
||||
first_layer_extrusion_width = 0.42
|
||||
first_layer_height = 0.2
|
||||
first_layer_speed = 50%
|
||||
first_layer_speed_over_raft = 30
|
||||
fuzzy_skin = none
|
||||
fuzzy_skin_point_dist = 0.8
|
||||
fuzzy_skin_thickness = 0.3
|
||||
gap_fill_enabled = 1
|
||||
gap_fill_speed = 20
|
||||
gcode_comments = 0
|
||||
gcode_label_objects = 0
|
||||
gcode_resolution = 0.0125
|
||||
gcode_substitutions =
|
||||
infill_acceleration = 0
|
||||
infill_anchor = 2.5
|
||||
infill_anchor_max = 12
|
||||
infill_every_layers = 1
|
||||
infill_extruder = 1
|
||||
infill_extrusion_width = 0.45
|
||||
infill_first = 1
|
||||
infill_only_where_needed = 0
|
||||
infill_overlap = 25%
|
||||
infill_speed = 60
|
||||
inherits =
|
||||
interface_shells = 0
|
||||
ironing = 0
|
||||
ironing_flowrate = 15%
|
||||
ironing_spacing = 0.1
|
||||
ironing_speed = 15
|
||||
ironing_type = top
|
||||
max_print_speed = 80
|
||||
max_volumetric_speed = 0
|
||||
min_skirt_length = 0
|
||||
mmu_segmented_region_max_width = 0
|
||||
notes =
|
||||
only_retract_when_crossing_perimeters = 0
|
||||
ooze_prevention = 0
|
||||
output_filename_format = {input_filename_base}_{layer_height}mm_{initial_filament_type}_{printer_model}_{print_time}.gcode
|
||||
overhangs = 1
|
||||
perimeter_acceleration = 0
|
||||
perimeter_extruder = 1
|
||||
perimeter_extrusion_width = 0.45
|
||||
perimeter_speed = 60
|
||||
perimeters = 2
|
||||
post_process =
|
||||
print_settings_id =
|
||||
raft_contact_distance = 0.1
|
||||
raft_expansion = 1.5
|
||||
raft_first_layer_density = 90%
|
||||
raft_first_layer_expansion = 3
|
||||
raft_layers = 0
|
||||
resolution = 0
|
||||
seam_position = rear
|
||||
single_extruder_multi_material_priming = 1
|
||||
skirt_distance = 6
|
||||
skirt_height = 1
|
||||
skirts = 0
|
||||
slice_closing_radius = 0.049
|
||||
slicing_mode = regular
|
||||
small_perimeter_speed = 15
|
||||
solid_infill_below_area = 70
|
||||
solid_infill_every_layers = 0
|
||||
solid_infill_extruder = 1
|
||||
solid_infill_extrusion_width = 0.45
|
||||
solid_infill_speed = 100%
|
||||
spiral_vase = 0
|
||||
standby_temperature_delta = -5
|
||||
support_material = 0
|
||||
support_material_angle = 0
|
||||
support_material_auto = 1
|
||||
support_material_bottom_contact_distance = 0
|
||||
support_material_bottom_interface_layers = -1
|
||||
support_material_buildplate_only = 0
|
||||
support_material_closing_radius = 2
|
||||
support_material_contact_distance = 0.2
|
||||
support_material_enforce_layers = 0
|
||||
support_material_extruder = 1
|
||||
support_material_extrusion_width = 0.35
|
||||
support_material_interface_contact_loops = 0
|
||||
support_material_interface_extruder = 1
|
||||
support_material_interface_layers = 3
|
||||
support_material_interface_pattern = rectilinear
|
||||
support_material_interface_spacing = 0
|
||||
support_material_interface_speed = 100%
|
||||
support_material_pattern = rectilinear
|
||||
support_material_spacing = 2.5
|
||||
support_material_speed = 60
|
||||
support_material_style = grid
|
||||
support_material_synchronize_layers = 0
|
||||
support_material_threshold = 0
|
||||
support_material_with_sheath = 1
|
||||
support_material_xy_spacing = 50%
|
||||
thick_bridges = 0
|
||||
thin_walls = 1
|
||||
top_fill_pattern = monotonic
|
||||
top_infill_extrusion_width = 0.4
|
||||
top_solid_infill_speed = 100%
|
||||
top_solid_min_thickness = 0.8
|
||||
travel_speed = 80
|
||||
travel_speed_z = 0
|
||||
wipe_tower = 0
|
||||
wipe_tower_bridging = 10
|
||||
wipe_tower_brim_width = 2
|
||||
wipe_tower_no_sparse_layers = 0
|
||||
wipe_tower_rotation_angle = 0
|
||||
wipe_tower_width = 60
|
||||
wipe_tower_x = 180
|
||||
wipe_tower_y = 140
|
||||
xy_size_compensation = 0
|
||||
|
||||
[print:0.06mm - Ultra @Rigid3D]
|
||||
inherits = *common*
|
||||
layer_height = 0.06
|
||||
bottom_solid_layers = 10
|
||||
top_solid_layers = 14
|
||||
|
||||
[print:0.12mm - Super @Rigid3D]
|
||||
inherits = *common*
|
||||
layer_height = 0.12
|
||||
bottom_solid_layers = 7
|
||||
top_solid_layers = 7
|
||||
|
||||
[print:0.16mm - Good @Rigid3D]
|
||||
inherits = *common*
|
||||
layer_height = 0.16
|
||||
bottom_solid_layers = 5
|
||||
top_solid_layers = 5
|
||||
|
||||
[print:0.20mm - Standard @Rigid3D]
|
||||
inherits = *common*
|
||||
layer_height = 0.20
|
||||
bottom_solid_layers = 4
|
||||
top_solid_layers = 4
|
||||
|
||||
[print:0.24mm - Draft @Rigid3D]
|
||||
inherits = *common*
|
||||
layer_height = 0.24
|
||||
bottom_solid_layers = 3
|
||||
top_solid_layers = 4
|
||||
|
||||
[print:0.28mm - Low @Rigid3D]
|
||||
inherits = *common*
|
||||
layer_height = 0.28
|
||||
bottom_solid_layers = 3
|
||||
top_solid_layers = 4
|
||||
|
||||
[filament:*common*]
|
||||
disable_fan_first_layers = 3
|
||||
end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n"
|
||||
extrusion_multiplier = 1
|
||||
fan_below_layer_time = 60
|
||||
filament_cooling_final_speed = 3.4
|
||||
filament_cooling_initial_speed = 2.2
|
||||
filament_cooling_moves = 4
|
||||
filament_cost = 0
|
||||
filament_deretract_speed = nil
|
||||
filament_diameter = 1.75
|
||||
filament_minimal_purge_on_wipe_tower = 15
|
||||
filament_notes = ""
|
||||
filament_retract_before_travel = nil
|
||||
filament_retract_before_wipe = nil
|
||||
filament_retract_layer_change = nil
|
||||
filament_retract_length = nil
|
||||
filament_retract_lift = nil
|
||||
filament_retract_lift_above = nil
|
||||
filament_retract_lift_below = nil
|
||||
filament_retract_restart_extra = nil
|
||||
filament_retract_speed = nil
|
||||
filament_settings_id = ""
|
||||
filament_soluble = 0
|
||||
filament_spool_weight = 0
|
||||
filament_wipe = nil
|
||||
min_print_speed = 10
|
||||
slowdown_below_layer_time = 10
|
||||
start_filament_gcode = "; Filament gcode\n"
|
||||
|
||||
[filament:*PLA*]
|
||||
inherits = *common*
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_RIGID3D.*/
|
||||
bridge_fan_speed = 100
|
||||
cooling = 1
|
||||
fan_always_on = 1
|
||||
filament_type = PLA
|
||||
full_fan_speed_layer = 4
|
||||
max_fan_speed = 100
|
||||
min_fan_speed = 100
|
||||
|
||||
[filament:*ABS*]
|
||||
inherits = *common*
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_RIGID3D.*/ and printer_notes=~/.*PRINTER_HAS_HEATEDBED.*/
|
||||
cooling = 1
|
||||
fan_always_on = 0
|
||||
filament_type = ABS
|
||||
max_fan_speed = 0
|
||||
min_fan_speed = 0
|
||||
|
||||
[filament:*PETG*]
|
||||
inherits = *common*
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_RIGID3D.*/ and printer_notes=~/.*PRINTER_HAS_HEATEDBED.*/
|
||||
cooling = 1
|
||||
fan_always_on = 0
|
||||
filament_type = PETG
|
||||
max_fan_speed = 50
|
||||
min_fan_speed = 30
|
||||
|
||||
[filament:*FLEX*]
|
||||
inherits = *common*
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_RIGID3D.*/ and printer_notes=~/.*PRINTER_HAS_HEATEDBED.*/
|
||||
bridge_fan_speed = 100
|
||||
cooling = 1
|
||||
fan_always_on = 1
|
||||
filament_type = FLEX
|
||||
full_fan_speed_layer = 4
|
||||
max_fan_speed = 100
|
||||
min_fan_speed = 100
|
||||
|
||||
[filament:*NYLON*]
|
||||
inherits = *common*
|
||||
compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_RIGID3D.*/ and printer_notes=~/.*PRINTER_HAS_HEATEDBED.*/
|
||||
cooling = 1
|
||||
fan_always_on = 0
|
||||
filament_type = NYLON
|
||||
max_fan_speed = 0
|
||||
min_fan_speed = 0
|
||||
|
||||
[filament:Generic PLA @Rigid3D]
|
||||
inherits = *PLA*
|
||||
bed_temperature = 55
|
||||
filament_colour = #FFFF00
|
||||
filament_density = 1.24
|
||||
filament_max_volumetric_speed = 12
|
||||
first_layer_temperature = 215
|
||||
temperature = 215
|
||||
first_layer_bed_temperature = 60
|
||||
|
||||
[filament:Rigid3D PLA @Rigid3D]
|
||||
inherits = *PLA*
|
||||
filament_colour = #FFFF00
|
||||
filament_density = 1.24
|
||||
first_layer_temperature = 210
|
||||
temperature = 205
|
||||
first_layer_bed_temperature = 60
|
||||
bed_temperature = 55
|
||||
filament_max_volumetric_speed = 12
|
||||
|
||||
[filament:Generic ABS @Rigid3D]
|
||||
inherits = *ABS*
|
||||
filament_colour = #49B928
|
||||
filament_density = 1.04
|
||||
first_layer_temperature = 235
|
||||
temperature = 235
|
||||
first_layer_bed_temperature = 100
|
||||
bed_temperature = 100
|
||||
filament_max_volumetric_speed = 8
|
||||
|
||||
[filament:Generic PETG @Rigid3D]
|
||||
inherits = *PETG*
|
||||
filament_colour = #FF8000
|
||||
filament_density = 1.27
|
||||
first_layer_temperature = 240
|
||||
temperature = 240
|
||||
first_layer_bed_temperature = 70
|
||||
bed_temperature = 70
|
||||
filament_max_volumetric_speed = 8
|
||||
|
||||
[filament:Generic FLEX @Rigid3D]
|
||||
inherits = *FLEX*
|
||||
filament_colour = #C80000
|
||||
filament_density = 1.21
|
||||
first_layer_temperature = 225
|
||||
temperature = 225
|
||||
first_layer_bed_temperature = 70
|
||||
bed_temperature = 70
|
||||
filament_max_volumetric_speed = 2.5
|
||||
|
||||
[filament:Generic Nylon @Rigid3D]
|
||||
inherits = *NYLON*
|
||||
filament_colour = #0AF1CE
|
||||
filament_density = 1.12
|
||||
first_layer_temperature = 250
|
||||
temperature = 250
|
||||
first_layer_bed_temperature = 100
|
||||
bed_temperature = 100
|
||||
filament_max_volumetric_speed = 8
|
||||
|
||||
# Common printer preset
|
||||
[printer:*common*]
|
||||
before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n
|
||||
between_objects_gcode =
|
||||
color_change_gcode = M600
|
||||
default_filament_profile = "Rigid3D PLA @Rigid3D"
|
||||
default_print_profile = "0.20mm - Standard @Rigid3D"
|
||||
deretract_speed = 0
|
||||
extruder_offset = 0x0
|
||||
gcode_flavor = marlin2
|
||||
layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z]\n\n
|
||||
machine_limits_usage = time_estimate_only
|
||||
machine_max_acceleration_e = 1000
|
||||
machine_max_acceleration_extruding = 500
|
||||
machine_max_acceleration_retracting = 1000
|
||||
machine_max_acceleration_travel = 1000
|
||||
machine_max_acceleration_x = 500
|
||||
machine_max_acceleration_y = 500
|
||||
machine_max_acceleration_z = 100
|
||||
machine_max_feedrate_e = 25
|
||||
machine_max_feedrate_x = 120
|
||||
machine_max_feedrate_y = 120
|
||||
machine_max_feedrate_z = 20
|
||||
machine_max_jerk_e = 5
|
||||
machine_max_jerk_x = 10
|
||||
machine_max_jerk_y = 10
|
||||
machine_max_jerk_z = 0.3
|
||||
machine_min_extruding_rate = 0
|
||||
machine_min_travel_rate = 0
|
||||
max_layer_height = 0.32
|
||||
min_layer_height = 0.05
|
||||
nozzle_diameter = 0.4
|
||||
pause_print_gcode = M0
|
||||
printer_settings_id =
|
||||
printer_technology = FFF
|
||||
printer_variant = 0.4
|
||||
remaining_times = 1
|
||||
retract_before_travel = 2
|
||||
retract_before_wipe = 0%
|
||||
retract_layer_change = 0
|
||||
retract_length = 1
|
||||
retract_length_toolchange = 10
|
||||
retract_lift = 0
|
||||
retract_lift_above = 0
|
||||
retract_lift_below = 0
|
||||
retract_restart_extra = 0
|
||||
retract_restart_extra_toolchange = 0
|
||||
retract_speed = 25
|
||||
silent_mode = 0
|
||||
single_extruder_multi_material = 0
|
||||
template_custom_gcode =
|
||||
thumbnails =
|
||||
toolchange_gcode =
|
||||
use_firmware_retraction = 0
|
||||
use_relative_e_distances = 0
|
||||
use_volumetric_e = 0
|
||||
variable_layer_height = 1
|
||||
wipe = 0
|
||||
z_offset = 0
|
||||
|
||||
[printer:Rigid3D Zero2]
|
||||
inherits = *common*
|
||||
bed_shape = 0x0,200x0,200x200,0x200
|
||||
max_print_height = 190
|
||||
printer_model = Zero2
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_ZERO2\nPRINTER_HAS_HEATEDBED\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X190.0 Y0.1 Z0.3 F1500.0 E15\nG1 X190 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E30\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G1 X0 Y180\nM107\nG91\nG0 Z20\nT0\nG1 E-1\nM104 T0 S0\nG90\nG92 E0\nM140 S0\nM84\nM300 S2093 P150\nM300 S2637 P150\nM300 S3135 P150\nM300 S4186 P150\nM300 S3135 P150\nM300 S2637 P150\nM300 S2793 P150\nM300 S2349 P150\nM300 S1975 P150\nM300 S2093 P450\n
|
||||
|
||||
[printer:Rigid3D Zero3]
|
||||
inherits = *common*
|
||||
bed_shape = 0x0,200x0,200x200,0x200
|
||||
max_print_height = 200
|
||||
printer_model = Zero3
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_ZERO3\nPRINTER_HAS_HEATEDBED\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X190.0 Y0.1 Z0.3 F1500.0 E15\nG1 X190 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E30\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G92 E0\nT0\nG1 F1800 E-2\nG27 P2\nM107\nM104 T0 S0\nM140 S0\nG90\nG92 E0\nM18\n
|
||||
|
||||
[printer:Rigid3D Mucit]
|
||||
inherits = *common*
|
||||
bed_shape = 0x0,150x0,150x150,0x150
|
||||
max_print_height = 150
|
||||
printer_model = Mucit
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_MUCIT\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X140.0 Y0.1 Z0.3 F1500.0 E10\nG1 X140 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E20\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G1 X0 Y140\nM107\nG91\nG0 Z20\nT0\nG1 E-2\nM104 T0 S0\nG90\nG92 E0\nM140 S0\nM84\nM300 S2093 P150\nM300 S2637 P150\nM300 S3135 P150\nM300 S4186 P150\nM300 S3135 P150\nM300 S2637 P150\nM300 S2793 P150\nM300 S2349 P150\nM300 S1975 P150\nM300 S2093 P450\n
|
||||
|
||||
[printer:Rigid3D Mucit2]
|
||||
inherits = *common*
|
||||
bed_shape = 0x0,150x0,150x150,0x150
|
||||
max_print_height = 150
|
||||
printer_model = Mucit2
|
||||
printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_RIGID3D\nPRINTER_MODEL_MUCIT2\nPRINTER_HAS_HEATEDBED\n
|
||||
start_gcode = G21\nG92 E0\nG28\nM420 S1\nM107\nG90\nG1 X10.0 Y0.1 Z0.3 F3000.0\nG1 X140.0 Y0.1 Z0.3 F1500.0 E10\nG1 X140 Y0.4 Z0.3 F3000.0\nG1 X10.0 Y0.4 Z0.3 F1500.0 E20\nG1 Z2.0 F1500.0\nG92 E0\n
|
||||
end_gcode = G92 E0\nT0\nG1 F1800 E-2\nG27 P2\nM107\nM104 T0 S0\nM140 S0\nG90\nG92 E0\nM18\n
|
BIN
resources/profiles/Rigid3D/Mucit2_thumbnail.png
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
resources/profiles/Rigid3D/Mucit_thumbnail.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
resources/profiles/Rigid3D/Zero2_thumbnail.png
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
resources/profiles/Rigid3D/Zero3_thumbnail.png
Normal file
After Width: | Height: | Size: 46 KiB |
BIN
resources/profiles/Rigid3D/mucit2_bed.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
resources/profiles/Rigid3D/mucit2_bed.stl
Normal file
BIN
resources/profiles/Rigid3D/mucit_bed.png
Normal file
After Width: | Height: | Size: 9.1 KiB |
BIN
resources/profiles/Rigid3D/mucit_bed.stl
Normal file
BIN
resources/profiles/Rigid3D/zero2_bed.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
resources/profiles/Rigid3D/zero3_bed.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
resources/profiles/Rigid3D/zero_bed.stl
Normal file
@ -1,8 +1,6 @@
|
||||
#ifndef SRC_LIBSLIC3R_AABBTREELINES_HPP_
|
||||
#define SRC_LIBSLIC3R_AABBTREELINES_HPP_
|
||||
|
||||
#include "libslic3r/Point.hpp"
|
||||
#include "libslic3r/EdgeGrid.hpp"
|
||||
#include "libslic3r/AABBTreeIndirect.hpp"
|
||||
#include "libslic3r/Line.hpp"
|
||||
|
||||
|
@ -245,6 +245,8 @@ set(SLIC3R_SOURCES
|
||||
SlicingAdaptive.hpp
|
||||
Subdivide.cpp
|
||||
Subdivide.hpp
|
||||
SupportSpotsGenerator.cpp
|
||||
SupportSpotsGenerator.hpp
|
||||
SupportMaterial.cpp
|
||||
SupportMaterial.hpp
|
||||
Surface.cpp
|
||||
@ -277,6 +279,8 @@ set(SLIC3R_SOURCES
|
||||
TriangleSelector.hpp
|
||||
TriangleSetSampling.cpp
|
||||
TriangleSetSampling.hpp
|
||||
TriangleSelectorWrapper.cpp
|
||||
TriangleSelectorWrapper.hpp
|
||||
MTUtils.hpp
|
||||
Zipper.hpp
|
||||
Zipper.cpp
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "libslic3r/format.hpp"
|
||||
#include "GCodeProcessor.hpp"
|
||||
|
||||
#include <boost/algorithm/string/case_conv.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
@ -777,8 +778,7 @@ void GCodeProcessorResult::reset() {
|
||||
max_print_height = 0.0f;
|
||||
settings_ids.reset();
|
||||
extruders_count = 0;
|
||||
extruder_colors = DEFAULT_EXTRUDER_COLORS;
|
||||
assert(extruder_colors.size() == MIN_EXTRUDERS_COUNT);
|
||||
extruder_colors = std::vector<std::string>();
|
||||
filament_diameters = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DIAMETER);
|
||||
filament_densities = std::vector<float>(MIN_EXTRUDERS_COUNT, DEFAULT_FILAMENT_DENSITY);
|
||||
#if ENABLE_USED_FILAMENT_POST_PROCESS
|
||||
@ -870,6 +870,7 @@ void GCodeProcessor::apply_config(const PrintConfig& config)
|
||||
{
|
||||
m_parser.apply_config(config);
|
||||
|
||||
m_producer = EProducer::PrusaSlicer;
|
||||
m_flavor = config.gcode_flavor;
|
||||
|
||||
size_t extruders_count = config.nozzle_diameter.values.size();
|
||||
@ -1093,6 +1094,20 @@ void GCodeProcessor::apply_config(const DynamicPrintConfig& config)
|
||||
}
|
||||
}
|
||||
|
||||
// With MM setups like Prusa MMU2, the filaments may be expected to be parked at the beginning.
|
||||
// Remember the parking position so the initial load is not included in filament estimate.
|
||||
const ConfigOptionBool* single_extruder_multi_material = config.option<ConfigOptionBool>("single_extruder_multi_material");
|
||||
const ConfigOptionBool* wipe_tower = config.option<ConfigOptionBool>("wipe_tower");
|
||||
const ConfigOptionFloat* parking_pos_retraction = config.option<ConfigOptionFloat>("parking_pos_retraction");
|
||||
const ConfigOptionFloat* extra_loading_move = config.option<ConfigOptionFloat>("extra_loading_move");
|
||||
|
||||
if (single_extruder_multi_material != nullptr && wipe_tower != nullptr && parking_pos_retraction != nullptr && extra_loading_move != nullptr) {
|
||||
if (single_extruder_multi_material->value && m_result.extruders_count > 1 && wipe_tower->value) {
|
||||
m_parking_position = float(parking_pos_retraction->value);
|
||||
m_extra_loading_move = float(extra_loading_move->value);
|
||||
}
|
||||
}
|
||||
|
||||
bool use_machine_limits = false;
|
||||
const ConfigOptionEnum<MachineLimitsUsage>* machine_limits_usage = config.option<ConfigOptionEnum<MachineLimitsUsage>>("machine_limits_usage");
|
||||
if (machine_limits_usage != nullptr)
|
||||
@ -1289,6 +1304,7 @@ void GCodeProcessor::reset()
|
||||
m_options_z_corrector.reset();
|
||||
|
||||
m_spiral_vase_active = false;
|
||||
m_kissslicer_toolchange_time_correction = 0.0f;
|
||||
|
||||
#if ENABLE_GCODE_VIEWER_DATA_CHECKING
|
||||
m_mm3_per_mm_compare.reset();
|
||||
@ -1343,10 +1359,16 @@ void GCodeProcessor::process_file(const std::string& filename, std::function<voi
|
||||
config.load_from_gcode_file(filename, ForwardCompatibilitySubstitutionRule::EnableSilent);
|
||||
apply_config(config);
|
||||
}
|
||||
else if (m_producer == EProducer::Simplify3D)
|
||||
apply_config_simplify3d(filename);
|
||||
else if (m_producer == EProducer::SuperSlicer)
|
||||
apply_config_superslicer(filename);
|
||||
else {
|
||||
m_result.extruder_colors = DEFAULT_EXTRUDER_COLORS;
|
||||
|
||||
if (m_producer == EProducer::Simplify3D)
|
||||
apply_config_simplify3d(filename);
|
||||
else if (m_producer == EProducer::SuperSlicer)
|
||||
apply_config_superslicer(filename);
|
||||
else if (m_producer == EProducer::KissSlicer)
|
||||
apply_config_kissslicer(filename);
|
||||
}
|
||||
}
|
||||
|
||||
// process gcode
|
||||
@ -1529,6 +1551,82 @@ void GCodeProcessor::apply_config_superslicer(const std::string& filename)
|
||||
apply_config(config);
|
||||
}
|
||||
|
||||
void GCodeProcessor::apply_config_kissslicer(const std::string& filename)
|
||||
{
|
||||
size_t found_counter = 0;
|
||||
m_parser.parse_file_raw(filename, [this, &found_counter](GCodeReader& reader, const char* begin, const char* end) {
|
||||
auto detect_flavor = [this](const std::string_view comment) {
|
||||
static const std::string search_str = "firmware_type";
|
||||
const size_t pos = comment.find(search_str);
|
||||
if (pos != comment.npos) {
|
||||
std::vector<std::string> elements;
|
||||
boost::split(elements, comment, boost::is_any_of("="));
|
||||
if (elements.size() == 2) {
|
||||
try
|
||||
{
|
||||
switch (std::stoi(elements[1]))
|
||||
{
|
||||
default: { break; }
|
||||
case 1:
|
||||
case 2:
|
||||
case 3: { m_flavor = gcfMarlinLegacy; break; }
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// invalid data, do nothing
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
auto detect_printer = [this](const std::string_view comment) {
|
||||
static const std::string search_str = "printer_name";
|
||||
const size_t pos = comment.find(search_str);
|
||||
if (pos != comment.npos) {
|
||||
std::vector<std::string> elements;
|
||||
boost::split(elements, comment, boost::is_any_of("="));
|
||||
if (elements.size() == 2) {
|
||||
elements[1] = boost::to_upper_copy(elements[1]);
|
||||
if (boost::contains(elements[1], "MK2.5") || boost::contains(elements[1], "MK3"))
|
||||
m_kissslicer_toolchange_time_correction = 18.0f; // MMU2
|
||||
else if (boost::contains(elements[1], "MK2"))
|
||||
m_kissslicer_toolchange_time_correction = 5.0f; // MMU
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
begin = skip_whitespaces(begin, end);
|
||||
if (begin != end) {
|
||||
if (*begin == ';') {
|
||||
// Comment.
|
||||
begin = skip_whitespaces(++begin, end);
|
||||
end = remove_eols(begin, end);
|
||||
if (begin != end) {
|
||||
const std::string_view comment(begin, end - begin);
|
||||
if (detect_flavor(comment) || detect_printer(comment))
|
||||
++found_counter;
|
||||
}
|
||||
|
||||
// we got the data,
|
||||
// force early exit to avoid parsing the entire file
|
||||
if (found_counter == 2)
|
||||
m_parser.quit_parsing();
|
||||
}
|
||||
else if (*begin == 'M' || *begin == 'G')
|
||||
// the header has been fully parsed, quit search
|
||||
m_parser.quit_parsing();
|
||||
}
|
||||
}
|
||||
);
|
||||
m_parser.reset();
|
||||
}
|
||||
|
||||
std::vector<float> GCodeProcessor::get_layers_time(PrintEstimatedStatistics::ETimeMode mode) const
|
||||
{
|
||||
return (mode < PrintEstimatedStatistics::ETimeMode::Count) ?
|
||||
@ -2559,7 +2657,7 @@ bool GCodeProcessor::process_bambustudio_tags(const std::string_view comment)
|
||||
bool GCodeProcessor::detect_producer(const std::string_view comment)
|
||||
{
|
||||
for (const auto& [id, search_string] : Producers) {
|
||||
size_t pos = comment.find(search_string);
|
||||
const size_t pos = comment.find(search_string);
|
||||
if (pos != comment.npos) {
|
||||
m_producer = id;
|
||||
BOOST_LOG_TRIVIAL(info) << "Detected gcode producer: " << search_string;
|
||||
@ -3615,10 +3713,12 @@ void GCodeProcessor::process_T(const std::string_view command)
|
||||
// T-1 is a valid gcode line for RepRap Firmwares (used to deselects all tools) see https://github.com/prusa3d/PrusaSlicer/issues/5677
|
||||
if ((m_flavor != gcfRepRapFirmware && m_flavor != gcfRepRapSprinter) || eid != -1)
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid toolchange (" << command << ").";
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
unsigned char id = static_cast<unsigned char>(eid);
|
||||
if (m_extruder_id != id) {
|
||||
if (id >= m_result.extruder_colors.size())
|
||||
if (((m_producer == EProducer::PrusaSlicer || m_producer == EProducer::Slic3rPE || m_producer == EProducer::Slic3r) && id >= m_result.extruders_count) ||
|
||||
((m_producer != EProducer::PrusaSlicer && m_producer != EProducer::Slic3rPE && m_producer != EProducer::Slic3r) && id >= m_result.extruder_colors.size()))
|
||||
BOOST_LOG_TRIVIAL(error) << "GCodeProcessor encountered an invalid toolchange, maybe from a custom gcode.";
|
||||
else {
|
||||
unsigned char old_extruder_id = m_extruder_id;
|
||||
@ -3631,6 +3731,8 @@ void GCodeProcessor::process_T(const std::string_view command)
|
||||
float extra_time = get_filament_unload_time(static_cast<size_t>(old_extruder_id));
|
||||
m_time_processor.extruder_unloaded = false;
|
||||
extra_time += get_filament_load_time(static_cast<size_t>(m_extruder_id));
|
||||
if (m_producer == EProducer::KissSlicer && m_flavor == gcfMarlinLegacy)
|
||||
extra_time += m_kissslicer_toolchange_time_correction;
|
||||
simulate_st_synchronize(extra_time);
|
||||
|
||||
m_result.extruders_count = std::max<size_t>(m_result.extruders_count, m_extruder_id + 1);
|
||||
|
@ -575,6 +575,7 @@ namespace Slic3r {
|
||||
OptionsZCorrector m_options_z_corrector;
|
||||
size_t m_last_default_color_id;
|
||||
bool m_spiral_vase_active;
|
||||
float m_kissslicer_toolchange_time_correction;
|
||||
#if ENABLE_GCODE_VIEWER_STATISTICS
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> m_start_time;
|
||||
#endif // ENABLE_GCODE_VIEWER_STATISTICS
|
||||
@ -648,6 +649,7 @@ namespace Slic3r {
|
||||
void apply_config(const DynamicPrintConfig& config);
|
||||
void apply_config_simplify3d(const std::string& filename);
|
||||
void apply_config_superslicer(const std::string& filename);
|
||||
void apply_config_kissslicer(const std::string& filename);
|
||||
void process_gcode_line(const GCodeReader::GCodeLine& line, bool producers_enabled);
|
||||
|
||||
// Process tags embedded into comments
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "SeamPlacer.hpp"
|
||||
|
||||
#include "Point.hpp"
|
||||
#include "libslic3r.h"
|
||||
#include "tbb/parallel_for.h"
|
||||
#include "tbb/blocked_range.h"
|
||||
#include "tbb/parallel_reduce.h"
|
||||
@ -642,8 +644,8 @@ void compute_global_occlusion(GlobalModelInfo &result, const PrintObject *po,
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< "SeamPlacer: decimate: start";
|
||||
its_short_edge_collpase(triangle_set, 25000);
|
||||
its_short_edge_collpase(negative_volumes_set, 25000);
|
||||
its_short_edge_collpase(triangle_set, SeamPlacer::fast_decimation_triangle_count_target);
|
||||
its_short_edge_collpase(negative_volumes_set, SeamPlacer::fast_decimation_triangle_count_target);
|
||||
|
||||
size_t negative_volumes_start_index = triangle_set.indices.size();
|
||||
its_merge(triangle_set, negative_volumes_set);
|
||||
@ -729,8 +731,9 @@ void gather_enforcers_blockers(GlobalModelInfo &result, const PrintObject *po) {
|
||||
struct SeamComparator {
|
||||
SeamPosition setup;
|
||||
float angle_importance;
|
||||
explicit SeamComparator(SeamPosition setup) :
|
||||
setup(setup) {
|
||||
Vec2f rear_attractor;
|
||||
explicit SeamComparator(SeamPosition setup, const Vec2f& rear_attractor = Vec2f::Zero()) :
|
||||
setup(setup), rear_attractor(rear_attractor) {
|
||||
angle_importance =
|
||||
setup == spNearest ? SeamPlacer::angle_importance_nearest : SeamPlacer::angle_importance_aligned;
|
||||
}
|
||||
@ -761,8 +764,9 @@ struct SeamComparator {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setup == SeamPosition::spRear && a.position.y() != b.position.y()) {
|
||||
return a.position.y() > b.position.y();
|
||||
if (setup == SeamPosition::spRear) {
|
||||
return (a.position.head<2>() - rear_attractor).squaredNorm() <
|
||||
(b.position.head<2>() - rear_attractor).squaredNorm();
|
||||
}
|
||||
|
||||
float distance_penalty_a = 0.0f;
|
||||
@ -824,7 +828,8 @@ struct SeamComparator {
|
||||
}
|
||||
|
||||
if (setup == SeamPosition::spRear) {
|
||||
return a.position.y() + SeamPlacer::seam_align_score_tolerance * 5.0f > b.position.y();
|
||||
return (a.position.head<2>() - rear_attractor).squaredNorm() - a.perimeter.flow_width <
|
||||
(b.position.head<2>() - rear_attractor).squaredNorm();
|
||||
}
|
||||
|
||||
float penalty_a = a.overhang + a.visibility
|
||||
@ -1452,7 +1457,9 @@ void SeamPlacer::init(const Print &print, std::function<void(void)> throw_if_can
|
||||
for (const PrintObject *po : print.objects()) {
|
||||
throw_if_canceled_func();
|
||||
SeamPosition configured_seam_preference = po->config().seam_position.value;
|
||||
SeamComparator comparator { configured_seam_preference };
|
||||
Vec2f rear_attractor = unscaled(po->bounding_box().center()).cast<float>() +
|
||||
1.5f * Vec2f(0.0f, unscale<float>(po->bounding_box().max.y()));
|
||||
SeamComparator comparator{configured_seam_preference, rear_attractor};
|
||||
|
||||
{
|
||||
GlobalModelInfo global_model_info { };
|
||||
|
@ -110,6 +110,7 @@ class SeamPlacer {
|
||||
public:
|
||||
// Number of samples generated on the mesh. There are sqr_rays_per_sample_point*sqr_rays_per_sample_point rays casted from each samples
|
||||
static constexpr size_t raycasting_visibility_samples_count = 30000;
|
||||
static constexpr size_t fast_decimation_triangle_count_target = 16000;
|
||||
//square of number of rays per sample point
|
||||
static constexpr size_t sqr_rays_per_sample_point = 5;
|
||||
|
||||
|
@ -924,6 +924,66 @@ void PresetCollection::save_current_preset(const std::string &new_name, bool det
|
||||
this->get_selected_preset().save();
|
||||
}
|
||||
|
||||
Preset& PresetCollection::get_preset_with_name(const std::string& new_name, const Preset* initial_preset)
|
||||
{
|
||||
// 1) Find the preset with a new_name or create a new one,
|
||||
// initialize it with the preset_to config.
|
||||
auto it = this->find_preset_internal(new_name);
|
||||
if (it != m_presets.end() && it->name == new_name) {
|
||||
// Preset with the same name found.
|
||||
Preset& preset = *it;
|
||||
if (!preset.is_default && !preset.is_external && !preset.is_system && initial_preset->name != new_name) {
|
||||
// Overwriting an existing preset if it isn't default/external/system or isn't an initial_preset
|
||||
preset.config = initial_preset->config;
|
||||
// The newly saved preset can be activated -> make it visible.
|
||||
preset.is_visible = true;
|
||||
}
|
||||
return preset;
|
||||
}
|
||||
|
||||
const std::string selected_preset_name = this->get_selected_preset_name();
|
||||
|
||||
// Creating a new preset.
|
||||
Preset& preset = *m_presets.insert(it, *initial_preset);
|
||||
std::string& inherits = preset.inherits();
|
||||
std::string old_name = preset.name;
|
||||
preset.name = new_name;
|
||||
preset.file = this->path_from_name(new_name);
|
||||
preset.vendor = nullptr;
|
||||
preset.alias.clear();
|
||||
preset.renamed_from.clear();
|
||||
if (preset.is_system) {
|
||||
// Inheriting from a system preset.
|
||||
inherits = old_name;
|
||||
}
|
||||
else if (inherits.empty()) {
|
||||
// Inheriting from a user preset. Link the new preset to the old preset.
|
||||
// inherits = old_name;
|
||||
}
|
||||
else {
|
||||
// Inherited from a user preset. Just maintain the "inherited" flag,
|
||||
// meaning it will inherit from either the system preset, or the inherited user preset.
|
||||
}
|
||||
preset.is_default = false;
|
||||
preset.is_system = false;
|
||||
preset.is_external = false;
|
||||
// The newly saved preset can be activated -> make it visible.
|
||||
preset.is_visible = true;
|
||||
// Just system presets have aliases
|
||||
preset.alias.clear();
|
||||
|
||||
// sort printers and get new it
|
||||
std::sort(m_presets.begin(), m_presets.end());
|
||||
|
||||
// set initial preset selection
|
||||
this->select_preset_by_name(selected_preset_name, true);
|
||||
|
||||
it = this->find_preset_internal(new_name);
|
||||
assert(it != m_presets.end());
|
||||
|
||||
return *it;
|
||||
}
|
||||
|
||||
bool PresetCollection::delete_current_preset()
|
||||
{
|
||||
const Preset &selected = this->get_selected_preset();
|
||||
@ -947,6 +1007,11 @@ bool PresetCollection::delete_current_preset()
|
||||
|
||||
bool PresetCollection::delete_preset(const std::string& name)
|
||||
{
|
||||
if (name == this->get_selected_preset().name)
|
||||
return delete_current_preset();
|
||||
|
||||
const std::string selected_preset_name = this->get_selected_preset_name();
|
||||
|
||||
auto it = this->find_preset_internal(name);
|
||||
|
||||
const Preset& preset = *it;
|
||||
@ -957,6 +1022,10 @@ bool PresetCollection::delete_preset(const std::string& name)
|
||||
boost::nowide::remove(preset.file.c_str());
|
||||
}
|
||||
m_presets.erase(it);
|
||||
|
||||
// update selected preset
|
||||
this->select_preset_by_name(selected_preset_name, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -341,6 +341,10 @@ public:
|
||||
// All presets are marked as not modified and the new preset is activated.
|
||||
void save_current_preset(const std::string &new_name, bool detach = false);
|
||||
|
||||
// Find the preset with a new_name or create a new one,
|
||||
// initialize it with the initial_preset config.
|
||||
Preset& get_preset_with_name(const std::string& new_name, const Preset* initial_preset);
|
||||
|
||||
// Delete the current preset, activate the first visible preset.
|
||||
// returns true if the preset was deleted successfully.
|
||||
bool delete_current_preset();
|
||||
|
@ -425,16 +425,24 @@ void PresetBundle::load_installed_printers(const AppConfig &config)
|
||||
preset.set_visible_from_appconfig(config);
|
||||
}
|
||||
|
||||
const std::string& PresetBundle::get_preset_name_by_alias( const Preset::Type& preset_type, const std::string& alias) const
|
||||
PresetCollection& PresetBundle::get_presets(Preset::Type type)
|
||||
{
|
||||
assert(type >= Preset::TYPE_PRINT && type <= Preset::TYPE_PRINTER);
|
||||
|
||||
return type == Preset::TYPE_PRINT ? prints :
|
||||
type == Preset::TYPE_SLA_PRINT ? sla_prints :
|
||||
type == Preset::TYPE_FILAMENT ? filaments :
|
||||
type == Preset::TYPE_SLA_MATERIAL ? sla_materials : printers;
|
||||
}
|
||||
|
||||
|
||||
const std::string& PresetBundle::get_preset_name_by_alias( const Preset::Type& preset_type, const std::string& alias)
|
||||
{
|
||||
// there are not aliases for Printers profiles
|
||||
if (preset_type == Preset::TYPE_PRINTER || preset_type == Preset::TYPE_INVALID)
|
||||
return alias;
|
||||
|
||||
const PresetCollection& presets = preset_type == Preset::TYPE_PRINT ? prints :
|
||||
preset_type == Preset::TYPE_SLA_PRINT ? sla_prints :
|
||||
preset_type == Preset::TYPE_FILAMENT ? filaments :
|
||||
sla_materials;
|
||||
const PresetCollection& presets = get_presets(preset_type);
|
||||
|
||||
return presets.get_preset_name_by_alias(alias);
|
||||
}
|
||||
@ -442,10 +450,7 @@ const std::string& PresetBundle::get_preset_name_by_alias( const Preset::Type& p
|
||||
void PresetBundle::save_changes_for_preset(const std::string& new_name, Preset::Type type,
|
||||
const std::vector<std::string>& unselected_options)
|
||||
{
|
||||
PresetCollection& presets = type == Preset::TYPE_PRINT ? prints :
|
||||
type == Preset::TYPE_SLA_PRINT ? sla_prints :
|
||||
type == Preset::TYPE_FILAMENT ? filaments :
|
||||
type == Preset::TYPE_SLA_MATERIAL ? sla_materials : printers;
|
||||
PresetCollection& presets = get_presets(type);
|
||||
|
||||
// if we want to save just some from selected options
|
||||
if (!unselected_options.empty()) {
|
||||
@ -468,6 +473,49 @@ void PresetBundle::save_changes_for_preset(const std::string& new_name, Preset::
|
||||
}
|
||||
}
|
||||
|
||||
bool PresetBundle::transfer_and_save(Preset::Type type, const std::string& preset_from_name, const std::string& preset_to_name,
|
||||
const std::string& preset_new_name, const std::vector<std::string>& options)
|
||||
{
|
||||
if (options.empty())
|
||||
return false;
|
||||
|
||||
PresetCollection& presets = get_presets(type);
|
||||
|
||||
const Preset* preset_to = presets.find_preset(preset_to_name, false, false);
|
||||
if (!preset_to)
|
||||
return false;
|
||||
|
||||
// Find the preset with a new_name or create a new one,
|
||||
// initialize it with the preset_to config.
|
||||
Preset& preset = presets.get_preset_with_name(preset_new_name, preset_to);
|
||||
if (preset.is_default || preset.is_external || preset.is_system)
|
||||
// Cannot overwrite the default preset.
|
||||
return false;
|
||||
|
||||
// Apply options from the preset_from_name.
|
||||
const Preset* preset_from = presets.find_preset(preset_from_name, false, false);
|
||||
if (!preset_from)
|
||||
return false;
|
||||
preset.config.apply_only(preset_from->config, options);
|
||||
|
||||
// Store new_name preset to disk.
|
||||
preset.save();
|
||||
|
||||
// Mark the print & filament enabled if they are compatible with the currently selected preset.
|
||||
// If saving the preset changes compatibility with other presets, keep the now incompatible dependent presets selected, however with a "red flag" icon showing that they are no more compatible.
|
||||
update_compatible(PresetSelectCompatibleType::Never);
|
||||
|
||||
if (type == Preset::TYPE_PRINTER)
|
||||
copy_bed_model_and_texture_if_needed(preset.config);
|
||||
|
||||
if (type == Preset::TYPE_FILAMENT) {
|
||||
// synchronize the first filament presets.
|
||||
set_filament_preset(0, filaments.get_selected_preset_name());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PresetBundle::load_installed_filaments(AppConfig &config)
|
||||
{
|
||||
if (! config.has_section(AppConfig::SECTION_FILAMENTS)) {
|
||||
|
@ -54,6 +54,8 @@ public:
|
||||
// extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
|
||||
std::vector<std::string> filament_presets;
|
||||
|
||||
PresetCollection& get_presets(Preset::Type preset_type);
|
||||
|
||||
// The project configuration values are kept separated from the print/filament/printer preset,
|
||||
// they are being serialized / deserialized from / to the .amf, .3mf, .config, .gcode,
|
||||
// and they are being used by slicing core.
|
||||
@ -142,11 +144,15 @@ public:
|
||||
// If the "vendor" section is missing, enable all models and variants of the particular vendor.
|
||||
void load_installed_printers(const AppConfig &config);
|
||||
|
||||
const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias) const;
|
||||
const std::string& get_preset_name_by_alias(const Preset::Type& preset_type, const std::string& alias);
|
||||
|
||||
// Save current preset of a provided type under a new name. If the name is different from the old one,
|
||||
// Unselected option would be reverted to the beginning values
|
||||
void save_changes_for_preset(const std::string& new_name, Preset::Type type, const std::vector<std::string>& unselected_options);
|
||||
// Transfer options form preset_from_name preset to preset_to_name preset and save preset_to_name preset as new new_name preset
|
||||
// Return false, if new preset wasn't saved
|
||||
bool transfer_and_save(Preset::Type type, const std::string& preset_from_name, const std::string& preset_to_name,
|
||||
const std::string& new_name, const std::vector<std::string>& options);
|
||||
|
||||
static const char *PRUSA_BUNDLE;
|
||||
private:
|
||||
|
@ -825,6 +825,8 @@ void Print::process()
|
||||
obj->infill();
|
||||
for (PrintObject *obj : m_objects)
|
||||
obj->ironing();
|
||||
for (PrintObject *obj : m_objects)
|
||||
obj->generate_support_spots();
|
||||
for (PrintObject *obj : m_objects)
|
||||
obj->generate_support_material();
|
||||
if (this->set_started(psWipeTower)) {
|
||||
|
@ -61,7 +61,7 @@ enum PrintStep : unsigned int {
|
||||
|
||||
enum PrintObjectStep : unsigned int {
|
||||
posSlice, posPerimeters, posPrepareInfill,
|
||||
posInfill, posIroning, posSupportMaterial, posCount,
|
||||
posInfill, posIroning, posSupportSpotsSearch, posSupportMaterial, posCount,
|
||||
};
|
||||
|
||||
// A PrintRegion object represents a group of volumes to print
|
||||
@ -381,6 +381,7 @@ private:
|
||||
void prepare_infill();
|
||||
void infill();
|
||||
void ironing();
|
||||
void generate_support_spots();
|
||||
void generate_support_material();
|
||||
|
||||
void slice_volumes();
|
||||
|
@ -1195,8 +1195,10 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_
|
||||
update_apply_status(false);
|
||||
}
|
||||
// Invalidate just the supports step.
|
||||
for (const PrintObjectStatus &print_object_status : print_objects_range)
|
||||
for (const PrintObjectStatus &print_object_status : print_objects_range) {
|
||||
update_apply_status(print_object_status.print_object->invalidate_step(posSupportSpotsSearch));
|
||||
update_apply_status(print_object_status.print_object->invalidate_step(posSupportMaterial));
|
||||
}
|
||||
if (supports_differ) {
|
||||
// Copy just the support volumes.
|
||||
model_volume_list_update_supports(model_object, model_object_new);
|
||||
|
@ -17,6 +17,9 @@
|
||||
#include "Fill/FillAdaptive.hpp"
|
||||
#include "Fill/FillLightning.hpp"
|
||||
#include "Format/STL.hpp"
|
||||
#include "SupportSpotsGenerator.hpp"
|
||||
#include "TriangleSelectorWrapper.hpp"
|
||||
#include "format.hpp"
|
||||
|
||||
#include <float.h>
|
||||
#include <string_view>
|
||||
@ -394,6 +397,65 @@ void PrintObject::ironing()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
std::vector<size_t> problematic_layers = SupportSpotsGenerator::quick_search(this);
|
||||
if (!problematic_layers.empty()) {
|
||||
std::cout << "Object needs supports" << std::endl;
|
||||
this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL,
|
||||
L("Supportable issues found. Consider enabling supports for this object"));
|
||||
this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL,
|
||||
L("Supportable issues found. Consider enabling supports for this object"));
|
||||
for (size_t index = 0; index < std::min(problematic_layers.size(), size_t(4)); ++index) {
|
||||
this->active_step_add_warning(PrintStateBase::WarningLevel::CRITICAL,
|
||||
format(L("Layer with issues: %1%"), problematic_layers[index] + 1));
|
||||
}
|
||||
}
|
||||
*/
|
||||
void PrintObject::generate_support_spots()
|
||||
{
|
||||
if (this->set_started(posSupportSpotsSearch)) {
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< "Searching support spots - start";
|
||||
m_print->set_status(75, L("Searching support spots"));
|
||||
if (this->m_config.support_material && !this->m_config.support_material_auto &&
|
||||
std::all_of(this->model_object()->volumes.begin(), this->model_object()->volumes.end(),
|
||||
[](const ModelVolume* mv){return mv->supported_facets.empty();})
|
||||
) {
|
||||
SupportSpotsGenerator::Params params{this->print()->m_config.filament_type.values};
|
||||
SupportSpotsGenerator::Issues issues = SupportSpotsGenerator::full_search(this, params);
|
||||
auto obj_transform = this->trafo_centered();
|
||||
for (ModelVolume *model_volume : this->model_object()->volumes) {
|
||||
if (model_volume->is_model_part()) {
|
||||
Transform3d mesh_transformation = obj_transform * model_volume->get_matrix();
|
||||
Transform3d inv_transform = mesh_transformation.inverse();
|
||||
TriangleSelectorWrapper selector { model_volume->mesh(), mesh_transformation};
|
||||
|
||||
for (const SupportSpotsGenerator::SupportPoint &support_point : issues.support_points) {
|
||||
Vec3f point = Vec3f(inv_transform.cast<float>() * support_point.position);
|
||||
Vec3f origin = Vec3f(
|
||||
inv_transform.cast<float>() * Vec3f(support_point.position.x(), support_point.position.y(), 0.0f));
|
||||
selector.enforce_spot(point, origin, support_point.spot_radius);
|
||||
}
|
||||
|
||||
model_volume->supported_facets.set(selector.selector);
|
||||
#if 0 //DEBUG export
|
||||
indexed_triangle_set copy = model_volume->mesh().its;
|
||||
its_transform(copy, obj_transform * model_transformation);
|
||||
its_write_obj(copy,
|
||||
debug_out_path(("model"+std::to_string(model_volume->id().id)+".obj").c_str()).c_str());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_print->throw_if_canceled();
|
||||
BOOST_LOG_TRIVIAL(debug)
|
||||
<< "Searching support spots - end";
|
||||
this->set_done(posSupportSpotsSearch);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintObject::generate_support_material()
|
||||
{
|
||||
if (this->set_started(posSupportMaterial)) {
|
||||
|
@ -97,7 +97,8 @@ void its_short_edge_collpase(indexed_triangle_set &mesh, size_t target_triangle_
|
||||
|
||||
//shuffle the faces and traverse in random order, this MASSIVELY improves the quality of the result
|
||||
std::shuffle(face_indices.begin(), face_indices.end(), generator);
|
||||
|
||||
|
||||
int allowed_face_removals = int(face_indices.size()) - int(target_triangle_count);
|
||||
for (const size_t &face_idx : face_indices) {
|
||||
if (face_removal_flags[face_idx]) {
|
||||
// if face already removed from previous collapses, skip (each collapse removes two triangles [at least] )
|
||||
@ -130,10 +131,13 @@ void its_short_edge_collpase(indexed_triangle_set &mesh, size_t target_triangle_
|
||||
// remove faces
|
||||
remove_face(face_idx, neighbor_to_remove_face_idx);
|
||||
remove_face(neighbor_to_remove_face_idx, face_idx);
|
||||
allowed_face_removals-=2;
|
||||
|
||||
// break. this triangle is done
|
||||
break;
|
||||
}
|
||||
|
||||
if (allowed_face_removals <= 0) { break; }
|
||||
}
|
||||
|
||||
// filter face_indices, remove those that have been collapsed
|
||||
|
1257
src/libslic3r/SupportSpotsGenerator.cpp
Normal file
82
src/libslic3r/SupportSpotsGenerator.hpp
Normal file
@ -0,0 +1,82 @@
|
||||
#ifndef SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_
|
||||
#define SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_
|
||||
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
namespace SupportSpotsGenerator {
|
||||
|
||||
struct Params {
|
||||
Params(const std::vector<std::string> &filament_types) {
|
||||
if (filament_types.size() > 1) {
|
||||
BOOST_LOG_TRIVIAL(warning)
|
||||
<< "SupportSpotsGenerator does not currently handle different materials properly, only first will be used";
|
||||
}
|
||||
if (filament_types.empty() || filament_types[0].empty()) {
|
||||
BOOST_LOG_TRIVIAL(error)
|
||||
<< "SupportSpotsGenerator error: empty filament_type";
|
||||
filament_type = std::string("PLA");
|
||||
} else {
|
||||
filament_type = filament_types[0];
|
||||
}
|
||||
}
|
||||
|
||||
// the algorithm should use the following units for all computations: distance [mm], mass [g], time [s], force [g*mm/s^2]
|
||||
const float bridge_distance = 12.0f; //mm
|
||||
const float bridge_distance_decrease_by_curvature_factor = 5.0f; // allowed bridge distance = bridge_distance / (1 + this factor * (curvature / PI) )
|
||||
const float overhang_angle_deg = 80.0f;
|
||||
const std::pair<float,float> malformation_angle_span_deg = std::pair<float, float> { 45.0f, 80.0f };
|
||||
|
||||
const float min_distance_between_support_points = 3.0f; //mm
|
||||
const float support_points_interface_radius = 1.5f; // mm
|
||||
const float connections_min_considerable_area = 1.5f; //mm^2
|
||||
const float small_parts_threshold = 5.0f; //mm^3
|
||||
const float small_parts_support_points_interface_radius = 3.0f; // mm
|
||||
|
||||
std::string filament_type;
|
||||
const float gravity_constant = 9806.65f; // mm/s^2; gravity acceleration on Earth's surface, algorithm assumes that printer is in upwards position.
|
||||
const float max_acceleration = 9 * 1000.0f; // mm/s^2 ; max acceleration of object (bed) in XY (NOTE: The max hit is received by the object in the jerk phase, so the usual machine limits are too low)
|
||||
const double filament_density = 1.25e-3f; // g/mm^3 ; Common filaments are very lightweight, so precise number is not that important
|
||||
const double material_yield_strength = 33.0f * 1e6f; // (g*mm/s^2)/mm^2; 33 MPa is yield strength of ABS, which has the lowest yield strength from common materials.
|
||||
const float standard_extruder_conflict_force = 20.0f * gravity_constant; // force that can occasionally push the model due to various factors (filament leaks, small curling, ... );
|
||||
const float malformations_additive_conflict_extruder_force = 300.0f * gravity_constant; // for areas with possible high layered curled filaments
|
||||
|
||||
// MPa * 1e^6 = (g*mm/s^2)/mm^2 = g/(mm*s^2); yield strength of the bed surface
|
||||
double get_bed_adhesion_yield_strength() const {
|
||||
if (filament_type == "PLA") {
|
||||
return 0.018 * 1e6;
|
||||
} else if (filament_type == "PET" || filament_type == "PETG") {
|
||||
return 0.3 * 1e6;
|
||||
} else { //PLA default value - defensive approach, PLA has quite low adhesion
|
||||
return 0.018 * 1e6;
|
||||
}
|
||||
}
|
||||
|
||||
//just return PLA adhesion value as value for supports
|
||||
double get_support_spots_adhesion_strength() const {
|
||||
return 0.018f * 1e6;
|
||||
}
|
||||
};
|
||||
|
||||
struct SupportPoint {
|
||||
SupportPoint(const Vec3f &position, float force, float spot_radius, const Vec3f &direction);
|
||||
Vec3f position;
|
||||
float force;
|
||||
float spot_radius;
|
||||
Vec3f direction;
|
||||
};
|
||||
|
||||
struct Issues {
|
||||
std::vector<SupportPoint> support_points;
|
||||
};
|
||||
|
||||
// std::vector<size_t> quick_search(const PrintObject *po, const Params ¶ms);
|
||||
Issues full_search(const PrintObject *po, const Params ¶ms);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif /* SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_ */
|
46
src/libslic3r/TriangleSelectorWrapper.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include "TriangleSelectorWrapper.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
TriangleSelectorWrapper::TriangleSelectorWrapper(const TriangleMesh &mesh, const Transform3d& mesh_transform) :
|
||||
mesh(mesh), mesh_transform(mesh_transform), selector(mesh), triangles_tree(
|
||||
AABBTreeIndirect::build_aabb_tree_over_indexed_triangle_set(mesh.its.vertices, mesh.its.indices)) {
|
||||
|
||||
}
|
||||
|
||||
void TriangleSelectorWrapper::enforce_spot(const Vec3f &point, const Vec3f &origin, float radius) {
|
||||
std::vector<igl::Hit> hits;
|
||||
Vec3f dir = (point - origin).normalized();
|
||||
if (AABBTreeIndirect::intersect_ray_all_hits(mesh.its.vertices, mesh.its.indices, triangles_tree,
|
||||
Vec3d(origin.cast<double>()),
|
||||
Vec3d(dir.cast<double>()),
|
||||
hits)) {
|
||||
for (int hit_idx = hits.size() - 1; hit_idx >= 0; --hit_idx) {
|
||||
const igl::Hit &hit = hits[hit_idx];
|
||||
Vec3f pos = origin + dir * hit.t;
|
||||
Vec3f face_normal = its_face_normal(mesh.its, hit.id);
|
||||
if ((point - pos).norm() < radius && face_normal.dot(dir) < 0) {
|
||||
std::unique_ptr<TriangleSelector::Cursor> cursor = std::make_unique<TriangleSelector::Sphere>(
|
||||
pos, origin, radius, this->mesh_transform, TriangleSelector::ClippingPlane { });
|
||||
selector.select_patch(hit.id, std::move(cursor), EnforcerBlockerType::ENFORCER, Transform3d::Identity(),
|
||||
true, 0.0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
size_t hit_idx_out;
|
||||
Vec3f hit_point_out;
|
||||
float dist = AABBTreeIndirect::squared_distance_to_indexed_triangle_set(mesh.its.vertices, mesh.its.indices,
|
||||
triangles_tree, point, hit_idx_out, hit_point_out);
|
||||
if (dist < radius) {
|
||||
std::unique_ptr<TriangleSelector::Cursor> cursor = std::make_unique<TriangleSelector::Sphere>(
|
||||
point, origin, radius, this->mesh_transform, TriangleSelector::ClippingPlane { });
|
||||
selector.select_patch(hit_idx_out, std::move(cursor), EnforcerBlockerType::ENFORCER,
|
||||
Transform3d::Identity(),
|
||||
true, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
31
src/libslic3r/TriangleSelectorWrapper.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef SRC_LIBSLIC3R_TRIANGLESELECTORWRAPPER_HPP_
|
||||
#define SRC_LIBSLIC3R_TRIANGLESELECTORWRAPPER_HPP_
|
||||
|
||||
#include "TriangleSelector.hpp"
|
||||
#include "Model.hpp"
|
||||
#include "AABBTreeIndirect.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
//NOTE: We need to replace the FacetsAnnotation struct for support storage (or extend/add another)
|
||||
// Problems: Does not support negative volumes, strange usage for supports computed from extrusion -
|
||||
// expensively converted back to triangles and then sliced again.
|
||||
// Another problem is weird and very limited interface when painting supports via algorithms
|
||||
|
||||
|
||||
class TriangleSelectorWrapper {
|
||||
public:
|
||||
const TriangleMesh &mesh;
|
||||
const Transform3d& mesh_transform;
|
||||
TriangleSelector selector;
|
||||
AABBTreeIndirect::Tree<3, float> triangles_tree;
|
||||
|
||||
TriangleSelectorWrapper(const TriangleMesh &mesh, const Transform3d& mesh_transform);
|
||||
|
||||
void enforce_spot(const Vec3f &point, const Vec3f& origin, float radius);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SRC_LIBSLIC3R_TRIANGLESELECTORWRAPPER_HPP_ */
|
@ -738,7 +738,7 @@ void BackgroundSlicingProcess::prepare_upload()
|
||||
|
||||
ThumbnailsList thumbnails = this->render_thumbnails(
|
||||
ThumbnailsParams{current_print()->full_print_config().option<ConfigOptionPoints>("thumbnails")->values, true, true, true, true});
|
||||
m_sla_print->export_print(source_path.string(),thumbnails, m_upload_job.upload_data.upload_path.string());
|
||||
m_sla_print->export_print(source_path.string(),thumbnails, m_upload_job.upload_data.upload_path.filename().string());
|
||||
}
|
||||
|
||||
m_print->set_status(100, (boost::format(_utf8(L("Scheduling upload to `%1%`. See Window -> Print Host Upload Queue"))) % m_upload_job.printhost->get_host()).str());
|
||||
|
@ -2564,9 +2564,9 @@ bool ConfigWizard::priv::apply_config(AppConfig *app_config, PresetBundle *prese
|
||||
bool check_unsaved_preset_changes = page_welcome->reset_user_profile();
|
||||
if (check_unsaved_preset_changes)
|
||||
header = _L("All user presets will be deleted.");
|
||||
int act_btns = UnsavedChangesDialog::ActionButtons::KEEP;
|
||||
int act_btns = ActionButtons::KEEP;
|
||||
if (!check_unsaved_preset_changes)
|
||||
act_btns |= UnsavedChangesDialog::ActionButtons::SAVE;
|
||||
act_btns |= ActionButtons::SAVE;
|
||||
|
||||
// Install bundles from resources if needed:
|
||||
std::vector<std::string> install_bundles;
|
||||
|
@ -3860,14 +3860,16 @@ void GCodeViewer::render_legend(float& legend_height)
|
||||
|
||||
if (m_view_type == EViewType::Tool) {
|
||||
// calculate used filaments data
|
||||
used_filaments_m = std::vector<double>(m_extruders_count, 0.0);
|
||||
used_filaments_g = std::vector<double>(m_extruders_count, 0.0);
|
||||
for (size_t extruder_id : m_extruder_ids) {
|
||||
if (m_print_statistics.volumes_per_extruder.find(extruder_id) == m_print_statistics.volumes_per_extruder.end())
|
||||
continue;
|
||||
double volume = m_print_statistics.volumes_per_extruder.at(extruder_id);
|
||||
|
||||
auto [used_filament_m, used_filament_g] = get_used_filament_from_volume(volume, extruder_id);
|
||||
used_filaments_m.push_back(used_filament_m);
|
||||
used_filaments_g.push_back(used_filament_g);
|
||||
used_filaments_m[extruder_id] = used_filament_m;
|
||||
used_filaments_g[extruder_id] = used_filament_g;
|
||||
}
|
||||
|
||||
std::string longest_used_filament_string;
|
||||
@ -4000,11 +4002,10 @@ void GCodeViewer::render_legend(float& legend_height)
|
||||
#endif // ENABLE_PREVIEW_LAYER_TIME
|
||||
case EViewType::Tool: {
|
||||
// shows only extruders actually used
|
||||
size_t i = 0;
|
||||
for (unsigned char extruder_id : m_extruder_ids) {
|
||||
append_item(EItemType::Rect, m_tool_colors[extruder_id], _u8L("Extruder") + " " + std::to_string(extruder_id + 1),
|
||||
true, "", 0.0f, 0.0f, offsets, used_filaments_m[i], used_filaments_g[i]);
|
||||
++i;
|
||||
if (used_filaments_m[extruder_id] > 0.0 && used_filaments_g[extruder_id] > 0.0)
|
||||
append_item(EItemType::Rect, m_tool_colors[extruder_id], _u8L("Extruder") + " " + std::to_string(extruder_id + 1),
|
||||
true, "", 0.0f, 0.0f, offsets, used_filaments_m[extruder_id], used_filaments_g[extruder_id]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -834,14 +834,14 @@ void GLCanvas3D::Labels::render(const std::vector<const ModelInstance*>& sorted_
|
||||
imgui.begin(owner.title, ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove);
|
||||
ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindow());
|
||||
float win_w = ImGui::GetWindowWidth();
|
||||
float label_len = imgui.calc_text_size(owner.label).x;
|
||||
float label_len = ImGui::CalcTextSize(owner.label.c_str()).x;
|
||||
ImGui::SetCursorPosX(0.5f * (win_w - label_len));
|
||||
ImGui::AlignTextToFramePadding();
|
||||
imgui.text(owner.label);
|
||||
|
||||
if (!owner.print_order.empty()) {
|
||||
ImGui::Separator();
|
||||
float po_len = imgui.calc_text_size(owner.print_order).x;
|
||||
float po_len = ImGui::CalcTextSize(owner.print_order.c_str()).x;
|
||||
ImGui::SetCursorPosX(0.5f * (win_w - po_len));
|
||||
ImGui::AlignTextToFramePadding();
|
||||
imgui.text(owner.print_order);
|
||||
@ -4185,7 +4185,7 @@ void GLCanvas3D::handle_sidebar_focus_event(const std::string& opt_key, bool foc
|
||||
|
||||
void GLCanvas3D::handle_layers_data_focus_event(const t_layer_height_range range, const EditorType type)
|
||||
{
|
||||
std::string field = "layer_" + std::to_string(type) + "_" + std::to_string(range.first) + "_" + std::to_string(range.second);
|
||||
std::string field = "layer_" + std::to_string(type) + "_" + float_to_string_decimal_point(range.first) + "_" + float_to_string_decimal_point(range.second);
|
||||
handle_sidebar_focus_event(field, true);
|
||||
}
|
||||
|
||||
|
@ -171,7 +171,7 @@ namespace GUI {
|
||||
GLModel::Geometry init_data;
|
||||
#if ENABLE_GL_CORE_PROFILE || ENABLE_OPENGL_ES
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::Lines, GLModel::Geometry::EVertexLayout::P4 };
|
||||
init_data.reserve_vertices(8);
|
||||
init_data.reserve_vertices(5);
|
||||
init_data.reserve_indices(8);
|
||||
#else
|
||||
init_data.format = { GLModel::Geometry::EPrimitiveType::LineLoop, GLModel::Geometry::EVertexLayout::P2 };
|
||||
@ -187,25 +187,19 @@ namespace GUI {
|
||||
|
||||
init_data.add_vertex(Vec4f(left, bottom, 0.0f, perimeter));
|
||||
perimeter += width;
|
||||
init_data.add_vertex(Vec4f(right, bottom, 0.0f, perimeter));
|
||||
|
||||
init_data.add_vertex(Vec4f(right, bottom, 0.0f, perimeter));
|
||||
perimeter += height;
|
||||
init_data.add_vertex(Vec4f(right, top, 0.0f, perimeter));
|
||||
|
||||
init_data.add_vertex(Vec4f(right, top, 0.0f, perimeter));
|
||||
perimeter += width;
|
||||
init_data.add_vertex(Vec4f(left, top, 0.0f, perimeter));
|
||||
|
||||
init_data.add_vertex(Vec4f(left, top, 0.0f, perimeter));
|
||||
perimeter += height;
|
||||
init_data.add_vertex(Vec4f(left, bottom, 0.0f, perimeter));
|
||||
|
||||
// indices
|
||||
init_data.add_line(0, 1);
|
||||
init_data.add_line(1, 2);
|
||||
init_data.add_line(2, 3);
|
||||
init_data.add_line(4, 5);
|
||||
init_data.add_line(6, 7);
|
||||
init_data.add_line(3, 4);
|
||||
#else
|
||||
init_data.add_vertex(Vec2f(left, bottom));
|
||||
init_data.add_vertex(Vec2f(right, bottom));
|
||||
|
@ -2521,9 +2521,9 @@ bool GUI_App::check_and_save_current_preset_changes(const wxString& caption, con
|
||||
{
|
||||
if (has_current_preset_changes()) {
|
||||
const std::string app_config_key = remember_choice ? "default_action_on_close_application" : "";
|
||||
int act_buttons = UnsavedChangesDialog::ActionButtons::SAVE;
|
||||
int act_buttons = ActionButtons::SAVE;
|
||||
if (dont_save_insted_of_discard)
|
||||
act_buttons |= UnsavedChangesDialog::ActionButtons::DONT_SAVE;
|
||||
act_buttons |= ActionButtons::DONT_SAVE;
|
||||
UnsavedChangesDialog dlg(caption, header, app_config_key, act_buttons);
|
||||
std::string act = app_config_key.empty() ? "none" : wxGetApp().app_config->get(app_config_key);
|
||||
if (act == "none" && dlg.ShowModal() == wxID_CANCEL)
|
||||
@ -2540,8 +2540,7 @@ bool GUI_App::check_and_save_current_preset_changes(const wxString& caption, con
|
||||
// synchronize config.ini with the current selections.
|
||||
preset_bundle->export_selections(*app_config);
|
||||
|
||||
MessageDialog(nullptr, _L_PLURAL("The preset modifications are successfully saved",
|
||||
"The presets modifications are successfully saved", dlg.get_names_and_types().size())).ShowModal();
|
||||
MessageDialog(nullptr, dlg.msg_success_saved_modifications(dlg.get_names_and_types().size())).ShowModal();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2601,8 +2600,7 @@ bool GUI_App::check_and_keep_current_preset_changes(const wxString& caption, con
|
||||
// synchronize config.ini with the current selections.
|
||||
preset_bundle->export_selections(*app_config);
|
||||
|
||||
wxString text = _L_PLURAL("The preset modifications are successfully saved",
|
||||
"The presets modifications are successfully saved", preset_names_and_types.size());
|
||||
wxString text = dlg.msg_success_saved_modifications(preset_names_and_types.size());
|
||||
if (!is_called_from_configwizard)
|
||||
text += "\n\n" + _L("For new project all modifications will be reseted");
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "slic3r/GUI/GUI_ObjectList.hpp"
|
||||
#include "slic3r/GUI/format.hpp"
|
||||
#include "slic3r/Utils/UndoRedo.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "slic3r/GUI/MsgDialog.hpp"
|
||||
|
||||
|
||||
#include <GL/glew.h>
|
||||
@ -39,6 +41,8 @@ bool GLGizmoFdmSupports::on_init()
|
||||
{
|
||||
m_shortcut_key = WXK_CONTROL_L;
|
||||
|
||||
m_desc["auto_generate"] = _L("Auto-generate supports");
|
||||
m_desc["generating"] = _L("Generating supports...");
|
||||
m_desc["clipping_of_view"] = _L("Clipping of view") + ": ";
|
||||
m_desc["reset_direction"] = _L("Reset direction");
|
||||
m_desc["cursor_size"] = _L("Brush size") + ": ";
|
||||
@ -91,7 +95,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
if (! m_c->selection_info()->model_object())
|
||||
return;
|
||||
|
||||
const float approx_height = m_imgui->scaled(23.f);
|
||||
const float approx_height = m_imgui->scaled(25.f);
|
||||
y = std::min(y, bottom_limit - approx_height);
|
||||
m_imgui->set_next_window_pos(x, y, ImGuiCond_Always);
|
||||
|
||||
@ -153,6 +157,15 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (waiting_for_autogenerated_supports) {
|
||||
m_imgui->text(m_desc.at("generating"));
|
||||
} else {
|
||||
bool generate = m_imgui->button(m_desc.at("auto_generate"));
|
||||
if (generate)
|
||||
auto_generate();
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
float position_before_text_y = ImGui::GetCursorPos().y;
|
||||
ImGui::AlignTextToFramePadding();
|
||||
m_imgui->text_wrapped(m_desc["highlight_by_angle"] + ":", autoset_slider_label_max_width);
|
||||
@ -319,6 +332,7 @@ void GLGizmoFdmSupports::on_render_input_window(float x, float y, float bottom_l
|
||||
}
|
||||
|
||||
update_model_object();
|
||||
this->waiting_for_autogenerated_supports = false;
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
|
||||
@ -366,9 +380,54 @@ void GLGizmoFdmSupports::select_facets_by_angle(float threshold_deg, bool block)
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), block ? _L("Block supports by angle")
|
||||
: _L("Add supports by angle"));
|
||||
update_model_object();
|
||||
this->waiting_for_autogenerated_supports = false;
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
|
||||
void GLGizmoFdmSupports::data_changed()
|
||||
{
|
||||
GLGizmoPainterBase::data_changed();
|
||||
if (! m_c->selection_info())
|
||||
return;
|
||||
|
||||
ModelObject* mo = m_c->selection_info()->model_object();
|
||||
if (mo && this->waiting_for_autogenerated_supports) {
|
||||
get_data_from_backend();
|
||||
} else {
|
||||
this->waiting_for_autogenerated_supports = false;
|
||||
}
|
||||
}
|
||||
|
||||
void GLGizmoFdmSupports::get_data_from_backend()
|
||||
{
|
||||
if (! has_backend_supports())
|
||||
return;
|
||||
ModelObject* mo = m_c->selection_info()->model_object();
|
||||
|
||||
// find the respective PrintObject, we need a pointer to it
|
||||
for (const PrintObject* po : m_parent.fff_print()->objects()) {
|
||||
if (po->model_object()->id() == mo->id()) {
|
||||
std::unordered_map<size_t, const ModelVolume*> mvs;
|
||||
for (const ModelVolume* mv : po->model_object()->volumes) {
|
||||
if (mv->is_model_part()) {
|
||||
mvs.emplace(mv->id().id, mv);
|
||||
}
|
||||
}
|
||||
int mesh_id = -1.0f;
|
||||
for (ModelVolume* mv : mo->volumes){
|
||||
if (mv->is_model_part()){
|
||||
mesh_id++;
|
||||
mv->supported_facets.assign(mvs[mv->id().id]->supported_facets);
|
||||
m_triangle_selectors[mesh_id]->deserialize(mv->supported_facets.get_data(), true);
|
||||
m_triangle_selectors[mesh_id]->request_update_render_data();
|
||||
}
|
||||
}
|
||||
this->waiting_for_autogenerated_supports = false;
|
||||
m_parent.post_event(SimpleEvent(EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS));
|
||||
m_parent.set_as_dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::update_model_object() const
|
||||
@ -391,8 +450,6 @@ void GLGizmoFdmSupports::update_model_object() const
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLGizmoFdmSupports::update_from_model_object()
|
||||
{
|
||||
wxBusyCursor wait;
|
||||
@ -417,6 +474,58 @@ void GLGizmoFdmSupports::update_from_model_object()
|
||||
}
|
||||
}
|
||||
|
||||
bool GLGizmoFdmSupports::has_backend_supports() const
|
||||
{
|
||||
const ModelObject* mo = m_c->selection_info()->model_object();
|
||||
if (! mo)
|
||||
return false;
|
||||
|
||||
// find PrintObject with this ID
|
||||
for (const PrintObject* po : m_parent.fff_print()->objects()) {
|
||||
if (po->model_object()->id() == mo->id())
|
||||
return po->is_step_done(posSupportSpotsSearch);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void GLGizmoFdmSupports::reslice_FDM_supports(bool postpone_error_messages) const {
|
||||
wxGetApp().CallAfter(
|
||||
[this, postpone_error_messages]() {
|
||||
wxGetApp().plater()->reslice_FFF_until_step(posSupportSpotsSearch,
|
||||
*m_c->selection_info()->model_object(), postpone_error_messages);
|
||||
});
|
||||
}
|
||||
|
||||
void GLGizmoFdmSupports::auto_generate()
|
||||
{
|
||||
ModelObject *mo = m_c->selection_info()->model_object();
|
||||
bool not_painted = std::all_of(mo->volumes.begin(), mo->volumes.end(), [](const ModelVolume* vol){
|
||||
return vol->type() != ModelVolumeType::MODEL_PART || vol->supported_facets.empty();
|
||||
});
|
||||
|
||||
MessageDialog dlg(GUI::wxGetApp().plater(),
|
||||
_L("Autogeneration will erase all currently painted areas.") + "\n\n" +
|
||||
_L("Are you sure you want to do it?") + "\n",
|
||||
_L("Warning"), wxICON_WARNING | wxYES | wxNO);
|
||||
|
||||
if (not_painted || dlg.ShowModal() == wxID_YES) {
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Autogenerate support points"));
|
||||
int mesh_id = -1.0f;
|
||||
for (ModelVolume *mv : mo->volumes) {
|
||||
if (mv->is_model_part()) {
|
||||
mesh_id++;
|
||||
mv->supported_facets.reset();
|
||||
m_triangle_selectors[mesh_id]->reset();
|
||||
m_triangle_selectors[mesh_id]->request_update_render_data();
|
||||
}
|
||||
}
|
||||
|
||||
mo->config.set("support_material", true);
|
||||
mo->config.set("support_material_auto", false);
|
||||
this->waiting_for_autogenerated_supports = true;
|
||||
wxGetApp().CallAfter([this]() { reslice_FDM_supports(); });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PainterGizmoType GLGizmoFdmSupports::get_painter_type() const
|
||||
|
@ -26,6 +26,7 @@ protected:
|
||||
|
||||
private:
|
||||
bool on_init() override;
|
||||
void data_changed() override;
|
||||
|
||||
void update_model_object() const override;
|
||||
void update_from_model_object() override;
|
||||
@ -39,6 +40,13 @@ private:
|
||||
// This map holds all translated description texts, so they can be easily referenced during layout calculations
|
||||
// etc. When language changes, GUI is recreated and this class constructed again, so the change takes effect.
|
||||
std::map<std::string, wxString> m_desc;
|
||||
|
||||
|
||||
bool waiting_for_autogenerated_supports = false;
|
||||
bool has_backend_supports() const;
|
||||
void reslice_FDM_supports(bool postpone_error_messages = false) const;
|
||||
void auto_generate();
|
||||
void get_data_from_backend();
|
||||
};
|
||||
|
||||
|
||||
|
@ -277,8 +277,51 @@ DPIFrame(NULL, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_S
|
||||
|
||||
preferences_dialog = new PreferencesDialog(this);
|
||||
}
|
||||
|
||||
// bind events from DiffDlg
|
||||
|
||||
bind_diff_dialog();
|
||||
}
|
||||
|
||||
void MainFrame::bind_diff_dialog()
|
||||
{
|
||||
auto get_tab = [](Preset::Type type) {
|
||||
Tab* null_tab = nullptr;
|
||||
for (Tab* tab : wxGetApp().tabs_list)
|
||||
if (tab->type() == type)
|
||||
return tab;
|
||||
return null_tab;
|
||||
};
|
||||
|
||||
auto transfer = [this, get_tab](Preset::Type type) {
|
||||
get_tab(type)->transfer_options(diff_dialog.get_left_preset_name(type),
|
||||
diff_dialog.get_right_preset_name(type),
|
||||
diff_dialog.get_selected_options(type));
|
||||
};
|
||||
|
||||
auto update_presets = [this, get_tab](Preset::Type type) {
|
||||
get_tab(type)->update_preset_choice();
|
||||
m_plater->sidebar().update_presets(type);
|
||||
};
|
||||
|
||||
auto process_options = [this](std::function<void(Preset::Type)> process) {
|
||||
const Preset::Type diff_dlg_type = diff_dialog.view_type();
|
||||
if (diff_dlg_type == Preset::TYPE_INVALID) {
|
||||
for (const Preset::Type& type : diff_dialog.printer_technology() == ptFFF ?
|
||||
std::initializer_list<Preset::Type>{Preset::TYPE_PRINTER, Preset::TYPE_PRINT, Preset::TYPE_FILAMENT} :
|
||||
std::initializer_list<Preset::Type>{ Preset::TYPE_PRINTER, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL } )
|
||||
process(type);
|
||||
}
|
||||
else
|
||||
process(diff_dlg_type);
|
||||
};
|
||||
|
||||
diff_dialog.Bind(EVT_DIFF_DIALOG_TRANSFER, [this, process_options, transfer](SimpleEvent&) { process_options(transfer); });
|
||||
|
||||
diff_dialog.Bind(EVT_DIFF_DIALOG_UPDATE_PRESETS,[this, process_options, update_presets](SimpleEvent&) { process_options(update_presets); });
|
||||
}
|
||||
|
||||
|
||||
#ifdef _MSW_DARK_MODE
|
||||
static wxString pref() { return " [ "; }
|
||||
static wxString suff() { return " ] "; }
|
||||
@ -2130,9 +2173,6 @@ void MainFrame::add_to_recent_projects(const wxString& filename)
|
||||
|
||||
void MainFrame::technology_changed()
|
||||
{
|
||||
// upadte DiffDlg
|
||||
diff_dialog.update_presets();
|
||||
|
||||
// update menu titles
|
||||
PrinterTechnology pt = plater()->printer_technology();
|
||||
if (int id = m_menubar->FindMenu(pt == ptFFF ? _L("Material Settings") : _L("Filament Settings")); id != wxNOT_FOUND)
|
||||
|
@ -107,6 +107,7 @@ class MainFrame : public DPIFrame
|
||||
bool can_delete() const;
|
||||
bool can_delete_all() const;
|
||||
bool can_reslice() const;
|
||||
void bind_diff_dialog();
|
||||
|
||||
// MenuBar items changeable in respect to printer technology
|
||||
enum MenuItems
|
||||
|
@ -1609,7 +1609,8 @@ bool PlaterDropTarget::OnDropFiles(wxCoord x, wxCoord y, const wxArrayString &fi
|
||||
|
||||
m_mainframe.Raise();
|
||||
m_mainframe.select_tab(size_t(0));
|
||||
m_plater.select_view_3D("3D");
|
||||
if (wxGetApp().is_editor())
|
||||
m_plater.select_view_3D("3D");
|
||||
bool res = m_plater.load_files(filenames);
|
||||
m_mainframe.update_title();
|
||||
return res;
|
||||
@ -5347,10 +5348,9 @@ void Plater::new_project()
|
||||
(saved_project == wxID_YES ? _L("You can keep presets modifications to the new project or discard them") :
|
||||
_L("You can keep presets modifications to the new project, discard them or save changes as new presets.\n"
|
||||
"Note, if changes will be saved then new project wouldn't keep them"));
|
||||
using ab = UnsavedChangesDialog::ActionButtons;
|
||||
int act_buttons = ab::KEEP;
|
||||
int act_buttons = ActionButtons::KEEP;
|
||||
if (saved_project == wxID_NO)
|
||||
act_buttons |= ab::SAVE;
|
||||
act_buttons |= ActionButtons::SAVE;
|
||||
if (!wxGetApp().check_and_keep_current_preset_changes(_L("Creating a new project"), header, act_buttons))
|
||||
return;
|
||||
}
|
||||
|
@ -38,7 +38,6 @@
|
||||
#include "../Utils/UndoRedo.hpp"
|
||||
#include "BitmapCache.hpp"
|
||||
#include "PhysicalPrinterDialog.hpp"
|
||||
#include "SavePresetDialog.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
|
||||
// A workaround for a set of issues related to text fitting into gtk widgets:
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/wupdlock.h>
|
||||
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
|
||||
@ -22,25 +21,23 @@ using Slic3r::GUI::format_wxstr;
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#define BORDER_W 10
|
||||
|
||||
constexpr auto BORDER_W = 10;
|
||||
|
||||
//-----------------------------------------------
|
||||
// SavePresetDialog::Item
|
||||
//-----------------------------------------------
|
||||
|
||||
SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBoxSizer* sizer, SavePresetDialog* parent):
|
||||
m_type(type),
|
||||
m_parent(parent)
|
||||
std::string SavePresetDialog::Item::get_init_preset_name(const std::string &suffix)
|
||||
{
|
||||
Tab* tab = wxGetApp().get_tab(m_type);
|
||||
assert(tab);
|
||||
m_presets = tab->get_presets();
|
||||
PresetBundle* preset_bundle = m_parent->get_preset_bundle();
|
||||
if (!preset_bundle)
|
||||
preset_bundle = wxGetApp().preset_bundle;
|
||||
m_presets = &preset_bundle->get_presets(m_type);
|
||||
|
||||
const Preset& sel_preset = m_presets->get_selected_preset();
|
||||
std::string preset_name = sel_preset.is_default ? "Untitled" :
|
||||
sel_preset.is_system ? (boost::format(("%1% - %2%")) % sel_preset.name % suffix).str() :
|
||||
sel_preset.name;
|
||||
std::string preset_name = sel_preset.is_default ? "Untitled" :
|
||||
sel_preset.is_system ? (boost::format(("%1% - %2%")) % sel_preset.name % suffix).str() :
|
||||
sel_preset.name;
|
||||
|
||||
// if name contains extension
|
||||
if (boost::iends_with(preset_name, ".ini")) {
|
||||
@ -48,18 +45,11 @@ SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBox
|
||||
preset_name.resize(len);
|
||||
}
|
||||
|
||||
std::vector<std::string> values;
|
||||
for (const Preset& preset : *m_presets) {
|
||||
if (preset.is_default || preset.is_system || preset.is_external)
|
||||
continue;
|
||||
values.push_back(preset.name);
|
||||
}
|
||||
|
||||
std::string label_str = m_parent->is_for_rename() ?_utf8(L("Rename %s to:")) : _utf8(L("Save %s as:"));
|
||||
wxStaticText* label_top = new wxStaticText(m_parent, wxID_ANY, from_u8((boost::format(label_str) % into_u8(tab->title())).str()));
|
||||
|
||||
m_valid_bmp = new wxStaticBitmap(m_parent, wxID_ANY, *get_bmp_bundle("tick_mark"));
|
||||
return preset_name;
|
||||
}
|
||||
|
||||
void SavePresetDialog::Item::init_input_name_ctrl(wxBoxSizer *input_name_sizer, const std::string preset_name)
|
||||
{
|
||||
if (m_parent->is_for_rename()) {
|
||||
#ifdef _WIN32
|
||||
long style = wxBORDER_SIMPLE;
|
||||
@ -68,10 +58,19 @@ SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBox
|
||||
#endif
|
||||
m_text_ctrl = new wxTextCtrl(m_parent, wxID_ANY, from_u8(preset_name), wxDefaultPosition, wxSize(35 * wxGetApp().em_unit(), -1), style);
|
||||
m_text_ctrl->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { update(); });
|
||||
|
||||
input_name_sizer->Add(m_text_ctrl,1, wxEXPAND, BORDER_W);
|
||||
}
|
||||
else {
|
||||
std::vector<std::string> values;
|
||||
for (const Preset&preset : *m_presets) {
|
||||
if (preset.is_default || preset.is_system || preset.is_external)
|
||||
continue;
|
||||
values.push_back(preset.name);
|
||||
}
|
||||
|
||||
m_combo = new wxComboBox(m_parent, wxID_ANY, from_u8(preset_name), wxDefaultPosition, wxSize(35 * wxGetApp().em_unit(), -1));
|
||||
for (const std::string& value : values)
|
||||
for (const std::string&value : values)
|
||||
m_combo->Append(from_u8(value));
|
||||
|
||||
m_combo->Bind(wxEVT_TEXT, [this](wxCommandEvent&) { update(); });
|
||||
@ -80,20 +79,34 @@ SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBox
|
||||
// So process wxEVT_COMBOBOX too
|
||||
m_combo->Bind(wxEVT_COMBOBOX, [this](wxCommandEvent&) { update(); });
|
||||
#endif //__WXOSX__
|
||||
}
|
||||
|
||||
m_valid_label = new wxStaticText(m_parent, wxID_ANY, "");
|
||||
input_name_sizer->Add(m_combo, 1, wxEXPAND, BORDER_W);
|
||||
}
|
||||
}
|
||||
|
||||
wxString SavePresetDialog::Item::get_top_label_text() const
|
||||
{
|
||||
const std::string label_str = m_parent->is_for_rename() ?_u8L("Rename %s to:") : _u8L("Save %s as:");
|
||||
Tab* tab = wxGetApp().get_tab(m_type);
|
||||
return from_u8((boost::format(label_str) % into_u8(tab->title())).str());
|
||||
}
|
||||
|
||||
SavePresetDialog::Item::Item(Preset::Type type, const std::string& suffix, wxBoxSizer* sizer, SavePresetDialog* parent):
|
||||
m_type(type),
|
||||
m_parent(parent),
|
||||
m_valid_bmp(new wxStaticBitmap(m_parent, wxID_ANY, *get_bmp_bundle("tick_mark"))),
|
||||
m_valid_label(new wxStaticText(m_parent, wxID_ANY, ""))
|
||||
{
|
||||
m_valid_label->SetFont(wxGetApp().bold_font());
|
||||
|
||||
wxBoxSizer* combo_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
combo_sizer->Add(m_valid_bmp, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, BORDER_W);
|
||||
if (m_parent->is_for_rename())
|
||||
combo_sizer->Add(m_text_ctrl,1, wxEXPAND, BORDER_W);
|
||||
else
|
||||
combo_sizer->Add(m_combo, 1, wxEXPAND, BORDER_W);
|
||||
wxStaticText* label_top = new wxStaticText(m_parent, wxID_ANY, get_top_label_text());
|
||||
|
||||
wxBoxSizer* input_name_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
input_name_sizer->Add(m_valid_bmp, 0, wxALIGN_CENTER_VERTICAL | wxRIGHT, BORDER_W);
|
||||
init_input_name_ctrl(input_name_sizer, get_init_preset_name(suffix));
|
||||
|
||||
sizer->Add(label_top, 0, wxEXPAND | wxTOP| wxBOTTOM, BORDER_W);
|
||||
sizer->Add(combo_sizer, 0, wxEXPAND | wxBOTTOM, BORDER_W);
|
||||
sizer->Add(input_name_sizer,0, wxEXPAND | wxBOTTOM, BORDER_W);
|
||||
sizer->Add(m_valid_label, 0, wxEXPAND | wxLEFT, 3*BORDER_W);
|
||||
|
||||
if (m_type == Preset::TYPE_PRINTER)
|
||||
@ -107,7 +120,7 @@ void SavePresetDialog::Item::update()
|
||||
bool rename = m_parent->is_for_rename();
|
||||
m_preset_name = into_u8(rename ? m_text_ctrl->GetValue() : m_combo->GetValue());
|
||||
|
||||
m_valid_type = Valid;
|
||||
m_valid_type = ValidationType::Valid;
|
||||
wxString info_line;
|
||||
|
||||
const char* unusable_symbols = "<>[]:/\\|?*\"";
|
||||
@ -117,44 +130,45 @@ void SavePresetDialog::Item::update()
|
||||
if (m_preset_name.find_first_of(unusable_symbols[i]) != std::string::npos) {
|
||||
info_line = _L("The supplied name is not valid;") + "\n" +
|
||||
_L("the following characters are not allowed:") + " " + unusable_symbols;
|
||||
m_valid_type = NoValid;
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_valid_type == Valid && m_preset_name.find(unusable_suffix) != std::string::npos) {
|
||||
if (m_valid_type == ValidationType::Valid && m_preset_name.find(unusable_suffix) != std::string::npos) {
|
||||
info_line = _L("The supplied name is not valid;") + "\n" +
|
||||
_L("the following suffix is not allowed:") + "\n\t" +
|
||||
from_u8(PresetCollection::get_suffix_modified());
|
||||
m_valid_type = NoValid;
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
||||
if (m_valid_type == Valid && m_preset_name == "- default -") {
|
||||
if (m_valid_type == ValidationType::Valid && m_preset_name == "- default -") {
|
||||
info_line = _L("The supplied name is not available.");
|
||||
m_valid_type = NoValid;
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
||||
const Preset* existing = m_presets->find_preset(m_preset_name, false);
|
||||
if (m_valid_type == Valid && existing && (existing->is_default || existing->is_system)) {
|
||||
if (m_valid_type == ValidationType::Valid && existing && (existing->is_default || existing->is_system)) {
|
||||
info_line = rename ? _L("The supplied name is used for a system profile.") :
|
||||
_L("Cannot overwrite a system profile.");
|
||||
m_valid_type = NoValid;
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
||||
if (m_valid_type == Valid && existing && (existing->is_external)) {
|
||||
if (m_valid_type == ValidationType::Valid && existing && (existing->is_external)) {
|
||||
info_line = rename ? _L("The supplied name is used for a external profile.") :
|
||||
_L("Cannot overwrite an external profile.");
|
||||
m_valid_type = NoValid;
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
||||
if (m_valid_type == Valid && existing)
|
||||
if (m_valid_type == ValidationType::Valid && existing)
|
||||
{
|
||||
if (m_preset_name == m_presets->get_selected_preset_name()) {
|
||||
if (!rename && m_presets->get_edited_preset().is_dirty)
|
||||
info_line = _L("Just save preset modifications");
|
||||
if (!rename && m_presets->get_edited_preset().is_dirty ||
|
||||
m_parent->get_preset_bundle()) // means that we save modifications from the DiffDialog
|
||||
info_line = _L("Save preset modifications to existing user profile");
|
||||
else
|
||||
info_line = _L("Nothing changed");
|
||||
m_valid_type = Valid;
|
||||
m_valid_type = ValidationType::Valid;
|
||||
}
|
||||
else {
|
||||
if (existing->is_compatible)
|
||||
@ -162,31 +176,31 @@ void SavePresetDialog::Item::update()
|
||||
else
|
||||
info_line = from_u8((boost::format(_u8L("Preset with name \"%1%\" already exists and is incompatible with selected printer.")) % m_preset_name).str());
|
||||
info_line += "\n" + _L("Note: This preset will be replaced after saving");
|
||||
m_valid_type = Warning;
|
||||
m_valid_type = ValidationType::Warning;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_valid_type == Valid && m_preset_name.empty()) {
|
||||
if (m_valid_type == ValidationType::Valid && m_preset_name.empty()) {
|
||||
info_line = _L("The name cannot be empty.");
|
||||
m_valid_type = NoValid;
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
||||
if (m_valid_type == Valid && m_preset_name.find_first_of(' ') == 0) {
|
||||
if (m_valid_type == ValidationType::Valid && m_preset_name.find_first_of(' ') == 0) {
|
||||
info_line = _L("The name cannot start with space character.");
|
||||
m_valid_type = NoValid;
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
||||
if (m_valid_type == Valid && m_preset_name.find_last_of(' ') == m_preset_name.length()-1) {
|
||||
if (m_valid_type == ValidationType::Valid && m_preset_name.find_last_of(' ') == m_preset_name.length()-1) {
|
||||
info_line = _L("The name cannot end with space character.");
|
||||
m_valid_type = NoValid;
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
||||
if (m_valid_type == Valid && m_presets->get_preset_name_by_alias(m_preset_name) != m_preset_name) {
|
||||
if (m_valid_type == ValidationType::Valid && m_presets->get_preset_name_by_alias(m_preset_name) != m_preset_name) {
|
||||
info_line = _L("The name cannot be the same as a preset alias name.");
|
||||
m_valid_type = NoValid;
|
||||
m_valid_type = ValidationType::NoValid;
|
||||
}
|
||||
|
||||
if (!m_parent->get_info_line_extention().IsEmpty() && m_valid_type != NoValid)
|
||||
if (!m_parent->get_info_line_extention().IsEmpty() && m_valid_type != ValidationType::NoValid)
|
||||
info_line += "\n\n" + m_parent->get_info_line_extention();
|
||||
|
||||
m_valid_label->SetLabel(info_line);
|
||||
@ -202,14 +216,14 @@ void SavePresetDialog::Item::update()
|
||||
|
||||
void SavePresetDialog::Item::update_valid_bmp()
|
||||
{
|
||||
std::string bmp_name = m_valid_type == Warning ? "exclamation" :
|
||||
m_valid_type == NoValid ? "cross" : "tick_mark" ;
|
||||
std::string bmp_name = m_valid_type == ValidationType::Warning ? "exclamation" :
|
||||
m_valid_type == ValidationType::NoValid ? "cross" : "tick_mark" ;
|
||||
m_valid_bmp->SetBitmap(*get_bmp_bundle(bmp_name));
|
||||
}
|
||||
|
||||
void SavePresetDialog::Item::accept()
|
||||
{
|
||||
if (m_valid_type == Warning)
|
||||
if (m_valid_type == ValidationType::Warning)
|
||||
m_presets->delete_preset(m_preset_name);
|
||||
}
|
||||
|
||||
@ -224,8 +238,9 @@ SavePresetDialog::SavePresetDialog(wxWindow* parent, Preset::Type type, std::str
|
||||
build(std::vector<Preset::Type>{type}, suffix);
|
||||
}
|
||||
|
||||
SavePresetDialog::SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix)
|
||||
: DPIDialog(parent, wxID_ANY, _L("Save presets"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER)
|
||||
SavePresetDialog::SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix, PresetBundle* preset_bundle/* = nullptr*/)
|
||||
: DPIDialog(parent, wxID_ANY, _L("Save presets"), wxDefaultPosition, wxSize(45 * wxGetApp().em_unit(), 5 * wxGetApp().em_unit()), wxDEFAULT_DIALOG_STYLE | wxICON_WARNING | wxRESIZE_BORDER),
|
||||
m_preset_bundle(preset_bundle)
|
||||
{
|
||||
build(types, suffix);
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class SavePresetDialog : public DPIDialog
|
||||
|
||||
struct Item
|
||||
{
|
||||
enum ValidationType
|
||||
enum class ValidationType
|
||||
{
|
||||
Valid,
|
||||
NoValid,
|
||||
@ -41,15 +41,15 @@ class SavePresetDialog : public DPIDialog
|
||||
void update_valid_bmp();
|
||||
void accept();
|
||||
|
||||
bool is_valid() const { return m_valid_type != NoValid; }
|
||||
bool is_valid() const { return m_valid_type != ValidationType::NoValid; }
|
||||
Preset::Type type() const { return m_type; }
|
||||
std::string preset_name() const { return m_preset_name; }
|
||||
|
||||
private:
|
||||
Preset::Type m_type;
|
||||
ValidationType m_valid_type;
|
||||
std::string m_preset_name;
|
||||
|
||||
ValidationType m_valid_type {ValidationType::NoValid};
|
||||
SavePresetDialog* m_parent {nullptr};
|
||||
wxStaticBitmap* m_valid_bmp {nullptr};
|
||||
wxComboBox* m_combo {nullptr};
|
||||
@ -58,7 +58,11 @@ class SavePresetDialog : public DPIDialog
|
||||
|
||||
PresetCollection* m_presets {nullptr};
|
||||
|
||||
void update();
|
||||
std::string get_init_preset_name(const std::string &suffix);
|
||||
void init_input_name_ctrl(wxBoxSizer *input_name_sizer, std::string preset_name);
|
||||
wxString get_top_label_text() const ;
|
||||
|
||||
void update();
|
||||
};
|
||||
|
||||
std::vector<Item*> m_items;
|
||||
@ -73,19 +77,22 @@ class SavePresetDialog : public DPIDialog
|
||||
bool m_use_for_rename{false};
|
||||
wxString m_info_line_extention{wxEmptyString};
|
||||
|
||||
PresetBundle* m_preset_bundle{ nullptr };
|
||||
|
||||
public:
|
||||
|
||||
const wxString& get_info_line_extention() { return m_info_line_extention; }
|
||||
|
||||
SavePresetDialog(wxWindow* parent, Preset::Type type, std::string suffix = "");
|
||||
SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix = "");
|
||||
SavePresetDialog(wxWindow* parent, std::vector<Preset::Type> types, std::string suffix = "", PresetBundle* preset_bundle = nullptr);
|
||||
SavePresetDialog(wxWindow* parent, Preset::Type type, bool rename, const wxString& info_line_extention);
|
||||
~SavePresetDialog();
|
||||
~SavePresetDialog() override;
|
||||
|
||||
void AddItem(Preset::Type type, const std::string& suffix);
|
||||
|
||||
std::string get_name();
|
||||
std::string get_name(Preset::Type type);
|
||||
PresetBundle* get_preset_bundle() const { return m_preset_bundle; }
|
||||
std::string get_name();
|
||||
std::string get_name(Preset::Type type);
|
||||
|
||||
bool enable_ok_btn() const;
|
||||
void add_info_for_edit_ph_printer(wxBoxSizer *sizer);
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/exception/diagnostic_information.hpp>
|
||||
|
||||
#include "wxExtensions.hpp"
|
||||
#include "PresetComboBoxes.hpp"
|
||||
#include <wx/wupdlock.h>
|
||||
@ -39,21 +41,20 @@
|
||||
#include "Plater.hpp"
|
||||
#include "MainFrame.hpp"
|
||||
#include "format.hpp"
|
||||
#include "PhysicalPrinterDialog.hpp"
|
||||
#include "UnsavedChangesDialog.hpp"
|
||||
#include "SavePresetDialog.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
#include "Notebook.hpp"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <commctrl.h>
|
||||
#include <CommCtrl.h>
|
||||
#endif // WIN32
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
Tab::Tab(wxBookCtrlBase* parent, const wxString& title, Preset::Type type) :
|
||||
m_parent(parent), m_title(title), m_type(type)
|
||||
m_parent(parent), m_type(type), m_title(title)
|
||||
{
|
||||
Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL/*, name*/);
|
||||
this->SetFont(Slic3r::GUI::wxGetApp().normal_font());
|
||||
@ -1183,9 +1184,9 @@ void Tab::activate_option(const std::string& opt_key, const wxString& category)
|
||||
m_highlighter.init(get_custom_ctrl_with_blinking_ptr(opt_key));
|
||||
}
|
||||
|
||||
void Tab::cache_config_diff(const std::vector<std::string>& selected_options)
|
||||
void Tab::cache_config_diff(const std::vector<std::string>& selected_options, const DynamicPrintConfig* config/* = nullptr*/)
|
||||
{
|
||||
m_cache_config.apply_only(m_presets->get_edited_preset().config, selected_options);
|
||||
m_cache_config.apply_only(config ? *config : m_presets->get_edited_preset().config, selected_options);
|
||||
}
|
||||
|
||||
void Tab::apply_config_from_cache()
|
||||
@ -3185,7 +3186,8 @@ void Tab::update_btns_enabling()
|
||||
const Preset& preset = m_presets->get_edited_preset();
|
||||
m_btn_delete_preset->Show((m_type == Preset::TYPE_PRINTER && m_preset_bundle->physical_printers.has_selection())
|
||||
|| (!preset.is_default && !preset.is_system));
|
||||
m_btn_rename_preset->Show(!preset.is_default && !preset.is_system && !m_presets_choice->is_selected_physical_printer());
|
||||
m_btn_rename_preset->Show(!preset.is_default && !preset.is_system && !preset.is_external &&
|
||||
!wxGetApp().preset_bundle->physical_printers.has_selection());
|
||||
|
||||
if (m_btn_edit_ph_printer)
|
||||
m_btn_edit_ph_printer->SetToolTip( m_preset_bundle->physical_printers.has_selection() ?
|
||||
@ -3583,6 +3585,32 @@ void Tab::compare_preset()
|
||||
wxGetApp().mainframe->diff_dialog.show(m_type);
|
||||
}
|
||||
|
||||
void Tab::transfer_options(const std::string &name_from, const std::string &name_to, std::vector<std::string> options)
|
||||
{
|
||||
if (options.empty())
|
||||
return;
|
||||
|
||||
Preset* preset_from = m_presets->find_preset(name_from);
|
||||
Preset* preset_to = m_presets->find_preset(name_to);
|
||||
|
||||
if (m_type == Preset::TYPE_PRINTER) {
|
||||
auto it = std::find(options.begin(), options.end(), "extruders_count");
|
||||
if (it != options.end()) {
|
||||
// erase "extruders_count" option from the list
|
||||
options.erase(it);
|
||||
// cache the extruders count
|
||||
static_cast<TabPrinter*>(this)->cache_extruder_cnt(&preset_from->config);
|
||||
}
|
||||
}
|
||||
cache_config_diff(options, &preset_from->config);
|
||||
|
||||
if (name_to != m_presets->get_edited_preset().name )
|
||||
select_preset(preset_to->name);
|
||||
|
||||
apply_config_from_cache();
|
||||
load_current_preset();
|
||||
}
|
||||
|
||||
// Save the current preset into file.
|
||||
// This removes the "dirty" flag of the preset, possibly creates a new preset under a new name,
|
||||
// and activates the new preset.
|
||||
@ -3674,12 +3702,11 @@ void Tab::rename_preset()
|
||||
if (m_presets_choice->is_selected_physical_printer())
|
||||
return;
|
||||
|
||||
Preset& selected_preset = m_presets->get_selected_preset();
|
||||
wxString msg;
|
||||
|
||||
if (m_type == Preset::TYPE_PRINTER && !m_preset_bundle->physical_printers.empty()) {
|
||||
// Check preset for rename in physical printers
|
||||
std::vector<std::string> ph_printers = m_preset_bundle->physical_printers.get_printers_with_preset(selected_preset.name);
|
||||
std::vector<std::string> ph_printers = m_preset_bundle->physical_printers.get_printers_with_preset(m_presets->get_selected_preset().name);
|
||||
if (!ph_printers.empty()) {
|
||||
msg += _L_PLURAL("The physical printer below is based on the preset, you are going to rename.",
|
||||
"The physical printers below are based on the preset, you are going to rename.", ph_printers.size());
|
||||
@ -3696,31 +3723,51 @@ void Tab::rename_preset()
|
||||
SavePresetDialog dlg(m_parent, m_type, true, msg);
|
||||
if (dlg.ShowModal() != wxID_OK)
|
||||
return;
|
||||
std::string new_name = into_u8(dlg.get_name());
|
||||
|
||||
const std::string new_name = into_u8(dlg.get_name());
|
||||
if (new_name.empty() || new_name == m_presets->get_selected_preset().name)
|
||||
return;
|
||||
|
||||
// rename selected and edited presets
|
||||
// Note: selected preset can be changed, if in SavePresetDialog was selected name of existing preset
|
||||
Preset& selected_preset = m_presets->get_selected_preset();
|
||||
Preset& edited_preset = m_presets->get_edited_preset();
|
||||
|
||||
std::string old_name = selected_preset.name;
|
||||
std::string old_file_name = selected_preset.file;
|
||||
const std::string old_name = selected_preset.name;
|
||||
const std::string old_file_name = selected_preset.file;
|
||||
|
||||
selected_preset.name = new_name;
|
||||
boost::replace_last(selected_preset.file, old_name, new_name);
|
||||
assert(old_name == edited_preset.name);
|
||||
|
||||
Preset& edited_preset = m_presets->get_edited_preset();
|
||||
edited_preset.name = new_name;
|
||||
boost::replace_last(edited_preset.file, old_name, new_name);
|
||||
using namespace boost;
|
||||
try {
|
||||
// rename selected and edited presets
|
||||
|
||||
// rename file with renamed preset configuration
|
||||
boost::filesystem::rename(old_file_name, selected_preset.file);
|
||||
selected_preset.name = new_name;
|
||||
replace_last(selected_preset.file, old_name, new_name);
|
||||
|
||||
// rename selected preset in printers, if it's needed
|
||||
if (!msg.IsEmpty())
|
||||
m_preset_bundle->physical_printers.rename_preset_in_printers(old_name, new_name);
|
||||
edited_preset.name = new_name;
|
||||
replace_last(edited_preset.file, old_name, new_name);
|
||||
|
||||
// rename file with renamed preset configuration
|
||||
|
||||
filesystem::rename(old_file_name, selected_preset.file);
|
||||
|
||||
// rename selected preset in printers, if it's needed
|
||||
|
||||
if (!msg.IsEmpty())
|
||||
m_preset_bundle->physical_printers.rename_preset_in_printers(old_name, new_name);
|
||||
}
|
||||
catch (const exception& ex) {
|
||||
const std::string exception = diagnostic_information(ex);
|
||||
printf("Can't rename a preset : %s", exception.c_str());
|
||||
}
|
||||
|
||||
// sort presets after renaming
|
||||
std::sort(m_presets->begin(), m_presets->end());
|
||||
// update selection
|
||||
m_presets->select_preset_by_name(new_name, true);
|
||||
|
||||
m_presets_choice->update();
|
||||
on_presets_changed();
|
||||
}
|
||||
|
||||
// Called for a currently selected preset.
|
||||
@ -4267,12 +4314,15 @@ wxSizer* TabPrinter::create_bed_shape_widget(wxWindow* parent)
|
||||
return sizer;
|
||||
}
|
||||
|
||||
void TabPrinter::cache_extruder_cnt()
|
||||
void TabPrinter::cache_extruder_cnt(const DynamicPrintConfig* config/* = nullptr*/)
|
||||
{
|
||||
if (m_presets->get_edited_preset().printer_technology() == ptSLA)
|
||||
const DynamicPrintConfig& cached_config = config ? *config : m_presets->get_edited_preset().config;
|
||||
if (Preset::printer_technology(cached_config) == ptSLA)
|
||||
return;
|
||||
|
||||
m_cache_extruder_count = m_extruders_count;
|
||||
// get extruders count
|
||||
auto* nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(cached_config.option("nozzle_diameter"));
|
||||
m_cache_extruder_count = nozzle_diameter->values.size(); //m_extruders_count;
|
||||
}
|
||||
|
||||
bool TabPrinter::apply_extruder_cnt_from_cache()
|
||||
@ -4282,6 +4332,7 @@ bool TabPrinter::apply_extruder_cnt_from_cache()
|
||||
|
||||
if (m_cache_extruder_count > 0) {
|
||||
m_presets->get_edited_preset().set_num_extruders(m_cache_extruder_count);
|
||||
// extruders_count_changed(m_cache_extruder_count);
|
||||
m_cache_extruder_count = 0;
|
||||
return true;
|
||||
}
|
||||
|
@ -322,6 +322,7 @@ public:
|
||||
void OnKeyDown(wxKeyEvent& event);
|
||||
|
||||
void compare_preset();
|
||||
void transfer_options(const std::string&name_from, const std::string&name_to, std::vector<std::string> options);
|
||||
void save_preset(std::string name = std::string(), bool detach = false);
|
||||
void rename_preset();
|
||||
void delete_preset();
|
||||
@ -374,7 +375,7 @@ public:
|
||||
|
||||
void update_wiping_button_visibility();
|
||||
void activate_option(const std::string& opt_key, const wxString& category);
|
||||
void cache_config_diff(const std::vector<std::string>& selected_options);
|
||||
void cache_config_diff(const std::vector<std::string>& selected_options, const DynamicPrintConfig* config = nullptr);
|
||||
void apply_config_from_cache();
|
||||
|
||||
const std::map<wxString, std::string>& get_category_icon_map() { return m_category_icon; }
|
||||
@ -503,7 +504,7 @@ public:
|
||||
bool supports_printer_technology(const PrinterTechnology /* tech */) const override { return true; }
|
||||
|
||||
wxSizer* create_bed_shape_widget(wxWindow* parent);
|
||||
void cache_extruder_cnt();
|
||||
void cache_extruder_cnt(const DynamicPrintConfig* config = nullptr);
|
||||
bool apply_extruder_cnt_from_cache();
|
||||
};
|
||||
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <vector>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
|
||||
#include <wx/tokenzr.h>
|
||||
|
||||
@ -22,10 +21,6 @@
|
||||
#include "MainFrame.hpp"
|
||||
#include "MsgDialog.hpp"
|
||||
|
||||
//#define FTS_FUZZY_MATCH_IMPLEMENTATION
|
||||
//#include "fts_fuzzy_match.h"
|
||||
|
||||
#include "BitmapCache.hpp"
|
||||
#include "PresetComboBoxes.hpp"
|
||||
|
||||
using boost::optional;
|
||||
@ -40,6 +35,10 @@ namespace Slic3r {
|
||||
|
||||
namespace GUI {
|
||||
|
||||
wxDEFINE_EVENT(EVT_DIFF_DIALOG_TRANSFER, SimpleEvent);
|
||||
wxDEFINE_EVENT(EVT_DIFF_DIALOG_UPDATE_PRESETS, SimpleEvent);
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ModelNode: a node inside DiffModel
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -104,8 +103,8 @@ ModelNode::ModelNode(ModelNode* parent, const wxString& text, const std::string&
|
||||
ModelNode::ModelNode(ModelNode* parent, const wxString& text) :
|
||||
m_parent_win(parent->m_parent_win),
|
||||
m_parent(parent),
|
||||
m_text(text),
|
||||
m_icon_name("dot_small")
|
||||
m_icon_name("dot_small"),
|
||||
m_text(text)
|
||||
{
|
||||
UpdateIcons();
|
||||
}
|
||||
@ -135,12 +134,12 @@ ModelNode::ModelNode(ModelNode* parent, const wxString& text, const wxString& ol
|
||||
m_old_color(old_value.StartsWith("#") ? old_value : ""),
|
||||
m_mod_color(mod_value.StartsWith("#") ? mod_value : ""),
|
||||
m_new_color(new_value.StartsWith("#") ? new_value : ""),
|
||||
m_container(false),
|
||||
m_text(text),
|
||||
m_icon_name("empty"),
|
||||
m_text(text),
|
||||
m_old_value(old_value),
|
||||
m_mod_value(mod_value),
|
||||
m_new_value(new_value)
|
||||
m_new_value(new_value),
|
||||
m_container(false)
|
||||
{
|
||||
// check if old/new_value is color
|
||||
if (m_old_color.IsEmpty()) {
|
||||
@ -505,7 +504,7 @@ unsigned int DiffModel::GetChildren(const wxDataViewItem& parent, wxDataViewItem
|
||||
for (const std::unique_ptr<ModelNode>& child : children)
|
||||
array.Add(wxDataViewItem((void*)child.get()));
|
||||
|
||||
return array.size();
|
||||
return array.Count();
|
||||
}
|
||||
|
||||
|
||||
@ -591,7 +590,7 @@ void DiffModel::Clear()
|
||||
|
||||
static std::string get_pure_opt_key(std::string opt_key)
|
||||
{
|
||||
int pos = opt_key.find("#");
|
||||
const int pos = opt_key.find("#");
|
||||
if (pos > 0)
|
||||
boost::erase_tail(opt_key, opt_key.size() - pos);
|
||||
return opt_key;
|
||||
@ -1337,6 +1336,12 @@ void UnsavedChangesDialog::update_tree(Preset::Type type, PresetCollection* pres
|
||||
searcher.sort_options_by_label();
|
||||
}
|
||||
|
||||
wxString UnsavedChangesDialog::msg_success_saved_modifications(size_t saved_presets_cnt)
|
||||
{
|
||||
return _L_PLURAL("The preset modifications are successfully saved",
|
||||
"The presets modifications are successfully saved", static_cast<unsigned int>(saved_presets_cnt));
|
||||
}
|
||||
|
||||
void UnsavedChangesDialog::on_dpi_changed(const wxRect& suggested_rect)
|
||||
{
|
||||
int em = em_unit();
|
||||
@ -1380,7 +1385,7 @@ FullCompareDialog::FullCompareDialog(const wxString& option_name, const wxString
|
||||
|
||||
wxFlexGridSizer* grid_sizer = new wxFlexGridSizer(2, has_new_value_column ? 3 : 2, 1, 0);
|
||||
grid_sizer->SetFlexibleDirection(wxBOTH);
|
||||
for (size_t col = 0 ; col < grid_sizer->GetCols(); col++)
|
||||
for (int col = 0 ; col < grid_sizer->GetCols(); col++)
|
||||
grid_sizer->AddGrowableCol(col, 1);
|
||||
grid_sizer->AddGrowableRow(1,1);
|
||||
|
||||
@ -1472,34 +1477,11 @@ static std::string get_selection(PresetComboBox* preset_combo)
|
||||
return into_u8(preset_combo->GetString(preset_combo->GetSelection()));
|
||||
}
|
||||
|
||||
DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe)
|
||||
: DPIDialog(mainframe, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
|
||||
m_pr_technology(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology())
|
||||
{
|
||||
#if defined(__WXMSW__)
|
||||
// ys_FIXME! temporary workaround for correct font scaling
|
||||
// Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts,
|
||||
// From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT
|
||||
this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
#endif // __WXMSW__
|
||||
void DiffPresetDialog::create_presets_sizer()
|
||||
{
|
||||
m_presets_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
int border = 10;
|
||||
int em = em_unit();
|
||||
|
||||
assert(wxGetApp().preset_bundle);
|
||||
|
||||
m_preset_bundle_left = std::make_unique<PresetBundle>(*wxGetApp().preset_bundle);
|
||||
m_preset_bundle_right = std::make_unique<PresetBundle>(*wxGetApp().preset_bundle);
|
||||
|
||||
m_top_info_line = new wxStaticText(this, wxID_ANY, _L("Select presets to compare"));
|
||||
m_top_info_line->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold());
|
||||
|
||||
m_bottom_info_line = new wxStaticText(this, wxID_ANY, "");
|
||||
m_bottom_info_line->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold());
|
||||
|
||||
wxBoxSizer* presets_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
for (auto new_type : { Preset::TYPE_PRINT, Preset::TYPE_FILAMENT, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL, Preset::TYPE_PRINTER })
|
||||
for (auto new_type : { Preset::TYPE_PRINT, Preset::TYPE_SLA_PRINT, Preset::TYPE_FILAMENT, Preset::TYPE_SLA_MATERIAL, Preset::TYPE_PRINTER })
|
||||
{
|
||||
const PresetCollection* collection = get_preset_collection(new_type);
|
||||
wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
@ -1507,15 +1489,16 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe)
|
||||
PresetComboBox* presets_right;
|
||||
ScalableButton* equal_bmp = new ScalableButton(this, wxID_ANY, "equal");
|
||||
|
||||
auto add_preset_combobox = [collection, sizer, new_type, em, this](PresetComboBox** cb_, PresetBundle* preset_bundle) {
|
||||
*cb_ = new PresetComboBox(this, new_type, wxSize(em * 35, -1), preset_bundle);
|
||||
PresetComboBox* cb = (*cb_);
|
||||
auto add_preset_combobox = [collection, sizer, new_type, this](PresetComboBox** cb_, PresetBundle* preset_bundle) {
|
||||
*cb_ = new PresetComboBox(this, new_type, wxSize(em_unit() * 35, -1), preset_bundle);
|
||||
PresetComboBox*cb = (*cb_);
|
||||
cb->show_modif_preset_separately();
|
||||
cb->set_selection_changed_function([this, new_type, preset_bundle, cb](int selection) {
|
||||
if (m_view_type == Preset::TYPE_INVALID) {
|
||||
std::string preset_name = cb->GetString(selection).ToUTF8().data();
|
||||
std::string preset_name = Preset::remove_suffix_modified(cb->GetString(selection).ToUTF8().data());
|
||||
if (m_view_type == Preset::TYPE_INVALID)
|
||||
update_compatibility(preset_name, new_type, preset_bundle);
|
||||
}
|
||||
// update selection inside of related presets
|
||||
preset_bundle->get_presets(new_type).select_preset_by_name(preset_name, true);
|
||||
update_tree();
|
||||
});
|
||||
if (collection->get_selected_idx() != (size_t)-1)
|
||||
@ -1527,7 +1510,7 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe)
|
||||
add_preset_combobox(&presets_left, m_preset_bundle_left.get());
|
||||
sizer->Add(equal_bmp, 0, wxRIGHT | wxLEFT | wxALIGN_CENTER_VERTICAL, 5);
|
||||
add_preset_combobox(&presets_right, m_preset_bundle_right.get());
|
||||
presets_sizer->Add(sizer, 1, wxTOP, 5);
|
||||
m_presets_sizer->Add(sizer, 1, wxTOP, 5);
|
||||
equal_bmp->Show(new_type == Preset::TYPE_PRINTER);
|
||||
|
||||
m_preset_combos.push_back({ presets_left, equal_bmp, presets_right });
|
||||
@ -1540,7 +1523,10 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe)
|
||||
update_tree();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void DiffPresetDialog::create_show_all_presets_chb()
|
||||
{
|
||||
m_show_all_presets = new wxCheckBox(this, wxID_ANY, _L("Show all presets (including incompatible)"));
|
||||
m_show_all_presets->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {
|
||||
bool show_all = m_show_all_presets->GetValue();
|
||||
@ -1553,26 +1539,171 @@ DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe)
|
||||
if (m_view_type == Preset::TYPE_INVALID)
|
||||
update_tree();
|
||||
});
|
||||
}
|
||||
|
||||
m_tree = new DiffViewCtrl(this, wxSize(em * 65, em * 40));
|
||||
void DiffPresetDialog::create_info_lines()
|
||||
{
|
||||
const wxFont font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold();
|
||||
|
||||
m_top_info_line = new wxStaticText(this, wxID_ANY, _L("Select presets to compare"));
|
||||
m_top_info_line->SetFont(font);
|
||||
|
||||
m_bottom_info_line = new wxStaticText(this, wxID_ANY, "");
|
||||
m_bottom_info_line->SetFont(font);
|
||||
}
|
||||
|
||||
void DiffPresetDialog::create_tree()
|
||||
{
|
||||
m_tree = new DiffViewCtrl(this, wxSize(em_unit() * 65, em_unit() * 40));
|
||||
m_tree->AppendToggleColumn_(L"\u2714", DiffModel::colToggle, wxLinux ? 9 : 6);
|
||||
m_tree->AppendBmpTextColumn("", DiffModel::colIconText, 35);
|
||||
m_tree->AppendBmpTextColumn(_L("Left Preset Value"), DiffModel::colOldValue, 15);
|
||||
m_tree->AppendBmpTextColumn(_L("Right Preset Value"),DiffModel::colModValue, 15);
|
||||
m_tree->Hide();
|
||||
m_tree->GetColumn(DiffModel::colToggle)->SetHidden(true);
|
||||
}
|
||||
|
||||
wxBoxSizer* topSizer = new wxBoxSizer(wxVERTICAL);
|
||||
void DiffPresetDialog::create_buttons()
|
||||
{
|
||||
wxFont font = this->GetFont().Scaled(1.4f);
|
||||
m_buttons = new wxBoxSizer(wxHORIZONTAL);
|
||||
|
||||
topSizer->Add(m_top_info_line, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, 2 * border);
|
||||
topSizer->Add(presets_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
|
||||
topSizer->Add(m_show_all_presets, 0, wxEXPAND | wxALL, border);
|
||||
topSizer->Add(m_tree, 1, wxEXPAND | wxALL, border);
|
||||
topSizer->Add(m_bottom_info_line, 0, wxEXPAND | wxALL, 2 * border);
|
||||
auto show_in_bottom_info = [this](const wxString& ext_line, wxMouseEvent& e) {
|
||||
m_bottom_info_line->SetLabel(ext_line);
|
||||
m_bottom_info_line->Show(true);
|
||||
Layout();
|
||||
e.Skip();
|
||||
};
|
||||
|
||||
this->SetMinSize(wxSize(80 * em, 30 * em));
|
||||
// Transfer
|
||||
m_transfer_btn = new ScalableButton(this, wxID_ANY, "paste_menu", _L("Transfer"), wxDefaultSize, wxDefaultPosition, wxBORDER_DEFAULT, 24);
|
||||
m_transfer_btn->Bind(wxEVT_BUTTON, [this](wxEvent&) { button_event(Action::Transfer);});
|
||||
|
||||
|
||||
auto enable_transfer = [this](const Preset::Type& type) {
|
||||
const Preset& main_edited_preset = get_preset_collection(type, wxGetApp().preset_bundle)->get_edited_preset();
|
||||
if (main_edited_preset.is_dirty)
|
||||
return main_edited_preset.name == get_right_preset_name(type);
|
||||
return true;
|
||||
};
|
||||
m_transfer_btn->Bind(wxEVT_UPDATE_UI, [this, enable_transfer](wxUpdateUIEvent& evt) {
|
||||
bool enable = m_tree->has_selection();
|
||||
if (enable) {
|
||||
if (m_view_type == Preset::TYPE_INVALID) {
|
||||
for (const Preset::Type& type : (m_pr_technology == ptFFF ? std::initializer_list<Preset::Type>{Preset::TYPE_PRINTER, Preset::TYPE_PRINT, Preset::TYPE_FILAMENT} :
|
||||
std::initializer_list<Preset::Type>{ Preset::TYPE_PRINTER, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL }))
|
||||
if (!enable_transfer(type)) {
|
||||
enable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
enable = enable_transfer(m_view_type);
|
||||
}
|
||||
evt.Enable(enable);
|
||||
});
|
||||
m_transfer_btn->Bind(wxEVT_ENTER_WINDOW, [this, show_in_bottom_info](wxMouseEvent& e) {
|
||||
show_in_bottom_info(_L("Transfer the selected options from left preset to the right.\n"
|
||||
"Note: New modified presets will be selected in setting stabs after close this dialog."), e); });
|
||||
|
||||
// Save
|
||||
m_save_btn = new ScalableButton(this, wxID_ANY, "save", _L("Save"), wxDefaultSize, wxDefaultPosition, wxBORDER_DEFAULT, 24);
|
||||
m_save_btn->Bind(wxEVT_BUTTON, [this](wxEvent&) { button_event(Action::Save); });
|
||||
m_save_btn->Bind(wxEVT_UPDATE_UI, [this](wxUpdateUIEvent& evt) { evt.Enable(m_tree->has_selection()); });
|
||||
m_save_btn->Bind(wxEVT_ENTER_WINDOW, [this, show_in_bottom_info](wxMouseEvent& e) {
|
||||
show_in_bottom_info(_L("Save the selected options from left preset to the right."), e); });
|
||||
|
||||
// Cancel
|
||||
m_cancel_btn = new ScalableButton(this, wxID_CANCEL, "cross", _L("Cancel"), wxDefaultSize, wxDefaultPosition, wxBORDER_DEFAULT, 24);
|
||||
m_cancel_btn->Bind(wxEVT_BUTTON, [this](wxEvent&) { button_event(Action::Discard);});
|
||||
|
||||
for (ScalableButton* btn : { m_transfer_btn, m_save_btn, m_cancel_btn }) {
|
||||
btn->Bind(wxEVT_LEAVE_WINDOW, [this](wxMouseEvent& e) { update_bottom_info(); Layout(); e.Skip(); });
|
||||
m_buttons->Add(btn, 1, wxLEFT, 5);
|
||||
btn->SetFont(font);
|
||||
}
|
||||
|
||||
m_buttons->Show(false);
|
||||
}
|
||||
|
||||
void DiffPresetDialog::create_edit_sizer()
|
||||
{
|
||||
// Add check box for the edit mode
|
||||
m_use_for_transfer = new wxCheckBox(this, wxID_ANY, _L("Transfer values from left to right"));
|
||||
m_use_for_transfer->SetToolTip(_L("If enabled, this dialog can be used for transver selected values from left to right preset."));
|
||||
m_use_for_transfer->Bind(wxEVT_CHECKBOX, [this](wxCommandEvent&) {
|
||||
bool use = m_use_for_transfer->GetValue();
|
||||
m_tree->GetColumn(DiffModel::colToggle)->SetHidden(!use);
|
||||
if (m_tree->IsShown()) {
|
||||
m_buttons->Show(use);
|
||||
Fit();
|
||||
Refresh();
|
||||
}
|
||||
else
|
||||
this->Layout();
|
||||
});
|
||||
|
||||
// Add Buttons
|
||||
create_buttons();
|
||||
|
||||
// Create and fill edit sizer
|
||||
m_edit_sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
m_edit_sizer->Add(m_use_for_transfer, 0, wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT, 5);
|
||||
m_edit_sizer->AddSpacer(em_unit() * 10);
|
||||
m_edit_sizer->Add(m_buttons, 1, wxLEFT, 5);
|
||||
m_edit_sizer->Show(false);
|
||||
}
|
||||
|
||||
void DiffPresetDialog::complete_dialog_creation()
|
||||
{
|
||||
wxBoxSizer*topSizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
int border = 10;
|
||||
topSizer->Add(m_top_info_line, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, 2 * border);
|
||||
topSizer->Add(m_presets_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, border);
|
||||
topSizer->Add(m_show_all_presets, 0, wxEXPAND | wxALL, border);
|
||||
topSizer->Add(m_tree, 1, wxEXPAND | wxALL, border);
|
||||
topSizer->Add(m_bottom_info_line, 0, wxEXPAND | wxALL, 2 * border);
|
||||
topSizer->Add(m_edit_sizer, 0, wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT, 2 * border);
|
||||
|
||||
this->SetMinSize(wxSize(80 * em_unit(), 30 * em_unit()));
|
||||
this->SetSizer(topSizer);
|
||||
topSizer->SetSizeHints(this);
|
||||
}
|
||||
|
||||
DiffPresetDialog::DiffPresetDialog(MainFrame* mainframe)
|
||||
: DPIDialog(mainframe, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER),
|
||||
m_pr_technology(wxGetApp().preset_bundle->printers.get_edited_preset().printer_technology())
|
||||
{
|
||||
#if defined(__WXMSW__)
|
||||
// ys_FIXME! temporary workaround for correct font scaling
|
||||
// Because of from wxWidgets 3.1.3 auto rescaling is implemented for the Fonts,
|
||||
// From the very beginning set dialog font to the wxSYS_DEFAULT_GUI_FONT
|
||||
this->SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
|
||||
#endif // __WXMSW__
|
||||
|
||||
// Init bundles
|
||||
|
||||
assert(wxGetApp().preset_bundle);
|
||||
|
||||
m_preset_bundle_left = std::make_unique<PresetBundle>(*wxGetApp().preset_bundle);
|
||||
m_preset_bundle_right = std::make_unique<PresetBundle>(*wxGetApp().preset_bundle);
|
||||
|
||||
// Create UI items
|
||||
|
||||
create_info_lines();
|
||||
|
||||
create_presets_sizer();
|
||||
|
||||
create_show_all_presets_chb();
|
||||
|
||||
create_tree();
|
||||
|
||||
create_edit_sizer();
|
||||
|
||||
complete_dialog_creation();
|
||||
}
|
||||
|
||||
void DiffPresetDialog::update_controls_visibility(Preset::Type type /* = Preset::TYPE_INVALID*/)
|
||||
{
|
||||
for (auto preset_combos : m_preset_combos) {
|
||||
@ -1598,6 +1729,8 @@ void DiffPresetDialog::update_bundles_from_app()
|
||||
{
|
||||
*m_preset_bundle_left = *wxGetApp().preset_bundle;
|
||||
*m_preset_bundle_right = *wxGetApp().preset_bundle;
|
||||
|
||||
m_pr_technology = m_preset_bundle_left.get()->printers.get_edited_preset().printer_technology();
|
||||
}
|
||||
|
||||
void DiffPresetDialog::show(Preset::Type type /* = Preset::TYPE_INVALID*/)
|
||||
@ -1618,11 +1751,10 @@ void DiffPresetDialog::show(Preset::Type type /* = Preset::TYPE_INVALID*/)
|
||||
Show();
|
||||
}
|
||||
|
||||
void DiffPresetDialog::update_presets(Preset::Type type)
|
||||
void DiffPresetDialog::update_presets(Preset::Type type, bool update_preset_bundles_from_app/* = true */)
|
||||
{
|
||||
m_pr_technology = m_preset_bundle_left.get()->printers.get_edited_preset().printer_technology();
|
||||
|
||||
update_bundles_from_app();
|
||||
if (update_preset_bundles_from_app)
|
||||
update_bundles_from_app();
|
||||
update_controls_visibility(type);
|
||||
|
||||
if (type == Preset::TYPE_INVALID)
|
||||
@ -1645,9 +1777,20 @@ void DiffPresetDialog::update_presets(Preset::Type type)
|
||||
update_tree();
|
||||
}
|
||||
|
||||
void DiffPresetDialog::update_bottom_info(wxString bottom_info)
|
||||
{
|
||||
if (m_tree->has_long_strings())
|
||||
bottom_info = _L("Some fields are too long to fit. Right mouse click reveals the full text.");
|
||||
|
||||
const bool show_bottom_info = !m_tree->IsShown() || m_tree->has_long_strings();
|
||||
if (show_bottom_info)
|
||||
m_bottom_info_line->SetLabel(bottom_info);
|
||||
m_bottom_info_line->Show(show_bottom_info);
|
||||
}
|
||||
|
||||
void DiffPresetDialog::update_tree()
|
||||
{
|
||||
// update searcher befofre update of tree
|
||||
// update searcher before update of tree
|
||||
wxGetApp().sidebar().check_and_update_searcher();
|
||||
Search::OptionsSearcher& searcher = wxGetApp().sidebar().get_searcher();
|
||||
searcher.sort_options_by_key();
|
||||
@ -1739,17 +1882,15 @@ void DiffPresetDialog::update_tree()
|
||||
left_val, right_val, "", category_icon_map.at(option.category));
|
||||
}
|
||||
}
|
||||
|
||||
if (m_tree->has_long_strings())
|
||||
bottom_info = _L("Some fields are too long to fit. Right mouse click reveals the full text.");
|
||||
|
||||
bool tree_was_shown = m_tree->IsShown();
|
||||
m_tree->Show(show_tree);
|
||||
|
||||
bool show_bottom_info = !show_tree || m_tree->has_long_strings();
|
||||
if (show_bottom_info)
|
||||
m_bottom_info_line->SetLabel(bottom_info);
|
||||
m_bottom_info_line->Show(show_bottom_info);
|
||||
bool can_transfer_options = m_view_type == Preset::TYPE_INVALID || get_left_preset_name(m_view_type) != get_right_preset_name(m_view_type);
|
||||
m_edit_sizer->Show(show_tree && can_transfer_options);
|
||||
m_buttons->Show(m_edit_sizer->IsShown(size_t(0)) && m_use_for_transfer->GetValue());
|
||||
|
||||
update_bottom_info(bottom_info);
|
||||
|
||||
if (tree_was_shown == m_tree->IsShown())
|
||||
Layout();
|
||||
@ -1802,6 +1943,10 @@ void DiffPresetDialog::on_sys_color_changed()
|
||||
preset_combos.equal_bmp->sys_color_changed();
|
||||
preset_combos.presets_right->sys_color_changed();
|
||||
}
|
||||
|
||||
for (ScalableButton* btn : { m_transfer_btn, m_save_btn, m_cancel_btn })
|
||||
btn->sys_color_changed();
|
||||
|
||||
// msw_rescale updates just icons, so use it
|
||||
m_tree->Rescale();
|
||||
Refresh();
|
||||
@ -1865,6 +2010,90 @@ void DiffPresetDialog::update_compatibility(const std::string& preset_name, Pres
|
||||
}
|
||||
}
|
||||
|
||||
bool DiffPresetDialog::save()
|
||||
{
|
||||
presets_to_save.clear();
|
||||
|
||||
std::vector<Preset::Type> types_for_save;
|
||||
|
||||
for (const Preset::Type& type : m_pr_technology == ptFFF ? std::initializer_list<Preset::Type>{Preset::TYPE_PRINTER, Preset::TYPE_PRINT, Preset::TYPE_FILAMENT} :
|
||||
std::initializer_list<Preset::Type>{Preset::TYPE_PRINTER, Preset::TYPE_SLA_PRINT, Preset::TYPE_SLA_MATERIAL })
|
||||
if (!m_tree->options(type, true).empty()) {
|
||||
types_for_save.emplace_back(type);
|
||||
presets_to_save.emplace_back(PresetToSave{ type, get_left_preset_name(type), get_right_preset_name(type), get_right_preset_name(type) });
|
||||
}
|
||||
|
||||
if (!types_for_save.empty()) {
|
||||
SavePresetDialog save_dlg(this, types_for_save, _u8L("Modified"), m_preset_bundle_right.get());
|
||||
if (save_dlg.ShowModal() != wxID_OK)
|
||||
return false;
|
||||
|
||||
for (auto& preset : presets_to_save) {
|
||||
const std::string& name = save_dlg.get_name(preset.type);
|
||||
if (!name.empty())
|
||||
preset.new_name = name;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::string> DiffPresetDialog::get_options_to_save(Preset::Type type)
|
||||
{
|
||||
auto options = m_tree->options(type, true);
|
||||
|
||||
// erase "inherits" option from the list if it exists there
|
||||
if (const auto it = std::find(options.begin(), options.end(), "inherits"); it != options.end())
|
||||
options.erase(it);
|
||||
|
||||
if (type == Preset::TYPE_PRINTER) {
|
||||
// erase "extruders_count" option from the list if it exists there
|
||||
if (const auto it = std::find(options.begin(), options.end(), "extruders_count"); it != options.end())
|
||||
options.erase(it);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
void DiffPresetDialog::button_event(Action act)
|
||||
{
|
||||
if (act == Action::Save) {
|
||||
if (save()) {
|
||||
size_t saved_cnt = 0;
|
||||
for (const auto& preset : presets_to_save)
|
||||
if (wxGetApp().preset_bundle->transfer_and_save(preset.type, preset.from_name, preset.to_name, preset.new_name, get_options_to_save(preset.type)))
|
||||
saved_cnt++;
|
||||
|
||||
if (saved_cnt > 0) {
|
||||
MessageDialog(this, UnsavedChangesDialog::msg_success_saved_modifications(saved_cnt)).ShowModal();
|
||||
update_bundles_from_app();
|
||||
for (const auto& preset : presets_to_save) {
|
||||
m_preset_bundle_left->get_presets(preset.type).select_preset_by_name(preset.from_name, true);
|
||||
m_preset_bundle_right->get_presets(preset.type).select_preset_by_name(preset.new_name, true);
|
||||
}
|
||||
update_presets(m_view_type, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Hide();
|
||||
if (act == Action::Transfer)
|
||||
wxPostEvent(this, SimpleEvent(EVT_DIFF_DIALOG_TRANSFER));
|
||||
else if (!presets_to_save.empty())
|
||||
wxPostEvent(this, SimpleEvent(EVT_DIFF_DIALOG_UPDATE_PRESETS));
|
||||
}
|
||||
}
|
||||
|
||||
std::string DiffPresetDialog::get_left_preset_name(Preset::Type type)
|
||||
{
|
||||
PresetComboBox* cb = m_preset_combos[int(type - Preset::TYPE_PRINT)].presets_left;
|
||||
return Preset::remove_suffix_modified(get_selection(cb));
|
||||
}
|
||||
|
||||
std::string DiffPresetDialog::get_right_preset_name(Preset::Type type)
|
||||
{
|
||||
PresetComboBox* cb = m_preset_combos[int(type - Preset::TYPE_PRINT)].presets_right;
|
||||
return Preset::remove_suffix_modified(get_selection(cb));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Slic3r::GUI
|
||||
|
@ -15,6 +15,9 @@ class wxStaticText;
|
||||
namespace Slic3r {
|
||||
namespace GUI{
|
||||
|
||||
wxDECLARE_EVENT(EVT_DIFF_DIALOG_TRANSFER, SimpleEvent);
|
||||
wxDECLARE_EVENT(EVT_DIFF_DIALOG_UPDATE_PRESETS, SimpleEvent);
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ModelNode: a node inside DiffModel
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -103,7 +106,7 @@ public:
|
||||
ModelNode* GetParent() { return m_parent; }
|
||||
ModelNodePtrArray& GetChildren() { return m_children; }
|
||||
ModelNode* GetNthChild(unsigned int n) { return m_children[n].get(); }
|
||||
unsigned int GetChildCount() const { return m_children.size(); }
|
||||
unsigned int GetChildCount() const { return (unsigned int)(m_children.size()); }
|
||||
|
||||
void Append(std::unique_ptr<ModelNode> child) { m_children.emplace_back(std::move(child)); }
|
||||
|
||||
@ -154,7 +157,7 @@ public:
|
||||
};
|
||||
|
||||
DiffModel(wxWindow* parent);
|
||||
~DiffModel() {}
|
||||
~DiffModel() override = default;
|
||||
|
||||
void SetAssociatedControl(wxDataViewCtrl* ctrl) { m_ctrl = ctrl; }
|
||||
|
||||
@ -242,6 +245,20 @@ public:
|
||||
std::vector<std::string> selected_options();
|
||||
};
|
||||
|
||||
// Discard and Cancel buttons are always but next buttons are optional
|
||||
enum ActionButtons {
|
||||
TRANSFER = 1,
|
||||
KEEP = 2,
|
||||
SAVE = 4,
|
||||
DONT_SAVE = 8,
|
||||
};
|
||||
|
||||
enum class Action {
|
||||
Undef,
|
||||
Transfer,
|
||||
Discard,
|
||||
Save
|
||||
};
|
||||
|
||||
//------------------------------------------
|
||||
// UnsavedChangesDialog
|
||||
@ -262,13 +279,6 @@ class UnsavedChangesDialog : public DPIDialog
|
||||
|
||||
std::string m_app_config_key;
|
||||
|
||||
enum class Action {
|
||||
Undef,
|
||||
Transfer,
|
||||
Discard,
|
||||
Save
|
||||
};
|
||||
|
||||
static constexpr char ActTransfer[] = "transfer";
|
||||
static constexpr char ActDiscard[] = "discard";
|
||||
static constexpr char ActSave[] = "save";
|
||||
@ -281,19 +291,12 @@ class UnsavedChangesDialog : public DPIDialog
|
||||
int m_buttons { ActionButtons::TRANSFER | ActionButtons::SAVE };
|
||||
|
||||
public:
|
||||
// Discard and Cancel buttons are always but next buttons are optional
|
||||
enum ActionButtons {
|
||||
TRANSFER = 1,
|
||||
KEEP = 2,
|
||||
SAVE = 4,
|
||||
DONT_SAVE = 8,
|
||||
};
|
||||
|
||||
// show unsaved changes when preset is switching
|
||||
UnsavedChangesDialog(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset = std::string());
|
||||
// show unsaved changes for all another cases
|
||||
UnsavedChangesDialog(const wxString& caption, const wxString& header, const std::string& app_config_key, int act_buttons);
|
||||
~UnsavedChangesDialog() {}
|
||||
~UnsavedChangesDialog() override = default;
|
||||
|
||||
void build(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset, const wxString& header = "");
|
||||
void update(Preset::Type type, PresetCollection* dependent_presets, const std::string& new_selected_preset, const wxString& header);
|
||||
@ -318,6 +321,8 @@ public:
|
||||
std::vector<std::string> get_selected_options() { return m_tree->selected_options(); }
|
||||
bool has_unselected_options() { return m_tree->has_unselected_options(); }
|
||||
|
||||
static wxString msg_success_saved_modifications(size_t saved_presets_cnt);
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
void on_sys_color_changed() override;
|
||||
@ -332,7 +337,7 @@ class FullCompareDialog : public wxDialog
|
||||
public:
|
||||
FullCompareDialog(const wxString& option_name, const wxString& old_value, const wxString& mod_value, const wxString& new_value,
|
||||
const wxString& old_value_header, const wxString& mod_value_header, const wxString& new_value_header);
|
||||
~FullCompareDialog() {}
|
||||
~FullCompareDialog() override = default;
|
||||
};
|
||||
|
||||
|
||||
@ -342,19 +347,39 @@ public:
|
||||
class DiffPresetDialog : public DPIDialog
|
||||
{
|
||||
DiffViewCtrl* m_tree { nullptr };
|
||||
wxBoxSizer* m_presets_sizer { nullptr };
|
||||
wxStaticText* m_top_info_line { nullptr };
|
||||
wxStaticText* m_bottom_info_line { nullptr };
|
||||
wxCheckBox* m_show_all_presets { nullptr };
|
||||
wxCheckBox* m_use_for_transfer { nullptr };
|
||||
ScalableButton* m_transfer_btn { nullptr };
|
||||
ScalableButton* m_save_btn { nullptr };
|
||||
ScalableButton* m_cancel_btn { nullptr };
|
||||
wxBoxSizer* m_buttons { nullptr };
|
||||
wxBoxSizer* m_edit_sizer { nullptr };
|
||||
|
||||
Preset::Type m_view_type { Preset::TYPE_INVALID };
|
||||
PrinterTechnology m_pr_technology;
|
||||
std::unique_ptr<PresetBundle> m_preset_bundle_left;
|
||||
std::unique_ptr<PresetBundle> m_preset_bundle_right;
|
||||
|
||||
void update_tree();
|
||||
void update_bundles_from_app();
|
||||
void update_controls_visibility(Preset::Type type = Preset::TYPE_INVALID);
|
||||
void update_compatibility(const std::string& preset_name, Preset::Type type, PresetBundle* preset_bundle);
|
||||
void create_buttons();
|
||||
void create_edit_sizer();
|
||||
void complete_dialog_creation();
|
||||
void create_presets_sizer();
|
||||
void create_info_lines();
|
||||
void create_tree();
|
||||
void create_show_all_presets_chb();
|
||||
|
||||
void update_bottom_info(wxString bottom_info = "");
|
||||
void update_tree();
|
||||
void update_bundles_from_app();
|
||||
void update_controls_visibility(Preset::Type type = Preset::TYPE_INVALID);
|
||||
void update_compatibility(const std::string& preset_name, Preset::Type type, PresetBundle* preset_bundle);
|
||||
|
||||
std::vector<std::string> get_options_to_save(Preset::Type type);
|
||||
void button_event(Action act);
|
||||
bool save();
|
||||
|
||||
struct DiffPresets
|
||||
{
|
||||
@ -365,12 +390,31 @@ class DiffPresetDialog : public DPIDialog
|
||||
|
||||
std::vector<DiffPresets> m_preset_combos;
|
||||
|
||||
public:
|
||||
DiffPresetDialog(MainFrame* mainframe);
|
||||
~DiffPresetDialog() {}
|
||||
// attributes witch are used for save preset
|
||||
struct PresetToSave
|
||||
{
|
||||
Preset::Type type;
|
||||
std::string from_name;
|
||||
std::string to_name;
|
||||
std::string new_name;
|
||||
};
|
||||
|
||||
void show(Preset::Type type = Preset::TYPE_INVALID);
|
||||
void update_presets(Preset::Type type = Preset::TYPE_INVALID);
|
||||
std::vector<PresetToSave> presets_to_save;
|
||||
|
||||
public:
|
||||
DiffPresetDialog(MainFrame*mainframe);
|
||||
~DiffPresetDialog() override = default;
|
||||
|
||||
void show(Preset::Type type = Preset::TYPE_INVALID);
|
||||
void update_presets(Preset::Type type = Preset::TYPE_INVALID, bool update_preset_bundles_from_app = true);
|
||||
|
||||
Preset::Type view_type() const { return m_view_type; }
|
||||
PrinterTechnology printer_technology() const { return m_pr_technology; }
|
||||
|
||||
std::string get_left_preset_name(Preset::Type type);
|
||||
std::string get_right_preset_name(Preset::Type type);
|
||||
|
||||
std::vector<std::string> get_selected_options(Preset::Type type) const { return std::move(m_tree->options(type, true)); }
|
||||
|
||||
protected:
|
||||
void on_dpi_changed(const wxRect& suggested_rect) override;
|
||||
|