Merge remote-tracking branch 'PRIVATE/master' into ys_cut

This commit is contained in:
YuSanka 2022-09-19 08:26:52 +02:00
commit 737117e474
52 changed files with 2959 additions and 262 deletions

View File

@ -46,7 +46,7 @@ BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 78
ColumnLimit: 140
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -0,0 +1,3 @@
min_slic3r_version = 2.6.0-alpha0
1.0.0 Initial Rigid3D bundle

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

View 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"

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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 { };

View File

@ -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;

View File

@ -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;
}

View File

@ -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();

View File

@ -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)) {

View File

@ -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:

View File

@ -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)) {

View File

@ -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();

View File

@ -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);

View File

@ -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)) {

View File

@ -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

File diff suppressed because it is too large Load Diff

View 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 &params);
Issues full_search(const PrintObject *po, const Params &params);
}
}
#endif /* SRC_LIBSLIC3R_SUPPORTABLEISSUESSEARCH_HPP_ */

View 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);
}
}
}
}

View 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_ */

View File

@ -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());

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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));

View File

@ -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");

View File

@ -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

View File

@ -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();
};

View File

@ -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)

View File

@ -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

View File

@ -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;
}

View File

@ -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:

View File

@ -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);
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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();
};

View File

@ -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

View File

@ -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;