Merge branch 'master' into updating
This commit is contained in:
commit
214ad2925b
52 changed files with 3331 additions and 1146 deletions
27
My Settings
27
My Settings
|
@ -1,27 +0,0 @@
|
|||
# generated by Slic3r Prusa Edition 1.38.4 on 2017-12-20 at 11:02:03
|
||||
bed_temperature = 0
|
||||
bridge_fan_speed = 100
|
||||
compatible_printers =
|
||||
compatible_printers_condition =
|
||||
cooling = 1
|
||||
disable_fan_first_layers = 3
|
||||
end_filament_gcode = "; Filament-specific end gcode \n;END gcode for filament\n"
|
||||
extrusion_multiplier = 1
|
||||
fan_always_on = 0
|
||||
fan_below_layer_time = 60
|
||||
filament_colour = #29b2b2
|
||||
filament_cost = 0
|
||||
filament_density = 0
|
||||
filament_diameter = 3
|
||||
filament_max_volumetric_speed = 0
|
||||
filament_notes = ""
|
||||
filament_soluble = 0
|
||||
filament_type = PLA
|
||||
first_layer_bed_temperature = 0
|
||||
first_layer_temperature = 205
|
||||
max_fan_speed = 100
|
||||
min_fan_speed = 35
|
||||
min_print_speed = 10
|
||||
slowdown_below_layer_time = 5
|
||||
start_filament_gcode = "; Filament gcode\n"
|
||||
temperature = 200
|
|
@ -1527,10 +1527,13 @@ sub draw_active_object_annotations {
|
|||
my ($reset_left, $reset_bottom, $reset_right, $reset_top) = $self->_variable_layer_thickness_reset_rect_viewport;
|
||||
my $z_cursor_relative = $self->_variable_layer_thickness_bar_mouse_cursor_z_relative;
|
||||
|
||||
my $print_object = $self->{print}->get_object($object_idx);
|
||||
my $z_max = $print_object->model_object->bounding_box->z_max;
|
||||
|
||||
$self->{layer_height_edit_shader}->enable;
|
||||
$self->{layer_height_edit_shader}->set_uniform('z_to_texture_row', $volume->layer_height_texture_z_to_row_id);
|
||||
$self->{layer_height_edit_shader}->set_uniform('z_texture_row_to_normalized', 1. / $volume->layer_height_texture_height);
|
||||
$self->{layer_height_edit_shader}->set_uniform('z_cursor', $volume->bounding_box->z_max * $z_cursor_relative);
|
||||
$self->{layer_height_edit_shader}->set_uniform('z_cursor', $z_max * $z_cursor_relative);
|
||||
$self->{layer_height_edit_shader}->set_uniform('z_cursor_band_width', $self->{layer_height_edit_band_width});
|
||||
glBindTexture(GL_TEXTURE_2D, $self->{layer_preview_z_texture_id});
|
||||
glTexImage2D_c(GL_TEXTURE_2D, 0, GL_RGBA8, $volume->layer_height_texture_width, $volume->layer_height_texture_height,
|
||||
|
@ -1552,8 +1555,8 @@ sub draw_active_object_annotations {
|
|||
glBegin(GL_QUADS);
|
||||
glVertex3f($bar_left, $bar_bottom, 0);
|
||||
glVertex3f($bar_right, $bar_bottom, 0);
|
||||
glVertex3f($bar_right, $bar_top, $volume->bounding_box->z_max);
|
||||
glVertex3f($bar_left, $bar_top, $volume->bounding_box->z_max);
|
||||
glVertex3f($bar_right, $bar_top, $z_max);
|
||||
glVertex3f($bar_left, $bar_top, $z_max);
|
||||
glEnd();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
$self->{layer_height_edit_shader}->disable;
|
||||
|
@ -1572,7 +1575,6 @@ sub draw_active_object_annotations {
|
|||
|
||||
# Paint the graph.
|
||||
#FIXME show some kind of legend.
|
||||
my $print_object = $self->{print}->get_object($object_idx);
|
||||
my $max_z = unscale($print_object->size->z);
|
||||
my $profile = $print_object->model_object->layer_height_profile;
|
||||
my $layer_height = $print_object->config->get('layer_height');
|
||||
|
@ -1677,6 +1679,11 @@ sub draw_warning {
|
|||
}
|
||||
}
|
||||
|
||||
sub update_volumes_colors_by_extruder {
|
||||
my ($self, $config) = @_;
|
||||
$self->volumes->update_colors_by_extruder($config);
|
||||
}
|
||||
|
||||
sub opengl_info
|
||||
{
|
||||
my ($self, %params) = @_;
|
||||
|
@ -1823,7 +1830,6 @@ sub _fragment_shader_Gouraud {
|
|||
return <<'FRAGMENT';
|
||||
#version 110
|
||||
|
||||
const vec4 OUTSIDE_COLOR = vec4(0.24, 0.42, 0.62, 1.0);
|
||||
const vec3 ZERO = vec3(0.0, 0.0, 0.0);
|
||||
|
||||
// x = tainted, y = specular;
|
||||
|
@ -1836,11 +1842,9 @@ uniform vec4 uniform_color;
|
|||
|
||||
void main()
|
||||
{
|
||||
// if the fragment is outside the print volume use predefined color
|
||||
vec4 color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? OUTSIDE_COLOR : uniform_color;
|
||||
|
||||
gl_FragColor = vec4(intensity.y, intensity.y, intensity.y, 0.0) + color * intensity.x;
|
||||
gl_FragColor.a = color.a;
|
||||
// if the fragment is outside the print volume -> use darker color
|
||||
vec3 color = (any(lessThan(delta_box_min, ZERO)) || any(greaterThan(delta_box_max, ZERO))) ? mix(uniform_color.rgb, ZERO, 0.3333) : uniform_color.rgb;
|
||||
gl_FragColor = vec4(vec3(intensity.y, intensity.y, intensity.y) + color * intensity.x, uniform_color.a);
|
||||
}
|
||||
|
||||
FRAGMENT
|
||||
|
@ -1932,8 +1936,6 @@ const vec3 LIGHT_FRONT_DIR = vec3(0.6985074, 0.1397015, 0.6985074);
|
|||
|
||||
#define INTENSITY_AMBIENT 0.3
|
||||
|
||||
uniform float z_to_texture_row;
|
||||
|
||||
// x = tainted, y = specular;
|
||||
varying vec2 intensity;
|
||||
|
||||
|
|
|
@ -52,9 +52,8 @@ sub new {
|
|||
$self->{config} = Slic3r::Config::new_from_defaults_keys([qw(
|
||||
bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width variable_layer_height
|
||||
serial_port serial_speed octoprint_host octoprint_apikey octoprint_cafile
|
||||
nozzle_diameter single_extruder_multi_material
|
||||
wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width wipe_tower_per_color_wipe extruder_colour filament_colour
|
||||
max_print_height
|
||||
nozzle_diameter single_extruder_multi_material wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width
|
||||
wipe_tower_rotation_angle extruder_colour filament_colour max_print_height
|
||||
)]);
|
||||
# C++ Slic3r::Model with Perl extensions in Slic3r/Model.pm
|
||||
$self->{model} = Slic3r::Model->new;
|
||||
|
@ -105,7 +104,6 @@ sub new {
|
|||
$self->{btn_reslice}->Enable($enable);
|
||||
$self->{btn_print}->Enable($enable);
|
||||
$self->{btn_send_gcode}->Enable($enable);
|
||||
$self->{btn_export_stl}->Enable($enable);
|
||||
};
|
||||
|
||||
# Initialize 3D plater
|
||||
|
@ -738,8 +736,14 @@ sub load_model_objects {
|
|||
{
|
||||
# if the object is too large (more than 5 times the bed), scale it down
|
||||
my $size = $o->bounding_box->size;
|
||||
my $ratio = max(@$size[X,Y]) / unscale(max(@$bed_size[X,Y]));
|
||||
if ($ratio > 5) {
|
||||
my $ratio = max($size->x / unscale($bed_size->x), $size->y / unscale($bed_size->y));
|
||||
if ($ratio > 10000) {
|
||||
# the size of the object is too big -> this could lead to overflow when moving to clipper coordinates,
|
||||
# so scale down the mesh
|
||||
$o->scale_xyz(Slic3r::Pointf3->new(1/$ratio, 1/$ratio, 1/$ratio));
|
||||
$scaled_down = 1;
|
||||
}
|
||||
elsif ($ratio > 5) {
|
||||
$_->set_scaling_factor(1/$ratio) for @{$o->instances};
|
||||
$scaled_down = 1;
|
||||
}
|
||||
|
@ -1915,7 +1919,8 @@ sub object_list_changed {
|
|||
}
|
||||
|
||||
my $export_in_progress = $self->{export_gcode_output_file} || $self->{send_gcode_file};
|
||||
my $method = ($have_objects && ! $export_in_progress) ? 'Enable' : 'Disable';
|
||||
my $model_fits = $self->{model}->fits_print_volume($self->{config});
|
||||
my $method = ($have_objects && ! $export_in_progress && $model_fits) ? 'Enable' : 'Disable';
|
||||
$self->{"btn_$_"}->$method
|
||||
for grep $self->{"btn_$_"}, qw(reslice export_gcode print send_gcode);
|
||||
}
|
||||
|
|
|
@ -210,12 +210,15 @@ sub reload_scene {
|
|||
if ($extruders_count > 1 && $self->{config}->single_extruder_multi_material && $self->{config}->wipe_tower &&
|
||||
! $self->{config}->complete_objects) {
|
||||
$self->volumes->load_wipe_tower_preview(1000,
|
||||
$self->{config}->wipe_tower_x, $self->{config}->wipe_tower_y,
|
||||
$self->{config}->wipe_tower_width, $self->{config}->wipe_tower_per_color_wipe * ($extruders_count - 1),
|
||||
$self->{model}->bounding_box->z_max, $self->UseVBOs);
|
||||
$self->{config}->wipe_tower_x, $self->{config}->wipe_tower_y, $self->{config}->wipe_tower_width,
|
||||
#$self->{config}->wipe_tower_per_color_wipe# 15 * ($extruders_count - 1), # this is just a hack when the config parameter became obsolete
|
||||
15 * ($extruders_count - 1),
|
||||
$self->{model}->bounding_box->z_max, $self->{config}->wipe_tower_rotation_angle, $self->UseVBOs);
|
||||
}
|
||||
}
|
||||
|
||||
$self->update_volumes_colors_by_extruder($self->{config});
|
||||
|
||||
# checks for geometry outside the print volume to render it accordingly
|
||||
if (scalar @{$self->volumes} > 0)
|
||||
{
|
||||
|
@ -229,6 +232,9 @@ sub reload_scene {
|
|||
Slic3r::GUI::_3DScene::reset_warning_texture();
|
||||
$self->on_enable_action_buttons->(1) if ($self->on_enable_action_buttons);
|
||||
}
|
||||
} else {
|
||||
$self->set_warning_enabled(0);
|
||||
Slic3r::GUI::_3DScene::reset_warning_texture();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ sub new {
|
|||
label => 'Z',
|
||||
default => $self->{cut_options}{z},
|
||||
min => 0,
|
||||
max => $self->{model_object}->bounding_box->size->z * $self->{model_object}->instances->[0]->scaling_factor,
|
||||
max => $self->{model_object}->bounding_box->size->z,
|
||||
full_width => 1,
|
||||
));
|
||||
{
|
||||
|
@ -247,6 +247,7 @@ sub _update {
|
|||
$self->{cut_options}{z},
|
||||
[@expolygons],
|
||||
);
|
||||
$self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->{config});
|
||||
$self->{canvas}->Render;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use utf8;
|
|||
use File::Basename qw(basename);
|
||||
use Wx qw(:misc :sizer :treectrl :button :keycode wxTAB_TRAVERSAL wxSUNKEN_BORDER wxBITMAP_TYPE_PNG wxID_CANCEL wxMOD_CONTROL
|
||||
wxTheApp);
|
||||
use Wx::Event qw(EVT_BUTTON EVT_TREE_ITEM_COLLAPSING EVT_TREE_SEL_CHANGED EVT_TREE_KEY_DOWN);
|
||||
use Wx::Event qw(EVT_BUTTON EVT_TREE_ITEM_COLLAPSING EVT_TREE_SEL_CHANGED EVT_TREE_KEY_DOWN EVT_KEY_DOWN);
|
||||
use base 'Wx::Panel';
|
||||
|
||||
use constant ICON_OBJECT => 0;
|
||||
|
@ -88,7 +88,7 @@ sub new {
|
|||
$self->{btn_move_down}->SetFont($Slic3r::GUI::small_font);
|
||||
|
||||
# part settings panel
|
||||
$self->{settings_panel} = Slic3r::GUI::Plater::OverrideSettingsPanel->new($self, on_change => sub { $self->{part_settings_changed} = 1; });
|
||||
$self->{settings_panel} = Slic3r::GUI::Plater::OverrideSettingsPanel->new($self, on_change => sub { $self->{part_settings_changed} = 1; $self->_update_canvas; });
|
||||
my $settings_sizer = Wx::StaticBoxSizer->new($self->{staticbox} = Wx::StaticBox->new($self, -1, "Part Settings"), wxVERTICAL);
|
||||
$settings_sizer->Add($self->{settings_panel}, 1, wxEXPAND | wxALL, 0);
|
||||
|
||||
|
@ -162,6 +162,7 @@ sub new {
|
|||
$canvas->load_object($self->{model_object}, undef, undef, [0]);
|
||||
$canvas->set_auto_bed_shape;
|
||||
$canvas->SetSize([500,700]);
|
||||
$canvas->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
|
||||
$canvas->zoom_to_volumes;
|
||||
}
|
||||
|
||||
|
@ -190,6 +191,14 @@ sub new {
|
|||
EVT_BUTTON($self, $self->{btn_split}, \&on_btn_split);
|
||||
EVT_BUTTON($self, $self->{btn_move_up}, \&on_btn_move_up);
|
||||
EVT_BUTTON($self, $self->{btn_move_down}, \&on_btn_move_down);
|
||||
EVT_KEY_DOWN($canvas, sub {
|
||||
my ($canvas, $event) = @_;
|
||||
if ($event->GetKeyCode == WXK_DELETE) {
|
||||
$canvas->GetParent->on_btn_delete;
|
||||
} else {
|
||||
$event->Skip;
|
||||
}
|
||||
});
|
||||
|
||||
$self->reload_tree;
|
||||
|
||||
|
@ -400,14 +409,17 @@ sub on_tree_key_down {
|
|||
my ($self, $event) = @_;
|
||||
my $keycode = $event->GetKeyCode;
|
||||
# Wx >= 0.9911
|
||||
if (defined(&Wx::TreeEvent::GetKeyEvent) &&
|
||||
($event->GetKeyEvent->GetModifiers & wxMOD_CONTROL)) {
|
||||
if ($keycode == WXK_UP) {
|
||||
$event->Skip;
|
||||
$self->on_btn_move_up;
|
||||
} elsif ($keycode == WXK_DOWN) {
|
||||
$event->Skip;
|
||||
$self->on_btn_move_down;
|
||||
if (defined(&Wx::TreeEvent::GetKeyEvent)) {
|
||||
if ($event->GetKeyEvent->GetModifiers & wxMOD_CONTROL) {
|
||||
if ($keycode == WXK_UP) {
|
||||
$event->Skip;
|
||||
$self->on_btn_move_up;
|
||||
} elsif ($keycode == WXK_DOWN) {
|
||||
$event->Skip;
|
||||
$self->on_btn_move_down;
|
||||
}
|
||||
} elsif ($keycode == WXK_DELETE) {
|
||||
$self->on_btn_delete;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -478,6 +490,7 @@ sub _parts_changed {
|
|||
$self->{canvas}->reset_objects;
|
||||
$self->{canvas}->load_object($self->{model_object});
|
||||
$self->{canvas}->zoom_to_volumes;
|
||||
$self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
|
||||
$self->{canvas}->Render;
|
||||
}
|
||||
}
|
||||
|
@ -508,6 +521,25 @@ sub PartSettingsChanged {
|
|||
return $self->{part_settings_changed};
|
||||
}
|
||||
|
||||
sub _update_canvas {
|
||||
my ($self) = @_;
|
||||
|
||||
if ($self->{canvas}) {
|
||||
$self->{canvas}->reset_objects;
|
||||
$self->{canvas}->load_object($self->{model_object});
|
||||
|
||||
# restore selection, if any
|
||||
if (my $itemData = $self->get_selection) {
|
||||
if ($itemData->{type} eq 'volume') {
|
||||
$self->{canvas}->volumes->[ $itemData->{volume_id} ]->set_selected(1);
|
||||
}
|
||||
}
|
||||
|
||||
$self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
|
||||
$self->{canvas}->Render;
|
||||
}
|
||||
}
|
||||
|
||||
sub _update {
|
||||
my ($self) = @_;
|
||||
my ($m_x, $m_y, $m_z) = ($self->{move_options}{x}, $self->{move_options}{y}, $self->{move_options}{z});
|
||||
|
@ -528,6 +560,7 @@ sub _update {
|
|||
push @objects, $self->{model_object};
|
||||
$self->{canvas}->reset_objects;
|
||||
$self->{canvas}->load_object($_, undef, [0]) for @objects;
|
||||
$self->{canvas}->update_volumes_colors_by_extruder($self->GetParent->GetParent->GetParent->{config});
|
||||
$self->{canvas}->Render;
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 616 B After Width: | Height: | Size: 491 B |
Binary file not shown.
Before Width: | Height: | Size: 448 B After Width: | Height: | Size: 510 B |
Binary file not shown.
Before Width: | Height: | Size: 454 B After Width: | Height: | Size: 419 B |
|
@ -600,6 +600,7 @@ temperature = 255
|
|||
|
||||
[filament:*FLEX*]
|
||||
inherits = *common*
|
||||
bed_temperature = 50
|
||||
bridge_fan_speed = 100
|
||||
compatible_printers_condition = nozzle_diameter[0]>0.35 and num_extruders==1
|
||||
cooling = 0
|
||||
|
@ -950,6 +951,7 @@ variable_layer_height = 0
|
|||
|
||||
[printer:Original Prusa i3 MK2]
|
||||
inherits = *common*
|
||||
default_print_profile = 0.15mm OPTIMAL
|
||||
|
||||
[printer:Original Prusa i3 MK2 0.25 nozzle]
|
||||
inherits = *common*
|
||||
|
@ -968,6 +970,7 @@ max_layer_height = 0.35
|
|||
min_layer_height = 0.1
|
||||
nozzle_diameter = 0.6
|
||||
printer_variant = 0.6
|
||||
default_print_profile = 0.20mm NORMAL 0.6 nozzle
|
||||
|
||||
[printer:Original Prusa i3 MK2 MM Single Mode]
|
||||
inherits = *mm-single*
|
||||
|
@ -976,6 +979,7 @@ inherits = *mm-single*
|
|||
inherits = *mm-single*
|
||||
nozzle_diameter = 0.6
|
||||
printer_variant = 0.6
|
||||
default_print_profile = 0.20mm NORMAL 0.6 nozzle
|
||||
|
||||
[printer:Original Prusa i3 MK2 MultiMaterial]
|
||||
inherits = *mm-multi*
|
||||
|
|
|
@ -57,7 +57,7 @@ plan tests => 8;
|
|||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('layer_height', 0.2);
|
||||
$config->set('first_layer_height', 0.2);
|
||||
$config->set('nozzle_diameter', [0.5]);
|
||||
$config->set('nozzle_diameter', [0.5,0.5,0.5,0.5]);
|
||||
$config->set('infill_every_layers', 2);
|
||||
$config->set('perimeter_extruder', 1);
|
||||
$config->set('infill_extruder', 2);
|
||||
|
|
|
@ -49,7 +49,7 @@ use Slic3r::Test;
|
|||
my $parser = Slic3r::GCode::PlaceholderParser->new;
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('printer_notes', ' PRINTER_VENDOR_PRUSA3D PRINTER_MODEL_MK2 ');
|
||||
$config->set('nozzle_diameter', [0.6, 0.6, 0.6, 0.6]);
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$parser->apply_config($config);
|
||||
$parser->set('foo' => 0);
|
||||
$parser->set('bar' => 2);
|
||||
|
@ -123,6 +123,7 @@ use Slic3r::Test;
|
|||
|
||||
{
|
||||
my $config = Slic3r::Config->new;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('extruder', 2);
|
||||
$config->set('first_layer_temperature', [200,205]);
|
||||
|
||||
|
@ -204,6 +205,7 @@ use Slic3r::Test;
|
|||
|
||||
{
|
||||
my $config = Slic3r::Config->new;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6,0.6]);
|
||||
$config->set('start_gcode', qq!
|
||||
;substitution:{if infill_extruder==1}if block
|
||||
{elsif infill_extruder==2}elsif block 1
|
||||
|
@ -228,6 +230,7 @@ use Slic3r::Test;
|
|||
|
||||
{
|
||||
my $config = Slic3r::Config->new;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('start_gcode',
|
||||
';substitution:{if infill_extruder==1}{if perimeter_extruder==1}block11{else}block12{endif}' .
|
||||
'{elsif infill_extruder==2}{if perimeter_extruder==1}block21{else}block22{endif}' .
|
||||
|
|
4
t/fill.t
4
t/fill.t
|
@ -164,6 +164,7 @@ SKIP:
|
|||
|
||||
for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.4,0.4,0.4,0.4]);
|
||||
$config->set('fill_pattern', $pattern);
|
||||
$config->set('external_fill_pattern', $pattern);
|
||||
$config->set('perimeters', 1);
|
||||
|
@ -195,6 +196,7 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
|
|||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.4,0.4,0.4,0.4]);
|
||||
$config->set('infill_only_where_needed', 1);
|
||||
$config->set('bottom_solid_layers', 0);
|
||||
$config->set('infill_extruder', 2);
|
||||
|
@ -276,7 +278,7 @@ for my $pattern (qw(rectilinear honeycomb hilbertcurve concentric)) {
|
|||
$config->set('fill_density', 0);
|
||||
$config->set('layer_height', 0.2);
|
||||
$config->set('first_layer_height', 0.2);
|
||||
$config->set('nozzle_diameter', [0.35]);
|
||||
$config->set('nozzle_diameter', [0.35,0.35,0.35,0.35]);
|
||||
$config->set('infill_extruder', 2);
|
||||
$config->set('solid_infill_extruder', 2);
|
||||
$config->set('infill_extrusion_width', 0.52);
|
||||
|
|
|
@ -16,6 +16,7 @@ use Slic3r::Test;
|
|||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('raft_layers', 2);
|
||||
$config->set('infill_extruder', 2);
|
||||
$config->set('solid_infill_extruder', 3);
|
||||
|
@ -89,6 +90,7 @@ use Slic3r::Test;
|
|||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('support_material_extruder', 3);
|
||||
|
||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
||||
|
@ -97,6 +99,7 @@ use Slic3r::Test;
|
|||
|
||||
{
|
||||
my $config = Slic3r::Config->new;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('extruder', 2);
|
||||
|
||||
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
|
||||
|
@ -105,6 +108,7 @@ use Slic3r::Test;
|
|||
|
||||
{
|
||||
my $config = Slic3r::Config->new;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('perimeter_extruder', 2);
|
||||
$config->set('infill_extruder', 2);
|
||||
$config->set('support_material_extruder', 2);
|
||||
|
@ -126,6 +130,7 @@ use Slic3r::Test;
|
|||
$upper_config->set('bottom_solid_layers', 1);
|
||||
$upper_config->set('top_solid_layers', 0);
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('fill_density', 0);
|
||||
$config->set('solid_infill_speed', 99);
|
||||
$config->set('top_solid_infill_speed', 99);
|
||||
|
@ -172,6 +177,7 @@ use Slic3r::Test;
|
|||
my $object = $model->objects->[0];
|
||||
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('layer_height', 0.4);
|
||||
$config->set('first_layer_height', '100%');
|
||||
$config->set('skirts', 0);
|
||||
|
|
|
@ -95,6 +95,7 @@ use Slic3r::Test qw(_eq);
|
|||
1;
|
||||
};
|
||||
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('first_layer_height', $config->layer_height);
|
||||
$config->set('first_layer_speed', '100%');
|
||||
$config->set('start_gcode', ''); # to avoid dealing with the nozzle lift in start G-code
|
||||
|
@ -207,6 +208,7 @@ use Slic3r::Test qw(_eq);
|
|||
|
||||
{
|
||||
my $config = Slic3r::Config::new_from_defaults;
|
||||
$config->set('nozzle_diameter', [0.6,0.6,0.6,0.6]);
|
||||
$config->set('start_gcode', '');
|
||||
$config->set('retract_lift', [3, 4]);
|
||||
|
||||
|
@ -255,4 +257,4 @@ use Slic3r::Test qw(_eq);
|
|||
'Z is not lifted above the configured value for 2. extruder';
|
||||
}
|
||||
|
||||
__END__
|
||||
__END__
|
||||
|
|
|
@ -206,6 +206,10 @@ add_library(libslic3r_gui STATIC
|
|||
${LIBDIR}/slic3r/GUI/2DBed.hpp
|
||||
${LIBDIR}/slic3r/GUI/wxExtensions.cpp
|
||||
${LIBDIR}/slic3r/GUI/wxExtensions.hpp
|
||||
${LIBDIR}/slic3r/GUI/WipeTowerDialog.cpp
|
||||
${LIBDIR}/slic3r/GUI/WipeTowerDialog.hpp
|
||||
${LIBDIR}/slic3r/GUI/RammingChart.cpp
|
||||
${LIBDIR}/slic3r/GUI/RammingChart.hpp
|
||||
${LIBDIR}/slic3r/GUI/BonjourDialog.cpp
|
||||
${LIBDIR}/slic3r/GUI/BonjourDialog.hpp
|
||||
${LIBDIR}/slic3r/Config/Snapshot.cpp
|
||||
|
|
|
@ -9,74 +9,115 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
static inline Polyline make_wave_vertical(
|
||||
double width, double height, double x0,
|
||||
double segmentSize, double scaleFactor,
|
||||
double z_cos, double z_sin, bool flip)
|
||||
static inline double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
|
||||
{
|
||||
Polyline polyline;
|
||||
polyline.points.emplace_back(Point(coord_t(clamp(0., width, x0) * scaleFactor), 0));
|
||||
double phase_offset_sin = (z_cos < 0 ? M_PI : 0) + M_PI;
|
||||
double phase_offset_cos = (z_cos < 0 ? M_PI : 0) + M_PI + (flip ? M_PI : 0.);
|
||||
for (double y = 0.; y < height + segmentSize; y += segmentSize) {
|
||||
y = std::min(y, height);
|
||||
double a = sin(y + phase_offset_sin);
|
||||
if (vertical) {
|
||||
double phase_offset = (z_cos < 0 ? M_PI : 0) + M_PI;
|
||||
double a = sin(x + phase_offset);
|
||||
double b = - z_cos;
|
||||
double res = z_sin * cos(y + phase_offset_cos);
|
||||
double res = z_sin * cos(x + phase_offset + (flip ? M_PI : 0.));
|
||||
double r = sqrt(sqr(a) + sqr(b));
|
||||
double x = clamp(0., width, asin(a/r) + asin(res/r) + M_PI + x0);
|
||||
polyline.points.emplace_back(convert_to<Point>(Pointf(x, y) * scaleFactor));
|
||||
return asin(a/r) + asin(res/r) + M_PI;
|
||||
}
|
||||
if (flip)
|
||||
std::reverse(polyline.points.begin(), polyline.points.end());
|
||||
else {
|
||||
double phase_offset = z_sin < 0 ? M_PI : 0.;
|
||||
double a = cos(x + phase_offset);
|
||||
double b = - z_sin;
|
||||
double res = z_cos * sin(x + phase_offset + (flip ? 0 : M_PI));
|
||||
double r = sqrt(sqr(a) + sqr(b));
|
||||
return (asin(a/r) + asin(res/r) + 0.5 * M_PI);
|
||||
}
|
||||
}
|
||||
|
||||
static inline Polyline make_wave(
|
||||
const std::vector<Pointf>& one_period, double width, double height, double offset, double scaleFactor,
|
||||
double z_cos, double z_sin, bool vertical)
|
||||
{
|
||||
std::vector<Pointf> points = one_period;
|
||||
double period = points.back().x;
|
||||
points.pop_back();
|
||||
int n = points.size();
|
||||
do {
|
||||
points.emplace_back(Pointf(points[points.size()-n].x + period, points[points.size()-n].y));
|
||||
} while (points.back().x < width);
|
||||
points.back().x = width;
|
||||
|
||||
// and construct the final polyline to return:
|
||||
Polyline polyline;
|
||||
for (auto& point : points) {
|
||||
point.y += offset;
|
||||
point.y = clamp(0., height, double(point.y));
|
||||
if (vertical)
|
||||
std::swap(point.x, point.y);
|
||||
polyline.points.emplace_back(convert_to<Point>(point * scaleFactor));
|
||||
}
|
||||
|
||||
return polyline;
|
||||
}
|
||||
|
||||
static inline Polyline make_wave_horizontal(
|
||||
double width, double height, double y0,
|
||||
double segmentSize, double scaleFactor,
|
||||
double z_cos, double z_sin, bool flip)
|
||||
static std::vector<Pointf> make_one_period(double width, double scaleFactor, double z_cos, double z_sin, bool vertical, bool flip)
|
||||
{
|
||||
Polyline polyline;
|
||||
polyline.points.emplace_back(Point(0, coord_t(clamp(0., height, y0) * scaleFactor)));
|
||||
double phase_offset_sin = (z_sin < 0 ? M_PI : 0) + (flip ? 0 : M_PI);
|
||||
double phase_offset_cos = z_sin < 0 ? M_PI : 0.;
|
||||
for (double x = 0.; x < width + segmentSize; x += segmentSize) {
|
||||
x = std::min(x, width);
|
||||
double a = cos(x + phase_offset_cos);
|
||||
double b = - z_sin;
|
||||
double res = z_cos * sin(x + phase_offset_sin);
|
||||
double r = sqrt(sqr(a) + sqr(b));
|
||||
double y = clamp(0., height, asin(a/r) + asin(res/r) + 0.5 * M_PI + y0);
|
||||
polyline.points.emplace_back(convert_to<Point>(Pointf(x, y) * scaleFactor));
|
||||
std::vector<Pointf> points;
|
||||
double dx = M_PI_4; // very coarse spacing to begin with
|
||||
double limit = std::min(2*M_PI, width);
|
||||
for (double x = 0.; x < limit + EPSILON; x += dx) { // so the last point is there too
|
||||
x = std::min(x, limit);
|
||||
points.emplace_back(Pointf(x,f(x, z_sin,z_cos, vertical, flip)));
|
||||
}
|
||||
if (flip)
|
||||
std::reverse(polyline.points.begin(), polyline.points.end());
|
||||
return polyline;
|
||||
|
||||
// now we will check all internal points and in case some are too far from the line connecting its neighbours,
|
||||
// we will add one more point on each side:
|
||||
const double tolerance = .1;
|
||||
for (unsigned int i=1;i<points.size()-1;++i) {
|
||||
auto& lp = points[i-1]; // left point
|
||||
auto& tp = points[i]; // this point
|
||||
auto& rp = points[i+1]; // right point
|
||||
// calculate distance of the point to the line:
|
||||
double dist_mm = unscale(scaleFactor * std::abs( (rp.y - lp.y)*tp.x + (lp.x - rp.x)*tp.y + (rp.x*lp.y - rp.y*lp.x) ) / std::hypot((rp.y - lp.y),(lp.x - rp.x)));
|
||||
|
||||
if (dist_mm > tolerance) { // if the difference from straight line is more than this
|
||||
double x = 0.5f * (points[i-1].x + points[i].x);
|
||||
points.emplace_back(Pointf(x, f(x, z_sin, z_cos, vertical, flip)));
|
||||
x = 0.5f * (points[i+1].x + points[i].x);
|
||||
points.emplace_back(Pointf(x, f(x, z_sin, z_cos, vertical, flip)));
|
||||
std::sort(points.begin(), points.end()); // we added the points to the end, but need them all in order
|
||||
--i; // decrement i so we also check the first newly added point
|
||||
}
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
static Polylines make_gyroid_waves(double gridZ, double density_adjusted, double line_spacing, double width, double height)
|
||||
{
|
||||
double scaleFactor = scale_(line_spacing) / density_adjusted;
|
||||
double segmentSize = 0.5 * density_adjusted;
|
||||
const double scaleFactor = scale_(line_spacing) / density_adjusted;
|
||||
//scale factor for 5% : 8 712 388
|
||||
// 1z = 10^-6 mm ?
|
||||
double z = gridZ / scaleFactor;
|
||||
double z_sin = sin(z);
|
||||
double z_cos = cos(z);
|
||||
Polylines result;
|
||||
if (std::abs(z_sin) <= std::abs(z_cos)) {
|
||||
// Vertical wave
|
||||
double x0 = M_PI * (int)((- 0.5 * M_PI) / M_PI - 1.);
|
||||
bool flip = ((int)(x0 / M_PI + 1.) & 1) != 0;
|
||||
for (; x0 < width - 0.5 * M_PI; x0 += M_PI, flip = ! flip)
|
||||
result.emplace_back(make_wave_vertical(width, height, x0, segmentSize, scaleFactor, z_cos, z_sin, flip));
|
||||
} else {
|
||||
// Horizontal wave
|
||||
bool flip = true;
|
||||
for (double y0 = 0.; y0 < height; y0 += M_PI, flip = !flip)
|
||||
result.emplace_back(make_wave_horizontal(width, height, y0, segmentSize, scaleFactor, z_cos, z_sin, flip));
|
||||
const double z = gridZ / scaleFactor;
|
||||
const double z_sin = sin(z);
|
||||
const double z_cos = cos(z);
|
||||
|
||||
bool vertical = (std::abs(z_sin) <= std::abs(z_cos));
|
||||
double lower_bound = 0.;
|
||||
double upper_bound = height;
|
||||
bool flip = true;
|
||||
if (vertical) {
|
||||
flip = false;
|
||||
lower_bound = -M_PI;
|
||||
upper_bound = width - M_PI_2;
|
||||
std::swap(width,height);
|
||||
}
|
||||
|
||||
std::vector<Pointf> one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // creates one period of the waves, so it doesn't have to be recalculated all the time
|
||||
Polylines result;
|
||||
|
||||
for (double y0 = lower_bound; y0 < upper_bound+EPSILON; y0 += 2*M_PI) // creates odd polylines
|
||||
result.emplace_back(make_wave(one_period, width, height, y0, scaleFactor, z_cos, z_sin, vertical));
|
||||
|
||||
flip = !flip; // even polylines are a bit shifted
|
||||
one_period = make_one_period(width, scaleFactor, z_cos, z_sin, vertical, flip); // updates the one period sample
|
||||
for (double y0 = lower_bound + M_PI; y0 < upper_bound+EPSILON; y0 += 2*M_PI) // creates even polylines
|
||||
result.emplace_back(make_wave(one_period, width, height, y0, scaleFactor, z_cos, z_sin, vertical));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -90,13 +131,13 @@ void FillGyroid::_fill_surface_single(
|
|||
// no rotation is supported for this infill pattern (yet)
|
||||
BoundingBox bb = expolygon.contour.bounding_box();
|
||||
// Density adjusted to have a good %of weight.
|
||||
double density_adjusted = params.density * 1.75;
|
||||
double density_adjusted = std::max(0., params.density * 2.);
|
||||
// Distance between the gyroid waves in scaled coordinates.
|
||||
coord_t distance = coord_t(scale_(this->spacing) / density_adjusted);
|
||||
|
||||
// align bounding box to a multiple of our grid module
|
||||
bb.merge(_align_to_grid(bb.min, Point(2.*M_PI*distance, 2.*M_PI*distance)));
|
||||
|
||||
|
||||
// generate pattern
|
||||
Polylines polylines = make_gyroid_waves(
|
||||
scale_(this->z),
|
||||
|
|
|
@ -388,7 +388,6 @@ namespace Slic3r {
|
|||
|
||||
bool _create_object_instance(int object_id, const Matrix4x4& matrix, unsigned int recur_counter);
|
||||
|
||||
void _apply_transform(ModelObject& object, const Matrix4x4& matrix);
|
||||
void _apply_transform(ModelInstance& instance, const Matrix4x4& matrix);
|
||||
|
||||
bool _handle_start_config(const char** attributes, unsigned int num_attributes);
|
||||
|
@ -557,19 +556,6 @@ namespace Slic3r {
|
|||
|
||||
if (!_generate_volumes(*object.second, obj_geometry->second, *volumes_ptr))
|
||||
return false;
|
||||
|
||||
// apply transformation if the object contains a single instance
|
||||
if (object.second->instances.size() == 1)
|
||||
{
|
||||
for (const Instance& instance : m_instances)
|
||||
{
|
||||
if (object.second->instances[0] == instance.instance)
|
||||
{
|
||||
_apply_transform(*object.second, instance.matrix);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fixes the min z of the model if negative
|
||||
|
@ -822,10 +808,9 @@ namespace Slic3r {
|
|||
if (instance.instance != nullptr)
|
||||
{
|
||||
ModelObject* object = instance.instance->get_object();
|
||||
if ((object != nullptr) && (object->instances.size() > 1))
|
||||
if (object != nullptr)
|
||||
{
|
||||
// multiple instances -> apply the matrix to the instance
|
||||
// (for single instance the transformation can be applied only after the volumes have been generated)
|
||||
// apply the matrix to the instance
|
||||
_apply_transform(*instance.instance, instance.matrix);
|
||||
}
|
||||
}
|
||||
|
@ -1120,15 +1105,6 @@ namespace Slic3r {
|
|||
return true;
|
||||
}
|
||||
|
||||
void _3MF_Importer::_apply_transform(ModelObject& object, const Matrix4x4& matrix)
|
||||
{
|
||||
float matrix3x4[12] = { matrix(0, 0), matrix(0, 1), matrix(0, 2), matrix(0, 3),
|
||||
matrix(1, 0), matrix(1, 1), matrix(1, 2), matrix(1, 3),
|
||||
matrix(2, 0), matrix(2, 1), matrix(2, 2), matrix(2, 3) };
|
||||
|
||||
object.transform(matrix3x4);
|
||||
}
|
||||
|
||||
void _3MF_Importer::_apply_transform(ModelInstance& instance, const Matrix4x4& matrix)
|
||||
{
|
||||
// slic3r ModelInstance cannot be transformed using a matrix
|
||||
|
@ -1645,9 +1621,7 @@ namespace Slic3r {
|
|||
}
|
||||
|
||||
Eigen::Affine3f transform;
|
||||
transform = Eigen::Translation3f((float)(instance->offset.x + object.origin_translation.x), (float)(instance->offset.y + object.origin_translation.y), (float)object.origin_translation.z)
|
||||
* Eigen::AngleAxisf((float)instance->rotation, Eigen::Vector3f::UnitZ())
|
||||
* Eigen::Scaling((float)instance->scaling_factor);
|
||||
transform = Eigen::Translation3f((float)instance->offset.x, (float)instance->offset.y, 0.0f) * Eigen::AngleAxisf((float)instance->rotation, Eigen::Vector3f::UnitZ()) * Eigen::Scaling((float)instance->scaling_factor);
|
||||
build_items.emplace_back(instance_id, transform.matrix());
|
||||
|
||||
stream << " </" << OBJECT_TAG << ">\n";
|
||||
|
@ -1690,10 +1664,9 @@ namespace Slic3r {
|
|||
for (int i = 0; i < stl.stats.shared_vertices; ++i)
|
||||
{
|
||||
stream << " <" << VERTEX_TAG << " ";
|
||||
// Subtract origin_translation in order to restore the original local coordinates
|
||||
stream << "x=\"" << (stl.v_shared[i].x - object.origin_translation.x) << "\" ";
|
||||
stream << "y=\"" << (stl.v_shared[i].y - object.origin_translation.y) << "\" ";
|
||||
stream << "z=\"" << (stl.v_shared[i].z - object.origin_translation.z) << "\" />\n";
|
||||
stream << "x=\"" << stl.v_shared[i].x << "\" ";
|
||||
stream << "y=\"" << stl.v_shared[i].y << "\" ";
|
||||
stream << "z=\"" << stl.v_shared[i].z << "\" />\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,12 +17,26 @@ public:
|
|||
struct xy
|
||||
{
|
||||
xy(float x = 0.f, float y = 0.f) : x(x), y(y) {}
|
||||
xy(const xy& pos,float xp,float yp) : x(pos.x+xp), y(pos.y+yp) {}
|
||||
xy operator+(const xy &rhs) const { xy out(*this); out.x += rhs.x; out.y += rhs.y; return out; }
|
||||
xy operator-(const xy &rhs) const { xy out(*this); out.x -= rhs.x; out.y -= rhs.y; return out; }
|
||||
xy& operator+=(const xy &rhs) { x += rhs.x; y += rhs.y; return *this; }
|
||||
xy& operator-=(const xy &rhs) { x -= rhs.x; y -= rhs.y; return *this; }
|
||||
bool operator==(const xy &rhs) const { return x == rhs.x && y == rhs.y; }
|
||||
bool operator!=(const xy &rhs) const { return x != rhs.x || y != rhs.y; }
|
||||
|
||||
// Rotate the point around given point about given angle (in degrees)
|
||||
// shifts the result so that point of rotation is in the middle of the tower
|
||||
xy rotate(const xy& origin, float width, float depth, float angle) const {
|
||||
xy out(0,0);
|
||||
float temp_x = x - width / 2.f;
|
||||
float temp_y = y - depth / 2.f;
|
||||
angle *= M_PI/180.;
|
||||
out.x += (temp_x - origin.x) * cos(angle) - (temp_y - origin.y) * sin(angle);
|
||||
out.y += (temp_x - origin.x) * sin(angle) + (temp_y - origin.y) * cos(angle);
|
||||
return out + origin;
|
||||
}
|
||||
|
||||
float x;
|
||||
float y;
|
||||
};
|
||||
|
@ -112,17 +126,15 @@ public:
|
|||
const std::vector<unsigned int> &tools,
|
||||
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
|
||||
// If false, the last priming are will be large enough to wipe the last extruder sufficiently.
|
||||
bool last_wipe_inside_wipe_tower,
|
||||
// May be used by a stand alone post processor.
|
||||
Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0;
|
||||
bool last_wipe_inside_wipe_tower) = 0;
|
||||
|
||||
// Returns gcode for toolchange and the end position.
|
||||
// if new_tool == -1, just unload the current filament over the wipe tower.
|
||||
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer, Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0;
|
||||
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer) = 0;
|
||||
|
||||
// Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag.
|
||||
// Call this method only if layer_finished() is false.
|
||||
virtual ToolChangeResult finish_layer(Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) = 0;
|
||||
virtual ToolChangeResult finish_layer() = 0;
|
||||
|
||||
// Is the current layer finished? A layer is finished if either the wipe tower is finished, or
|
||||
// the wipe tower has been completely covered by the tool change extrusions,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,13 +1,14 @@
|
|||
#ifndef WipeTowerPrusaMM_hpp_
|
||||
#define WipeTowerPrusaMM_hpp_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include "WipeTower.hpp"
|
||||
|
||||
|
||||
namespace Slic3r
|
||||
{
|
||||
|
||||
|
@ -15,6 +16,8 @@ namespace PrusaMultiMaterial {
|
|||
class Writer;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class WipeTowerPrusaMM : public WipeTower
|
||||
{
|
||||
public:
|
||||
|
@ -39,65 +42,98 @@ public:
|
|||
// y -- y coordinates of wipe tower in mm ( left bottom corner )
|
||||
// width -- width of wipe tower in mm ( default 60 mm - leave as it is )
|
||||
// wipe_area -- space available for one toolchange in mm
|
||||
WipeTowerPrusaMM(float x, float y, float width, float wipe_area, unsigned int initial_tool) :
|
||||
WipeTowerPrusaMM(float x, float y, float width, float rotation_angle, float cooling_tube_retraction,
|
||||
float cooling_tube_length, float parking_pos_retraction, float bridging, const std::vector<float>& wiping_matrix,
|
||||
unsigned int initial_tool) :
|
||||
m_wipe_tower_pos(x, y),
|
||||
m_wipe_tower_width(width),
|
||||
m_wipe_area(wipe_area),
|
||||
m_wipe_tower_rotation_angle(rotation_angle),
|
||||
m_y_shift(0.f),
|
||||
m_z_pos(0.f),
|
||||
m_current_tool(initial_tool)
|
||||
m_is_first_layer(false),
|
||||
m_cooling_tube_retraction(cooling_tube_retraction),
|
||||
m_cooling_tube_length(cooling_tube_length),
|
||||
m_parking_pos_retraction(parking_pos_retraction),
|
||||
m_bridging(bridging),
|
||||
m_current_tool(initial_tool)
|
||||
{
|
||||
for (size_t i = 0; i < 4; ++ i) {
|
||||
// Extruder specific parameters.
|
||||
m_material[i] = PLA;
|
||||
m_temperature[i] = 0;
|
||||
m_first_layer_temperature[i] = 0;
|
||||
}
|
||||
unsigned int number_of_extruders = (unsigned int)(sqrt(wiping_matrix.size())+WT_EPSILON);
|
||||
for (unsigned int i = 0; i<number_of_extruders; ++i)
|
||||
wipe_volumes.push_back(std::vector<float>(wiping_matrix.begin()+i*number_of_extruders,wiping_matrix.begin()+(i+1)*number_of_extruders));
|
||||
}
|
||||
|
||||
virtual ~WipeTowerPrusaMM() {}
|
||||
|
||||
// _retract - retract value in mm
|
||||
void set_retract(float retract) { m_retract = retract; }
|
||||
|
||||
// _zHop - z hop value in mm
|
||||
void set_zhop(float zhop) { m_zhop = zhop; }
|
||||
|
||||
// Set the extruder properties.
|
||||
void set_extruder(size_t idx, material_type material, int temp, int first_layer_temp)
|
||||
void set_extruder(size_t idx, material_type material, int temp, int first_layer_temp, float loading_speed,
|
||||
float unloading_speed, float delay, float cooling_time, std::string ramming_parameters, float nozzle_diameter)
|
||||
{
|
||||
m_material[idx] = material;
|
||||
m_temperature[idx] = temp;
|
||||
m_first_layer_temperature[idx] = first_layer_temp;
|
||||
//while (m_filpar.size() < idx+1) // makes sure the required element is in the vector
|
||||
m_filpar.push_back(FilamentParameters());
|
||||
|
||||
m_filpar[idx].material = material;
|
||||
m_filpar[idx].temperature = temp;
|
||||
m_filpar[idx].first_layer_temperature = first_layer_temp;
|
||||
m_filpar[idx].loading_speed = loading_speed;
|
||||
m_filpar[idx].unloading_speed = unloading_speed;
|
||||
m_filpar[idx].delay = delay;
|
||||
m_filpar[idx].cooling_time = cooling_time;
|
||||
m_filpar[idx].nozzle_diameter = nozzle_diameter; // to be used in future with (non-single) multiextruder MM
|
||||
|
||||
m_perimeter_width = nozzle_diameter * Width_To_Nozzle_Ratio; // all extruders are now assumed to have the same diameter
|
||||
|
||||
std::stringstream stream{ramming_parameters};
|
||||
float speed = 0.f;
|
||||
stream >> m_filpar[idx].ramming_line_width_multiplicator >> m_filpar[idx].ramming_step_multiplicator;
|
||||
m_filpar[idx].ramming_line_width_multiplicator /= 100;
|
||||
m_filpar[idx].ramming_step_multiplicator /= 100;
|
||||
while (stream >> speed)
|
||||
m_filpar[idx].ramming_speed.push_back(speed);
|
||||
}
|
||||
|
||||
|
||||
// Appends into internal structure m_plan containing info about the future wipe tower
|
||||
// to be used before building begins. The entries must be added ordered in z.
|
||||
void plan_toolchange(float z_par, float layer_height_par, unsigned int old_tool, unsigned int new_tool, bool brim);
|
||||
|
||||
// Iterates through prepared m_plan, generates ToolChangeResults and appends them to "result"
|
||||
void generate(std::vector<std::vector<WipeTower::ToolChangeResult>> &result);
|
||||
|
||||
|
||||
|
||||
// Switch to a next layer.
|
||||
virtual void set_layer(
|
||||
// Print height of this layer.
|
||||
float print_z,
|
||||
// Layer height, used to calculate extrusion the rate.
|
||||
float layer_height,
|
||||
float print_z,
|
||||
// Layer height, used to calculate extrusion the rate.
|
||||
float layer_height,
|
||||
// Maximum number of tool changes on this layer or the layers below.
|
||||
size_t max_tool_changes,
|
||||
size_t max_tool_changes,
|
||||
// Is this the first layer of the print? In that case print the brim first.
|
||||
bool is_first_layer,
|
||||
bool is_first_layer,
|
||||
// Is this the last layer of the waste tower?
|
||||
bool is_last_layer)
|
||||
bool is_last_layer)
|
||||
{
|
||||
m_z_pos = print_z;
|
||||
m_layer_height = layer_height;
|
||||
m_max_color_changes = max_tool_changes;
|
||||
m_is_first_layer = is_first_layer;
|
||||
m_is_last_layer = is_last_layer;
|
||||
// Start counting the color changes from zero. Special case: -1 - extrude a brim first.
|
||||
m_idx_tool_change_in_layer = is_first_layer ? (unsigned int)(-1) : 0;
|
||||
m_current_wipe_start_y = 0.f;
|
||||
m_print_brim = is_first_layer;
|
||||
m_depth_traversed = 0.f;
|
||||
m_current_shape = (! is_first_layer && m_current_shape == SHAPE_NORMAL) ? SHAPE_REVERSED : SHAPE_NORMAL;
|
||||
++ m_num_layer_changes;
|
||||
// Extrusion rate for an extrusion aka perimeter width 0.35mm.
|
||||
// Clamp the extrusion height to a 0.2mm layer height, independent of the nozzle diameter.
|
||||
// m_extrusion_flow = std::min(0.2f, layer_height) * 0.145f;
|
||||
// Use a strictly
|
||||
m_extrusion_flow = layer_height * 0.145f;
|
||||
if (is_first_layer) {
|
||||
this->m_num_layer_changes = 0;
|
||||
this->m_num_tool_changes = 0;
|
||||
}
|
||||
else
|
||||
++ m_num_layer_changes;
|
||||
|
||||
// Calculate extrusion flow from desired line width, nozzle diameter, filament diameter and layer_height:
|
||||
m_extrusion_flow = extrusion_flow(layer_height);
|
||||
|
||||
// Advance m_layer_info iterator, making sure we got it right
|
||||
while (!m_plan.empty() && m_layer_info->z < print_z - WT_EPSILON && m_layer_info+1 != m_plan.end())
|
||||
++m_layer_info;
|
||||
}
|
||||
|
||||
// Return the wipe tower position.
|
||||
|
@ -115,79 +151,114 @@ public:
|
|||
const std::vector<unsigned int> &tools,
|
||||
// If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower.
|
||||
// If false, the last priming are will be large enough to wipe the last extruder sufficiently.
|
||||
bool last_wipe_inside_wipe_tower,
|
||||
// May be used by a stand alone post processor.
|
||||
Purpose purpose = PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE);
|
||||
bool last_wipe_inside_wipe_tower);
|
||||
|
||||
// Returns gcode for a toolchange and a final print head position.
|
||||
// On the first layer, extrude a brim around the future wipe tower first.
|
||||
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer, Purpose purpose);
|
||||
virtual ToolChangeResult tool_change(unsigned int new_tool, bool last_in_layer);
|
||||
|
||||
// Close the current wipe tower layer with a perimeter and possibly fill the unfilled space with a zig-zag.
|
||||
// Fill the unfilled space with a sparse infill.
|
||||
// Call this method only if layer_finished() is false.
|
||||
virtual ToolChangeResult finish_layer(Purpose purpose);
|
||||
virtual ToolChangeResult finish_layer();
|
||||
|
||||
// Is the current layer finished?
|
||||
virtual bool layer_finished() const {
|
||||
return ( (m_is_first_layer ? m_wipe_tower_depth - m_perimeter_width : m_layer_info->depth) - WT_EPSILON < m_depth_traversed);
|
||||
}
|
||||
|
||||
// Is the current layer finished? A layer is finished if either the wipe tower is finished, or
|
||||
// the wipe tower has been completely covered by the tool change extrusions,
|
||||
// or the rest of the tower has been filled by a sparse infill with the finish_layer() method.
|
||||
virtual bool layer_finished() const
|
||||
{ return m_idx_tool_change_in_layer == m_max_color_changes; }
|
||||
|
||||
private:
|
||||
WipeTowerPrusaMM();
|
||||
|
||||
// A fill-in direction (positive Y, negative Y) alternates with each layer.
|
||||
enum wipe_shape
|
||||
enum wipe_shape // A fill-in direction
|
||||
{
|
||||
SHAPE_NORMAL = 1,
|
||||
SHAPE_NORMAL = 1,
|
||||
SHAPE_REVERSED = -1
|
||||
};
|
||||
|
||||
// Left front corner of the wipe tower in mm.
|
||||
xy m_wipe_tower_pos;
|
||||
// Width of the wipe tower.
|
||||
float m_wipe_tower_width;
|
||||
// Per color Y span.
|
||||
float m_wipe_area;
|
||||
// Current Z position.
|
||||
float m_z_pos = 0.f;
|
||||
// Current layer height.
|
||||
float m_layer_height = 0.f;
|
||||
// Maximum number of color changes per layer.
|
||||
size_t m_max_color_changes = 0;
|
||||
// Is this the 1st layer of the print? If so, print the brim around the waste tower.
|
||||
bool m_is_first_layer = false;
|
||||
// Is this the last layer of this waste tower?
|
||||
bool m_is_last_layer = false;
|
||||
|
||||
const bool m_peters_wipe_tower = false; // sparse wipe tower inspired by Peter's post processor - not finished yet
|
||||
const float Filament_Area = M_PI * 1.75f * 1.75f / 4.f; // filament area in mm^2
|
||||
const float Width_To_Nozzle_Ratio = 1.25f; // desired line width (oval) in multiples of nozzle diameter - may not be actually neccessary to adjust
|
||||
const float WT_EPSILON = 1e-3f;
|
||||
|
||||
|
||||
xy m_wipe_tower_pos; // Left front corner of the wipe tower in mm.
|
||||
float m_wipe_tower_width; // Width of the wipe tower.
|
||||
float m_wipe_tower_depth = 0.f; // Depth of the wipe tower
|
||||
float m_wipe_tower_rotation_angle = 0.f; // Wipe tower rotation angle in degrees (with respect to x axis)
|
||||
float m_y_shift = 0.f; // y shift passed to writer
|
||||
float m_z_pos = 0.f; // Current Z position.
|
||||
float m_layer_height = 0.f; // Current layer height.
|
||||
size_t m_max_color_changes = 0; // Maximum number of color changes per layer.
|
||||
bool m_is_first_layer = false;// Is this the 1st layer of the print? If so, print the brim around the waste tower.
|
||||
|
||||
// G-code generator parameters.
|
||||
float m_zhop = 0.5f;
|
||||
float m_retract = 4.f;
|
||||
// Width of an extrusion line, also a perimeter spacing for 100% infill.
|
||||
float m_perimeter_width = 0.5f;
|
||||
// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
|
||||
float m_extrusion_flow = 0.029f;
|
||||
float m_cooling_tube_retraction = 0.f;
|
||||
float m_cooling_tube_length = 0.f;
|
||||
float m_parking_pos_retraction = 0.f;
|
||||
float m_bridging = 0.f;
|
||||
bool m_adhesion = true;
|
||||
|
||||
float m_perimeter_width = 0.4 * Width_To_Nozzle_Ratio; // Width of an extrusion line, also a perimeter spacing for 100% infill.
|
||||
float m_extrusion_flow = 0.038; //0.029f;// Extrusion flow is derived from m_perimeter_width, layer height and filament diameter.
|
||||
|
||||
|
||||
struct FilamentParameters {
|
||||
material_type material = PLA;
|
||||
int temperature = 0;
|
||||
int first_layer_temperature = 0;
|
||||
float loading_speed = 0.f;
|
||||
float unloading_speed = 0.f;
|
||||
float delay = 0.f ;
|
||||
float cooling_time = 0.f;
|
||||
float ramming_line_width_multiplicator = 0.f;
|
||||
float ramming_step_multiplicator = 0.f;
|
||||
std::vector<float> ramming_speed;
|
||||
float nozzle_diameter;
|
||||
};
|
||||
|
||||
// Extruder specific parameters.
|
||||
material_type m_material[4];
|
||||
int m_temperature[4];
|
||||
int m_first_layer_temperature[4];
|
||||
std::vector<FilamentParameters> m_filpar;
|
||||
|
||||
// State of the wiper tower generator.
|
||||
// Layer change counter for the output statistics.
|
||||
unsigned int m_num_layer_changes = 0;
|
||||
// Tool change change counter for the output statistics.
|
||||
unsigned int m_num_tool_changes = 0;
|
||||
// Layer change counter in this layer. Counting up to m_max_color_changes.
|
||||
unsigned int m_idx_tool_change_in_layer = 0;
|
||||
|
||||
// State of the wipe tower generator.
|
||||
unsigned int m_num_layer_changes = 0; // Layer change counter for the output statistics.
|
||||
unsigned int m_num_tool_changes = 0; // Tool change change counter for the output statistics.
|
||||
///unsigned int m_idx_tool_change_in_layer = 0; // Layer change counter in this layer. Counting up to m_max_color_changes.
|
||||
bool m_print_brim = true;
|
||||
// A fill-in direction (positive Y, negative Y) alternates with each layer.
|
||||
wipe_shape m_current_shape = SHAPE_NORMAL;
|
||||
unsigned int m_current_tool = 0;
|
||||
// Current y position at the wipe tower.
|
||||
float m_current_wipe_start_y = 0.f;
|
||||
// How much to wipe the 1st extruder over the wipe tower at the 1st layer
|
||||
// after the wipe tower brim has been extruded?
|
||||
float m_initial_extra_wipe = 0.f;
|
||||
std::vector<std::vector<float>> wipe_volumes;
|
||||
|
||||
float m_depth_traversed = 0.f; // Current y position at the wipe tower.
|
||||
bool m_left_to_right = true;
|
||||
float m_extra_spacing = 1.f;
|
||||
|
||||
|
||||
// Calculates extrusion flow needed to produce required line width for given layer height
|
||||
float extrusion_flow(float layer_height = -1.f) const // negative layer_height - return current m_extrusion_flow
|
||||
{
|
||||
if ( layer_height < 0 )
|
||||
return m_extrusion_flow;
|
||||
return layer_height * ( m_perimeter_width - layer_height * (1-M_PI/4.f)) / Filament_Area;
|
||||
}
|
||||
|
||||
// Calculates length of extrusion line to extrude given volume
|
||||
float volume_to_length(float volume, float line_width, float layer_height) const {
|
||||
return volume / (layer_height * (line_width - layer_height * (1. - M_PI / 4.)));
|
||||
}
|
||||
|
||||
// Calculates depth for all layers and propagates them downwards
|
||||
void plan_tower();
|
||||
|
||||
// Goes through m_plan and recalculates depths and width of the WT to make it exactly square - experimental
|
||||
void make_wipe_tower_square();
|
||||
|
||||
// Goes through m_plan, calculates border and finish_layer extrusions and subtracts them from last wipe
|
||||
void save_on_last_wipe();
|
||||
|
||||
|
||||
struct box_coordinates
|
||||
{
|
||||
|
@ -216,14 +287,42 @@ private:
|
|||
}
|
||||
xy ld; // left down
|
||||
xy lu; // left upper
|
||||
xy ru; // right upper
|
||||
xy rd; // right lower
|
||||
xy ru; // right upper
|
||||
};
|
||||
|
||||
|
||||
// to store information about tool changes for a given layer
|
||||
struct WipeTowerInfo{
|
||||
struct ToolChange {
|
||||
unsigned int old_tool;
|
||||
unsigned int new_tool;
|
||||
float required_depth;
|
||||
float ramming_depth;
|
||||
float first_wipe_line;
|
||||
ToolChange(unsigned int old,unsigned int newtool,float depth=0.f,float ramming_depth=0.f,float fwl=0.f)
|
||||
: old_tool{old}, new_tool{newtool}, required_depth{depth}, ramming_depth{ramming_depth},first_wipe_line{fwl} {}
|
||||
};
|
||||
float z; // z position of the layer
|
||||
float height; // layer height
|
||||
float depth; // depth of the layer based on all layers above
|
||||
float extra_spacing;
|
||||
float toolchanges_depth() const { float sum = 0.f; for (const auto &a : tool_changes) sum += a.required_depth; return sum; }
|
||||
|
||||
std::vector<ToolChange> tool_changes;
|
||||
|
||||
WipeTowerInfo(float z_par, float layer_height_par)
|
||||
: z{z_par}, height{layer_height_par}, depth{0}, extra_spacing{1.f} {}
|
||||
};
|
||||
|
||||
std::vector<WipeTowerInfo> m_plan; // Stores information about all layers and toolchanges for the future wipe tower (filled by plan_toolchange(...))
|
||||
std::vector<WipeTowerInfo>::iterator m_layer_info = m_plan.end();
|
||||
|
||||
|
||||
// Returns gcode for wipe tower brim
|
||||
// sideOnly -- set to false -- experimental, draw brim on sides of wipe tower
|
||||
// sideOnly -- set to false -- experimental, draw brim on sides of wipe tower
|
||||
// offset -- set to 0 -- experimental, offset to replace brim in front / rear of wipe tower
|
||||
ToolChangeResult toolchange_Brim(Purpose purpose, bool sideOnly = false, float y_offset = 0.f);
|
||||
ToolChangeResult toolchange_Brim(bool sideOnly = false, float y_offset = 0.f);
|
||||
|
||||
void toolchange_Unload(
|
||||
PrusaMultiMaterial::Writer &writer,
|
||||
|
@ -243,11 +342,12 @@ private:
|
|||
void toolchange_Wipe(
|
||||
PrusaMultiMaterial::Writer &writer,
|
||||
const box_coordinates &cleaning_box,
|
||||
bool skip_initial_y_move);
|
||||
|
||||
void toolchange_Perimeter();
|
||||
float wipe_volume);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* WipeTowerPrusaMM_hpp_ */
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
unsigned int Model::s_auto_extruder_id = 1;
|
||||
|
||||
Model::Model(const Model &other)
|
||||
{
|
||||
// copy materials
|
||||
|
@ -405,10 +407,19 @@ void Model::convert_multipart_object()
|
|||
|
||||
ModelObject* object = new ModelObject(this);
|
||||
object->input_file = this->objects.front()->input_file;
|
||||
|
||||
|
||||
reset_auto_extruder_id();
|
||||
|
||||
for (const ModelObject* o : this->objects)
|
||||
for (const ModelVolume* v : o->volumes)
|
||||
object->add_volume(*v)->name = o->name;
|
||||
{
|
||||
ModelVolume* new_v = object->add_volume(*v);
|
||||
if (new_v != nullptr)
|
||||
{
|
||||
new_v->name = o->name;
|
||||
new_v->config.set_deserialize("extruder", get_auto_extruder_id_as_string());
|
||||
}
|
||||
}
|
||||
|
||||
for (const ModelInstance* i : this->objects.front()->instances)
|
||||
object->add_instance(*i);
|
||||
|
@ -466,6 +477,28 @@ bool Model::fits_print_volume(const FullPrintConfig &config) const
|
|||
return print_volume.contains(transformed_bounding_box());
|
||||
}
|
||||
|
||||
unsigned int Model::get_auto_extruder_id()
|
||||
{
|
||||
unsigned int id = s_auto_extruder_id;
|
||||
|
||||
if (++s_auto_extruder_id > 4)
|
||||
reset_auto_extruder_id();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string Model::get_auto_extruder_id_as_string()
|
||||
{
|
||||
char str_extruder[64];
|
||||
sprintf(str_extruder, "%ud", get_auto_extruder_id());
|
||||
return str_extruder;
|
||||
}
|
||||
|
||||
void Model::reset_auto_extruder_id()
|
||||
{
|
||||
s_auto_extruder_id = 1;
|
||||
}
|
||||
|
||||
ModelObject::ModelObject(Model *model, const ModelObject &other, bool copy_volumes) :
|
||||
name(other.name),
|
||||
input_file(other.input_file),
|
||||
|
@ -830,33 +863,8 @@ void ModelObject::cut(coordf_t z, Model* model) const
|
|||
lower->add_volume(*volume);
|
||||
} else {
|
||||
TriangleMesh upper_mesh, lower_mesh;
|
||||
// TODO: shouldn't we use object bounding box instead of per-volume bb?
|
||||
coordf_t cut_z = z + volume->mesh.bounding_box().min.z;
|
||||
if (false) {
|
||||
// if (volume->mesh.has_multiple_patches()) {
|
||||
// Cutting algorithm does not work on intersecting meshes.
|
||||
// As we are not sure whether the meshes don't intersect,
|
||||
// we rather split the mesh into multiple non-intersecting pieces.
|
||||
TriangleMeshPtrs meshptrs = volume->mesh.split();
|
||||
for (TriangleMeshPtrs::iterator mesh = meshptrs.begin(); mesh != meshptrs.end(); ++mesh) {
|
||||
printf("Cutting mesh patch %d of %d\n", int(mesh - meshptrs.begin()), int(meshptrs.size()));
|
||||
(*mesh)->repair();
|
||||
TriangleMeshSlicer tms(*mesh);
|
||||
if (mesh == meshptrs.begin()) {
|
||||
tms.cut(cut_z, &upper_mesh, &lower_mesh);
|
||||
} else {
|
||||
TriangleMesh upper_mesh_this, lower_mesh_this;
|
||||
tms.cut(cut_z, &upper_mesh_this, &lower_mesh_this);
|
||||
upper_mesh.merge(upper_mesh_this);
|
||||
lower_mesh.merge(lower_mesh_this);
|
||||
}
|
||||
delete *mesh;
|
||||
}
|
||||
} else {
|
||||
printf("Cutting mesh patch\n");
|
||||
TriangleMeshSlicer tms(&volume->mesh);
|
||||
tms.cut(cut_z, &upper_mesh, &lower_mesh);
|
||||
}
|
||||
TriangleMeshSlicer tms(&volume->mesh);
|
||||
tms.cut(z, &upper_mesh, &lower_mesh);
|
||||
|
||||
upper_mesh.repair();
|
||||
lower_mesh.repair();
|
||||
|
@ -995,6 +1003,9 @@ size_t ModelVolume::split()
|
|||
size_t idx = 0;
|
||||
size_t ivolume = std::find(this->object->volumes.begin(), this->object->volumes.end(), this) - this->object->volumes.begin();
|
||||
std::string name = this->name;
|
||||
|
||||
Model::reset_auto_extruder_id();
|
||||
|
||||
for (TriangleMesh *mesh : meshptrs) {
|
||||
mesh->repair();
|
||||
if (idx == 0)
|
||||
|
@ -1004,6 +1015,7 @@ size_t ModelVolume::split()
|
|||
char str_idx[64];
|
||||
sprintf(str_idx, "_%d", idx + 1);
|
||||
this->object->volumes[ivolume]->name = name + str_idx;
|
||||
this->object->volumes[ivolume]->config.set_deserialize("extruder", Model::get_auto_extruder_id_as_string());
|
||||
delete mesh;
|
||||
++ idx;
|
||||
}
|
||||
|
|
|
@ -230,6 +230,8 @@ private:
|
|||
// all objects may share mutliple materials.
|
||||
class Model
|
||||
{
|
||||
static unsigned int s_auto_extruder_id;
|
||||
|
||||
public:
|
||||
// Materials are owned by a model and referenced by objects through t_model_material_id.
|
||||
// Single material may be shared by multiple models.
|
||||
|
@ -288,6 +290,10 @@ public:
|
|||
bool fits_print_volume(const FullPrintConfig &config) const;
|
||||
|
||||
void print_info() const { for (const ModelObject *o : this->objects) o->print_info(); }
|
||||
|
||||
static unsigned int get_auto_extruder_id();
|
||||
static std::string get_auto_extruder_id_as_string();
|
||||
static void reset_auto_extruder_id();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -183,6 +183,11 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
|| opt_key == "filament_type"
|
||||
|| opt_key == "filament_soluble"
|
||||
|| opt_key == "first_layer_temperature"
|
||||
|| opt_key == "filament_loading_speed"
|
||||
|| opt_key == "filament_unloading_speed"
|
||||
|| opt_key == "filament_toolchange_delay"
|
||||
|| opt_key == "filament_cooling_time"
|
||||
|| opt_key == "filament_ramming_parameters"
|
||||
|| opt_key == "gcode_flavor"
|
||||
|| opt_key == "single_extruder_multi_material"
|
||||
|| opt_key == "spiral_vase"
|
||||
|
@ -191,7 +196,12 @@ bool Print::invalidate_state_by_config_options(const std::vector<t_config_option
|
|||
|| opt_key == "wipe_tower_x"
|
||||
|| opt_key == "wipe_tower_y"
|
||||
|| opt_key == "wipe_tower_width"
|
||||
|| opt_key == "wipe_tower_per_color_wipe"
|
||||
|| opt_key == "wipe_tower_rotation_angle"
|
||||
|| opt_key == "wipe_tower_bridging"
|
||||
|| opt_key == "wiping_volumes_matrix"
|
||||
|| opt_key == "parking_pos_retraction"
|
||||
|| opt_key == "cooling_tube_retraction"
|
||||
|| opt_key == "cooling_tube_length"
|
||||
|| opt_key == "z_offset") {
|
||||
steps.emplace_back(psWipeTower);
|
||||
} else if (
|
||||
|
@ -571,6 +581,12 @@ std::string Print::validate() const
|
|||
return "The Spiral Vase option can only be used when printing single material objects.";
|
||||
}
|
||||
|
||||
if (this->config.single_extruder_multi_material) {
|
||||
for (size_t i=1; i<this->config.nozzle_diameter.values.size(); ++i)
|
||||
if (this->config.nozzle_diameter.values[i] != this->config.nozzle_diameter.values[i-1])
|
||||
return "All extruders must have the same diameter for single extruder multimaterial printer.";
|
||||
}
|
||||
|
||||
if (this->has_wipe_tower() && ! this->objects.empty()) {
|
||||
#if 0
|
||||
for (auto dmr : this->config.nozzle_diameter.values)
|
||||
|
@ -582,6 +598,12 @@ std::string Print::validate() const
|
|||
if (! this->config.use_relative_e_distances)
|
||||
return "The Wipe Tower is currently only supported with the relative extruder addressing (use_relative_e_distances=1).";
|
||||
SlicingParameters slicing_params0 = this->objects.front()->slicing_parameters();
|
||||
|
||||
const PrintObject* most_layered_object = this->objects.front(); // object with highest layer_height_profile.size() encountered so far
|
||||
for (const auto* object : objects)
|
||||
if (object->layer_height_profile.size() > most_layered_object->layer_height_profile.size())
|
||||
most_layered_object = object;
|
||||
|
||||
for (PrintObject *object : this->objects) {
|
||||
SlicingParameters slicing_params = object->slicing_parameters();
|
||||
if (std::abs(slicing_params.first_print_layer_height - slicing_params0.first_print_layer_height) > EPSILON ||
|
||||
|
@ -596,10 +618,24 @@ std::string Print::validate() const
|
|||
bool was_layer_height_profile_valid = object->layer_height_profile_valid;
|
||||
object->update_layer_height_profile();
|
||||
object->layer_height_profile_valid = was_layer_height_profile_valid;
|
||||
for (size_t i = 5; i < object->layer_height_profile.size(); i += 2)
|
||||
|
||||
if ( this->config.variable_layer_height ) {
|
||||
int i = 0;
|
||||
while ( i < object->layer_height_profile.size() ) {
|
||||
if (std::abs(most_layered_object->layer_height_profile[i] - object->layer_height_profile[i]) > EPSILON)
|
||||
return "The Wipe tower is only supported if all objects have the same layer height profile";
|
||||
++i;
|
||||
if (i == object->layer_height_profile.size()-2) // this element contains the objects max z, if the other object is taller,
|
||||
// it does not have to match - we will step over it
|
||||
if (most_layered_object->layer_height_profile[i] > object->layer_height_profile[i])
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
/*for (size_t i = 5; i < object->layer_height_profile.size(); i += 2)
|
||||
if (object->layer_height_profile[i-1] > slicing_params.object_print_z_min + EPSILON &&
|
||||
std::abs(object->layer_height_profile[i] - object->config.layer_height) > EPSILON)
|
||||
return "The Wipe Tower is currently only supported with constant Z layer spacing. Layer editing is not allowed.";
|
||||
return "The Wipe Tower is currently only supported with constant Z layer spacing. Layer editing is not allowed.";*/
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -613,7 +649,12 @@ std::string Print::validate() const
|
|||
for (unsigned int extruder_id : extruders)
|
||||
nozzle_diameters.push_back(this->config.nozzle_diameter.get_at(extruder_id));
|
||||
double min_nozzle_diameter = *std::min_element(nozzle_diameters.begin(), nozzle_diameters.end());
|
||||
|
||||
|
||||
unsigned int total_extruders_count = this->config.nozzle_diameter.size();
|
||||
for (const auto& extruder_idx : extruders)
|
||||
if ( extruder_idx >= total_extruders_count )
|
||||
return "One or more object were assigned an extruder that the printer does not have.";
|
||||
|
||||
for (PrintObject *object : this->objects) {
|
||||
if ((object->config.support_material_extruder == -1 || object->config.support_material_interface_extruder == -1) &&
|
||||
(object->config.raft_layers > 0 || object->config.support_material.value)) {
|
||||
|
@ -1026,22 +1067,33 @@ void Print::_make_wipe_tower()
|
|||
}
|
||||
}
|
||||
|
||||
// Get wiping matrix to get number of extruders and convert vector<double> to vector<float>:
|
||||
std::vector<float> wiping_volumes((this->config.wiping_volumes_matrix.values).begin(),(this->config.wiping_volumes_matrix.values).end());
|
||||
|
||||
// Initialize the wipe tower.
|
||||
WipeTowerPrusaMM wipe_tower(
|
||||
float(this->config.wipe_tower_x.value), float(this->config.wipe_tower_y.value),
|
||||
float(this->config.wipe_tower_width.value), float(this->config.wipe_tower_per_color_wipe.value),
|
||||
m_tool_ordering.first_extruder());
|
||||
|
||||
float(this->config.wipe_tower_width.value),
|
||||
float(this->config.wipe_tower_rotation_angle.value), float(this->config.cooling_tube_retraction.value),
|
||||
float(this->config.cooling_tube_length.value), float(this->config.parking_pos_retraction.value),
|
||||
float(this->config.wipe_tower_bridging), wiping_volumes, m_tool_ordering.first_extruder());
|
||||
|
||||
//wipe_tower.set_retract();
|
||||
//wipe_tower.set_zhop();
|
||||
|
||||
// Set the extruder & material properties at the wipe tower object.
|
||||
for (size_t i = 0; i < 4; ++ i)
|
||||
for (size_t i = 0; i < (int)(sqrt(wiping_volumes.size())+EPSILON); ++ i)
|
||||
wipe_tower.set_extruder(
|
||||
i,
|
||||
WipeTowerPrusaMM::parse_material(this->config.filament_type.get_at(i).c_str()),
|
||||
this->config.temperature.get_at(i),
|
||||
this->config.first_layer_temperature.get_at(i));
|
||||
this->config.first_layer_temperature.get_at(i),
|
||||
this->config.filament_loading_speed.get_at(i),
|
||||
this->config.filament_unloading_speed.get_at(i),
|
||||
this->config.filament_toolchange_delay.get_at(i),
|
||||
this->config.filament_cooling_time.get_at(i),
|
||||
this->config.filament_ramming_parameters.get_at(i),
|
||||
this->config.nozzle_diameter.get_at(i));
|
||||
|
||||
// When printing the first layer's wipe tower, the first extruder is expected to be active and primed.
|
||||
// Therefore the number of wipe sections at the wipe tower will be (m_tool_ordering.front().extruders-1) at the 1st layer.
|
||||
|
@ -1049,12 +1101,37 @@ void Print::_make_wipe_tower()
|
|||
bool last_priming_wipe_full = m_tool_ordering.front().extruders.size() > m_tool_ordering.front().wipe_tower_partitions;
|
||||
|
||||
m_wipe_tower_priming = Slic3r::make_unique<WipeTower::ToolChangeResult>(
|
||||
wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), ! last_priming_wipe_full, WipeTower::PURPOSE_EXTRUDE));
|
||||
wipe_tower.prime(this->skirt_first_layer_height(), m_tool_ordering.all_extruders(), ! last_priming_wipe_full));
|
||||
|
||||
|
||||
// Lets go through the wipe tower layers and determine pairs of extruder changes for each
|
||||
// to pass to wipe_tower (so that it can use it for planning the layout of the tower)
|
||||
{
|
||||
unsigned int current_extruder_id = m_tool_ordering.all_extruders().back();
|
||||
for (const auto &layer_tools : m_tool_ordering.layer_tools()) { // for all layers
|
||||
if (!layer_tools.has_wipe_tower) continue;
|
||||
bool first_layer = &layer_tools == &m_tool_ordering.front();
|
||||
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, current_extruder_id,false);
|
||||
for (const auto extruder_id : layer_tools.extruders) {
|
||||
if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) || extruder_id != current_extruder_id) {
|
||||
wipe_tower.plan_toolchange(layer_tools.print_z, layer_tools.wipe_tower_layer_height, current_extruder_id, extruder_id, first_layer && extruder_id == m_tool_ordering.all_extruders().back());
|
||||
current_extruder_id = extruder_id;
|
||||
}
|
||||
}
|
||||
if (&layer_tools == &m_tool_ordering.back() || (&layer_tools + 1)->wipe_tower_partitions == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Generate the wipe tower layers.
|
||||
m_wipe_tower_tool_changes.reserve(m_tool_ordering.layer_tools().size());
|
||||
wipe_tower.generate(m_wipe_tower_tool_changes);
|
||||
|
||||
// Set current_extruder_id to the last extruder primed.
|
||||
unsigned int current_extruder_id = m_tool_ordering.all_extruders().back();
|
||||
/*unsigned int current_extruder_id = m_tool_ordering.all_extruders().back();
|
||||
|
||||
for (const ToolOrdering::LayerTools &layer_tools : m_tool_ordering.layer_tools()) {
|
||||
if (! layer_tools.has_wipe_tower)
|
||||
// This is a support only layer, or the wipe tower does not reach to this height.
|
||||
|
@ -1098,7 +1175,7 @@ void Print::_make_wipe_tower()
|
|||
m_wipe_tower_tool_changes.emplace_back(std::move(tool_changes));
|
||||
if (last_layer)
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
// Unload the current filament over the purge tower.
|
||||
coordf_t layer_height = this->objects.front()->config.layer_height.value;
|
||||
|
@ -1117,7 +1194,7 @@ void Print::_make_wipe_tower()
|
|||
wipe_tower.set_layer(float(m_tool_ordering.back().print_z), float(layer_height), 0, false, true);
|
||||
}
|
||||
m_wipe_tower_final_purge = Slic3r::make_unique<WipeTower::ToolChangeResult>(
|
||||
wipe_tower.tool_change((unsigned int)-1, false, WipeTower::PURPOSE_EXTRUDE));
|
||||
wipe_tower.tool_change((unsigned int)-1, false));
|
||||
}
|
||||
|
||||
std::string Print::output_filename()
|
||||
|
|
|
@ -166,6 +166,22 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->cli = "cooling!";
|
||||
def->default_value = new ConfigOptionBools { true };
|
||||
|
||||
def = this->add("cooling_tube_retraction", coFloat);
|
||||
def->label = L("Cooling tube position");
|
||||
def->tooltip = L("Distance of the center-point of the cooling tube from the extruder tip ");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "cooling_tube_retraction=f";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(91.5f);
|
||||
|
||||
def = this->add("cooling_tube_length", coFloat);
|
||||
def->label = L("Cooling tube length");
|
||||
def->tooltip = L("Length of the cooling tube to limit space for cooling moves inside it ");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "cooling_tube_length=f";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(5.f);
|
||||
|
||||
def = this->add("default_acceleration", coFloat);
|
||||
def->label = L("Default");
|
||||
def->tooltip = L("This is the acceleration your printer will be reset to after "
|
||||
|
@ -439,6 +455,49 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 0. };
|
||||
|
||||
def = this->add("filament_loading_speed", coFloats);
|
||||
def->label = L("Loading speed");
|
||||
def->tooltip = L("Speed used for loading the filament on the wipe tower. ");
|
||||
def->sidetext = L("mm/s");
|
||||
def->cli = "filament-loading-speed=f@";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 28. };
|
||||
|
||||
def = this->add("filament_unloading_speed", coFloats);
|
||||
def->label = L("Unloading speed");
|
||||
def->tooltip = L("Speed used for unloading the filament on the wipe tower (does not affect "
|
||||
" initial part of unloading just after ramming). ");
|
||||
def->sidetext = L("mm/s");
|
||||
def->cli = "filament-unloading-speed=f@";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 90. };
|
||||
|
||||
def = this->add("filament_toolchange_delay", coFloats);
|
||||
def->label = L("Delay after unloading");
|
||||
def->tooltip = L("Time to wait after the filament is unloaded. "
|
||||
"May help to get reliable toolchanges with flexible materials "
|
||||
"that may need more time to shrink to original dimensions. ");
|
||||
def->sidetext = L("s");
|
||||
def->cli = "filament-toolchange-delay=f@";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 0. };
|
||||
|
||||
def = this->add("filament_cooling_time", coFloats);
|
||||
def->label = L("Cooling time");
|
||||
def->tooltip = L("The filament is slowly moved back and forth after retraction into the cooling tube "
|
||||
"for this amount of time.");
|
||||
def->cli = "filament_cooling_time=i@";
|
||||
def->sidetext = L("s");
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloats { 14.f };
|
||||
|
||||
def = this->add("filament_ramming_parameters", coStrings);
|
||||
def->label = L("Ramming parameters");
|
||||
def->tooltip = L("This string is edited by RammingDialog and contains ramming specific parameters ");
|
||||
def->cli = "filament-ramming-parameters=s@";
|
||||
def->default_value = new ConfigOptionStrings { "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0|"
|
||||
" 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6" };
|
||||
|
||||
def = this->add("filament_diameter", coFloats);
|
||||
def->label = L("Diameter");
|
||||
def->tooltip = L("Enter your filament diameter here. Good precision is required, so use a caliper "
|
||||
|
@ -977,6 +1036,15 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->cli = "overhangs!";
|
||||
def->default_value = new ConfigOptionBool(true);
|
||||
|
||||
def = this->add("parking_pos_retraction", coFloat);
|
||||
def->label = L("Filament parking position");
|
||||
def->tooltip = L("Distance of the extruder tip from the position where the filament is parked "
|
||||
"when unloaded. This should match the value in printer firmware. ");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "parking_pos_retraction=f";
|
||||
def->min = 0;
|
||||
def->default_value = new ConfigOptionFloat(92.f);
|
||||
|
||||
def = this->add("perimeter_acceleration", coFloat);
|
||||
def->label = L("Perimeters");
|
||||
def->tooltip = L("This is the acceleration your printer will use for perimeters. "
|
||||
|
@ -1744,6 +1812,25 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->cli = "wipe-tower!";
|
||||
def->default_value = new ConfigOptionBool(false);
|
||||
|
||||
def = this->add("wiping_volumes_extruders", coFloats);
|
||||
def->label = L("Purging volumes - load/unload volumes");
|
||||
def->tooltip = L("This vector saves required volumes to change from/to each tool used on the "
|
||||
"wipe tower. These values are used to simplify creation of the full purging "
|
||||
"volumes below. ");
|
||||
def->cli = "wiping-volumes-extruders=f@";
|
||||
def->default_value = new ConfigOptionFloats { 70.f, 70.f, 70.f, 70.f, 70.f, 70.f, 70.f, 70.f, 70.f, 70.f };
|
||||
|
||||
def = this->add("wiping_volumes_matrix", coFloats);
|
||||
def->label = L("Purging volumes - matrix");
|
||||
def->tooltip = L("This matrix describes volumes (in cubic milimetres) required to purge the"
|
||||
" new filament on the wipe tower for any given pair of tools. ");
|
||||
def->cli = "wiping-volumes-matrix=f@";
|
||||
def->default_value = new ConfigOptionFloats { 0.f, 140.f, 140.f, 140.f, 140.f,
|
||||
140.f, 0.f, 140.f, 140.f, 140.f,
|
||||
140.f, 140.f, 0.f, 140.f, 140.f,
|
||||
140.f, 140.f, 140.f, 0.f, 140.f,
|
||||
140.f, 140.f, 140.f, 140.f, 0.f };
|
||||
|
||||
def = this->add("wipe_tower_x", coFloat);
|
||||
def->label = L("Position X");
|
||||
def->tooltip = L("X coordinate of the left front corner of a wipe tower");
|
||||
|
@ -1765,14 +1852,19 @@ PrintConfigDef::PrintConfigDef()
|
|||
def->cli = "wipe-tower-width=f";
|
||||
def->default_value = new ConfigOptionFloat(60.);
|
||||
|
||||
def = this->add("wipe_tower_per_color_wipe", coFloat);
|
||||
def->label = L("Per color change depth");
|
||||
def->tooltip = L("Depth of a wipe color per color change. For N colors, there will be "
|
||||
"maximum (N-1) tool switches performed, therefore the total depth "
|
||||
"of the wipe tower will be (N-1) times this value.");
|
||||
def = this->add("wipe_tower_rotation_angle", coFloat);
|
||||
def->label = L("Wipe tower rotation angle");
|
||||
def->tooltip = L("Wipe tower rotation angle with respect to x-axis ");
|
||||
def->sidetext = L("degrees");
|
||||
def->cli = "wipe-tower-rotation-angle=f";
|
||||
def->default_value = new ConfigOptionFloat(0.);
|
||||
|
||||
def = this->add("wipe_tower_bridging", coFloat);
|
||||
def->label = L("Maximal bridging distance");
|
||||
def->tooltip = L("Maximal distance between supports on sparse infill sections. ");
|
||||
def->sidetext = L("mm");
|
||||
def->cli = "wipe-tower-per-color-wipe=f";
|
||||
def->default_value = new ConfigOptionFloat(15.);
|
||||
def->cli = "wipe-tower-bridging=f";
|
||||
def->default_value = new ConfigOptionFloat(10.);
|
||||
|
||||
def = this->add("xy_size_compensation", coFloat);
|
||||
def->label = L("XY Size Compensation");
|
||||
|
@ -1852,8 +1944,9 @@ void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &va
|
|||
"standby_temperature", "scale", "rotate", "duplicate", "duplicate_grid",
|
||||
"start_perimeters_at_concave_points", "start_perimeters_at_non_overhang", "randomize_start",
|
||||
"seal_position", "vibration_limit", "bed_size", "octoprint_host",
|
||||
"print_center", "g0", "threads", "pressure_advance"
|
||||
"print_center", "g0", "threads", "pressure_advance", "wipe_tower_per_color_wipe"
|
||||
};
|
||||
|
||||
if (ignore.find(opt_key) != ignore.end()) {
|
||||
opt_key = "";
|
||||
return;
|
||||
|
|
|
@ -154,6 +154,13 @@ public:
|
|||
|
||||
// Validate the PrintConfig. Returns an empty string on success, otherwise an error message is returned.
|
||||
std::string validate();
|
||||
|
||||
// Verify whether the opt_key has not been obsoleted or renamed.
|
||||
// Both opt_key and value may be modified by handle_legacy().
|
||||
// If the opt_key is no more valid in this version of Slic3r, opt_key is cleared by handle_legacy().
|
||||
// handle_legacy() is called internally by set_deserialize().
|
||||
void handle_legacy(t_config_option_key &opt_key, std::string &value) const override
|
||||
{ PrintConfigDef::handle_legacy(opt_key, value); }
|
||||
};
|
||||
|
||||
template<typename CONFIG>
|
||||
|
@ -466,6 +473,11 @@ public:
|
|||
ConfigOptionBools filament_soluble;
|
||||
ConfigOptionFloats filament_cost;
|
||||
ConfigOptionFloats filament_max_volumetric_speed;
|
||||
ConfigOptionFloats filament_loading_speed;
|
||||
ConfigOptionFloats filament_unloading_speed;
|
||||
ConfigOptionFloats filament_toolchange_delay;
|
||||
ConfigOptionFloats filament_cooling_time;
|
||||
ConfigOptionStrings filament_ramming_parameters;
|
||||
ConfigOptionBool gcode_comments;
|
||||
ConfigOptionEnum<GCodeFlavor> gcode_flavor;
|
||||
ConfigOptionString layer_gcode;
|
||||
|
@ -491,7 +503,11 @@ public:
|
|||
ConfigOptionBool use_relative_e_distances;
|
||||
ConfigOptionBool use_volumetric_e;
|
||||
ConfigOptionBool variable_layer_height;
|
||||
|
||||
ConfigOptionFloat cooling_tube_retraction;
|
||||
ConfigOptionFloat cooling_tube_length;
|
||||
ConfigOptionFloat parking_pos_retraction;
|
||||
|
||||
|
||||
std::string get_extrusion_axis() const
|
||||
{
|
||||
return
|
||||
|
@ -515,6 +531,11 @@ protected:
|
|||
OPT_PTR(filament_soluble);
|
||||
OPT_PTR(filament_cost);
|
||||
OPT_PTR(filament_max_volumetric_speed);
|
||||
OPT_PTR(filament_loading_speed);
|
||||
OPT_PTR(filament_unloading_speed);
|
||||
OPT_PTR(filament_toolchange_delay);
|
||||
OPT_PTR(filament_cooling_time);
|
||||
OPT_PTR(filament_ramming_parameters);
|
||||
OPT_PTR(gcode_comments);
|
||||
OPT_PTR(gcode_flavor);
|
||||
OPT_PTR(layer_gcode);
|
||||
|
@ -540,6 +561,9 @@ protected:
|
|||
OPT_PTR(use_relative_e_distances);
|
||||
OPT_PTR(use_volumetric_e);
|
||||
OPT_PTR(variable_layer_height);
|
||||
OPT_PTR(cooling_tube_retraction);
|
||||
OPT_PTR(cooling_tube_length);
|
||||
OPT_PTR(parking_pos_retraction);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -610,6 +634,10 @@ public:
|
|||
ConfigOptionFloat wipe_tower_y;
|
||||
ConfigOptionFloat wipe_tower_width;
|
||||
ConfigOptionFloat wipe_tower_per_color_wipe;
|
||||
ConfigOptionFloat wipe_tower_rotation_angle;
|
||||
ConfigOptionFloat wipe_tower_bridging;
|
||||
ConfigOptionFloats wiping_volumes_matrix;
|
||||
ConfigOptionFloats wiping_volumes_extruders;
|
||||
ConfigOptionFloat z_offset;
|
||||
|
||||
protected:
|
||||
|
@ -675,6 +703,10 @@ protected:
|
|||
OPT_PTR(wipe_tower_y);
|
||||
OPT_PTR(wipe_tower_width);
|
||||
OPT_PTR(wipe_tower_per_color_wipe);
|
||||
OPT_PTR(wipe_tower_rotation_angle);
|
||||
OPT_PTR(wipe_tower_bridging);
|
||||
OPT_PTR(wiping_volumes_matrix);
|
||||
OPT_PTR(wiping_volumes_extruders);
|
||||
OPT_PTR(z_offset);
|
||||
}
|
||||
};
|
||||
|
@ -713,6 +745,7 @@ class FullPrintConfig :
|
|||
public:
|
||||
// Validate the FullPrintConfig. Returns an empty string on success, otherwise an error message is returned.
|
||||
std::string validate();
|
||||
|
||||
protected:
|
||||
// Protected constructor to be called to initialize ConfigCache::m_default.
|
||||
FullPrintConfig(int) : PrintObjectConfig(0), PrintRegionConfig(0), PrintConfig(0), HostConfig(0) {}
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace GUI {
|
|||
|
||||
class Bed_2D : public wxPanel
|
||||
{
|
||||
bool m_user_drawn_background = false;
|
||||
bool m_user_drawn_background = true;
|
||||
|
||||
bool m_painted = false;
|
||||
bool m_interactive = false;
|
||||
|
@ -26,7 +26,9 @@ public:
|
|||
{
|
||||
Create(parent, wxID_ANY, wxDefaultPosition, wxSize(250, -1), wxTAB_TRAVERSAL);
|
||||
// m_user_drawn_background = $^O ne 'darwin';
|
||||
m_user_drawn_background = true;
|
||||
#ifdef __APPLE__
|
||||
m_user_drawn_background = false;
|
||||
#endif /*__APPLE__*/
|
||||
Bind(wxEVT_PAINT, ([this](wxPaintEvent e) { repaint(); }));
|
||||
// EVT_ERASE_BACKGROUND($self, sub{}) if $self->{user_drawn_background};
|
||||
// Bind(EVT_MOUSE_EVENTS, ([this](wxMouseEvent event){/*mouse_event()*/; }));
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "../../libslic3r/GCode/PreviewData.hpp"
|
||||
#include "../../libslic3r/Print.hpp"
|
||||
#include "../../libslic3r/Slicing.hpp"
|
||||
#include "../../slic3r/GUI/PresetBundle.hpp"
|
||||
#include "GCode/Analyzer.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -304,7 +305,7 @@ void GLVolume::render_using_layer_height() const
|
|||
glUniform1f(z_texture_row_to_normalized_id, (GLfloat)(1.0f / layer_height_texture_height()));
|
||||
|
||||
if (z_cursor_id >= 0)
|
||||
glUniform1f(z_cursor_id, (GLfloat)(bounding_box.max.z * layer_height_texture_data.z_cursor_relative));
|
||||
glUniform1f(z_cursor_id, (GLfloat)(layer_height_texture_data.print_object->model_object()->bounding_box().max.z * layer_height_texture_data.z_cursor_relative));
|
||||
|
||||
if (z_cursor_band_width_id >= 0)
|
||||
glUniform1f(z_cursor_band_width_id, (GLfloat)layer_height_texture_data.edit_band_width);
|
||||
|
@ -326,6 +327,11 @@ void GLVolume::render_using_layer_height() const
|
|||
glUseProgram(current_program_id);
|
||||
}
|
||||
|
||||
double GLVolume::layer_height_texture_z_to_row_id() const
|
||||
{
|
||||
return (this->layer_height_texture.get() == nullptr) ? 0.0 : double(this->layer_height_texture->cells - 1) / (double(this->layer_height_texture->width) * this->layer_height_texture_data.print_object->model_object()->bounding_box().max.z);
|
||||
}
|
||||
|
||||
void GLVolume::generate_layer_height_texture(PrintObject *print_object, bool force)
|
||||
{
|
||||
GLTexture *tex = this->layer_height_texture.get();
|
||||
|
@ -381,6 +387,15 @@ std::vector<int> GLVolumeCollection::load_object(
|
|||
std::vector<int> volumes_idx;
|
||||
for (int volume_idx = 0; volume_idx < int(model_object->volumes.size()); ++ volume_idx) {
|
||||
const ModelVolume *model_volume = model_object->volumes[volume_idx];
|
||||
|
||||
int extruder_id = -1;
|
||||
if (!model_volume->modifier)
|
||||
{
|
||||
extruder_id = model_volume->config.has("extruder") ? model_volume->config.option("extruder")->getInt() : 0;
|
||||
if (extruder_id == 0)
|
||||
extruder_id = model_object->config.has("extruder") ? model_object->config.option("extruder")->getInt() : 0;
|
||||
}
|
||||
|
||||
for (int instance_idx : instance_idxs) {
|
||||
const ModelInstance *instance = model_object->instances[instance_idx];
|
||||
TriangleMesh mesh = model_volume->mesh;
|
||||
|
@ -410,8 +425,14 @@ std::vector<int> GLVolumeCollection::load_object(
|
|||
v.drag_group_id = obj_idx * 1000;
|
||||
else if (drag_by == "instance")
|
||||
v.drag_group_id = obj_idx * 1000 + instance_idx;
|
||||
if (! model_volume->modifier)
|
||||
|
||||
if (!model_volume->modifier)
|
||||
{
|
||||
v.layer_height_texture = layer_height_texture;
|
||||
if (extruder_id != -1)
|
||||
v.extruder_id = extruder_id;
|
||||
}
|
||||
v.is_modifier = model_volume->modifier;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -420,12 +441,17 @@ std::vector<int> GLVolumeCollection::load_object(
|
|||
|
||||
|
||||
int GLVolumeCollection::load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, bool use_VBOs)
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs)
|
||||
{
|
||||
float color[4] = { 1.0f, 1.0f, 0.0f, 0.5f };
|
||||
this->volumes.emplace_back(new GLVolume(color));
|
||||
GLVolume &v = *this->volumes.back();
|
||||
auto mesh = make_cube(width, depth, height);
|
||||
|
||||
auto mesh = make_cube(width, depth, height);
|
||||
mesh.translate(-width/2.f,-depth/2.f,0.f);
|
||||
Point origin_of_rotation(0.f,0.f);
|
||||
mesh.rotate(rotation_angle,&origin_of_rotation);
|
||||
|
||||
if (use_VBOs)
|
||||
v.indexed_vertex_array.load_mesh_full_shading(mesh);
|
||||
else
|
||||
|
@ -438,6 +464,7 @@ int GLVolumeCollection::load_wipe_tower_preview(
|
|||
v.composite_id = obj_idx * 1000000;
|
||||
v.select_group_id = obj_idx * 1000000;
|
||||
v.drag_group_id = obj_idx * 1000;
|
||||
v.is_wipe_tower = true;
|
||||
return int(this->volumes.size() - 1);
|
||||
}
|
||||
|
||||
|
@ -642,6 +669,83 @@ void GLVolumeCollection::update_outside_state(const DynamicPrintConfig* config,
|
|||
}
|
||||
}
|
||||
|
||||
void GLVolumeCollection::update_colors_by_extruder(const DynamicPrintConfig* config)
|
||||
{
|
||||
static const float inv_255 = 1.0f / 255.0f;
|
||||
|
||||
struct Color
|
||||
{
|
||||
std::string text;
|
||||
unsigned char rgb[3];
|
||||
|
||||
Color()
|
||||
: text("")
|
||||
{
|
||||
rgb[0] = 255;
|
||||
rgb[1] = 255;
|
||||
rgb[2] = 255;
|
||||
}
|
||||
|
||||
void set(const std::string& text, unsigned char* rgb)
|
||||
{
|
||||
this->text = text;
|
||||
::memcpy((void*)this->rgb, (const void*)rgb, 3 * sizeof(unsigned char));
|
||||
}
|
||||
};
|
||||
|
||||
if (config == nullptr)
|
||||
return;
|
||||
|
||||
const ConfigOptionStrings* extruders_opt = dynamic_cast<const ConfigOptionStrings*>(config->option("extruder_colour"));
|
||||
if (extruders_opt == nullptr)
|
||||
return;
|
||||
|
||||
const ConfigOptionStrings* filamemts_opt = dynamic_cast<const ConfigOptionStrings*>(config->option("filament_colour"));
|
||||
if (filamemts_opt == nullptr)
|
||||
return;
|
||||
|
||||
unsigned int colors_count = std::max((unsigned int)extruders_opt->values.size(), (unsigned int)filamemts_opt->values.size());
|
||||
if (colors_count == 0)
|
||||
return;
|
||||
|
||||
std::vector<Color> colors(colors_count);
|
||||
|
||||
unsigned char rgb[3];
|
||||
for (unsigned int i = 0; i < colors_count; ++i)
|
||||
{
|
||||
const std::string& txt_color = config->opt_string("extruder_colour", i);
|
||||
if (PresetBundle::parse_color(txt_color, rgb))
|
||||
{
|
||||
colors[i].set(txt_color, rgb);
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string& txt_color = config->opt_string("filament_colour", i);
|
||||
if (PresetBundle::parse_color(txt_color, rgb))
|
||||
colors[i].set(txt_color, rgb);
|
||||
}
|
||||
}
|
||||
|
||||
for (GLVolume* volume : volumes)
|
||||
{
|
||||
if ((volume == nullptr) || volume->is_modifier || volume->is_wipe_tower)
|
||||
continue;
|
||||
|
||||
int extruder_id = volume->extruder_id - 1;
|
||||
if ((extruder_id < 0) || ((unsigned int)colors.size() <= extruder_id))
|
||||
extruder_id = 0;
|
||||
|
||||
const Color& color = colors[extruder_id];
|
||||
if (!color.text.empty())
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
volume->color[i] = (float)color.rgb[i] * inv_255;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<double> GLVolumeCollection::get_current_print_zs() const
|
||||
{
|
||||
// Collect layer top positions of all volumes.
|
||||
|
@ -2594,8 +2698,10 @@ void _3DScene::_load_shells(const Print& print, GLVolumeCollection& volumes, boo
|
|||
coordf_t max_z = print.objects[0]->model_object()->get_model()->bounding_box().max.z;
|
||||
const PrintConfig& config = print.config;
|
||||
unsigned int extruders_count = config.nozzle_diameter.size();
|
||||
if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects)
|
||||
volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, config.wipe_tower_per_color_wipe * (extruders_count - 1), max_z, use_VBOs);
|
||||
if ((extruders_count > 1) && config.single_extruder_multi_material && config.wipe_tower && !config.complete_objects) {
|
||||
const float width_per_extruder = 15.f; // a simple workaround after wipe_tower_per_color_wipe got obsolete
|
||||
volumes.load_wipe_tower_preview(1000, config.wipe_tower_x, config.wipe_tower_y, config.wipe_tower_width, width_per_extruder * (extruders_count - 1), max_z, config.wipe_tower_rotation_angle, use_VBOs);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Slic3r
|
||||
|
|
|
@ -246,12 +246,15 @@ public:
|
|||
composite_id(-1),
|
||||
select_group_id(-1),
|
||||
drag_group_id(-1),
|
||||
extruder_id(0),
|
||||
selected(false),
|
||||
is_active(true),
|
||||
zoom_to_volumes(true),
|
||||
outside_printer_detection_enabled(true),
|
||||
is_outside(false),
|
||||
hover(false),
|
||||
is_modifier(false),
|
||||
is_wipe_tower(false),
|
||||
tverts_range(0, size_t(-1)),
|
||||
qverts_range(0, size_t(-1))
|
||||
{
|
||||
|
@ -271,7 +274,7 @@ public:
|
|||
const std::string &drag_by);
|
||||
|
||||
int load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, bool use_VBOs);
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs);
|
||||
|
||||
// Bounding box of this volume, in unscaled coordinates.
|
||||
BoundingBoxf3 bounding_box;
|
||||
|
@ -287,6 +290,8 @@ public:
|
|||
int select_group_id;
|
||||
// An ID for group dragging. It may be the same for all meshes of all object instances, or for just a single object instance.
|
||||
int drag_group_id;
|
||||
// An ID containing the extruder ID (used to select color).
|
||||
int extruder_id;
|
||||
// Is this object selected?
|
||||
bool selected;
|
||||
// Whether or not this volume is active for rendering
|
||||
|
@ -299,6 +304,10 @@ public:
|
|||
bool is_outside;
|
||||
// Boolean: Is mouse over this object?
|
||||
bool hover;
|
||||
// Wheter or not this volume has been generated from a modifier
|
||||
bool is_modifier;
|
||||
// Wheter or not this volume has been generated from the wipe tower
|
||||
bool is_wipe_tower;
|
||||
|
||||
// Interleaved triangles & normals with indexed triangles & quads.
|
||||
GLIndexedVertexArray indexed_vertex_array;
|
||||
|
@ -352,10 +361,7 @@ public:
|
|||
return (layer_height_texture.get() == nullptr) ? 0 :
|
||||
(void*)(layer_height_texture->data.data() + layer_height_texture->width * layer_height_texture->height * 4);
|
||||
}
|
||||
double layer_height_texture_z_to_row_id() const {
|
||||
return (this->layer_height_texture.get() == nullptr) ? 0. :
|
||||
double(this->layer_height_texture->cells - 1) / (double(this->layer_height_texture->width) * bounding_box.max.z);
|
||||
}
|
||||
double layer_height_texture_z_to_row_id() const;
|
||||
void generate_layer_height_texture(PrintObject *print_object, bool force);
|
||||
|
||||
void set_layer_height_texture_data(unsigned int texture_id, unsigned int shader_id, PrintObject* print_object, float z_cursor_relative, float edit_band_width)
|
||||
|
@ -392,7 +398,7 @@ public:
|
|||
bool use_VBOs);
|
||||
|
||||
int load_wipe_tower_preview(
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, bool use_VBOs);
|
||||
int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs);
|
||||
|
||||
// Render the volumes by OpenGL.
|
||||
void render_VBOs() const;
|
||||
|
@ -417,6 +423,7 @@ public:
|
|||
}
|
||||
|
||||
void update_outside_state(const DynamicPrintConfig* config, bool all_inside);
|
||||
void update_colors_by_extruder(const DynamicPrintConfig* config);
|
||||
|
||||
// Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection
|
||||
std::vector<double> get_current_print_zs() const;
|
||||
|
|
|
@ -34,7 +34,7 @@ void BedShapeDialog::build_dialog(ConfigOptionPoints* default_pt)
|
|||
|
||||
void BedShapePanel::build_panel(ConfigOptionPoints* default_pt)
|
||||
{
|
||||
// on_change(nullptr);
|
||||
// on_change(nullptr);
|
||||
|
||||
auto box = new wxStaticBox(this, wxID_ANY, _(L("Shape")));
|
||||
auto sbsizer = new wxStaticBoxSizer(box, wxVERTICAL);
|
||||
|
|
|
@ -1,5 +1,14 @@
|
|||
#include "BitmapCache.hpp"
|
||||
|
||||
#if ! defined(WIN32) && ! defined(__APPLE__)
|
||||
#define BROKEN_ALPHA
|
||||
#endif
|
||||
|
||||
#ifdef BROKEN_ALPHA
|
||||
#include <wx/mstream.h>
|
||||
#include <wx/rawbmp.h>
|
||||
#endif /* BROKEN_ALPHA */
|
||||
|
||||
namespace Slic3r { namespace GUI {
|
||||
|
||||
void BitmapCache::clear()
|
||||
|
@ -8,19 +17,31 @@ void BitmapCache::clear()
|
|||
delete bitmap.second;
|
||||
}
|
||||
|
||||
static wxBitmap wxImage_to_wxBitmap_with_alpha(wxImage &&image)
|
||||
{
|
||||
#ifdef BROKEN_ALPHA
|
||||
wxMemoryOutputStream stream;
|
||||
image.SaveFile(stream, wxBITMAP_TYPE_PNG);
|
||||
wxStreamBuffer *buf = stream.GetOutputStreamBuffer();
|
||||
return wxBitmap::NewFromPNGData(buf->GetBufferStart(), buf->GetBufferSize());
|
||||
#else
|
||||
return wxBitmap(std::move(image));
|
||||
#endif
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height)
|
||||
{
|
||||
wxBitmap *bitmap = nullptr;
|
||||
auto it = m_map.find(bitmap_key);
|
||||
if (it == m_map.end()) {
|
||||
bitmap = new wxBitmap(width, height);
|
||||
m_map[bitmap_key] = bitmap;
|
||||
} else {
|
||||
bitmap = it->second;
|
||||
if (bitmap->GetWidth() != width || bitmap->GetHeight() != height)
|
||||
bitmap->Create(width, height);
|
||||
}
|
||||
#if defined(__APPLE__) || defined(_MSC_VER)
|
||||
wxBitmap *bitmap = nullptr;
|
||||
auto it = m_map.find(bitmap_key);
|
||||
if (it == m_map.end()) {
|
||||
bitmap = new wxBitmap(width, height);
|
||||
m_map[bitmap_key] = bitmap;
|
||||
} else {
|
||||
bitmap = it->second;
|
||||
if (bitmap->GetWidth() != width || bitmap->GetHeight() != height)
|
||||
bitmap->Create(width, height);
|
||||
}
|
||||
#ifndef BROKEN_ALPHA
|
||||
bitmap->UseAlpha();
|
||||
#endif
|
||||
return bitmap;
|
||||
|
@ -28,77 +49,108 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_
|
|||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp)
|
||||
{
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth(), bmp.GetHeight());
|
||||
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
memDC.DrawBitmap(bmp, 0, 0, true);
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
return bitmap;
|
||||
wxBitmap *bitmap = nullptr;
|
||||
auto it = m_map.find(bitmap_key);
|
||||
if (it == m_map.end()) {
|
||||
bitmap = new wxBitmap(bmp);
|
||||
m_map[bitmap_key] = bitmap;
|
||||
} else {
|
||||
bitmap = it->second;
|
||||
*bitmap = bmp;
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp, const wxBitmap &bmp2)
|
||||
{
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth() + bmp2.GetWidth(), std::max(bmp.GetHeight(), bmp2.GetHeight()));
|
||||
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
if (bmp.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp, 0, 0, true);
|
||||
if (bmp2.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp2, bmp.GetWidth(), 0, true);
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
return bitmap;
|
||||
// Copying the wxBitmaps is cheap as the bitmap's content is reference counted.
|
||||
const wxBitmap bmps[2] = { bmp, bmp2 };
|
||||
return this->insert(bitmap_key, bmps, bmps + 2);
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3)
|
||||
{
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, bmp.GetWidth() + bmp2.GetWidth() + bmp3.GetWidth(), std::max(std::max(bmp.GetHeight(), bmp2.GetHeight()), bmp3.GetHeight()));
|
||||
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
if (bmp.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp, 0, 0, true);
|
||||
if (bmp2.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp2, bmp.GetWidth(), 0, true);
|
||||
if (bmp3.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp3, bmp.GetWidth() + bmp2.GetWidth(), 0, true);
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
|
||||
return bitmap;
|
||||
// Copying the wxBitmaps is cheap as the bitmap's content is reference counted.
|
||||
const wxBitmap bmps[3] = { bmp, bmp2, bmp3 };
|
||||
return this->insert(bitmap_key, bmps, bmps + 3);
|
||||
}
|
||||
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, std::vector<wxBitmap> &bmps)
|
||||
wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *begin, const wxBitmap *end)
|
||||
{
|
||||
size_t width = 0;
|
||||
size_t height = 0;
|
||||
for (wxBitmap &bmp : bmps) {
|
||||
width += bmp.GetWidth();
|
||||
height = std::max<size_t>(height, bmp.GetHeight());
|
||||
}
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, width, height);
|
||||
size_t width = 0;
|
||||
size_t height = 0;
|
||||
for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) {
|
||||
width += bmp->GetWidth();
|
||||
height = std::max<size_t>(height, bmp->GetHeight());
|
||||
}
|
||||
|
||||
#ifdef BROKEN_ALPHA
|
||||
|
||||
wxImage image(width, height);
|
||||
image.InitAlpha();
|
||||
// Fill in with a white color.
|
||||
memset(image.GetData(), 0x0ff, width * height * 3);
|
||||
// Fill in with full transparency.
|
||||
memset(image.GetAlpha(), 0, width * height);
|
||||
size_t x = 0;
|
||||
for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) {
|
||||
if (bmp->GetWidth() > 0) {
|
||||
if (bmp->GetDepth() == 32) {
|
||||
wxAlphaPixelData data(*const_cast<wxBitmap*>(bmp));
|
||||
data.UseAlpha();
|
||||
if (data) {
|
||||
for (int r = 0; r < bmp->GetHeight(); ++ r) {
|
||||
wxAlphaPixelData::Iterator src(data);
|
||||
src.Offset(data, 0, r);
|
||||
unsigned char *dst_pixels = image.GetData() + (x + r * width) * 3;
|
||||
unsigned char *dst_alpha = image.GetAlpha() + x + r * width;
|
||||
for (int c = 0; c < bmp->GetWidth(); ++ c, ++ src) {
|
||||
*dst_pixels ++ = src.Red();
|
||||
*dst_pixels ++ = src.Green();
|
||||
*dst_pixels ++ = src.Blue();
|
||||
*dst_alpha ++ = src.Alpha();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (bmp->GetDepth() == 24) {
|
||||
wxNativePixelData data(*const_cast<wxBitmap*>(bmp));
|
||||
if (data) {
|
||||
for (int r = 0; r < bmp->GetHeight(); ++ r) {
|
||||
wxNativePixelData::Iterator src(data);
|
||||
src.Offset(data, 0, r);
|
||||
unsigned char *dst_pixels = image.GetData() + (x + r * width) * 3;
|
||||
unsigned char *dst_alpha = image.GetAlpha() + x + r * width;
|
||||
for (int c = 0; c < bmp->GetWidth(); ++ c, ++ src) {
|
||||
*dst_pixels ++ = src.Red();
|
||||
*dst_pixels ++ = src.Green();
|
||||
*dst_pixels ++ = src.Blue();
|
||||
*dst_alpha ++ = wxALPHA_OPAQUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
x += bmp->GetWidth();
|
||||
}
|
||||
return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image)));
|
||||
|
||||
#else
|
||||
|
||||
wxBitmap *bitmap = this->insert(bitmap_key, width, height);
|
||||
wxMemoryDC memDC;
|
||||
memDC.SelectObject(*bitmap);
|
||||
memDC.SetBackground(*wxTRANSPARENT_BRUSH);
|
||||
memDC.Clear();
|
||||
size_t x = 0;
|
||||
for (wxBitmap &bmp : bmps) {
|
||||
if (bmp.GetWidth() > 0)
|
||||
memDC.DrawBitmap(bmp, x, 0, true);
|
||||
x += bmp.GetWidth();
|
||||
}
|
||||
for (const wxBitmap *bmp = begin; bmp != end; ++ bmp) {
|
||||
if (bmp->GetWidth() > 0)
|
||||
memDC.DrawBitmap(*bmp, x, 0, true);
|
||||
x += bmp->GetWidth();
|
||||
}
|
||||
memDC.SelectObject(wxNullBitmap);
|
||||
return bitmap;
|
||||
|
||||
return bitmap;
|
||||
#endif
|
||||
}
|
||||
|
||||
wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency)
|
||||
|
@ -113,7 +165,7 @@ wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsi
|
|||
*imgdata ++ = b;
|
||||
*imgalpha ++ = transparency;
|
||||
}
|
||||
return wxBitmap(std::move(image));
|
||||
return wxImage_to_wxBitmap_with_alpha(std::move(image));
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
|
|
|
@ -27,7 +27,8 @@ public:
|
|||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp);
|
||||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2);
|
||||
wxBitmap* insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3);
|
||||
wxBitmap* insert(const std::string &name, std::vector<wxBitmap> &bmps);
|
||||
wxBitmap* insert(const std::string &name, const std::vector<wxBitmap> &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); }
|
||||
wxBitmap* insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end);
|
||||
|
||||
static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency);
|
||||
static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); }
|
||||
|
|
|
@ -75,13 +75,13 @@ namespace Slic3r { namespace GUI {
|
|||
return tooltip_text;
|
||||
}
|
||||
|
||||
bool Field::is_matched(std::string string, std::string pattern)
|
||||
bool Field::is_matched(const std::string& string, const std::string& pattern)
|
||||
{
|
||||
std::regex regex_pattern(pattern, std::regex_constants::icase); // use ::icase to make the matching case insensitive like /i in perl
|
||||
return std::regex_match(string, regex_pattern);
|
||||
}
|
||||
|
||||
boost::any Field::get_value_by_opt_type(wxString str)
|
||||
boost::any Field::get_value_by_opt_type(wxString& str)
|
||||
{
|
||||
boost::any ret_val;
|
||||
switch (m_opt.type){
|
||||
|
@ -173,8 +173,7 @@ namespace Slic3r { namespace GUI {
|
|||
|
||||
temp->Bind(wxEVT_KILL_FOCUS, ([this, temp](wxEvent& e)
|
||||
{
|
||||
// on_kill_focus(e);
|
||||
e.Skip();
|
||||
e.Skip();// on_kill_focus(e);
|
||||
temp->GetToolTip()->Enable(true);
|
||||
}), temp->GetId());
|
||||
|
||||
|
@ -378,7 +377,7 @@ void Choice::set_selection()
|
|||
}
|
||||
}
|
||||
|
||||
void Choice::set_value(const std::string value, bool change_event) //! Redundant?
|
||||
void Choice::set_value(const std::string& value, bool change_event) //! Redundant?
|
||||
{
|
||||
m_disable_change_event = !change_event;
|
||||
|
||||
|
@ -397,7 +396,7 @@ void Choice::set_value(const std::string value, bool change_event) //! Redundan
|
|||
m_disable_change_event = false;
|
||||
}
|
||||
|
||||
void Choice::set_value(boost::any value, bool change_event)
|
||||
void Choice::set_value(const boost::any& value, bool change_event)
|
||||
{
|
||||
m_disable_change_event = !change_event;
|
||||
|
||||
|
@ -436,7 +435,7 @@ void Choice::set_value(boost::any value, bool change_event)
|
|||
}
|
||||
|
||||
//! it's needed for _update_serial_ports()
|
||||
void Choice::set_values(const std::vector<std::string> values)
|
||||
void Choice::set_values(const std::vector<std::string>& values)
|
||||
{
|
||||
if (values.empty())
|
||||
return;
|
||||
|
@ -555,7 +554,7 @@ void PointCtrl::BUILD()
|
|||
y_textctrl->SetToolTip(get_tooltip_text(X+", "+Y));
|
||||
}
|
||||
|
||||
void PointCtrl::set_value(const Pointf value, bool change_event)
|
||||
void PointCtrl::set_value(const Pointf& value, bool change_event)
|
||||
{
|
||||
m_disable_change_event = !change_event;
|
||||
|
||||
|
@ -567,10 +566,10 @@ void PointCtrl::set_value(const Pointf value, bool change_event)
|
|||
m_disable_change_event = false;
|
||||
}
|
||||
|
||||
void PointCtrl::set_value(boost::any value, bool change_event)
|
||||
void PointCtrl::set_value(const boost::any& value, bool change_event)
|
||||
{
|
||||
Pointf pt;
|
||||
Pointf *ptf = boost::any_cast<Pointf>(&value);
|
||||
const Pointf *ptf = boost::any_cast<Pointf>(&value);
|
||||
if (!ptf)
|
||||
{
|
||||
ConfigOptionPoints* pts = boost::any_cast<ConfigOptionPoints*>(value);
|
||||
|
@ -578,21 +577,6 @@ void PointCtrl::set_value(boost::any value, bool change_event)
|
|||
}
|
||||
else
|
||||
pt = *ptf;
|
||||
// try
|
||||
// {
|
||||
// pt = boost::any_cast<ConfigOptionPoints*>(value)->values.at(0);
|
||||
// }
|
||||
// catch (const std::exception &e)
|
||||
// {
|
||||
// try{
|
||||
// pt = boost::any_cast<Pointf>(value);
|
||||
// }
|
||||
// catch (const std::exception &e)
|
||||
// {
|
||||
// std::cerr << "Error! Can't cast PointCtrl value" << m_opt_id << "\n";
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
set_value(pt, change_event);
|
||||
}
|
||||
|
||||
|
|
|
@ -31,8 +31,8 @@ namespace Slic3r { namespace GUI {
|
|||
class Field;
|
||||
using t_field = std::unique_ptr<Field>;
|
||||
using t_kill_focus = std::function<void()>;
|
||||
using t_change = std::function<void(t_config_option_key, boost::any)>;
|
||||
using t_back_to_init = std::function<void(std::string)>;
|
||||
using t_change = std::function<void(t_config_option_key, const boost::any&)>;
|
||||
using t_back_to_init = std::function<void(const std::string&)>;
|
||||
|
||||
wxString double_to_string(double const value);
|
||||
|
||||
|
@ -81,7 +81,7 @@ public:
|
|||
/// Sets a value for this control.
|
||||
/// subclasses should overload with a specific version
|
||||
/// Postcondition: Method does not fire the on_change event.
|
||||
virtual void set_value(boost::any value, bool change_event) = 0;
|
||||
virtual void set_value(const boost::any& value, bool change_event) = 0;
|
||||
|
||||
/// Gets a boost::any representing this control.
|
||||
/// subclasses should overload with a specific version
|
||||
|
@ -100,7 +100,7 @@ public:
|
|||
virtual wxString get_tooltip_text(const wxString& default_string);
|
||||
|
||||
// set icon to "UndoToSystemValue" button according to an inheritance of preset
|
||||
void set_nonsys_btn_icon(const std::string& icon);
|
||||
void set_nonsys_btn_icon(const std::string& icon);
|
||||
|
||||
Field(const ConfigOptionDef& opt, const t_config_option_key& id) : m_opt(opt), m_opt_id(id) {};
|
||||
Field(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : m_parent(parent), m_opt(opt), m_opt_id(id) {};
|
||||
|
@ -109,8 +109,8 @@ public:
|
|||
virtual wxSizer* getSizer() { return nullptr; }
|
||||
virtual wxWindow* getWindow() { return nullptr; }
|
||||
|
||||
bool is_matched(std::string string, std::string pattern);
|
||||
boost::any get_value_by_opt_type(wxString str);
|
||||
bool is_matched(const std::string& string, const std::string& pattern);
|
||||
boost::any get_value_by_opt_type(wxString& str);
|
||||
|
||||
/// Factory method for generating new derived classes.
|
||||
template<class T>
|
||||
|
@ -137,16 +137,17 @@ class TextCtrl : public Field {
|
|||
public:
|
||||
TextCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
||||
TextCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
||||
~TextCtrl() {}
|
||||
|
||||
void BUILD();
|
||||
wxWindow* window {nullptr};
|
||||
|
||||
virtual void set_value(std::string value, bool change_event = false) {
|
||||
virtual void set_value(const std::string& value, bool change_event = false) {
|
||||
m_disable_change_event = !change_event;
|
||||
dynamic_cast<wxTextCtrl*>(window)->SetValue(wxString(value));
|
||||
m_disable_change_event = false;
|
||||
}
|
||||
virtual void set_value(boost::any value, bool change_event = false) {
|
||||
virtual void set_value(const boost::any& value, bool change_event = false) {
|
||||
m_disable_change_event = !change_event;
|
||||
dynamic_cast<wxTextCtrl*>(window)->SetValue(boost::any_cast<wxString>(value));
|
||||
m_disable_change_event = false;
|
||||
|
@ -164,6 +165,7 @@ class CheckBox : public Field {
|
|||
public:
|
||||
CheckBox(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
||||
CheckBox(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
||||
~CheckBox() {}
|
||||
|
||||
wxWindow* window{ nullptr };
|
||||
void BUILD() override;
|
||||
|
@ -173,7 +175,7 @@ public:
|
|||
dynamic_cast<wxCheckBox*>(window)->SetValue(value);
|
||||
m_disable_change_event = false;
|
||||
}
|
||||
void set_value(boost::any value, bool change_event = false) {
|
||||
void set_value(const boost::any& value, bool change_event = false) {
|
||||
m_disable_change_event = !change_event;
|
||||
dynamic_cast<wxCheckBox*>(window)->SetValue(boost::any_cast<bool>(value));
|
||||
m_disable_change_event = false;
|
||||
|
@ -190,21 +192,22 @@ class SpinCtrl : public Field {
|
|||
public:
|
||||
SpinCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id), tmp_value(-9999) {}
|
||||
SpinCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id), tmp_value(-9999) {}
|
||||
~SpinCtrl() {}
|
||||
|
||||
int tmp_value;
|
||||
|
||||
wxWindow* window{ nullptr };
|
||||
void BUILD() override;
|
||||
|
||||
void set_value(const std::string value, bool change_event = false) {
|
||||
void set_value(const std::string& value, bool change_event = false) {
|
||||
m_disable_change_event = !change_event;
|
||||
dynamic_cast<wxSpinCtrl*>(window)->SetValue(value);
|
||||
m_disable_change_event = false;
|
||||
}
|
||||
void set_value(boost::any value, bool change_event = false) {
|
||||
void set_value(const boost::any& value, bool change_event = false) {
|
||||
m_disable_change_event = !change_event;
|
||||
tmp_value = boost::any_cast<int>(value);
|
||||
dynamic_cast<wxSpinCtrl*>(window)->SetValue(tmp_value/*boost::any_cast<int>(value)*/);
|
||||
dynamic_cast<wxSpinCtrl*>(window)->SetValue(tmp_value);
|
||||
m_disable_change_event = false;
|
||||
}
|
||||
boost::any get_value() override {
|
||||
|
@ -221,14 +224,15 @@ class Choice : public Field {
|
|||
public:
|
||||
Choice(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
||||
Choice(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
||||
~Choice() {}
|
||||
|
||||
wxWindow* window{ nullptr };
|
||||
void BUILD() override;
|
||||
|
||||
void set_selection();
|
||||
void set_value(const std::string value, bool change_event = false);
|
||||
void set_value(boost::any value, bool change_event = false);
|
||||
void set_values(const std::vector<std::string> values);
|
||||
void set_value(const std::string& value, bool change_event = false);
|
||||
void set_value(const boost::any& value, bool change_event = false);
|
||||
void set_values(const std::vector<std::string> &values);
|
||||
boost::any get_value() override;
|
||||
|
||||
void enable() override { dynamic_cast<wxComboBox*>(window)->Enable(); };
|
||||
|
@ -241,16 +245,17 @@ class ColourPicker : public Field {
|
|||
public:
|
||||
ColourPicker(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
||||
ColourPicker(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
||||
~ColourPicker() {}
|
||||
|
||||
wxWindow* window{ nullptr };
|
||||
void BUILD() override;
|
||||
|
||||
void set_value(const std::string value, bool change_event = false) {
|
||||
void set_value(const std::string& value, bool change_event = false) {
|
||||
m_disable_change_event = !change_event;
|
||||
dynamic_cast<wxColourPickerCtrl*>(window)->SetColour(value);
|
||||
m_disable_change_event = false;
|
||||
}
|
||||
void set_value(boost::any value, bool change_event = false) {
|
||||
void set_value(const boost::any& value, bool change_event = false) {
|
||||
m_disable_change_event = !change_event;
|
||||
dynamic_cast<wxColourPickerCtrl*>(window)->SetColour(boost::any_cast<wxString>(value));
|
||||
m_disable_change_event = false;
|
||||
|
@ -268,23 +273,24 @@ class PointCtrl : public Field {
|
|||
public:
|
||||
PointCtrl(const ConfigOptionDef& opt, const t_config_option_key& id) : Field(opt, id) {}
|
||||
PointCtrl(wxWindow* parent, const ConfigOptionDef& opt, const t_config_option_key& id) : Field(parent, opt, id) {}
|
||||
~PointCtrl() {}
|
||||
|
||||
wxSizer* sizer{ nullptr };
|
||||
wxTextCtrl* x_textctrl;
|
||||
wxTextCtrl* y_textctrl;
|
||||
wxTextCtrl* x_textctrl{ nullptr };
|
||||
wxTextCtrl* y_textctrl{ nullptr };
|
||||
|
||||
void BUILD() override;
|
||||
|
||||
void set_value(const Pointf value, bool change_event = false);
|
||||
void set_value(boost::any value, bool change_event = false);
|
||||
void set_value(const Pointf& value, bool change_event = false);
|
||||
void set_value(const boost::any& value, bool change_event = false);
|
||||
boost::any get_value() override;
|
||||
|
||||
void enable() override {
|
||||
x_textctrl->Enable();
|
||||
y_textctrl->Enable(); };
|
||||
y_textctrl->Enable(); }
|
||||
void disable() override{
|
||||
x_textctrl->Disable();
|
||||
y_textctrl->Disable(); };
|
||||
y_textctrl->Disable(); }
|
||||
wxSizer* getSizer() override { return sizer; }
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "GUI.hpp"
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <cmath>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
@ -38,6 +40,7 @@
|
|||
#include <wx/combo.h>
|
||||
#include <wx/window.h>
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/settings.h>
|
||||
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
|
@ -182,6 +185,8 @@ wxNotebook *g_wxTabPanel = nullptr;
|
|||
AppConfig *g_AppConfig = nullptr;
|
||||
PresetBundle *g_PresetBundle= nullptr;
|
||||
PresetUpdater *g_PresetUpdater = nullptr;
|
||||
wxColour g_color_label_modified;
|
||||
wxColour g_color_label_sys;
|
||||
|
||||
std::vector<Tab *> g_tabs_list;
|
||||
|
||||
|
@ -189,10 +194,24 @@ wxLocale* g_wxLocale;
|
|||
|
||||
std::shared_ptr<ConfigOptionsGroup> m_optgroup;
|
||||
double m_brim_width = 0.0;
|
||||
wxButton* g_wiping_dialog_button = nullptr;
|
||||
|
||||
static void init_label_colours()
|
||||
{
|
||||
auto luma = get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
|
||||
if (luma >= 128) {
|
||||
g_color_label_modified = wxColour(253, 88, 0);
|
||||
g_color_label_sys = wxColour(26, 132, 57);
|
||||
} else {
|
||||
g_color_label_modified = wxColour(253, 111, 40);
|
||||
g_color_label_sys = wxColour(115, 220, 103);
|
||||
}
|
||||
}
|
||||
|
||||
void set_wxapp(wxApp *app)
|
||||
{
|
||||
g_wxApp = app;
|
||||
init_label_colours();
|
||||
}
|
||||
|
||||
void set_main_frame(wxFrame *main_frame)
|
||||
|
@ -531,7 +550,7 @@ TabIface* get_preset_tab_iface(char *name)
|
|||
}
|
||||
|
||||
// opt_index = 0, by the reason of zero-index in ConfigOptionVector by default (in case only one element)
|
||||
void change_opt_value(DynamicPrintConfig& config, t_config_option_key opt_key, boost::any value, int opt_index /*= 0*/)
|
||||
void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index /*= 0*/)
|
||||
{
|
||||
try{
|
||||
switch (config.def()->get(opt_key)->type){
|
||||
|
@ -567,11 +586,18 @@ void change_opt_value(DynamicPrintConfig& config, t_config_option_key opt_key, b
|
|||
config.set_key_value(opt_key, new ConfigOptionString(boost::any_cast<std::string>(value)));
|
||||
break;
|
||||
case coStrings:{
|
||||
if (opt_key.compare("compatible_printers") == 0 ||
|
||||
config.def()->get(opt_key)->gui_flags.compare("serialized") == 0){
|
||||
config.option<ConfigOptionStrings>(opt_key)->values.resize(0);
|
||||
std::vector<std::string> values = boost::any_cast<std::vector<std::string>>(value);
|
||||
if (values.size() == 1 && values[0] == "")
|
||||
if (opt_key.compare("compatible_printers") == 0) {
|
||||
config.option<ConfigOptionStrings>(opt_key)->values =
|
||||
boost::any_cast<std::vector<std::string>>(value);
|
||||
}
|
||||
else if (config.def()->get(opt_key)->gui_flags.compare("serialized") == 0){
|
||||
std::string str = boost::any_cast<std::string>(value);
|
||||
if (str.back() == ';') str.pop_back();
|
||||
// Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values.
|
||||
// Currently used for the post_process config value only.
|
||||
std::vector<std::string> values;
|
||||
boost::split(values, str, boost::is_any_of(";"));
|
||||
if (values.size() == 1 && values[0] == "")
|
||||
break;
|
||||
config.option<ConfigOptionStrings>(opt_key)->values = values;
|
||||
}
|
||||
|
@ -638,17 +664,17 @@ void add_created_tab(Tab* panel)
|
|||
g_wxTabPanel->AddPage(panel, panel->title());
|
||||
}
|
||||
|
||||
void show_error(wxWindow* parent, wxString message){
|
||||
void show_error(wxWindow* parent, const wxString& message){
|
||||
auto msg_wingow = new wxMessageDialog(parent, message, _(L("Error")), wxOK | wxICON_ERROR);
|
||||
msg_wingow->ShowModal();
|
||||
}
|
||||
|
||||
void show_info(wxWindow* parent, wxString message, wxString title){
|
||||
void show_info(wxWindow* parent, const wxString& message, const wxString& title){
|
||||
auto msg_wingow = new wxMessageDialog(parent, message, title.empty() ? _(L("Notice")) : title, wxOK | wxICON_INFORMATION);
|
||||
msg_wingow->ShowModal();
|
||||
}
|
||||
|
||||
void warning_catcher(wxWindow* parent, wxString message){
|
||||
void warning_catcher(wxWindow* parent, const wxString& message){
|
||||
if (message == _(L("GLUquadricObjPtr | Attempt to free unreferenced scalar")) )
|
||||
return;
|
||||
auto msg = new wxMessageDialog(parent, message, _(L("Warning")), wxOK | wxICON_WARNING);
|
||||
|
@ -659,12 +685,25 @@ wxApp* get_app(){
|
|||
return g_wxApp;
|
||||
}
|
||||
|
||||
wxColour* get_modified_label_clr(){
|
||||
return new wxColour(253, 88, 0);
|
||||
const wxColour& get_modified_label_clr() {
|
||||
return g_color_label_modified;
|
||||
}
|
||||
|
||||
wxColour* get_sys_label_clr(){
|
||||
return new wxColour(26, 132, 57);
|
||||
const wxColour& get_sys_label_clr() {
|
||||
return g_color_label_sys;
|
||||
}
|
||||
|
||||
unsigned get_colour_approx_luma(const wxColour &colour)
|
||||
{
|
||||
double r = colour.Red();
|
||||
double g = colour.Green();
|
||||
double b = colour.Blue();
|
||||
|
||||
return std::round(std::sqrt(
|
||||
r * r * .241 +
|
||||
g * g * .691 +
|
||||
b * b * .068
|
||||
));
|
||||
}
|
||||
|
||||
void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string items, bool initial_value)
|
||||
|
@ -829,6 +868,33 @@ void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFl
|
|||
option = Option(def, "brim");
|
||||
m_optgroup->append_single_option_line(option);
|
||||
|
||||
|
||||
Line line = { _(L("")), "" };
|
||||
line.widget = [config](wxWindow* parent){
|
||||
g_wiping_dialog_button = new wxButton(parent, wxID_ANY, _(L("Purging volumes")) + "\u2026", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(g_wiping_dialog_button);
|
||||
g_wiping_dialog_button->Bind(wxEVT_BUTTON, ([parent](wxCommandEvent& e)
|
||||
{
|
||||
auto &config = g_PresetBundle->project_config;
|
||||
std::vector<double> init_matrix = (config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values;
|
||||
std::vector<double> init_extruders = (config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values;
|
||||
|
||||
WipingDialog dlg(parent,std::vector<float>(init_matrix.begin(),init_matrix.end()),std::vector<float>(init_extruders.begin(),init_extruders.end()));
|
||||
|
||||
if (dlg.ShowModal() == wxID_OK) {
|
||||
std::vector<float> matrix = dlg.get_matrix();
|
||||
std::vector<float> extruders = dlg.get_extruders();
|
||||
(config.option<ConfigOptionFloats>("wiping_volumes_matrix"))->values = std::vector<double>(matrix.begin(),matrix.end());
|
||||
(config.option<ConfigOptionFloats>("wiping_volumes_extruders"))->values = std::vector<double>(extruders.begin(),extruders.end());
|
||||
}
|
||||
}));
|
||||
return sizer;
|
||||
};
|
||||
m_optgroup->append_line(line);
|
||||
|
||||
|
||||
|
||||
sizer->Add(m_optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxBottom, 1);
|
||||
}
|
||||
|
||||
|
@ -837,6 +903,12 @@ ConfigOptionsGroup* get_optgroup()
|
|||
return m_optgroup.get();
|
||||
}
|
||||
|
||||
|
||||
wxButton* get_wiping_dialog_button()
|
||||
{
|
||||
return g_wiping_dialog_button;
|
||||
}
|
||||
|
||||
wxWindow* export_option_creator(wxWindow* parent)
|
||||
{
|
||||
wxPanel* panel = new wxPanel(parent, -1);
|
||||
|
@ -880,6 +952,7 @@ int get_export_option(wxFileDialog* dlg)
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void about()
|
||||
|
|
|
@ -18,6 +18,7 @@ class wxArrayLong;
|
|||
class wxColour;
|
||||
class wxBoxSizer;
|
||||
class wxFlexGridSizer;
|
||||
class wxButton;
|
||||
class wxFileDialog;
|
||||
|
||||
namespace Slic3r {
|
||||
|
@ -81,8 +82,10 @@ void set_preset_updater(PresetUpdater *updater);
|
|||
|
||||
AppConfig* get_app_config();
|
||||
wxApp* get_app();
|
||||
wxColour* get_modified_label_clr();
|
||||
wxColour* get_sys_label_clr();
|
||||
|
||||
const wxColour& get_modified_label_clr();
|
||||
const wxColour& get_sys_label_clr();
|
||||
unsigned get_colour_approx_luma(const wxColour &colour);
|
||||
|
||||
extern void add_config_menu(wxMenuBar *menu, int event_preferences_changed, int event_language_change);
|
||||
|
||||
|
@ -106,11 +109,11 @@ TabIface* get_preset_tab_iface(char *name);
|
|||
// add it at the end of the tab panel.
|
||||
void add_created_tab(Tab* panel);
|
||||
// Change option value in config
|
||||
void change_opt_value(DynamicPrintConfig& config, t_config_option_key opt_key, boost::any value, int opt_index = 0);
|
||||
void change_opt_value(DynamicPrintConfig& config, const t_config_option_key& opt_key, const boost::any& value, int opt_index = 0);
|
||||
|
||||
void show_error(wxWindow* parent, wxString message);
|
||||
void show_info(wxWindow* parent, wxString message, wxString title);
|
||||
void warning_catcher(wxWindow* parent, wxString message);
|
||||
void show_error(wxWindow* parent, const wxString& message);
|
||||
void show_info(wxWindow* parent, const wxString& message, const wxString& title);
|
||||
void warning_catcher(wxWindow* parent, const wxString& message);
|
||||
|
||||
// load language saved at application config
|
||||
bool load_language();
|
||||
|
@ -143,6 +146,7 @@ wxString from_u8(const std::string &str);
|
|||
void add_frequently_changed_parameters(wxWindow* parent, wxBoxSizer* sizer, wxFlexGridSizer* preset_sizer);
|
||||
|
||||
ConfigOptionsGroup* get_optgroup();
|
||||
wxButton* get_wiping_dialog_button();
|
||||
|
||||
void add_export_option(wxFileDialog* dlg, const std::string& format);
|
||||
int get_export_option(wxFileDialog* dlg);
|
||||
|
|
|
@ -97,7 +97,7 @@ const t_field& OptionsGroup::build_field(const t_config_option_key& id, const Co
|
|||
return field;
|
||||
}
|
||||
|
||||
void OptionsGroup::append_line(const Line& line) {
|
||||
void OptionsGroup::append_line(const Line& line, wxStaticText** colored_Label/* = nullptr*/) {
|
||||
//! if (line.sizer != nullptr || (line.widget != nullptr && line.full_width > 0)){
|
||||
if ( (line.sizer != nullptr || line.widget != nullptr) && line.full_width){
|
||||
if (line.sizer != nullptr) {
|
||||
|
@ -150,6 +150,7 @@ void OptionsGroup::append_line(const Line& line) {
|
|||
if (line.widget != nullptr) {
|
||||
auto wgt = line.widget(parent());
|
||||
grid_sizer->Add(wgt, 0, wxEXPAND | wxBOTTOM | wxTOP, wxOSX ? 0 : 5);
|
||||
if (colored_Label != nullptr) *colored_Label = label;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -227,12 +228,12 @@ Line OptionsGroup::create_single_option_line(const Option& option) const {
|
|||
return retval;
|
||||
}
|
||||
|
||||
void OptionsGroup::on_change_OG(t_config_option_key id, /*config_value*/boost::any value) {
|
||||
void OptionsGroup::on_change_OG(const t_config_option_key& opt_id, const boost::any& value) {
|
||||
if (m_on_change != nullptr)
|
||||
m_on_change(id, value);
|
||||
m_on_change(opt_id, value);
|
||||
}
|
||||
|
||||
Option ConfigOptionsGroup::get_option(const std::string opt_key, int opt_index /*= -1*/)
|
||||
Option ConfigOptionsGroup::get_option(const std::string& opt_key, int opt_index /*= -1*/)
|
||||
{
|
||||
if (!m_config->has(opt_key)) {
|
||||
std::cerr << "No " << opt_key << " in ConfigOptionsGroup config.";
|
||||
|
@ -245,7 +246,7 @@ Option ConfigOptionsGroup::get_option(const std::string opt_key, int opt_index /
|
|||
return Option(*m_config->def()->get(opt_key), opt_id);
|
||||
}
|
||||
|
||||
void ConfigOptionsGroup::on_change_OG(t_config_option_key opt_id, boost::any value)
|
||||
void ConfigOptionsGroup::on_change_OG(const t_config_option_key& opt_id, const boost::any& value)
|
||||
{
|
||||
if (!m_opt_map.empty())
|
||||
{
|
||||
|
@ -268,16 +269,7 @@ void ConfigOptionsGroup::on_change_OG(t_config_option_key opt_id, boost::any val
|
|||
if (opt_index != -1){
|
||||
// die "Can't set serialized option indexed value" ;
|
||||
}
|
||||
// # Split a string to multiple strings by a semi - colon.This is the old way of storing multi - string values.
|
||||
// # Currently used for the post_process config value only.
|
||||
// my @values = split / ; / , $field_value;
|
||||
// $self->config->set($opt_key, \@values);
|
||||
std::string str = boost::any_cast<std::string>(value);
|
||||
if (str.back() == ';')
|
||||
str.pop_back();
|
||||
std::vector<std::string> values;
|
||||
boost::split(values, str, boost::is_any_of(";"));
|
||||
change_opt_value(*m_config, opt_key, values);
|
||||
change_opt_value(*m_config, opt_key, value);
|
||||
}
|
||||
else {
|
||||
if (opt_index == -1) {
|
||||
|
@ -297,14 +289,14 @@ void ConfigOptionsGroup::on_change_OG(t_config_option_key opt_id, boost::any val
|
|||
OptionsGroup::on_change_OG(opt_id, value); //!? Why doing this
|
||||
}
|
||||
|
||||
void ConfigOptionsGroup::back_to_initial_value(const std::string opt_key)
|
||||
void ConfigOptionsGroup::back_to_initial_value(const std::string& opt_key)
|
||||
{
|
||||
if (m_get_initial_config == nullptr)
|
||||
return;
|
||||
back_to_config_value(m_get_initial_config(), opt_key);
|
||||
}
|
||||
|
||||
void ConfigOptionsGroup::back_to_sys_value(const std::string opt_key)
|
||||
void ConfigOptionsGroup::back_to_sys_value(const std::string& opt_key)
|
||||
{
|
||||
if (m_get_sys_config == nullptr)
|
||||
return;
|
||||
|
@ -313,7 +305,7 @@ void ConfigOptionsGroup::back_to_sys_value(const std::string opt_key)
|
|||
back_to_config_value(m_get_sys_config(), opt_key);
|
||||
}
|
||||
|
||||
void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, const std::string opt_key)
|
||||
void ConfigOptionsGroup::back_to_config_value(const DynamicPrintConfig& config, const std::string& opt_key)
|
||||
{
|
||||
boost::any value;
|
||||
if (opt_key == "extruders_count"){
|
||||
|
@ -348,7 +340,7 @@ void ConfigOptionsGroup::reload_config(){
|
|||
|
||||
}
|
||||
|
||||
boost::any ConfigOptionsGroup::config_value(std::string opt_key, int opt_index, bool deserialize){
|
||||
boost::any ConfigOptionsGroup::config_value(const std::string& opt_key, int opt_index, bool deserialize){
|
||||
|
||||
if (deserialize) {
|
||||
// Want to edit a vector value(currently only multi - strings) in a single edit box.
|
||||
|
@ -365,7 +357,7 @@ boost::any ConfigOptionsGroup::config_value(std::string opt_key, int opt_index,
|
|||
}
|
||||
}
|
||||
|
||||
boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config, std::string opt_key, int opt_index /*= -1*/)
|
||||
boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config, const std::string& opt_key, int opt_index /*= -1*/)
|
||||
{
|
||||
size_t idx = opt_index == -1 ? 0 : opt_index;
|
||||
|
||||
|
@ -405,6 +397,10 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
|
|||
ret = static_cast<wxString>(config.opt_string(opt_key));
|
||||
break;
|
||||
case coStrings:
|
||||
if (opt_key.compare("compatible_printers") == 0){
|
||||
ret = config.option<ConfigOptionStrings>(opt_key)->values;
|
||||
break;
|
||||
}
|
||||
if (config.option<ConfigOptionStrings>(opt_key)->values.empty())
|
||||
ret = text_value;
|
||||
else if (opt->gui_flags.compare("serialized") == 0){
|
||||
|
@ -457,7 +453,7 @@ boost::any ConfigOptionsGroup::get_config_value(const DynamicPrintConfig& config
|
|||
return ret;
|
||||
}
|
||||
|
||||
Field* ConfigOptionsGroup::get_fieldc(t_config_option_key opt_key, int opt_index){
|
||||
Field* ConfigOptionsGroup::get_fieldc(const t_config_option_key& opt_key, int opt_index){
|
||||
Field* field = get_field(opt_key);
|
||||
if (field != nullptr)
|
||||
return field;
|
||||
|
@ -471,7 +467,7 @@ Field* ConfigOptionsGroup::get_fieldc(t_config_option_key opt_key, int opt_index
|
|||
return opt_id.empty() ? nullptr : get_field(opt_id);
|
||||
}
|
||||
|
||||
void ogStaticText::SetText(wxString value)
|
||||
void ogStaticText::SetText(const wxString& value)
|
||||
{
|
||||
SetLabel(value);
|
||||
Wrap(400);
|
||||
|
|
|
@ -93,21 +93,21 @@ public:
|
|||
/// but defining it as const means a lot of const_casts to deal with wx functions.
|
||||
inline wxWindow* parent() const { return m_parent; }
|
||||
|
||||
void append_line(const Line& line);
|
||||
void append_line(const Line& line, wxStaticText** colored_Label = nullptr);
|
||||
Line create_single_option_line(const Option& option) const;
|
||||
void append_single_option_line(const Option& option) { append_line(create_single_option_line(option)); }
|
||||
|
||||
// return a non-owning pointer reference
|
||||
inline Field* get_field(t_config_option_key id) const{
|
||||
inline Field* get_field(const t_config_option_key& id) const{
|
||||
if (m_fields.find(id) == m_fields.end()) return nullptr;
|
||||
return m_fields.at(id).get();
|
||||
}
|
||||
bool set_value(t_config_option_key id, boost::any value, bool change_event = false) {
|
||||
bool set_value(const t_config_option_key& id, const boost::any& value, bool change_event = false) {
|
||||
if (m_fields.find(id) == m_fields.end()) return false;
|
||||
m_fields.at(id)->set_value(value, change_event);
|
||||
return true;
|
||||
}
|
||||
boost::any get_value(t_config_option_key id) {
|
||||
boost::any get_value(const t_config_option_key& id) {
|
||||
boost::any out;
|
||||
if (m_fields.find(id) == m_fields.end()) ;
|
||||
else
|
||||
|
@ -118,7 +118,7 @@ public:
|
|||
inline void enable() { for (auto& field : m_fields) field.second->enable(); }
|
||||
inline void disable() { for (auto& field : m_fields) field.second->disable(); }
|
||||
|
||||
OptionsGroup(wxWindow* _parent, wxString title, bool is_tab_opt=false) :
|
||||
OptionsGroup(wxWindow* _parent, const wxString& title, bool is_tab_opt=false) :
|
||||
m_parent(_parent), title(title), m_is_tab_opt(is_tab_opt), staticbox(title!="") {
|
||||
sizer = (staticbox ? new wxStaticBoxSizer(new wxStaticBox(_parent, wxID_ANY, title), wxVERTICAL) : new wxBoxSizer(wxVERTICAL));
|
||||
auto num_columns = 1U;
|
||||
|
@ -152,14 +152,14 @@ protected:
|
|||
const t_field& build_field(const Option& opt, wxStaticText* label = nullptr);
|
||||
|
||||
virtual void on_kill_focus (){};
|
||||
virtual void on_change_OG(t_config_option_key opt_id, boost::any value);
|
||||
virtual void back_to_initial_value(const std::string opt_key){};
|
||||
virtual void back_to_sys_value(const std::string opt_key){};
|
||||
virtual void on_change_OG(const t_config_option_key& opt_id, const boost::any& value);
|
||||
virtual void back_to_initial_value(const std::string& opt_key){}
|
||||
virtual void back_to_sys_value(const std::string& opt_key){}
|
||||
};
|
||||
|
||||
class ConfigOptionsGroup: public OptionsGroup {
|
||||
public:
|
||||
ConfigOptionsGroup(wxWindow* parent, wxString title, DynamicPrintConfig* _config = nullptr, bool is_tab_opt = false) :
|
||||
ConfigOptionsGroup(wxWindow* parent, const wxString& title, DynamicPrintConfig* _config = nullptr, bool is_tab_opt = false) :
|
||||
OptionsGroup(parent, title, is_tab_opt), m_config(_config) {}
|
||||
|
||||
/// reference to libslic3r config, non-owning pointer (?).
|
||||
|
@ -167,8 +167,8 @@ public:
|
|||
bool m_full_labels {0};
|
||||
t_opt_map m_opt_map;
|
||||
|
||||
Option get_option(const std::string opt_key, int opt_index = -1);
|
||||
Line create_single_option_line(const std::string title, int idx = -1) /*const*/{
|
||||
Option get_option(const std::string& opt_key, int opt_index = -1);
|
||||
Line create_single_option_line(const std::string& title, int idx = -1) /*const*/{
|
||||
Option option = get_option(title, idx);
|
||||
return OptionsGroup::create_single_option_line(option);
|
||||
}
|
||||
|
@ -181,16 +181,16 @@ public:
|
|||
append_single_option_line(option);
|
||||
}
|
||||
|
||||
void on_change_OG(t_config_option_key opt_id, boost::any value) override;
|
||||
void back_to_initial_value(const std::string opt_key) override;
|
||||
void back_to_sys_value(const std::string opt_key) override;
|
||||
void back_to_config_value(const DynamicPrintConfig& config, const std::string opt_key);
|
||||
void on_change_OG(const t_config_option_key& opt_id, const boost::any& value) override;
|
||||
void back_to_initial_value(const std::string& opt_key) override;
|
||||
void back_to_sys_value(const std::string& opt_key) override;
|
||||
void back_to_config_value(const DynamicPrintConfig& config, const std::string& opt_key);
|
||||
void on_kill_focus() override{ reload_config();}
|
||||
void reload_config();
|
||||
boost::any config_value(std::string opt_key, int opt_index, bool deserialize);
|
||||
boost::any config_value(const std::string& opt_key, int opt_index, bool deserialize);
|
||||
// return option value from config
|
||||
boost::any get_config_value(const DynamicPrintConfig& config, std::string opt_key, int opt_index = -1);
|
||||
Field* get_fieldc(t_config_option_key opt_key, int opt_index);
|
||||
boost::any get_config_value(const DynamicPrintConfig& config, const std::string& opt_key, int opt_index = -1);
|
||||
Field* get_fieldc(const t_config_option_key& opt_key, int opt_index);
|
||||
};
|
||||
|
||||
// Static text shown among the options.
|
||||
|
@ -200,7 +200,7 @@ public:
|
|||
ogStaticText(wxWindow* parent, const char *text) : wxStaticText(parent, wxID_ANY, text, wxDefaultPosition, wxDefaultSize){}
|
||||
~ogStaticText(){}
|
||||
|
||||
void SetText(wxString value);
|
||||
void SetText(const wxString& value);
|
||||
};
|
||||
|
||||
}}
|
||||
|
|
|
@ -287,8 +287,7 @@ const std::vector<std::string>& Preset::print_options()
|
|||
"perimeter_extrusion_width", "external_perimeter_extrusion_width", "infill_extrusion_width", "solid_infill_extrusion_width",
|
||||
"top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects",
|
||||
"elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y",
|
||||
"wipe_tower_width", "wipe_tower_per_color_wipe",
|
||||
"compatible_printers", "compatible_printers_condition", "inherits"
|
||||
"wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging", "compatible_printers", "compatible_printers_condition","inherits"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
@ -296,12 +295,12 @@ const std::vector<std::string>& Preset::print_options()
|
|||
const std::vector<std::string>& Preset::filament_options()
|
||||
{
|
||||
static std::vector<std::string> s_opts {
|
||||
"filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed",
|
||||
"extrusion_multiplier", "filament_density", "filament_cost", "temperature", "first_layer_temperature", "bed_temperature",
|
||||
"first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed",
|
||||
"disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", "start_filament_gcode",
|
||||
"end_filament_gcode",
|
||||
"compatible_printers", "compatible_printers_condition", "inherits"
|
||||
"filament_colour", "filament_diameter", "filament_type", "filament_soluble", "filament_notes", "filament_max_volumetric_speed",
|
||||
"extrusion_multiplier", "filament_density", "filament_cost", "filament_loading_speed", "filament_unloading_speed", "filament_toolchange_delay",
|
||||
"filament_cooling_time", "filament_ramming_parameters", "temperature", "first_layer_temperature", "bed_temperature",
|
||||
"first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers",
|
||||
"fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", "start_filament_gcode", "end_filament_gcode","compatible_printers",
|
||||
"compatible_printers_condition", "inherits"
|
||||
};
|
||||
return s_opts;
|
||||
}
|
||||
|
@ -314,8 +313,8 @@ const std::vector<std::string>& Preset::printer_options()
|
|||
"bed_shape", "z_offset", "gcode_flavor", "use_relative_e_distances", "serial_port", "serial_speed",
|
||||
"octoprint_host", "octoprint_apikey", "octoprint_cafile", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
|
||||
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
|
||||
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "max_print_height",
|
||||
"default_print_profile", "inherits",
|
||||
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
|
||||
"cooling_tube_length", "parking_pos_retraction", "max_print_height", "default_print_profile", "inherits",
|
||||
};
|
||||
s_opts.insert(s_opts.end(), Preset::nozzle_options().begin(), Preset::nozzle_options().end());
|
||||
}
|
||||
|
@ -505,6 +504,20 @@ const Preset* PresetCollection::get_selected_preset_parent() const
|
|||
return (preset == nullptr || preset->is_default || preset->is_external) ? nullptr : preset;
|
||||
}
|
||||
|
||||
const Preset* PresetCollection::get_preset_parent(const Preset& child) const
|
||||
{
|
||||
auto *inherits = dynamic_cast<const ConfigOptionString*>(child.config.option("inherits"));
|
||||
if (inherits == nullptr || inherits->value.empty())
|
||||
// return this->get_selected_preset().is_system ? &this->get_selected_preset() : nullptr;
|
||||
return nullptr;
|
||||
const Preset* preset = this->find_preset(inherits->value, false);
|
||||
return (preset == nullptr/* || preset->is_default */|| preset->is_external) ? nullptr : preset;
|
||||
}
|
||||
|
||||
const std::string& PresetCollection::get_suffix_modified() {
|
||||
return g_suffix_modified;
|
||||
}
|
||||
|
||||
// Return a preset by its name. If the preset is active, a temporary copy is returned.
|
||||
// If a preset is not found by its name, null is returned.
|
||||
Preset* PresetCollection::find_preset(const std::string &name, bool first_visible_if_not_found)
|
||||
|
@ -572,16 +585,44 @@ void PresetCollection::update_platter_ui(wxBitmapComboBox *ui)
|
|||
// Otherwise fill in the list from scratch.
|
||||
ui->Freeze();
|
||||
ui->Clear();
|
||||
std::map<wxString, bool> nonsys_presets;
|
||||
wxString selected = "";
|
||||
for (size_t i = this->m_presets.front().is_visible ? 0 : 1; i < this->m_presets.size(); ++ i) {
|
||||
const Preset &preset = this->m_presets[i];
|
||||
if (! preset.is_visible || (! preset.is_compatible && i != m_idx_selected))
|
||||
continue;
|
||||
const wxBitmap *bmp = (i == 0 || preset.is_compatible) ? m_bitmap_main_frame : m_bitmap_incompatible;
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
|
||||
(bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
if (i == m_idx_selected)
|
||||
ui->SetSelection(ui->GetCount() - 1);
|
||||
}
|
||||
// ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
|
||||
// (bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
// if (i == m_idx_selected)
|
||||
// ui->SetSelection(ui->GetCount() - 1);
|
||||
|
||||
if (preset.is_default || preset.is_system){
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
|
||||
(bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
if (i == m_idx_selected)
|
||||
ui->SetSelection(ui->GetCount() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), preset.is_compatible);
|
||||
if (i == m_idx_selected)
|
||||
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str());
|
||||
}
|
||||
if (preset.is_default)
|
||||
ui->Append("------------------------------------", wxNullBitmap);
|
||||
}
|
||||
if (!nonsys_presets.empty())
|
||||
{
|
||||
ui->Append("------------------------------------", wxNullBitmap);
|
||||
for (std::map<wxString, bool>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
|
||||
const wxBitmap *bmp = it->second ? m_bitmap_compatible : m_bitmap_incompatible;
|
||||
ui->Append(it->first,
|
||||
(bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
if (it->first == selected)
|
||||
ui->SetSelection(ui->GetCount() - 1);
|
||||
}
|
||||
}
|
||||
ui->Thaw();
|
||||
}
|
||||
|
||||
|
@ -591,16 +632,44 @@ void PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompatibl
|
|||
return;
|
||||
ui->Freeze();
|
||||
ui->Clear();
|
||||
std::map<wxString, bool> nonsys_presets;
|
||||
wxString selected = "";
|
||||
for (size_t i = this->m_presets.front().is_visible ? 0 : 1; i < this->m_presets.size(); ++ i) {
|
||||
const Preset &preset = this->m_presets[i];
|
||||
if (! preset.is_visible || (! show_incompatible && ! preset.is_compatible && i != m_idx_selected))
|
||||
continue;
|
||||
const wxBitmap *bmp = preset.is_compatible ? m_bitmap_compatible : m_bitmap_incompatible;
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
|
||||
(bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
if (i == m_idx_selected)
|
||||
ui->SetSelection(ui->GetCount() - 1);
|
||||
// ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
|
||||
// (bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
// if (i == m_idx_selected)
|
||||
// ui->SetSelection(ui->GetCount() - 1);
|
||||
|
||||
if (preset.is_default || preset.is_system){
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()),
|
||||
(bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
if (i == m_idx_selected)
|
||||
ui->SetSelection(ui->GetCount() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), preset.is_compatible);
|
||||
if (i == m_idx_selected)
|
||||
selected = wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str());
|
||||
}
|
||||
if (preset.is_default)
|
||||
ui->Append("------------------------------------", wxNullBitmap);
|
||||
}
|
||||
if (!nonsys_presets.empty())
|
||||
{
|
||||
ui->Append("------------------------------------", wxNullBitmap);
|
||||
for (std::map<wxString, bool>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
|
||||
const wxBitmap *bmp = it->second ? m_bitmap_compatible : m_bitmap_incompatible;
|
||||
ui->Append(it->first,
|
||||
(bmp == 0) ? (m_bitmap_main_frame ? *m_bitmap_main_frame : wxNullBitmap) : *bmp);
|
||||
if (it->first == selected)
|
||||
ui->SetSelection(ui->GetCount() - 1);
|
||||
}
|
||||
}
|
||||
ui->Thaw();
|
||||
}
|
||||
|
||||
|
|
|
@ -228,9 +228,17 @@ public:
|
|||
// The parent preset may be a system preset or a user preset, which will be
|
||||
// reflected by the UI.
|
||||
const Preset* get_selected_preset_parent() const;
|
||||
// Return the selected preset including the user modifications.
|
||||
// get parent preset for some child preset
|
||||
const Preset* get_preset_parent(const Preset& child) const;
|
||||
// Return the selected preset including the user modifications.
|
||||
Preset& get_edited_preset() { return m_edited_preset; }
|
||||
const Preset& get_edited_preset() const { return m_edited_preset; }
|
||||
|
||||
// used to update preset_choice from Tab
|
||||
const std::deque<Preset>& get_presets() { return m_presets; }
|
||||
int get_idx_selected() { return m_idx_selected; }
|
||||
const std::string& get_suffix_modified();
|
||||
|
||||
// Return a preset possibly with modifications.
|
||||
const Preset& default_preset() const { return m_presets.front(); }
|
||||
// Return a preset by an index. If the preset is active, a temporary copy is returned.
|
||||
|
|
|
@ -34,6 +34,11 @@
|
|||
|
||||
namespace Slic3r {
|
||||
|
||||
static std::vector<std::string> s_project_options {
|
||||
"wiping_volumes_extruders",
|
||||
"wiping_volumes_matrix"
|
||||
};
|
||||
|
||||
PresetBundle::PresetBundle() :
|
||||
prints(Preset::TYPE_PRINT, Preset::print_options()),
|
||||
filaments(Preset::TYPE_FILAMENT, Preset::filament_options()),
|
||||
|
@ -69,6 +74,8 @@ PresetBundle::PresetBundle() :
|
|||
this->filaments.load_bitmap_default("spool.png");
|
||||
this->printers .load_bitmap_default("printer_empty.png");
|
||||
this->load_compatible_bitmaps();
|
||||
|
||||
this->project_config.apply_only(FullPrintConfig::defaults(), s_project_options);
|
||||
}
|
||||
|
||||
PresetBundle::~PresetBundle()
|
||||
|
@ -274,8 +281,8 @@ bool PresetBundle::load_compatible_bitmaps()
|
|||
{
|
||||
const std::string path_bitmap_compatible = "flag-green-icon.png";
|
||||
const std::string path_bitmap_incompatible = "flag-red-icon.png";
|
||||
const std::string path_bitmap_lock = "lock.png";
|
||||
const std::string path_bitmap_lock_open = "lock_open.png";
|
||||
const std::string path_bitmap_lock = "sys_lock.png";//"lock.png";
|
||||
const std::string path_bitmap_lock_open = "sys_unlock.png";//"lock_open.png";
|
||||
bool loaded_compatible = m_bitmapCompatible ->LoadFile(
|
||||
wxString::FromUTF8(Slic3r::var(path_bitmap_compatible).c_str()), wxBITMAP_TYPE_PNG);
|
||||
bool loaded_incompatible = m_bitmapIncompatible->LoadFile(
|
||||
|
@ -313,6 +320,7 @@ DynamicPrintConfig PresetBundle::full_config() const
|
|||
out.apply(FullPrintConfig());
|
||||
out.apply(this->prints.get_edited_preset().config);
|
||||
out.apply(this->printers.get_edited_preset().config);
|
||||
out.apply(this->project_config);
|
||||
|
||||
auto *nozzle_diameter = dynamic_cast<const ConfigOptionFloats*>(out.option("nozzle_diameter"));
|
||||
size_t num_extruders = nozzle_diameter->values.size();
|
||||
|
@ -502,6 +510,9 @@ void PresetBundle::load_config_file_config(const std::string &name_or_path, bool
|
|||
}
|
||||
}
|
||||
|
||||
// 4) Load the project config values (the per extruder wipe matrix etc).
|
||||
this->project_config.apply_only(config, s_project_options);
|
||||
|
||||
this->update_compatible_with_printer(false);
|
||||
}
|
||||
|
||||
|
@ -868,6 +879,34 @@ void PresetBundle::update_multi_material_filament_presets()
|
|||
// Append the rest of filament presets.
|
||||
// if (this->filament_presets.size() < num_extruders)
|
||||
this->filament_presets.resize(num_extruders, this->filament_presets.empty() ? this->filaments.first_visible().name : this->filament_presets.back());
|
||||
|
||||
|
||||
// Now verify if wiping_volumes_matrix has proper size (it is used to deduce number of extruders in wipe tower generator):
|
||||
std::vector<double> old_matrix = this->project_config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values;
|
||||
size_t old_number_of_extruders = int(sqrt(old_matrix.size())+EPSILON);
|
||||
if (num_extruders != old_number_of_extruders) {
|
||||
// First verify if purging volumes presets for each extruder matches number of extruders
|
||||
std::vector<double>& extruders = this->project_config.option<ConfigOptionFloats>("wiping_volumes_extruders")->values;
|
||||
while (extruders.size() < 2*num_extruders) {
|
||||
extruders.push_back(extruders.size()>1 ? extruders[0] : 50.); // copy the values from the first extruder
|
||||
extruders.push_back(extruders.size()>1 ? extruders[1] : 50.);
|
||||
}
|
||||
while (extruders.size() > 2*num_extruders) {
|
||||
extruders.pop_back();
|
||||
extruders.pop_back();
|
||||
}
|
||||
|
||||
std::vector<double> new_matrix;
|
||||
for (unsigned int i=0;i<num_extruders;++i)
|
||||
for (unsigned int j=0;j<num_extruders;++j) {
|
||||
// append the value for this pair from the old matrix (if it's there):
|
||||
if (i<old_number_of_extruders && j<old_number_of_extruders)
|
||||
new_matrix.push_back(old_matrix[i*old_number_of_extruders + j]);
|
||||
else
|
||||
new_matrix.push_back( i==j ? 0. : extruders[2*i]+extruders[2*j+1]); // so it matches new extruder volumes
|
||||
}
|
||||
this->project_config.option<ConfigOptionFloats>("wiping_volumes_matrix")->values = new_matrix;
|
||||
}
|
||||
}
|
||||
|
||||
void PresetBundle::update_compatible_with_printer(bool select_other_if_incompatible)
|
||||
|
@ -967,7 +1006,7 @@ static inline int hex_digit_to_int(const char c)
|
|||
(c >= 'a' && c <= 'f') ? int(c - 'a') + 10 : -1;
|
||||
}
|
||||
|
||||
static inline bool parse_color(const std::string &scolor, unsigned char *rgb_out)
|
||||
bool PresetBundle::parse_color(const std::string &scolor, unsigned char *rgb_out)
|
||||
{
|
||||
rgb_out[0] = rgb_out[1] = rgb_out[2] = 0;
|
||||
if (scolor.size() != 7 || scolor.front() != '#')
|
||||
|
@ -1002,6 +1041,8 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, wxBitma
|
|||
// and draw a red flag in front of the selected preset.
|
||||
bool wide_icons = selected_preset != nullptr && ! selected_preset->is_compatible && m_bitmapIncompatible != nullptr;
|
||||
assert(selected_preset != nullptr);
|
||||
std::map<wxString, wxBitmap> nonsys_presets;
|
||||
wxString selected_str = "";
|
||||
for (int i = this->filaments().front().is_visible ? 0 : 1; i < int(this->filaments().size()); ++ i) {
|
||||
const Preset &preset = this->filaments.preset(i);
|
||||
bool selected = this->filament_presets[idx_extruder] == preset.name;
|
||||
|
@ -1039,10 +1080,36 @@ void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, wxBitma
|
|||
(preset.is_dirty ? *m_bitmapLockOpen : *m_bitmapLock) : m_bitmapCache->mkclear(16, 16));
|
||||
bitmap = m_bitmapCache->insert(bitmap_key, bmps);
|
||||
}
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), (bitmap == 0) ? wxNullBitmap : *bitmap);
|
||||
if (selected)
|
||||
ui->SetSelection(ui->GetCount() - 1);
|
||||
// ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()), (bitmap == 0) ? wxNullBitmap : *bitmap);
|
||||
// if (selected)
|
||||
// ui->SetSelection(ui->GetCount() - 1);
|
||||
|
||||
if (preset.is_default || preset.is_system){
|
||||
ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()),
|
||||
(bitmap == 0) ? wxNullBitmap : *bitmap);
|
||||
if (selected)
|
||||
ui->SetSelection(ui->GetCount() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
nonsys_presets.emplace(wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str()),
|
||||
(bitmap == 0) ? wxNullBitmap : *bitmap);
|
||||
if (selected)
|
||||
selected_str = wxString::FromUTF8((preset.name + (preset.is_dirty ? Preset::suffix_modified() : "")).c_str());
|
||||
}
|
||||
if (preset.is_default)
|
||||
ui->Append("------------------------------------", wxNullBitmap);
|
||||
}
|
||||
|
||||
if (!nonsys_presets.empty())
|
||||
{
|
||||
ui->Append("------------------------------------", wxNullBitmap);
|
||||
for (std::map<wxString, wxBitmap>::iterator it = nonsys_presets.begin(); it != nonsys_presets.end(); ++it) {
|
||||
ui->Append(it->first, it->second);
|
||||
if (it->first == selected_str)
|
||||
ui->SetSelection(ui->GetCount() - 1);
|
||||
}
|
||||
}
|
||||
ui->Thaw();
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,11 @@ public:
|
|||
// extruders.size() should be the same as printers.get_edited_preset().config.nozzle_diameter.size()
|
||||
std::vector<std::string> filament_presets;
|
||||
|
||||
// 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.
|
||||
DynamicPrintConfig project_config;
|
||||
|
||||
// There will be an entry for each system profile loaded,
|
||||
// and the system profiles will point to the VendorProfile instances owned by PresetBundle::vendors.
|
||||
std::set<VendorProfile> vendors;
|
||||
|
@ -115,6 +120,8 @@ public:
|
|||
// preset if the current print or filament preset is not compatible.
|
||||
void update_compatible_with_printer(bool select_other_if_incompatible);
|
||||
|
||||
static bool parse_color(const std::string &scolor, unsigned char *rgb_out);
|
||||
|
||||
private:
|
||||
std::string load_system_presets();
|
||||
|
||||
|
|
284
xs/src/slic3r/GUI/RammingChart.cpp
Normal file
284
xs/src/slic3r/GUI/RammingChart.cpp
Normal file
|
@ -0,0 +1,284 @@
|
|||
#include <algorithm>
|
||||
#include <wx/dcbuffer.h>
|
||||
|
||||
#include "RammingChart.hpp"
|
||||
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) s
|
||||
|
||||
|
||||
|
||||
wxDEFINE_EVENT(EVT_WIPE_TOWER_CHART_CHANGED, wxCommandEvent);
|
||||
|
||||
|
||||
void Chart::draw() {
|
||||
wxAutoBufferedPaintDC dc(this); // unbuffered DC caused flickering on win
|
||||
|
||||
dc.SetBrush(GetBackgroundColour());
|
||||
dc.SetPen(GetBackgroundColour());
|
||||
dc.DrawRectangle(GetClientRect()); // otherwise the background would end up black on windows
|
||||
|
||||
dc.SetPen(*wxBLACK_PEN);
|
||||
dc.SetBrush(*wxWHITE_BRUSH);
|
||||
dc.DrawRectangle(m_rect);
|
||||
|
||||
if (visible_area.m_width < 0.499) {
|
||||
dc.DrawText("NO RAMMING AT ALL",wxPoint(m_rect.GetLeft()+m_rect.GetWidth()/2-50,m_rect.GetBottom()-m_rect.GetHeight()/2));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!m_line_to_draw.empty()) {
|
||||
for (unsigned int i=0;i<m_line_to_draw.size()-2;++i) {
|
||||
int color = 510*((m_rect.GetBottom()-(m_line_to_draw)[i])/double(m_rect.GetHeight()));
|
||||
dc.SetPen( wxPen( wxColor(std::min(255,color),255-std::max(color-255,0),0), 1 ) );
|
||||
dc.DrawLine(m_rect.GetLeft()+1+i,(m_line_to_draw)[i],m_rect.GetLeft()+1+i,m_rect.GetBottom());
|
||||
}
|
||||
dc.SetPen( wxPen( wxColor(0,0,0), 1 ) );
|
||||
for (unsigned int i=0;i<m_line_to_draw.size()-2;++i) {
|
||||
if (splines)
|
||||
dc.DrawLine(m_rect.GetLeft()+i,(m_line_to_draw)[i],m_rect.GetLeft()+i+1,(m_line_to_draw)[i+1]);
|
||||
else {
|
||||
dc.DrawLine(m_rect.GetLeft()+i,(m_line_to_draw)[i],m_rect.GetLeft()+i+1,(m_line_to_draw)[i]);
|
||||
dc.DrawLine(m_rect.GetLeft()+i+1,(m_line_to_draw)[i],m_rect.GetLeft()+i+1,(m_line_to_draw)[i+1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// draw draggable buttons
|
||||
dc.SetBrush(*wxBLUE_BRUSH);
|
||||
dc.SetPen( wxPen( wxColor(0,0,0), 1 ) );
|
||||
for (auto& button : m_buttons)
|
||||
//dc.DrawRectangle(math_to_screen(button.get_pos())-wxPoint(side/2.,side/2.), wxSize(side,side));
|
||||
dc.DrawCircle(math_to_screen(button.get_pos()),side/2.);
|
||||
//dc.DrawRectangle(math_to_screen(button.get_pos()-wxPoint2DDouble(0.125,0))-wxPoint(0,5),wxSize(50,10));
|
||||
|
||||
// draw x-axis:
|
||||
float last_mark = -10000;
|
||||
for (float math_x=int(visible_area.m_x*10)/10 ; math_x < (visible_area.m_x+visible_area.m_width) ; math_x+=0.1) {
|
||||
int x = math_to_screen(wxPoint2DDouble(math_x,visible_area.m_y)).x;
|
||||
int y = m_rect.GetBottom();
|
||||
if (x-last_mark < 50) continue;
|
||||
dc.DrawLine(x,y+3,x,y-3);
|
||||
dc.DrawText(wxString().Format(wxT("%.1f"), math_x),wxPoint(x-10,y+7));
|
||||
last_mark = x;
|
||||
}
|
||||
|
||||
// draw y-axis:
|
||||
last_mark=10000;
|
||||
for (int math_y=visible_area.m_y ; math_y < (visible_area.m_y+visible_area.m_height) ; math_y+=1) {
|
||||
int y = math_to_screen(wxPoint2DDouble(visible_area.m_x,math_y)).y;
|
||||
int x = m_rect.GetLeft();
|
||||
if (last_mark-y < 50) continue;
|
||||
dc.DrawLine(x-3,y,x+3,y);
|
||||
dc.DrawText(wxString()<<math_y,wxPoint(x-25,y-2/*7*/));
|
||||
last_mark = y;
|
||||
}
|
||||
|
||||
// axis labels:
|
||||
wxString label = L("Time (s)");
|
||||
int text_width = 0;
|
||||
int text_height = 0;
|
||||
dc.GetTextExtent(label,&text_width,&text_height);
|
||||
dc.DrawText(label,wxPoint(0.5*(m_rect.GetRight()+m_rect.GetLeft())-text_width/2.f, m_rect.GetBottom()+25));
|
||||
label = L("Volumetric speed (mm\u00B3/s)");
|
||||
dc.GetTextExtent(label,&text_width,&text_height);
|
||||
dc.DrawRotatedText(label,wxPoint(0,0.5*(m_rect.GetBottom()+m_rect.GetTop())+text_width/2.f),90);
|
||||
}
|
||||
|
||||
void Chart::mouse_right_button_clicked(wxMouseEvent& event) {
|
||||
if (!manual_points_manipulation)
|
||||
return;
|
||||
wxPoint point = event.GetPosition();
|
||||
int button_index = which_button_is_clicked(point);
|
||||
if (button_index != -1 && m_buttons.size()>2) {
|
||||
m_buttons.erase(m_buttons.begin()+button_index);
|
||||
recalculate_line();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Chart::mouse_clicked(wxMouseEvent& event) {
|
||||
wxPoint point = event.GetPosition();
|
||||
int button_index = which_button_is_clicked(point);
|
||||
if ( button_index != -1) {
|
||||
m_dragged = &m_buttons[button_index];
|
||||
m_previous_mouse = point;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Chart::mouse_moved(wxMouseEvent& event) {
|
||||
if (!event.Dragging() || !m_dragged) return;
|
||||
wxPoint pos = event.GetPosition();
|
||||
wxRect rect = m_rect;
|
||||
rect.Deflate(side/2.);
|
||||
if (!(rect.Contains(pos))) { // the mouse left chart area
|
||||
mouse_left_window(event);
|
||||
return;
|
||||
}
|
||||
int delta_x = pos.x - m_previous_mouse.x;
|
||||
int delta_y = pos.y - m_previous_mouse.y;
|
||||
m_dragged->move(fixed_x?0:double(delta_x)/m_rect.GetWidth() * visible_area.m_width,-double(delta_y)/m_rect.GetHeight() * visible_area.m_height);
|
||||
m_previous_mouse = pos;
|
||||
recalculate_line();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Chart::mouse_double_clicked(wxMouseEvent& event) {
|
||||
if (!manual_points_manipulation)
|
||||
return;
|
||||
wxPoint point = event.GetPosition();
|
||||
if (!m_rect.Contains(point)) // the click is outside the chart
|
||||
return;
|
||||
m_buttons.push_back(screen_to_math(point));
|
||||
std::sort(m_buttons.begin(),m_buttons.end());
|
||||
recalculate_line();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Chart::recalculate_line() {
|
||||
std::vector<wxPoint> points;
|
||||
for (auto& but : m_buttons) {
|
||||
points.push_back(wxPoint(math_to_screen(but.get_pos())));
|
||||
if (points.size()>1 && points.back().x==points[points.size()-2].x) points.pop_back();
|
||||
if (points.size()>1 && points.back().x > m_rect.GetRight()) {
|
||||
points.pop_back();
|
||||
break;
|
||||
}
|
||||
}
|
||||
std::sort(points.begin(),points.end(),[](wxPoint& a,wxPoint& b) { return a.x < b.x; });
|
||||
|
||||
m_line_to_draw.clear();
|
||||
m_total_volume = 0.f;
|
||||
|
||||
|
||||
// Cubic spline interpolation: see https://en.wikiversity.org/wiki/Cubic_Spline_Interpolation#Methods
|
||||
const bool boundary_first_derivative = true; // true - first derivative is 0 at the leftmost and rightmost point
|
||||
// false - second ---- || -------
|
||||
const int N = points.size()-1; // last point can be accessed as N, we have N+1 total points
|
||||
std::vector<float> diag(N+1);
|
||||
std::vector<float> mu(N+1);
|
||||
std::vector<float> lambda(N+1);
|
||||
std::vector<float> h(N+1);
|
||||
std::vector<float> rhs(N+1);
|
||||
|
||||
// let's fill in inner equations
|
||||
for (int i=1;i<=N;++i) h[i] = points[i].x-points[i-1].x;
|
||||
std::fill(diag.begin(),diag.end(),2.f);
|
||||
for (int i=1;i<=N-1;++i) {
|
||||
mu[i] = h[i]/(h[i]+h[i+1]);
|
||||
lambda[i] = 1.f - mu[i];
|
||||
rhs[i] = 6 * ( float(points[i+1].y-points[i].y )/(h[i+1]*(points[i+1].x-points[i-1].x)) -
|
||||
float(points[i].y -points[i-1].y)/(h[i] *(points[i+1].x-points[i-1].x)) );
|
||||
}
|
||||
|
||||
// now fill in the first and last equations, according to boundary conditions:
|
||||
if (boundary_first_derivative) {
|
||||
const float endpoints_derivative = 0;
|
||||
lambda[0] = 1;
|
||||
mu[N] = 1;
|
||||
rhs[0] = (6.f/h[1]) * (float(points[0].y-points[1].y)/(points[0].x-points[1].x) - endpoints_derivative);
|
||||
rhs[N] = (6.f/h[N]) * (endpoints_derivative - float(points[N-1].y-points[N].y)/(points[N-1].x-points[N].x));
|
||||
}
|
||||
else {
|
||||
lambda[0] = 0;
|
||||
mu[N] = 0;
|
||||
rhs[0] = 0;
|
||||
rhs[N] = 0;
|
||||
}
|
||||
|
||||
// the trilinear system is ready to be solved:
|
||||
for (int i=1;i<=N;++i) {
|
||||
float multiple = mu[i]/diag[i-1]; // let's subtract proper multiple of above equation
|
||||
diag[i]-= multiple * lambda[i-1];
|
||||
rhs[i] -= multiple * rhs[i-1];
|
||||
}
|
||||
// now the back substitution (vector mu contains invalid values from now on):
|
||||
rhs[N] = rhs[N]/diag[N];
|
||||
for (int i=N-1;i>=0;--i)
|
||||
rhs[i] = (rhs[i]-lambda[i]*rhs[i+1])/diag[i];
|
||||
|
||||
|
||||
|
||||
|
||||
unsigned int i=1;
|
||||
float y=0.f;
|
||||
for (int x=m_rect.GetLeft(); x<=m_rect.GetRight() ; ++x) {
|
||||
if (splines) {
|
||||
if (i<points.size()-1 && points[i].x < x ) {
|
||||
++i;
|
||||
}
|
||||
if (points[0].x > x)
|
||||
y = points[0].y;
|
||||
else
|
||||
if (points[N].x < x)
|
||||
y = points[N].y;
|
||||
else
|
||||
y = (rhs[i-1]*pow(points[i].x-x,3)+rhs[i]*pow(x-points[i-1].x,3)) / (6*h[i]) +
|
||||
(points[i-1].y-rhs[i-1]*h[i]*h[i]/6.f) * (points[i].x-x)/h[i] +
|
||||
(points[i].y -rhs[i] *h[i]*h[i]/6.f) * (x-points[i-1].x)/h[i];
|
||||
m_line_to_draw.push_back(y);
|
||||
}
|
||||
else {
|
||||
float x_math = screen_to_math(wxPoint(x,0)).m_x;
|
||||
if (i+2<=points.size() && m_buttons[i+1].get_pos().m_x-0.125 < x_math)
|
||||
++i;
|
||||
m_line_to_draw.push_back(math_to_screen(wxPoint2DDouble(x_math,m_buttons[i].get_pos().m_y)).y);
|
||||
}
|
||||
|
||||
|
||||
m_line_to_draw.back() = std::max(m_line_to_draw.back(), m_rect.GetTop()-1);
|
||||
m_line_to_draw.back() = std::min(m_line_to_draw.back(), m_rect.GetBottom()-1);
|
||||
m_total_volume += (m_rect.GetBottom() - m_line_to_draw.back()) * (visible_area.m_width / m_rect.GetWidth()) * (visible_area.m_height / m_rect.GetHeight());
|
||||
}
|
||||
|
||||
wxPostEvent(this->GetParent(), wxCommandEvent(EVT_WIPE_TOWER_CHART_CHANGED));
|
||||
Refresh();
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::vector<float> Chart::get_ramming_speed(float sampling) const {
|
||||
std::vector<float> speeds_out;
|
||||
|
||||
const int number_of_samples = std::round( visible_area.m_width / sampling);
|
||||
if (number_of_samples>0) {
|
||||
const int dx = (m_line_to_draw.size()-1) / number_of_samples;
|
||||
for (int j=0;j<number_of_samples;++j) {
|
||||
float left = screen_to_math(wxPoint(0,m_line_to_draw[j*dx])).m_y;
|
||||
float right = screen_to_math(wxPoint(0,m_line_to_draw[(j+1)*dx])).m_y;
|
||||
speeds_out.push_back((left+right)/2.f);
|
||||
}
|
||||
}
|
||||
return speeds_out;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::pair<float,float>> Chart::get_buttons() const {
|
||||
std::vector<std::pair<float, float>> buttons_out;
|
||||
for (const auto& button : m_buttons)
|
||||
buttons_out.push_back(std::make_pair(button.get_pos().m_x,button.get_pos().m_y));
|
||||
return buttons_out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
BEGIN_EVENT_TABLE(Chart, wxWindow)
|
||||
EVT_MOTION(Chart::mouse_moved)
|
||||
EVT_LEFT_DOWN(Chart::mouse_clicked)
|
||||
EVT_LEFT_UP(Chart::mouse_released)
|
||||
EVT_LEFT_DCLICK(Chart::mouse_double_clicked)
|
||||
EVT_RIGHT_DOWN(Chart::mouse_right_button_clicked)
|
||||
EVT_LEAVE_WINDOW(Chart::mouse_left_window)
|
||||
EVT_PAINT(Chart::paint_event)
|
||||
END_EVENT_TABLE()
|
115
xs/src/slic3r/GUI/RammingChart.hpp
Normal file
115
xs/src/slic3r/GUI/RammingChart.hpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
#ifndef RAMMING_CHART_H_
|
||||
#define RAMMING_CHART_H_
|
||||
|
||||
#include <vector>
|
||||
#include <wx/wxprec.h>
|
||||
#ifndef WX_PRECOMP
|
||||
#include <wx/wx.h>
|
||||
#endif
|
||||
|
||||
wxDECLARE_EVENT(EVT_WIPE_TOWER_CHART_CHANGED, wxCommandEvent);
|
||||
|
||||
|
||||
class Chart : public wxWindow {
|
||||
|
||||
public:
|
||||
Chart(wxWindow* parent, wxRect rect,const std::vector<std::pair<float,float>>& initial_buttons,int ramming_speed_size, float sampling) :
|
||||
wxWindow(parent,wxID_ANY,rect.GetTopLeft(),rect.GetSize())
|
||||
{
|
||||
SetBackgroundStyle(wxBG_STYLE_PAINT);
|
||||
m_rect = wxRect(wxPoint(50,0),rect.GetSize()-wxSize(50,50));
|
||||
visible_area = wxRect2DDouble(0.0, 0.0, sampling*ramming_speed_size, 20.);
|
||||
m_buttons.clear();
|
||||
if (initial_buttons.size()>0)
|
||||
for (const auto& pair : initial_buttons)
|
||||
m_buttons.push_back(wxPoint2DDouble(pair.first,pair.second));
|
||||
recalculate_line();
|
||||
}
|
||||
void set_xy_range(float x,float y) {
|
||||
x = int(x/0.5) * 0.5;
|
||||
if (x>=0) visible_area.SetRight(x);
|
||||
if (y>=0) visible_area.SetBottom(y);
|
||||
recalculate_line();
|
||||
}
|
||||
float get_volume() const { return m_total_volume; }
|
||||
float get_time() const { return visible_area.m_width; }
|
||||
|
||||
std::vector<float> get_ramming_speed(float sampling) const; //returns sampled ramming speed
|
||||
std::vector<std::pair<float,float>> get_buttons() const; // returns buttons position
|
||||
|
||||
void draw();
|
||||
|
||||
void mouse_clicked(wxMouseEvent& event);
|
||||
void mouse_right_button_clicked(wxMouseEvent& event);
|
||||
void mouse_moved(wxMouseEvent& event);
|
||||
void mouse_double_clicked(wxMouseEvent& event);
|
||||
void mouse_left_window(wxMouseEvent&) { m_dragged = nullptr; }
|
||||
void mouse_released(wxMouseEvent&) { m_dragged = nullptr; }
|
||||
void paint_event(wxPaintEvent&) { draw(); }
|
||||
DECLARE_EVENT_TABLE()
|
||||
|
||||
|
||||
|
||||
private:
|
||||
static const bool fixed_x = true;
|
||||
static const bool splines = true;
|
||||
static const bool manual_points_manipulation = false;
|
||||
static const int side = 10; // side of draggable button
|
||||
|
||||
class ButtonToDrag {
|
||||
public:
|
||||
bool operator<(const ButtonToDrag& a) const { return m_pos.m_x < a.m_pos.m_x; }
|
||||
ButtonToDrag(wxPoint2DDouble pos) : m_pos{pos} {};
|
||||
wxPoint2DDouble get_pos() const { return m_pos; }
|
||||
void move(double x,double y) { m_pos.m_x+=x; m_pos.m_y+=y; }
|
||||
private:
|
||||
wxPoint2DDouble m_pos; // position in math coordinates
|
||||
};
|
||||
|
||||
|
||||
|
||||
wxPoint math_to_screen(const wxPoint2DDouble& math) const {
|
||||
wxPoint screen;
|
||||
screen.x = (math.m_x-visible_area.m_x) * (m_rect.GetWidth() / visible_area.m_width );
|
||||
screen.y = (math.m_y-visible_area.m_y) * (m_rect.GetHeight() / visible_area.m_height );
|
||||
screen.y *= -1;
|
||||
screen += m_rect.GetLeftBottom();
|
||||
return screen;
|
||||
}
|
||||
wxPoint2DDouble screen_to_math(const wxPoint& screen) const {
|
||||
wxPoint2DDouble math = screen;
|
||||
math -= m_rect.GetLeftBottom();
|
||||
math.m_y *= -1;
|
||||
math.m_x *= visible_area.m_width / m_rect.GetWidth(); // scales to [0;1]x[0,1]
|
||||
math.m_y *= visible_area.m_height / m_rect.GetHeight();
|
||||
return (math+visible_area.GetLeftTop());
|
||||
}
|
||||
|
||||
int which_button_is_clicked(const wxPoint& point) const {
|
||||
if (!m_rect.Contains(point))
|
||||
return -1;
|
||||
for (unsigned int i=0;i<m_buttons.size();++i) {
|
||||
wxRect rect(math_to_screen(m_buttons[i].get_pos())-wxPoint(side/2.,side/2.),wxSize(side,side)); // bounding rectangle of this button
|
||||
if ( rect.Contains(point) )
|
||||
return i;
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
void recalculate_line();
|
||||
void recalculate_volume();
|
||||
|
||||
|
||||
wxRect m_rect; // rectangle on screen the chart is mapped into (screen coordinates)
|
||||
wxPoint m_previous_mouse;
|
||||
std::vector<ButtonToDrag> m_buttons;
|
||||
std::vector<int> m_line_to_draw;
|
||||
wxRect2DDouble visible_area;
|
||||
ButtonToDrag* m_dragged = nullptr;
|
||||
float m_total_volume = 0.f;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // RAMMING_CHART_H_
|
|
@ -3,9 +3,11 @@
|
|||
#include "PresetBundle.hpp"
|
||||
#include "PresetHints.hpp"
|
||||
#include "../../libslic3r/Utils.hpp"
|
||||
|
||||
#include "slic3r/Utils/Http.hpp"
|
||||
#include "slic3r/Utils/OctoPrint.hpp"
|
||||
#include "BonjourDialog.hpp"
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
||||
#include <wx/app.h>
|
||||
#include <wx/button.h>
|
||||
|
@ -20,6 +22,7 @@
|
|||
#include <wx/filedlg.h>
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include "wxExtensions.hpp"
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
@ -37,7 +40,42 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle)
|
|||
|
||||
// preset chooser
|
||||
m_presets_choice = new wxBitmapComboBox(panel, wxID_ANY, "", wxDefaultPosition, wxSize(270, -1), 0, 0,wxCB_READONLY);
|
||||
/*
|
||||
m_cc_presets_choice = new wxComboCtrl(panel, wxID_ANY, L(""), wxDefaultPosition, wxDefaultSize, wxCB_READONLY);
|
||||
wxDataViewTreeCtrlComboPopup* popup = new wxDataViewTreeCtrlComboPopup;
|
||||
if (popup != nullptr)
|
||||
{
|
||||
// FIXME If the following line is removed, the combo box popup list will not react to mouse clicks.
|
||||
// On the other side, with this line the combo box popup cannot be closed by clicking on the combo button on Windows 10.
|
||||
// m_cc_presets_choice->UseAltPopupWindow();
|
||||
|
||||
// m_cc_presets_choice->EnablePopupAnimation(false);
|
||||
m_cc_presets_choice->SetPopupControl(popup);
|
||||
popup->SetStringValue(from_u8("Text1"));
|
||||
|
||||
popup->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this, popup](wxCommandEvent& evt)
|
||||
{
|
||||
auto selected = popup->GetItemText(popup->GetSelection());
|
||||
if (selected != _(L("System presets")) && selected != _(L("Default presets")))
|
||||
{
|
||||
m_cc_presets_choice->SetText(selected);
|
||||
std::string selected_string = selected.ToUTF8().data();
|
||||
#ifdef __APPLE__
|
||||
#else
|
||||
select_preset(selected_string);
|
||||
#endif
|
||||
}
|
||||
});
|
||||
|
||||
// popup->Bind(wxEVT_KEY_DOWN, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); });
|
||||
// popup->Bind(wxEVT_KEY_UP, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); });
|
||||
|
||||
auto icons = new wxImageList(16, 16, true, 1);
|
||||
popup->SetImageList(icons);
|
||||
icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG));
|
||||
icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG));
|
||||
}
|
||||
*/
|
||||
auto color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
|
||||
|
||||
//buttons
|
||||
|
@ -82,11 +120,44 @@ void Tab::create_preset_tab(PresetBundle *preset_bundle)
|
|||
m_hsizer->AddSpacer(64);
|
||||
m_hsizer->Add(m_undo_to_sys_btn, 0, wxALIGN_CENTER_VERTICAL);
|
||||
m_hsizer->Add(m_undo_btn, 0, wxALIGN_CENTER_VERTICAL);
|
||||
// m_hsizer->AddSpacer(64);
|
||||
// m_hsizer->Add(m_cc_presets_choice, 1, wxLEFT | wxRIGHT | wxTOP | wxALIGN_CENTER_VERTICAL, 3);
|
||||
|
||||
//Horizontal sizer to hold the tree and the selected page.
|
||||
m_hsizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(m_hsizer, 1, wxEXPAND, 0);
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
//temporary left vertical sizer
|
||||
m_left_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_hsizer->Add(m_left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 3);
|
||||
|
||||
// tree
|
||||
m_presetctrl = new wxDataViewTreeCtrl(panel, wxID_ANY, wxDefaultPosition, wxSize(200, -1), wxDV_NO_HEADER);
|
||||
m_left_sizer->Add(m_presetctrl, 1, wxEXPAND);
|
||||
m_preset_icons = new wxImageList(16, 16, true, 1);
|
||||
m_presetctrl->SetImageList(m_preset_icons);
|
||||
m_preset_icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-green-icon.png")), wxBITMAP_TYPE_PNG));
|
||||
m_preset_icons->Add(*new wxIcon(from_u8(Slic3r::var("flag-red-icon.png")), wxBITMAP_TYPE_PNG));
|
||||
|
||||
m_presetctrl->Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxCommandEvent& evt)
|
||||
{
|
||||
auto selected = m_presetctrl->GetItemText(m_presetctrl->GetSelection());
|
||||
if (selected != _(L("System presets")) && selected != _(L("Default presets")))
|
||||
{
|
||||
std::string selected_string = selected.ToUTF8().data();
|
||||
#ifdef __APPLE__
|
||||
#else
|
||||
select_preset(selected_string);
|
||||
#endif
|
||||
}
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
//left vertical sizer
|
||||
m_left_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_hsizer->Add(m_left_sizer, 0, wxEXPAND | wxLEFT | wxTOP | wxBOTTOM, 3);
|
||||
|
@ -134,11 +205,10 @@ void Tab::load_initial_data()
|
|||
{
|
||||
m_config = &m_presets->get_edited_preset().config;
|
||||
m_nonsys_btn_icon = m_presets->get_selected_preset_parent() == nullptr ?
|
||||
"bullet_white.png" :
|
||||
wxMSW ? "sys_unlock.png" : "lock_open.png";
|
||||
"bullet_white.png" : "sys_unlock.png";
|
||||
}
|
||||
|
||||
PageShp Tab::add_options_page(wxString title, std::string icon, bool is_extruder_pages/* = false*/)
|
||||
PageShp Tab::add_options_page(const wxString& title, const std::string& icon, bool is_extruder_pages/* = false*/)
|
||||
{
|
||||
// Index of icon in an icon list $self->{icons}.
|
||||
auto icon_idx = 0;
|
||||
|
@ -258,27 +328,36 @@ void Tab::update_changed_ui()
|
|||
m_dirty_options = dirty_options;
|
||||
}
|
||||
|
||||
Freeze();
|
||||
//update options "decoration"
|
||||
for (const auto opt_key : m_full_options_list)
|
||||
{
|
||||
bool is_nonsys_value = false;
|
||||
bool is_modified_value = true;
|
||||
std::string sys_icon = wxMSW ? "sys_lock.png" : "lock.png";
|
||||
std::string icon = wxMSW ? "action_undo.png" : "arrow_undo.png";
|
||||
wxColour& color = *get_sys_label_clr();
|
||||
std::string sys_icon = "sys_lock.png";
|
||||
std::string icon = "action_undo.png";
|
||||
wxColour color = get_sys_label_clr();
|
||||
if (find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end()) {
|
||||
is_nonsys_value = true;
|
||||
sys_icon = m_nonsys_btn_icon;
|
||||
if(find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) == m_dirty_options.end())
|
||||
color = wxSYS_COLOUR_WINDOWTEXT;
|
||||
color = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
|
||||
else
|
||||
color = *get_modified_label_clr();
|
||||
color = get_modified_label_clr();
|
||||
}
|
||||
if (find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) == m_dirty_options.end())
|
||||
{
|
||||
is_modified_value = false;
|
||||
icon = "bullet_white.png";
|
||||
}
|
||||
if (opt_key == "bed_shape" || opt_key == "compatible_printers") {
|
||||
if (m_colored_Label != nullptr) {
|
||||
m_colored_Label->SetForegroundColour(color);
|
||||
m_colored_Label->Refresh(true);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Field* field = get_field(opt_key);
|
||||
if (field == nullptr) continue;
|
||||
field->m_is_nonsys_value = is_nonsys_value;
|
||||
|
@ -290,6 +369,7 @@ void Tab::update_changed_ui()
|
|||
field->m_Label->Refresh(true);
|
||||
}
|
||||
}
|
||||
Thaw();
|
||||
|
||||
wxTheApp->CallAfter([this]() {
|
||||
update_changed_tree_ui();
|
||||
|
@ -343,7 +423,7 @@ void Tab::update_sys_ui_after_sel_preset()
|
|||
field->m_Undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var(m_nonsys_btn_icon)), wxBITMAP_TYPE_PNG));
|
||||
field->m_is_nonsys_value = true;
|
||||
if (field->m_Label != nullptr){
|
||||
field->m_Label->SetForegroundColour(wxSYS_COLOUR_WINDOWTEXT);
|
||||
field->m_Label->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
field->m_Label->Refresh(true);
|
||||
}
|
||||
}
|
||||
|
@ -351,13 +431,20 @@ void Tab::update_sys_ui_after_sel_preset()
|
|||
m_sys_options.resize(0);
|
||||
}
|
||||
|
||||
void Tab::get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool& modified_page)
|
||||
{
|
||||
if (sys_page && find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end())
|
||||
sys_page = false;
|
||||
if (!modified_page && find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) != m_dirty_options.end())
|
||||
modified_page = true;
|
||||
}
|
||||
|
||||
void Tab::update_changed_tree_ui()
|
||||
{
|
||||
auto cur_item = m_treectrl->GetFirstVisibleItem();
|
||||
auto selection = m_treectrl->GetItemText(m_treectrl->GetSelection());
|
||||
while (cur_item){
|
||||
auto title = m_treectrl->GetItemText(cur_item);
|
||||
int i=0;
|
||||
for (auto page : m_pages)
|
||||
{
|
||||
if (page->title() != title)
|
||||
|
@ -367,30 +454,27 @@ void Tab::update_changed_tree_ui()
|
|||
if (title == _("General")){
|
||||
std::initializer_list<const char*> optional_keys{ "extruders_count", "bed_shape" };
|
||||
for (auto &opt_key : optional_keys) {
|
||||
if (sys_page && find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end())
|
||||
sys_page = false;
|
||||
if (!modified_page && find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) != m_dirty_options.end())
|
||||
modified_page = true;
|
||||
get_sys_and_mod_flags(opt_key, sys_page, modified_page);
|
||||
}
|
||||
}
|
||||
if (title == _("Dependencies")){
|
||||
get_sys_and_mod_flags("compatible_printers", sys_page, modified_page);
|
||||
}
|
||||
for (auto group : page->m_optgroups)
|
||||
{
|
||||
for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) {
|
||||
const std::string& opt_key = it->first;
|
||||
if (sys_page && find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end())
|
||||
sys_page = false;
|
||||
if (!modified_page && find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) != m_dirty_options.end())
|
||||
modified_page = true;
|
||||
}
|
||||
if (!sys_page && modified_page)
|
||||
break;
|
||||
for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) {
|
||||
const std::string& opt_key = it->first;
|
||||
get_sys_and_mod_flags(opt_key, sys_page, modified_page);
|
||||
}
|
||||
}
|
||||
if (sys_page)
|
||||
m_treectrl->SetItemTextColour(cur_item, *get_sys_label_clr());
|
||||
m_treectrl->SetItemTextColour(cur_item, get_sys_label_clr());
|
||||
else if (modified_page)
|
||||
m_treectrl->SetItemTextColour(cur_item, *get_modified_label_clr());
|
||||
m_treectrl->SetItemTextColour(cur_item, get_modified_label_clr());
|
||||
else
|
||||
m_treectrl->SetItemTextColour(cur_item, wxSYS_COLOUR_WINDOWTEXT);
|
||||
m_treectrl->SetItemTextColour(cur_item, wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT));
|
||||
|
||||
page->m_is_nonsys_values = !sys_page;
|
||||
page->m_is_modified_values = modified_page;
|
||||
|
@ -409,10 +493,8 @@ void Tab::update_changed_tree_ui()
|
|||
|
||||
void Tab::update_undo_buttons()
|
||||
{
|
||||
const std::string& undo_icon = !m_is_modified_values ? "bullet_white.png" :
|
||||
wxMSW ? "action_undo.png" : "arrow_undo.png";
|
||||
const std::string& undo_to_sys_icon = m_is_nonsys_values ? m_nonsys_btn_icon :
|
||||
wxMSW ? "sys_lock.png" : "lock.png";
|
||||
const std::string& undo_icon = !m_is_modified_values ? "bullet_white.png" : "action_undo.png";
|
||||
const std::string& undo_to_sys_icon = m_is_nonsys_values ? m_nonsys_btn_icon : "sys_lock.png";
|
||||
|
||||
m_undo_btn->SetBitmap(wxBitmap(from_u8(var(undo_icon)), wxBITMAP_TYPE_PNG));
|
||||
m_undo_to_sys_btn->SetBitmap(wxBitmap(from_u8(var(undo_to_sys_icon)), wxBITMAP_TYPE_PNG));
|
||||
|
@ -434,6 +516,14 @@ void Tab::on_back_to_initial_value()
|
|||
if (find(m_dirty_options.begin(), m_dirty_options.end(), "bed_shape") != m_dirty_options.end())
|
||||
group->back_to_initial_value("bed_shape");
|
||||
}
|
||||
if (group->title == _("Profile dependencies")){
|
||||
if (find(m_dirty_options.begin(), m_dirty_options.end(), "compatible_printers") != m_dirty_options.end())
|
||||
group->back_to_initial_value("compatible_printers");
|
||||
|
||||
bool is_empty = m_config->option<ConfigOptionStrings>("compatible_printers")->values.empty();
|
||||
m_compatible_printers_checkbox->SetValue(is_empty);
|
||||
is_empty ? m_compatible_printers_btn->Disable() : m_compatible_printers_btn->Enable();
|
||||
}
|
||||
for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) {
|
||||
const std::string& opt_key = it->first;
|
||||
if (find(m_dirty_options.begin(), m_dirty_options.end(), opt_key) != m_dirty_options.end())
|
||||
|
@ -461,6 +551,14 @@ void Tab::on_back_to_sys_value()
|
|||
if (find(m_sys_options.begin(), m_sys_options.end(), "bed_shape") == m_sys_options.end())
|
||||
group->back_to_sys_value("bed_shape");
|
||||
}
|
||||
if (group->title == _("Profile dependencies")){
|
||||
if (find(m_sys_options.begin(), m_sys_options.end(), "compatible_printers") == m_sys_options.end())
|
||||
group->back_to_sys_value("compatible_printers");
|
||||
|
||||
bool is_empty = m_config->option<ConfigOptionStrings>("compatible_printers")->values.empty();
|
||||
m_compatible_printers_checkbox->SetValue(is_empty);
|
||||
is_empty ? m_compatible_printers_btn->Disable() : m_compatible_printers_btn->Enable();
|
||||
}
|
||||
for (t_opt_map::iterator it = group->m_opt_map.begin(); it != group->m_opt_map.end(); ++it) {
|
||||
const std::string& opt_key = it->first;
|
||||
if (find(m_sys_options.begin(), m_sys_options.end(), opt_key) == m_sys_options.end())
|
||||
|
@ -478,16 +576,19 @@ void Tab::update_dirty(){
|
|||
m_presets->update_dirty_ui(m_presets_choice);
|
||||
on_presets_changed();
|
||||
update_changed_ui();
|
||||
// update_dirty_presets(m_cc_presets_choice);
|
||||
}
|
||||
|
||||
void Tab::update_tab_ui()
|
||||
{
|
||||
m_presets->update_tab_ui(m_presets_choice, m_show_incompatible_presets);
|
||||
// update_tab_presets(m_cc_presets_choice, m_show_incompatible_presets);
|
||||
// update_presetsctrl(m_presetctrl, m_show_incompatible_presets);
|
||||
}
|
||||
|
||||
// Load a provied DynamicConfig into the tab, modifying the active preset.
|
||||
// This could be used for example by setting a Wipe Tower position by interactive manipulation in the 3D view.
|
||||
void Tab::load_config(DynamicPrintConfig config)
|
||||
void Tab::load_config(const DynamicPrintConfig& config)
|
||||
{
|
||||
bool modified = 0;
|
||||
for(auto opt_key : m_config->diff(config)) {
|
||||
|
@ -510,7 +611,7 @@ void Tab::reload_config(){
|
|||
Thaw();
|
||||
}
|
||||
|
||||
Field* Tab::get_field(t_config_option_key opt_key, int opt_index/* = -1*/) const
|
||||
Field* Tab::get_field(const t_config_option_key& opt_key, int opt_index/* = -1*/) const
|
||||
{
|
||||
Field* field = nullptr;
|
||||
for (auto page : m_pages){
|
||||
|
@ -524,7 +625,7 @@ Field* Tab::get_field(t_config_option_key opt_key, int opt_index/* = -1*/) const
|
|||
// Set a key/value pair on this page. Return true if the value has been modified.
|
||||
// Currently used for distributing extruders_count over preset pages of Slic3r::GUI::Tab::Printer
|
||||
// after a preset is loaded.
|
||||
bool Tab::set_value(t_config_option_key opt_key, boost::any value){
|
||||
bool Tab::set_value(const t_config_option_key& opt_key, const boost::any& value){
|
||||
bool changed = false;
|
||||
for(auto page: m_pages) {
|
||||
if (page->set_value(opt_key, value))
|
||||
|
@ -535,7 +636,7 @@ bool Tab::set_value(t_config_option_key opt_key, boost::any value){
|
|||
|
||||
// To be called by custom widgets, load a value into a config,
|
||||
// update the preset selection boxes (the dirty flags)
|
||||
void Tab::load_key_value(std::string opt_key, boost::any value)
|
||||
void Tab::load_key_value(const std::string& opt_key, const boost::any& value)
|
||||
{
|
||||
change_opt_value(*m_config, opt_key, value);
|
||||
// Mark the print & filament enabled if they are compatible with the currently selected preset.
|
||||
|
@ -550,7 +651,7 @@ void Tab::load_key_value(std::string opt_key, boost::any value)
|
|||
|
||||
extern wxFrame *g_wxMainFrame;
|
||||
|
||||
void Tab::on_value_change(std::string opt_key, boost::any value)
|
||||
void Tab::on_value_change(const std::string& opt_key, const boost::any& value)
|
||||
{
|
||||
if (m_event_value_change > 0) {
|
||||
wxCommandEvent event(m_event_value_change);
|
||||
|
@ -565,8 +666,8 @@ void Tab::on_value_change(std::string opt_key, boost::any value)
|
|||
}
|
||||
if (opt_key == "fill_density")
|
||||
{
|
||||
value = get_optgroup()->get_config_value(*m_config, opt_key);
|
||||
get_optgroup()->set_value(opt_key, value);
|
||||
boost::any val = get_optgroup()->get_config_value(*m_config, opt_key);
|
||||
get_optgroup()->set_value(opt_key, val);
|
||||
}
|
||||
if (opt_key == "support_material" || opt_key == "support_material_buildplate_only")
|
||||
{
|
||||
|
@ -583,10 +684,27 @@ void Tab::on_value_change(std::string opt_key, boost::any value)
|
|||
get_optgroup()->set_value("brim", val);
|
||||
}
|
||||
|
||||
|
||||
if (opt_key == "wipe_tower" || opt_key == "single_extruder_multi_material" || opt_key == "extruders_count" )
|
||||
update_wiping_button_visibility();
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
// Show/hide the 'purging volumes' button
|
||||
void Tab::update_wiping_button_visibility() {
|
||||
bool wipe_tower_enabled = dynamic_cast<ConfigOptionBool*>( (m_preset_bundle->prints.get_edited_preset().config ).option("wipe_tower"))->value;
|
||||
bool multiple_extruders = dynamic_cast<ConfigOptionFloats*>((m_preset_bundle->printers.get_edited_preset().config).option("nozzle_diameter"))->values.size() > 1;
|
||||
bool single_extruder_mm = dynamic_cast<ConfigOptionBool*>( (m_preset_bundle->printers.get_edited_preset().config).option("single_extruder_multi_material"))->value;
|
||||
|
||||
if (wipe_tower_enabled && multiple_extruders && single_extruder_mm)
|
||||
get_wiping_dialog_button()->Show();
|
||||
else get_wiping_dialog_button()->Hide();
|
||||
|
||||
(get_wiping_dialog_button()->GetParent())->Layout();
|
||||
}
|
||||
|
||||
|
||||
// Call a callback to update the selection of presets on the platter:
|
||||
// To update the content of the selection boxes,
|
||||
// to update the filament colors of the selection boxes,
|
||||
|
@ -622,6 +740,8 @@ void Tab::update_frequently_changed_parameters()
|
|||
|
||||
bool val = m_config->opt_float("brim_width") > 0.0 ? true : false;
|
||||
get_optgroup()->set_value("brim", val);
|
||||
|
||||
update_wiping_button_visibility();
|
||||
}
|
||||
|
||||
void Tab::reload_compatible_printers_widget()
|
||||
|
@ -771,7 +891,8 @@ void TabPrint::build()
|
|||
optgroup->append_single_option_line("wipe_tower_x");
|
||||
optgroup->append_single_option_line("wipe_tower_y");
|
||||
optgroup->append_single_option_line("wipe_tower_width");
|
||||
optgroup->append_single_option_line("wipe_tower_per_color_wipe");
|
||||
optgroup->append_single_option_line("wipe_tower_rotation_angle");
|
||||
optgroup->append_single_option_line("wipe_tower_bridging");
|
||||
|
||||
optgroup = page->new_optgroup(_(L("Advanced")));
|
||||
optgroup->append_single_option_line("interface_shells");
|
||||
|
@ -837,7 +958,7 @@ void TabPrint::build()
|
|||
line.widget = [this](wxWindow* parent){
|
||||
return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn);
|
||||
};
|
||||
optgroup->append_line(line);
|
||||
optgroup->append_line(line, &m_colored_Label);
|
||||
|
||||
option = optgroup->get_option("compatible_printers_condition");
|
||||
option.opt.full_width = true;
|
||||
|
@ -1016,53 +1137,40 @@ void TabPrint::update()
|
|||
}
|
||||
|
||||
bool have_perimeters = m_config->opt_int("perimeters") > 0;
|
||||
std::vector<std::string> vec_enable = { "extra_perimeters", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
|
||||
"seam_position", "external_perimeters_first", "external_perimeter_extrusion_width",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"extra_perimeters", "ensure_vertical_shell_thickness", "thin_walls", "overhangs",
|
||||
"seam_position", "external_perimeters_first", "external_perimeter_extrusion_width",
|
||||
"perimeter_speed", "small_perimeter_speed", "external_perimeter_speed" })
|
||||
get_field(el)->toggle(have_perimeters);
|
||||
|
||||
bool have_infill = m_config->option<ConfigOptionPercent>("fill_density")->value > 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "fill_pattern", "infill_every_layers", "infill_only_where_needed",
|
||||
"solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" };
|
||||
// infill_extruder uses the same logic as in Print::extruders()
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"fill_pattern", "infill_every_layers", "infill_only_where_needed",
|
||||
"solid_infill_every_layers", "solid_infill_below_area", "infill_extruder" })
|
||||
get_field(el)->toggle(have_infill);
|
||||
|
||||
bool have_solid_infill = m_config->opt_int("top_solid_layers") > 0 || m_config->opt_int("bottom_solid_layers") > 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "external_fill_pattern", "infill_first", "solid_infill_extruder",
|
||||
"solid_infill_extrusion_width", "solid_infill_speed" };
|
||||
// solid_infill_extruder uses the same logic as in Print::extruders()
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"external_fill_pattern", "infill_first", "solid_infill_extruder",
|
||||
"solid_infill_extrusion_width", "solid_infill_speed" })
|
||||
get_field(el)->toggle(have_solid_infill);
|
||||
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "fill_angle", "bridge_angle", "infill_extrusion_width",
|
||||
"infill_speed", "bridge_speed" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"fill_angle", "bridge_angle", "infill_extrusion_width",
|
||||
"infill_speed", "bridge_speed" })
|
||||
get_field(el)->toggle(have_infill || have_solid_infill);
|
||||
|
||||
get_field("gap_fill_speed")->toggle(have_perimeters && have_infill);
|
||||
|
||||
bool have_top_solid_infill = m_config->opt_int("top_solid_layers") > 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "top_infill_extrusion_width", "top_solid_infill_speed" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "top_infill_extrusion_width", "top_solid_infill_speed" })
|
||||
get_field(el)->toggle(have_top_solid_infill);
|
||||
|
||||
bool have_default_acceleration = m_config->opt_float("default_acceleration") > 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "perimeter_acceleration", "infill_acceleration",
|
||||
"bridge_acceleration", "first_layer_acceleration" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"perimeter_acceleration", "infill_acceleration",
|
||||
"bridge_acceleration", "first_layer_acceleration" })
|
||||
get_field(el)->toggle(have_default_acceleration);
|
||||
|
||||
bool have_skirt = m_config->opt_int("skirts") > 0 || m_config->opt_float("min_skirt_length") > 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "skirt_distance", "skirt_height" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "skirt_distance", "skirt_height" })
|
||||
get_field(el)->toggle(have_skirt);
|
||||
|
||||
bool have_brim = m_config->opt_float("brim_width") > 0;
|
||||
|
@ -1073,18 +1181,14 @@ void TabPrint::update()
|
|||
bool have_support_material = m_config->opt_bool("support_material") || have_raft;
|
||||
bool have_support_interface = m_config->opt_int("support_material_interface_layers") > 0;
|
||||
bool have_support_soluble = have_support_material && m_config->opt_float("support_material_contact_distance") == 0;
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "support_material_threshold", "support_material_pattern", "support_material_with_sheath",
|
||||
for (auto el : {"support_material_threshold", "support_material_pattern", "support_material_with_sheath",
|
||||
"support_material_spacing", "support_material_angle", "support_material_interface_layers",
|
||||
"dont_support_bridges", "support_material_extrusion_width", "support_material_contact_distance",
|
||||
"support_material_xy_spacing" };
|
||||
for (auto el : vec_enable)
|
||||
"support_material_xy_spacing" })
|
||||
get_field(el)->toggle(have_support_material);
|
||||
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "support_material_interface_spacing", "support_material_interface_extruder",
|
||||
"support_material_interface_speed", "support_material_interface_contact_loops" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : {"support_material_interface_spacing", "support_material_interface_extruder",
|
||||
"support_material_interface_speed", "support_material_interface_contact_loops" })
|
||||
get_field(el)->toggle(have_support_material && have_support_interface);
|
||||
get_field("support_material_synchronize_layers")->toggle(have_support_soluble);
|
||||
|
||||
|
@ -1093,18 +1197,14 @@ void TabPrint::update()
|
|||
get_field("support_material_speed")->toggle(have_support_material || have_brim || have_skirt);
|
||||
|
||||
bool have_sequential_printing = m_config->opt_bool("complete_objects");
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "extruder_clearance_radius", "extruder_clearance_height" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "extruder_clearance_radius", "extruder_clearance_height" })
|
||||
get_field(el)->toggle(have_sequential_printing);
|
||||
|
||||
bool have_ooze_prevention = m_config->opt_bool("ooze_prevention");
|
||||
get_field("standby_temperature_delta")->toggle(have_ooze_prevention);
|
||||
|
||||
bool have_wipe_tower = m_config->opt_bool("wipe_tower");
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_per_color_wipe" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_rotation_angle", "wipe_tower_bridging"})
|
||||
get_field(el)->toggle(have_wipe_tower);
|
||||
|
||||
m_recommended_thin_wall_thickness_description_line->SetText(
|
||||
|
@ -1184,7 +1284,29 @@ void TabFilament::build()
|
|||
};
|
||||
optgroup->append_line(line);
|
||||
|
||||
page = add_options_page(_(L("Custom G-code")), "cog.png");
|
||||
optgroup = page->new_optgroup(_(L("Toolchange behaviour")));
|
||||
optgroup->append_single_option_line("filament_loading_speed");
|
||||
optgroup->append_single_option_line("filament_unloading_speed");
|
||||
optgroup->append_single_option_line("filament_toolchange_delay");
|
||||
optgroup->append_single_option_line("filament_cooling_time");
|
||||
line = { _(L("Ramming")), "" };
|
||||
line.widget = [this](wxWindow* parent){
|
||||
auto ramming_dialog_btn = new wxButton(parent, wxID_ANY, _(L("Ramming settings"))+"\u2026", wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(ramming_dialog_btn);
|
||||
|
||||
ramming_dialog_btn->Bind(wxEVT_BUTTON, ([this](wxCommandEvent& e)
|
||||
{
|
||||
RammingDialog dlg(this,(m_config->option<ConfigOptionStrings>("filament_ramming_parameters"))->get_at(0));
|
||||
if (dlg.ShowModal() == wxID_OK)
|
||||
(m_config->option<ConfigOptionStrings>("filament_ramming_parameters"))->get_at(0) = dlg.get_parameters();
|
||||
}));
|
||||
return sizer;
|
||||
};
|
||||
optgroup->append_line(line);
|
||||
|
||||
|
||||
page = add_options_page(_(L("Custom G-code")), "cog.png");
|
||||
optgroup = page->new_optgroup(_(L("Start G-code")), 0);
|
||||
Option option = optgroup->get_option("start_filament_gcode");
|
||||
option.opt.full_width = true;
|
||||
|
@ -1211,7 +1333,7 @@ void TabFilament::build()
|
|||
line.widget = [this](wxWindow* parent){
|
||||
return compatible_printers_widget(parent, &m_compatible_printers_checkbox, &m_compatible_printers_btn);
|
||||
};
|
||||
optgroup->append_line(line);
|
||||
optgroup->append_line(line, &m_colored_Label);
|
||||
|
||||
option = optgroup->get_option("compatible_printers_condition");
|
||||
option.opt.full_width = true;
|
||||
|
@ -1241,13 +1363,10 @@ void TabFilament::update()
|
|||
bool cooling = m_config->opt_bool("cooling", 0);
|
||||
bool fan_always_on = cooling || m_config->opt_bool("fan_always_on", 0);
|
||||
|
||||
std::vector<std::string> vec_enable = { "max_fan_speed", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "max_fan_speed", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed" })
|
||||
get_field(el)->toggle(cooling);
|
||||
|
||||
vec_enable.resize(0);
|
||||
vec_enable = { "min_fan_speed", "disable_fan_first_layers" };
|
||||
for (auto el : vec_enable)
|
||||
for (auto el : { "min_fan_speed", "disable_fan_first_layers" })
|
||||
get_field(el)->toggle(fan_always_on);
|
||||
}
|
||||
|
||||
|
@ -1308,7 +1427,7 @@ void TabPrinter::build()
|
|||
|
||||
return sizer;
|
||||
};
|
||||
optgroup->append_line(line);
|
||||
optgroup->append_line(line, &m_colored_Label);
|
||||
optgroup->append_single_option_line("max_print_height");
|
||||
optgroup->append_single_option_line("z_offset");
|
||||
|
||||
|
@ -1326,9 +1445,11 @@ void TabPrinter::build()
|
|||
optgroup->m_on_change = [this, optgroup](t_config_option_key opt_key, boost::any value){
|
||||
size_t extruders_count = boost::any_cast<int>(optgroup->get_value("extruders_count"));
|
||||
wxTheApp->CallAfter([this, opt_key, value, extruders_count](){
|
||||
if (opt_key.compare("extruders_count")==0) {
|
||||
if (opt_key.compare("extruders_count")==0 || opt_key.compare("single_extruder_multi_material")==0) {
|
||||
extruders_count_changed(extruders_count);
|
||||
update_dirty();
|
||||
if (opt_key.compare("single_extruder_multi_material")==0) // the single_extruder_multimaterial was added to force pages
|
||||
on_value_change(opt_key, value); // rebuild - let's make sure the on_value_change is not skipped
|
||||
}
|
||||
else {
|
||||
update_dirty();
|
||||
|
@ -1337,6 +1458,7 @@ void TabPrinter::build()
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
if (!m_no_controller)
|
||||
{
|
||||
optgroup = page->new_optgroup(_(L("USB/Serial connection")));
|
||||
|
@ -1607,6 +1729,25 @@ void TabPrinter::build_extruder_pages(){
|
|||
for (auto page_extruder : m_extruder_pages)
|
||||
m_pages.push_back(page_extruder);
|
||||
m_pages.push_back(page_note);
|
||||
|
||||
{
|
||||
// if we have a single extruder MM setup, add a page with configuration options:
|
||||
for (int i=0;i<m_pages.size();++i) // first make sure it's not there already
|
||||
if (m_pages[i]->title().find(_(L("Single extruder MM setup"))) != std::string::npos) {
|
||||
m_pages.erase(m_pages.begin()+i);
|
||||
break;
|
||||
}
|
||||
if ( m_extruder_pages.size()>1 && m_config->opt_bool("single_extruder_multi_material")) {
|
||||
// create a page, but pretend it's an extruder page, so we can add it to m_pages ourselves
|
||||
auto page = add_options_page(_(L("Single extruder MM setup")), "printer_empty.png",true);
|
||||
auto optgroup = page->new_optgroup(_(L("Single extruder multimaterial parameters")));
|
||||
optgroup->append_single_option_line("cooling_tube_retraction");
|
||||
optgroup->append_single_option_line("cooling_tube_length");
|
||||
optgroup->append_single_option_line("parking_pos_retraction");
|
||||
m_pages.insert(m_pages.begin()+1,page);
|
||||
}
|
||||
}
|
||||
|
||||
rebuild_page_tree();
|
||||
}
|
||||
|
||||
|
@ -1714,9 +1855,7 @@ void Tab::load_current_preset()
|
|||
// Reload preset pages with the new configuration values.
|
||||
reload_config();
|
||||
const Preset* parent = m_presets->get_selected_preset_parent();
|
||||
m_nonsys_btn_icon = parent == nullptr ?
|
||||
"bullet_white.png" :
|
||||
wxMSW ? "sys_unlock.png" : "lock_open.png";
|
||||
m_nonsys_btn_icon = parent == nullptr ? "bullet_white.png" : "sys_unlock.png";
|
||||
|
||||
// use CallAfter because some field triggers schedule on_change calls using CallAfter,
|
||||
// and we don't want them to be called after this update_dirty() as they would mark the
|
||||
|
@ -1773,7 +1912,7 @@ void Tab::rebuild_page_tree()
|
|||
// Called by the UI combo box when the user switches profiles.
|
||||
// Select a preset by a name.If !defined(name), then the default preset is selected.
|
||||
// If the current profile is modified, user is asked to save the changes.
|
||||
void Tab::select_preset(const std::string &preset_name /*= ""*/)
|
||||
void Tab::select_preset(const std::string& preset_name /*= ""*/)
|
||||
{
|
||||
std::string name = preset_name;
|
||||
auto force = false;
|
||||
|
@ -1840,7 +1979,7 @@ void Tab::select_preset(const std::string &preset_name /*= ""*/)
|
|||
|
||||
// If the current preset is dirty, the user is asked whether the changes may be discarded.
|
||||
// if the current preset was not dirty, or the user agreed to discard the changes, 1 is returned.
|
||||
bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr*/, std::string new_printer_name /*= ""*/)
|
||||
bool Tab::may_discard_current_dirty_preset(PresetCollection* presets /*= nullptr*/, const std::string& new_printer_name /*= ""*/)
|
||||
{
|
||||
if (presets == nullptr) presets = m_presets;
|
||||
// Display a dialog showing the dirty options in a human readable form.
|
||||
|
@ -2048,6 +2187,7 @@ wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox
|
|||
if ((*checkbox)->GetValue())
|
||||
load_key_value("compatible_printers", std::vector<std::string> {});
|
||||
get_field("compatible_printers_condition")->toggle((*checkbox)->GetValue());
|
||||
update_changed_ui();
|
||||
}) );
|
||||
|
||||
(*btn)->Bind(wxEVT_BUTTON, ([this, parent, checkbox, btn](wxCommandEvent e)
|
||||
|
@ -2090,18 +2230,186 @@ wxSizer* Tab::compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox
|
|||
}
|
||||
// All printers have been made compatible with this preset.
|
||||
load_key_value("compatible_printers", value);
|
||||
update_changed_ui();
|
||||
}
|
||||
}));
|
||||
return sizer;
|
||||
}
|
||||
|
||||
void Tab::update_presetsctrl(wxDataViewTreeCtrl* ui, bool show_incompatible)
|
||||
{
|
||||
if (ui == nullptr)
|
||||
return;
|
||||
ui->Freeze();
|
||||
ui->DeleteAllItems();
|
||||
auto presets = m_presets->get_presets();
|
||||
auto idx_selected = m_presets->get_idx_selected();
|
||||
auto suffix_modified = m_presets->get_suffix_modified();
|
||||
int icon_compatible = 0;
|
||||
int icon_incompatible = 1;
|
||||
int cnt_items = 0;
|
||||
|
||||
auto root_sys = ui->AppendContainer(wxDataViewItem(0), _(L("System presets")));
|
||||
auto root_def = ui->AppendContainer(wxDataViewItem(0), _(L("Default presets")));
|
||||
|
||||
auto show_def = get_app_config()->get("no_defaults")[0] != '1';
|
||||
|
||||
for (size_t i = presets.front().is_visible ? 0 : 1; i < presets.size(); ++i) {
|
||||
const Preset &preset = presets[i];
|
||||
if (!preset.is_visible || (!show_incompatible && !preset.is_compatible && i != idx_selected))
|
||||
continue;
|
||||
|
||||
auto preset_name = wxString::FromUTF8((preset.name + (preset.is_dirty ? suffix_modified : "")).c_str());
|
||||
|
||||
wxDataViewItem item;
|
||||
if (preset.is_system)
|
||||
item = ui->AppendItem(root_sys, preset_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
else if (show_def && preset.is_default)
|
||||
item = ui->AppendItem(root_def, preset_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
else
|
||||
{
|
||||
auto parent = m_presets->get_preset_parent(preset);
|
||||
if (parent == nullptr)
|
||||
item = ui->AppendItem(root_def, preset_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
else
|
||||
{
|
||||
auto parent_name = parent->name;
|
||||
|
||||
wxDataViewTreeStoreContainerNode *node = ui->GetStore()->FindContainerNode(root_sys);
|
||||
if (node)
|
||||
{
|
||||
wxDataViewTreeStoreNodeList::iterator iter;
|
||||
for (iter = node->GetChildren().begin(); iter != node->GetChildren().end(); iter++)
|
||||
{
|
||||
wxDataViewTreeStoreNode* child = *iter;
|
||||
auto child_item = child->GetItem();
|
||||
auto item_text = ui->GetItemText(child_item);
|
||||
if (item_text == parent_name)
|
||||
{
|
||||
auto added_child = ui->AppendItem(child->GetItem(), preset_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
if (!added_child){
|
||||
ui->DeleteItem(child->GetItem());
|
||||
auto new_parent = ui->AppendContainer(root_sys, parent_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
ui->AppendItem(new_parent, preset_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cnt_items++;
|
||||
if (i == idx_selected){
|
||||
ui->Select(item);
|
||||
m_cc_presets_choice->SetText(preset_name);
|
||||
}
|
||||
}
|
||||
if (ui->GetStore()->GetChildCount(root_def) == 0)
|
||||
ui->DeleteItem(root_def);
|
||||
|
||||
ui->Thaw();
|
||||
}
|
||||
|
||||
void Tab::update_tab_presets(wxComboCtrl* ui, bool show_incompatible)
|
||||
{
|
||||
if (ui == nullptr)
|
||||
return;
|
||||
ui->Freeze();
|
||||
ui->Clear();
|
||||
auto presets = m_presets->get_presets();
|
||||
auto idx_selected = m_presets->get_idx_selected();
|
||||
auto suffix_modified = m_presets->get_suffix_modified();
|
||||
int icon_compatible = 0;
|
||||
int icon_incompatible = 1;
|
||||
int cnt_items = 0;
|
||||
|
||||
wxDataViewTreeCtrlComboPopup* popup = wxDynamicCast(m_cc_presets_choice->GetPopupControl(), wxDataViewTreeCtrlComboPopup);
|
||||
if (popup != nullptr)
|
||||
{
|
||||
popup->DeleteAllItems();
|
||||
|
||||
auto root_sys = popup->AppendContainer(wxDataViewItem(0), _(L("System presets")));
|
||||
auto root_def = popup->AppendContainer(wxDataViewItem(0), _(L("Default presets")));
|
||||
|
||||
auto show_def = get_app_config()->get("no_defaults")[0] != '1';
|
||||
|
||||
for (size_t i = presets.front().is_visible ? 0 : 1; i < presets.size(); ++i) {
|
||||
const Preset &preset = presets[i];
|
||||
if (!preset.is_visible || (!show_incompatible && !preset.is_compatible && i != idx_selected))
|
||||
continue;
|
||||
|
||||
auto preset_name = wxString::FromUTF8((preset.name + (preset.is_dirty ? suffix_modified : "")).c_str());
|
||||
|
||||
wxDataViewItem item;
|
||||
if (preset.is_system)
|
||||
item = popup->AppendItem(root_sys, preset_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
else if (show_def && preset.is_default)
|
||||
item = popup->AppendItem(root_def, preset_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
else
|
||||
{
|
||||
auto parent = m_presets->get_preset_parent(preset);
|
||||
if (parent == nullptr)
|
||||
item = popup->AppendItem(root_def, preset_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
else
|
||||
{
|
||||
auto parent_name = parent->name;
|
||||
|
||||
wxDataViewTreeStoreContainerNode *node = popup->GetStore()->FindContainerNode(root_sys);
|
||||
if (node)
|
||||
{
|
||||
wxDataViewTreeStoreNodeList::iterator iter;
|
||||
for (iter = node->GetChildren().begin(); iter != node->GetChildren().end(); iter++)
|
||||
{
|
||||
wxDataViewTreeStoreNode* child = *iter;
|
||||
auto child_item = child->GetItem();
|
||||
auto item_text = popup->GetItemText(child_item);
|
||||
if (item_text == parent_name)
|
||||
{
|
||||
auto added_child = popup->AppendItem(child->GetItem(), preset_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
if (!added_child){
|
||||
popup->DeleteItem(child->GetItem());
|
||||
auto new_parent = popup->AppendContainer(root_sys, parent_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
popup->AppendItem(new_parent, preset_name,
|
||||
preset.is_compatible ? icon_compatible : icon_incompatible);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cnt_items++;
|
||||
if (i == idx_selected){
|
||||
popup->Select(item);
|
||||
m_cc_presets_choice->SetText(preset_name);
|
||||
}
|
||||
}
|
||||
if (popup->GetStore()->GetChildCount(root_def) == 0)
|
||||
popup->DeleteItem(root_def);
|
||||
}
|
||||
ui->Thaw();
|
||||
}
|
||||
|
||||
void Page::reload_config()
|
||||
{
|
||||
for (auto group : m_optgroups)
|
||||
group->reload_config();
|
||||
}
|
||||
|
||||
Field* Page::get_field(t_config_option_key opt_key, int opt_index/* = -1*/) const
|
||||
Field* Page::get_field(const t_config_option_key& opt_key, int opt_index /*= -1*/) const
|
||||
{
|
||||
Field* field = nullptr;
|
||||
for (auto opt : m_optgroups){
|
||||
|
@ -2112,7 +2420,7 @@ Field* Page::get_field(t_config_option_key opt_key, int opt_index/* = -1*/) cons
|
|||
return field;
|
||||
}
|
||||
|
||||
bool Page::set_value(t_config_option_key opt_key, boost::any value){
|
||||
bool Page::set_value(const t_config_option_key& opt_key, const boost::any& value){
|
||||
bool changed = false;
|
||||
for(auto optgroup: m_optgroups) {
|
||||
if (optgroup->set_value(opt_key, value))
|
||||
|
@ -2122,7 +2430,7 @@ bool Page::set_value(t_config_option_key opt_key, boost::any value){
|
|||
}
|
||||
|
||||
// package Slic3r::GUI::Tab::Page;
|
||||
ConfigOptionsGroupShp Page::new_optgroup(wxString title, int noncommon_label_width /*= -1*/)
|
||||
ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_label_width /*= -1*/)
|
||||
{
|
||||
//! config_ have to be "right"
|
||||
ConfigOptionsGroupShp optgroup = std::make_shared<ConfigOptionsGroup>(this, title, m_config, true);
|
||||
|
@ -2163,7 +2471,7 @@ ConfigOptionsGroupShp Page::new_optgroup(wxString title, int noncommon_label_wid
|
|||
return optgroup;
|
||||
}
|
||||
|
||||
void SavePresetWindow::build(wxString title, std::string default_name, std::vector<std::string> &values)
|
||||
void SavePresetWindow::build(const wxString& title, const std::string& default_name, std::vector<std::string> &values)
|
||||
{
|
||||
auto text = new wxStaticText(this, wxID_ANY, _(L("Save ")) + title + _(L(" as:")),
|
||||
wxDefaultPosition, wxDefaultSize);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <wx/treectrl.h>
|
||||
#include <wx/imaglist.h>
|
||||
#include <wx/statbox.h>
|
||||
#include <wx/dataview.h>
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
@ -67,9 +68,9 @@ public:
|
|||
size_t iconID() const { return m_iconID; }
|
||||
void set_config(DynamicPrintConfig* config_in) { m_config = config_in; }
|
||||
void reload_config();
|
||||
Field* get_field(t_config_option_key opt_key, int opt_index = -1) const;
|
||||
bool set_value(t_config_option_key opt_key, boost::any value);
|
||||
ConfigOptionsGroupShp new_optgroup(wxString title, int noncommon_label_width = -1);
|
||||
Field* get_field(const t_config_option_key& opt_key, int opt_index = -1) const;
|
||||
bool set_value(const t_config_option_key& opt_key, const boost::any& value);
|
||||
ConfigOptionsGroupShp new_optgroup(const wxString& title, int noncommon_label_width = -1);
|
||||
};
|
||||
|
||||
// Slic3r::GUI::Tab;
|
||||
|
@ -95,6 +96,9 @@ protected:
|
|||
wxButton* m_compatible_printers_btn;
|
||||
wxButton* m_undo_btn;
|
||||
wxButton* m_undo_to_sys_btn;
|
||||
wxComboCtrl* m_cc_presets_choice;
|
||||
wxDataViewTreeCtrl* m_presetctrl;
|
||||
wxImageList* m_preset_icons;
|
||||
|
||||
int m_icon_count;
|
||||
std::map<std::string, size_t> m_icon_index; // Map from an icon file name to its index
|
||||
|
@ -122,10 +126,11 @@ public:
|
|||
DynamicPrintConfig* m_config;
|
||||
std::string m_nonsys_btn_icon;
|
||||
ogStaticText* m_parent_preset_description_line;
|
||||
wxStaticText* m_colored_Label = nullptr;
|
||||
|
||||
public:
|
||||
Tab() {}
|
||||
Tab(wxNotebook* parent, wxString title, const char* name, bool no_controller) :
|
||||
Tab(wxNotebook* parent, const wxString& title, const char* name, bool no_controller) :
|
||||
m_parent(parent), m_title(title), m_name(name), m_no_controller(no_controller) {
|
||||
Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL);
|
||||
get_tabs_list().push_back(this);
|
||||
|
@ -143,11 +148,12 @@ public:
|
|||
void create_preset_tab(PresetBundle *preset_bundle);
|
||||
void load_current_preset();
|
||||
void rebuild_page_tree();
|
||||
void select_preset(const std::string &preset_name = "");
|
||||
bool may_discard_current_dirty_preset(PresetCollection* presets = nullptr, std::string new_printer_name = "");
|
||||
void select_preset(const std::string& preset_name = "");
|
||||
bool may_discard_current_dirty_preset(PresetCollection* presets = nullptr, const std::string& new_printer_name = "");
|
||||
wxSizer* compatible_printers_widget(wxWindow* parent, wxCheckBox** checkbox, wxButton** btn);
|
||||
|
||||
void load_key_value(std::string opt_key, boost::any value);
|
||||
void update_presetsctrl(wxDataViewTreeCtrl* ui, bool show_incompatible);
|
||||
void load_key_value(const std::string& opt_key, const boost::any& value);
|
||||
void reload_compatible_printers_widget();
|
||||
|
||||
void OnTreeSelChange(wxTreeEvent& event);
|
||||
|
@ -161,13 +167,14 @@ public:
|
|||
void update_changed_ui();
|
||||
void update_full_options_list();
|
||||
void update_sys_ui_after_sel_preset();
|
||||
void get_sys_and_mod_flags(const std::string& opt_key, bool& sys_page, bool& modified_page);
|
||||
void update_changed_tree_ui();
|
||||
void update_undo_buttons();
|
||||
|
||||
void on_back_to_initial_value();
|
||||
void on_back_to_sys_value();
|
||||
|
||||
PageShp add_options_page(wxString title, std::string icon, bool is_extruder_pages = false);
|
||||
PageShp add_options_page(const wxString& title, const std::string& icon, bool is_extruder_pages = false);
|
||||
|
||||
virtual void OnActivate(){}
|
||||
virtual void on_preset_loaded(){}
|
||||
|
@ -176,10 +183,10 @@ public:
|
|||
void load_initial_data();
|
||||
void update_dirty();
|
||||
void update_tab_ui();
|
||||
void load_config(DynamicPrintConfig config);
|
||||
void load_config(const DynamicPrintConfig& config);
|
||||
virtual void reload_config();
|
||||
Field* get_field(t_config_option_key opt_key, int opt_index = -1) const;
|
||||
bool set_value(t_config_option_key opt_key, boost::any value);
|
||||
Field* get_field(const t_config_option_key& opt_key, int opt_index = -1) const;
|
||||
bool set_value(const t_config_option_key& opt_key, const boost::any& value);
|
||||
wxSizer* description_line_widget(wxWindow* parent, ogStaticText** StaticText);
|
||||
bool current_preset_is_dirty();
|
||||
DynamicPrintConfig* get_config() { return m_config; }
|
||||
|
@ -189,11 +196,13 @@ public:
|
|||
}
|
||||
std::vector<std::string> get_dependent_tabs() { return m_reload_dependent_tabs; }
|
||||
|
||||
void on_value_change(std::string opt_key, boost::any value);
|
||||
void on_value_change(const std::string& opt_key, const boost::any& value);
|
||||
|
||||
protected:
|
||||
void on_presets_changed();
|
||||
void update_frequently_changed_parameters();
|
||||
void update_wiping_button_visibility();
|
||||
void update_tab_presets(wxComboCtrl* ui, bool show_incompatible);
|
||||
};
|
||||
|
||||
//Slic3r::GUI::Tab::Print;
|
||||
|
@ -264,7 +273,7 @@ public:
|
|||
std::string m_chosen_name;
|
||||
wxComboBox* m_combo;
|
||||
|
||||
void build(wxString title, std::string default_name, std::vector<std::string> &values);
|
||||
void build(const wxString& title, const std::string& default_name, std::vector<std::string> &values);
|
||||
void accept();
|
||||
std::string get_name() { return m_chosen_name; }
|
||||
};
|
||||
|
|
343
xs/src/slic3r/GUI/WipeTowerDialog.cpp
Normal file
343
xs/src/slic3r/GUI/WipeTowerDialog.cpp
Normal file
|
@ -0,0 +1,343 @@
|
|||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include "WipeTowerDialog.hpp"
|
||||
|
||||
#include <wx/sizer.h>
|
||||
|
||||
//! macro used to mark string used at localization,
|
||||
//! return same string
|
||||
#define L(s) s
|
||||
|
||||
|
||||
|
||||
RammingDialog::RammingDialog(wxWindow* parent,const std::string& parameters)
|
||||
: wxDialog(parent, wxID_ANY, _(L("Ramming customization")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/)
|
||||
{
|
||||
m_panel_ramming = new RammingPanel(this,parameters);
|
||||
|
||||
// Not found another way of getting the background colours of RammingDialog, RammingPanel and Chart correct than setting
|
||||
// them all explicitely. Reading the parent colour yielded colour that didn't really match it, no wxSYS_COLOUR_... matched
|
||||
// colour used for the dialog. Same issue (and "solution") here : https://forums.wxwidgets.org/viewtopic.php?f=1&t=39608
|
||||
// Whoever can fix this, feel free to do so.
|
||||
this-> SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK));
|
||||
m_panel_ramming->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK));
|
||||
m_panel_ramming->Show(true);
|
||||
this->Show();
|
||||
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
main_sizer->Add(m_panel_ramming, 1, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, 5);
|
||||
main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALIGN_CENTER_HORIZONTAL | wxTOP | wxBOTTOM, 10);
|
||||
SetSizer(main_sizer);
|
||||
main_sizer->SetSizeHints(this);
|
||||
|
||||
this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { EndModal(wxCANCEL); });
|
||||
|
||||
this->Bind(wxEVT_BUTTON,[this](wxCommandEvent&) {
|
||||
m_output_data = m_panel_ramming->get_parameters();
|
||||
EndModal(wxID_OK);
|
||||
},wxID_OK);
|
||||
this->Show();
|
||||
wxMessageDialog(this,_(L("Ramming denotes the rapid extrusion just before a tool change in a single-extruder MM printer. Its purpose is to "
|
||||
"properly shape the end of the unloaded filament so it does not prevent insertion of the new filament and can itself "
|
||||
"be reinserted later. This phase is important and different materials can require different extrusion speeds to get "
|
||||
"the good shape. For this reason, the extrusion rates during ramming are adjustable.\n\nThis is an expert-level "
|
||||
"setting, incorrect adjustment will likely lead to jams, extruder wheel grinding into filament etc.")),_(L("Warning")),wxOK|wxICON_EXCLAMATION).ShowModal();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
RammingPanel::RammingPanel(wxWindow* parent, const std::string& parameters)
|
||||
: wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxPoint(50,50), wxSize(800,350),wxBORDER_RAISED*/)
|
||||
{
|
||||
auto sizer_chart = new wxBoxSizer(wxVERTICAL);
|
||||
auto sizer_param = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
std::stringstream stream{ parameters };
|
||||
stream >> m_ramming_line_width_multiplicator >> m_ramming_step_multiplicator;
|
||||
int ramming_speed_size = 0;
|
||||
float dummy = 0.f;
|
||||
while (stream >> dummy)
|
||||
++ramming_speed_size;
|
||||
stream.clear();
|
||||
stream.get();
|
||||
|
||||
std::vector<std::pair<float, float>> buttons;
|
||||
float x = 0.f;
|
||||
float y = 0.f;
|
||||
while (stream >> x >> y)
|
||||
buttons.push_back(std::make_pair(x, y));
|
||||
|
||||
m_chart = new Chart(this, wxRect(10, 10, 480, 360), buttons, ramming_speed_size, 0.25f);
|
||||
m_chart->SetBackgroundColour(parent->GetBackgroundColour()); // see comment in RammingDialog constructor
|
||||
sizer_chart->Add(m_chart, 0, wxALL, 5);
|
||||
|
||||
m_widget_time = new wxSpinCtrlDouble(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,0.,5.0,3.,0.5);
|
||||
m_widget_volume = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,0,10000,0);
|
||||
m_widget_ramming_line_width_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,10,200,100);
|
||||
m_widget_ramming_step_multiplicator = new wxSpinCtrl(this,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(75, -1),wxSP_ARROW_KEYS,10,200,100);
|
||||
|
||||
auto gsizer_param = new wxFlexGridSizer(2, 5, 15);
|
||||
gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total ramming time (s):")))), 0, wxALIGN_CENTER_VERTICAL);
|
||||
gsizer_param->Add(m_widget_time);
|
||||
gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Total rammed volume (mm"))+"\u00B3):")), 0, wxALIGN_CENTER_VERTICAL);
|
||||
gsizer_param->Add(m_widget_volume);
|
||||
gsizer_param->AddSpacer(20);
|
||||
gsizer_param->AddSpacer(20);
|
||||
gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Ramming line width (%):")))), 0, wxALIGN_CENTER_VERTICAL);
|
||||
gsizer_param->Add(m_widget_ramming_line_width_multiplicator);
|
||||
gsizer_param->Add(new wxStaticText(this, wxID_ANY, wxString(_(L("Ramming line spacing (%):")))), 0, wxALIGN_CENTER_VERTICAL);
|
||||
gsizer_param->Add(m_widget_ramming_step_multiplicator);
|
||||
|
||||
sizer_param->Add(gsizer_param, 0, wxTOP, 100);
|
||||
|
||||
m_widget_time->SetValue(m_chart->get_time());
|
||||
m_widget_time->SetDigits(2);
|
||||
m_widget_volume->SetValue(m_chart->get_volume());
|
||||
m_widget_volume->Disable();
|
||||
m_widget_ramming_line_width_multiplicator->SetValue(m_ramming_line_width_multiplicator);
|
||||
m_widget_ramming_step_multiplicator->SetValue(m_ramming_step_multiplicator);
|
||||
|
||||
m_widget_ramming_step_multiplicator->Bind(wxEVT_TEXT,[this](wxCommandEvent&) { line_parameters_changed(); });
|
||||
m_widget_ramming_line_width_multiplicator->Bind(wxEVT_TEXT,[this](wxCommandEvent&) { line_parameters_changed(); });
|
||||
|
||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
sizer->Add(sizer_chart, 0, wxALL, 5);
|
||||
sizer->Add(sizer_param, 0, wxALL, 10);
|
||||
|
||||
sizer->SetSizeHints(this);
|
||||
SetSizer(sizer);
|
||||
|
||||
m_widget_time->Bind(wxEVT_TEXT,[this](wxCommandEvent&) {m_chart->set_xy_range(m_widget_time->GetValue(),-1);});
|
||||
m_widget_time->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value
|
||||
m_widget_volume->Bind(wxEVT_CHAR,[](wxKeyEvent&){}); // do nothing - prevents the user to change the value
|
||||
Bind(EVT_WIPE_TOWER_CHART_CHANGED,[this](wxCommandEvent&) {m_widget_volume->SetValue(m_chart->get_volume()); m_widget_time->SetValue(m_chart->get_time());} );
|
||||
Refresh(this);
|
||||
}
|
||||
|
||||
void RammingPanel::line_parameters_changed() {
|
||||
m_ramming_line_width_multiplicator = m_widget_ramming_line_width_multiplicator->GetValue();
|
||||
m_ramming_step_multiplicator = m_widget_ramming_step_multiplicator->GetValue();
|
||||
}
|
||||
|
||||
std::string RammingPanel::get_parameters()
|
||||
{
|
||||
std::vector<float> speeds = m_chart->get_ramming_speed(0.25f);
|
||||
std::vector<std::pair<float,float>> buttons = m_chart->get_buttons();
|
||||
std::stringstream stream;
|
||||
stream << m_ramming_line_width_multiplicator << " " << m_ramming_step_multiplicator;
|
||||
for (const float& speed_value : speeds)
|
||||
stream << " " << speed_value;
|
||||
stream << "|";
|
||||
for (const auto& button : buttons)
|
||||
stream << " " << button.first << " " << button.second;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
|
||||
#define ITEM_WIDTH 60
|
||||
// Parent dialog for purging volume adjustments - it fathers WipingPanel widget (that contains all controls) and a button to toggle simple/advanced mode:
|
||||
WipingDialog::WipingDialog(wxWindow* parent,const std::vector<float>& matrix, const std::vector<float>& extruders)
|
||||
: wxDialog(parent, wxID_ANY, _(L("Wipe tower - Purging volume adjustment")), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE/* | wxRESIZE_BORDER*/)
|
||||
{
|
||||
auto widget_button = new wxButton(this,wxID_ANY,"-",wxPoint(0,0),wxDefaultSize);
|
||||
m_panel_wiping = new WipingPanel(this,matrix,extruders, widget_button);
|
||||
|
||||
auto main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
// set min sizer width according to extruders count
|
||||
const auto sizer_width = (int)((sqrt(matrix.size()) + 2.8)*ITEM_WIDTH);
|
||||
main_sizer->SetMinSize(wxSize(sizer_width, -1));
|
||||
|
||||
main_sizer->Add(m_panel_wiping, 0, wxEXPAND | wxALL, 5);
|
||||
main_sizer->Add(widget_button, 0, wxALIGN_CENTER_HORIZONTAL | wxCENTER | wxBOTTOM, 5);
|
||||
main_sizer->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxALIGN_CENTER_HORIZONTAL | wxBOTTOM, 10);
|
||||
SetSizer(main_sizer);
|
||||
main_sizer->SetSizeHints(this);
|
||||
|
||||
this->Bind(wxEVT_CLOSE_WINDOW, [this](wxCloseEvent& e) { EndModal(wxCANCEL); });
|
||||
|
||||
this->Bind(wxEVT_BUTTON,[this](wxCommandEvent&) { // if OK button is clicked..
|
||||
m_output_matrix = m_panel_wiping->read_matrix_values(); // ..query wiping panel and save returned values
|
||||
m_output_extruders = m_panel_wiping->read_extruders_values(); // so they can be recovered later by calling get_...()
|
||||
EndModal(wxID_OK);
|
||||
},wxID_OK);
|
||||
|
||||
this->Show();
|
||||
}
|
||||
|
||||
// This function allows to "play" with sizers parameters (like align or border)
|
||||
void WipingPanel::format_sizer(wxSizer* sizer, wxPanel* page, wxGridSizer* grid_sizer, const wxString& info, const wxString& table_title, int table_lshift/*=0*/)
|
||||
{
|
||||
sizer->Add(new wxStaticText(page, wxID_ANY, info,wxDefaultPosition,wxSize(0,50)), 0, wxEXPAND | wxLEFT, 15);
|
||||
auto table_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
sizer->Add(table_sizer, 0, wxALIGN_CENTER | wxCENTER, table_lshift);
|
||||
table_sizer->Add(new wxStaticText(page, wxID_ANY, table_title), 0, wxALIGN_CENTER | wxTOP, 50);
|
||||
table_sizer->Add(grid_sizer, 0, wxALIGN_CENTER | wxTOP, 10);
|
||||
}
|
||||
|
||||
// This panel contains all control widgets for both simple and advanced mode (these reside in separate sizers)
|
||||
WipingPanel::WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, wxButton* widget_button)
|
||||
: wxPanel(parent,wxID_ANY, wxDefaultPosition, wxDefaultSize/*,wxBORDER_RAISED*/)
|
||||
{
|
||||
m_widget_button = widget_button; // pointer to the button in parent dialog
|
||||
m_widget_button->Bind(wxEVT_BUTTON,[this](wxCommandEvent&){ toggle_advanced(true); });
|
||||
|
||||
m_number_of_extruders = (int)(sqrt(matrix.size())+0.001);
|
||||
|
||||
// Create two switched panels with their own sizers
|
||||
m_sizer_simple = new wxBoxSizer(wxVERTICAL);
|
||||
m_sizer_advanced = new wxBoxSizer(wxVERTICAL);
|
||||
m_page_simple = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
m_page_advanced = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
|
||||
m_page_simple->SetSizer(m_sizer_simple);
|
||||
m_page_advanced->SetSizer(m_sizer_advanced);
|
||||
|
||||
auto gridsizer_simple = new wxGridSizer(3, 5, 10);
|
||||
m_gridsizer_advanced = new wxGridSizer(m_number_of_extruders+1, 5, 1);
|
||||
|
||||
// First create controls for advanced mode and assign them to m_page_advanced:
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
|
||||
edit_boxes.push_back(std::vector<wxTextCtrl*>(0));
|
||||
|
||||
for (unsigned int j = 0; j < m_number_of_extruders; ++j) {
|
||||
edit_boxes.back().push_back(new wxTextCtrl(m_page_advanced, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(ITEM_WIDTH, -1)));
|
||||
if (i == j)
|
||||
edit_boxes[i][j]->Disable();
|
||||
else
|
||||
edit_boxes[i][j]->SetValue(wxString("") << int(matrix[m_number_of_extruders*j + i]));
|
||||
}
|
||||
}
|
||||
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("")));
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i)
|
||||
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
for (unsigned int i = 0; i < m_number_of_extruders; ++i) {
|
||||
m_gridsizer_advanced->Add(new wxStaticText(m_page_advanced, wxID_ANY, wxString("") << i + 1), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
for (unsigned int j = 0; j < m_number_of_extruders; ++j)
|
||||
m_gridsizer_advanced->Add(edit_boxes[j][i], 0);
|
||||
}
|
||||
|
||||
// collect and format sizer
|
||||
format_sizer(m_sizer_advanced, m_page_advanced, m_gridsizer_advanced,
|
||||
_(L("Here you can adjust required purging volume (mm\u00B3) for any given pair of tools.")),
|
||||
_(L("Extruder changed to")));
|
||||
|
||||
// Hide preview page before new page creating
|
||||
// It allows to do that from a beginning of the main panel
|
||||
m_page_advanced->Hide();
|
||||
|
||||
// Now the same for simple mode:
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString("")), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("unloaded")))), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple,wxID_ANY,wxString(_(L("loaded")))), 0, wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL);
|
||||
|
||||
for (unsigned int i=0;i<m_number_of_extruders;++i) {
|
||||
m_old.push_back(new wxSpinCtrl(m_page_simple,wxID_ANY,wxEmptyString,wxDefaultPosition, wxSize(80, -1),wxSP_ARROW_KEYS|wxALIGN_RIGHT,0,300,extruders[2*i]));
|
||||
m_new.push_back(new wxSpinCtrl(m_page_simple,wxID_ANY,wxEmptyString,wxDefaultPosition, wxSize(80, -1),wxSP_ARROW_KEYS|wxALIGN_RIGHT,0,300,extruders[2*i+1]));
|
||||
gridsizer_simple->Add(new wxStaticText(m_page_simple, wxID_ANY, wxString(_(L("Tool #"))) << i + 1 << ": "), 0, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
|
||||
gridsizer_simple->Add(m_old.back(),0);
|
||||
gridsizer_simple->Add(m_new.back(),0);
|
||||
}
|
||||
|
||||
// collect and format sizer
|
||||
format_sizer(m_sizer_simple, m_page_simple, gridsizer_simple,
|
||||
_(L("Total purging volume is calculated by summing two values below, depending on which tools are loaded/unloaded.")),
|
||||
_(L("Volume to purge (mm\u00B3) when the filament is being")), 50);
|
||||
|
||||
m_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
m_sizer->Add(m_page_simple, 0, wxEXPAND | wxALL, 25);
|
||||
m_sizer->Add(m_page_advanced, 0, wxEXPAND | wxALL, 25);
|
||||
|
||||
m_sizer->SetSizeHints(this);
|
||||
SetSizer(m_sizer);
|
||||
|
||||
toggle_advanced(); // to show/hide what is appropriate
|
||||
|
||||
m_page_advanced->Bind(wxEVT_PAINT,[this](wxPaintEvent&) {
|
||||
wxPaintDC dc(m_page_advanced);
|
||||
int y_pos = 0.5 * (edit_boxes[0][0]->GetPosition().y + edit_boxes[0][edit_boxes.size()-1]->GetPosition().y + edit_boxes[0][edit_boxes.size()-1]->GetSize().y);
|
||||
wxString label = _(L("From"));
|
||||
int text_width = 0;
|
||||
int text_height = 0;
|
||||
dc.GetTextExtent(label,&text_width,&text_height);
|
||||
int xpos = m_gridsizer_advanced->GetPosition().x;
|
||||
dc.DrawRotatedText(label,xpos-text_height,y_pos + text_width/2.f,90);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Reads values from the (advanced) wiping matrix:
|
||||
std::vector<float> WipingPanel::read_matrix_values() {
|
||||
if (!m_advanced)
|
||||
fill_in_matrix();
|
||||
std::vector<float> output;
|
||||
for (unsigned int i=0;i<m_number_of_extruders;++i) {
|
||||
for (unsigned int j=0;j<m_number_of_extruders;++j) {
|
||||
double val = 0.;
|
||||
edit_boxes[j][i]->GetValue().ToDouble(&val);
|
||||
output.push_back((float)val);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// Reads values from simple mode to save them for next time:
|
||||
std::vector<float> WipingPanel::read_extruders_values() {
|
||||
std::vector<float> output;
|
||||
for (unsigned int i=0;i<m_number_of_extruders;++i) {
|
||||
output.push_back(m_old[i]->GetValue());
|
||||
output.push_back(m_new[i]->GetValue());
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
// This updates the "advanced" matrix based on values from "simple" mode
|
||||
void WipingPanel::fill_in_matrix() {
|
||||
for (unsigned i=0;i<m_number_of_extruders;++i) {
|
||||
for (unsigned j=0;j<m_number_of_extruders;++j) {
|
||||
if (i==j) continue;
|
||||
edit_boxes[j][i]->SetValue(wxString("")<< (m_old[i]->GetValue() + m_new[j]->GetValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Function to check if simple and advanced settings are matching
|
||||
bool WipingPanel::advanced_matches_simple() {
|
||||
for (unsigned i=0;i<m_number_of_extruders;++i) {
|
||||
for (unsigned j=0;j<m_number_of_extruders;++j) {
|
||||
if (i==j) continue;
|
||||
if (edit_boxes[j][i]->GetValue() != (wxString("")<< (m_old[i]->GetValue() + m_new[j]->GetValue())))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Switches the dialog from simple to advanced mode and vice versa
|
||||
void WipingPanel::toggle_advanced(bool user_action) {
|
||||
if (m_advanced && !advanced_matches_simple() && user_action) {
|
||||
if (wxMessageDialog(this,wxString(_(L("Switching to simple settings will discard changes done in the advanced mode!\n\nDo you want to proceed?"))),
|
||||
wxString(_(L("Warning"))),wxYES_NO|wxICON_EXCLAMATION).ShowModal() != wxID_YES)
|
||||
return;
|
||||
}
|
||||
if (user_action)
|
||||
m_advanced = !m_advanced; // user demands a change -> toggle
|
||||
else
|
||||
m_advanced = !advanced_matches_simple(); // if called from constructor, show what is appropriate
|
||||
|
||||
(m_advanced ? m_page_advanced : m_page_simple)->Show();
|
||||
(!m_advanced ? m_page_advanced : m_page_simple)->Hide();
|
||||
|
||||
m_widget_button->SetLabel(m_advanced ? _(L("Show simplified settings")) : _(L("Show advanced settings")));
|
||||
if (m_advanced)
|
||||
if (user_action) fill_in_matrix(); // otherwise keep values loaded from config
|
||||
|
||||
m_sizer->Layout();
|
||||
Refresh();
|
||||
}
|
90
xs/src/slic3r/GUI/WipeTowerDialog.hpp
Normal file
90
xs/src/slic3r/GUI/WipeTowerDialog.hpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
#ifndef _WIPE_TOWER_DIALOG_H_
|
||||
#define _WIPE_TOWER_DIALOG_H_
|
||||
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/stattext.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/msgdlg.h>
|
||||
|
||||
#include "RammingChart.hpp"
|
||||
|
||||
|
||||
class RammingPanel : public wxPanel {
|
||||
public:
|
||||
RammingPanel(wxWindow* parent);
|
||||
RammingPanel(wxWindow* parent,const std::string& data);
|
||||
std::string get_parameters();
|
||||
|
||||
private:
|
||||
Chart* m_chart = nullptr;
|
||||
wxSpinCtrl* m_widget_volume = nullptr;
|
||||
wxSpinCtrl* m_widget_ramming_line_width_multiplicator = nullptr;
|
||||
wxSpinCtrl* m_widget_ramming_step_multiplicator = nullptr;
|
||||
wxSpinCtrlDouble* m_widget_time = nullptr;
|
||||
int m_ramming_step_multiplicator;
|
||||
int m_ramming_line_width_multiplicator;
|
||||
|
||||
void line_parameters_changed();
|
||||
};
|
||||
|
||||
|
||||
class RammingDialog : public wxDialog {
|
||||
public:
|
||||
RammingDialog(wxWindow* parent,const std::string& parameters);
|
||||
std::string get_parameters() { return m_output_data; }
|
||||
private:
|
||||
RammingPanel* m_panel_ramming = nullptr;
|
||||
std::string m_output_data;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class WipingPanel : public wxPanel {
|
||||
public:
|
||||
WipingPanel(wxWindow* parent, const std::vector<float>& matrix, const std::vector<float>& extruders, wxButton* widget_button);
|
||||
std::vector<float> read_matrix_values();
|
||||
std::vector<float> read_extruders_values();
|
||||
void toggle_advanced(bool user_action = false);
|
||||
void format_sizer(wxSizer* sizer, wxPanel* page, wxGridSizer* grid_sizer, const wxString& info, const wxString& table_title, int table_lshift=0);
|
||||
|
||||
private:
|
||||
void fill_in_matrix();
|
||||
bool advanced_matches_simple();
|
||||
|
||||
std::vector<wxSpinCtrl*> m_old;
|
||||
std::vector<wxSpinCtrl*> m_new;
|
||||
std::vector<std::vector<wxTextCtrl*>> edit_boxes;
|
||||
unsigned int m_number_of_extruders = 0;
|
||||
bool m_advanced = false;
|
||||
wxPanel* m_page_simple = nullptr;
|
||||
wxPanel* m_page_advanced = nullptr;
|
||||
wxBoxSizer* m_sizer = nullptr;
|
||||
wxBoxSizer* m_sizer_simple = nullptr;
|
||||
wxBoxSizer* m_sizer_advanced = nullptr;
|
||||
wxGridSizer* m_gridsizer_advanced = nullptr;
|
||||
wxButton* m_widget_button = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class WipingDialog : public wxDialog {
|
||||
public:
|
||||
WipingDialog(wxWindow* parent,const std::vector<float>& matrix, const std::vector<float>& extruders);
|
||||
std::vector<float> get_matrix() const { return m_output_matrix; }
|
||||
std::vector<float> get_extruders() const { return m_output_extruders; }
|
||||
|
||||
|
||||
private:
|
||||
WipingPanel* m_panel_wiping = nullptr;
|
||||
std::vector<float> m_output_matrix;
|
||||
std::vector<float> m_output_extruders;
|
||||
};
|
||||
|
||||
#endif // _WIPE_TOWER_DIALOG_H_
|
|
@ -109,3 +109,59 @@ void wxCheckListBoxComboPopup::OnListBoxSelection(wxCommandEvent& evt)
|
|||
ProcessEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// *** wxDataViewTreeCtrlComboPopup ***
|
||||
|
||||
const unsigned int wxDataViewTreeCtrlComboPopup::DefaultWidth = 270;
|
||||
const unsigned int wxDataViewTreeCtrlComboPopup::DefaultHeight = 200;
|
||||
const unsigned int wxDataViewTreeCtrlComboPopup::DefaultItemHeight = 22;
|
||||
|
||||
bool wxDataViewTreeCtrlComboPopup::Create(wxWindow* parent)
|
||||
{
|
||||
return wxDataViewTreeCtrl::Create(parent, wxID_ANY/*HIGHEST + 1*/, wxPoint(0, 0), wxDefaultSize/*wxSize(270, -1)*/, wxDV_NO_HEADER);
|
||||
}
|
||||
/*
|
||||
wxSize wxDataViewTreeCtrlComboPopup::GetAdjustedSize(int minWidth, int prefHeight, int maxHeight)
|
||||
{
|
||||
// matches owner wxComboCtrl's width
|
||||
// and sets height dinamically in dependence of contained items count
|
||||
wxComboCtrl* cmb = GetComboCtrl();
|
||||
if (cmb != nullptr)
|
||||
{
|
||||
wxSize size = GetComboCtrl()->GetSize();
|
||||
if (m_cnt_open_items > 0)
|
||||
size.SetHeight(m_cnt_open_items * DefaultItemHeight);
|
||||
else
|
||||
size.SetHeight(DefaultHeight);
|
||||
|
||||
return size;
|
||||
}
|
||||
else
|
||||
return wxSize(DefaultWidth, DefaultHeight);
|
||||
}
|
||||
*/
|
||||
void wxDataViewTreeCtrlComboPopup::OnKeyEvent(wxKeyEvent& evt)
|
||||
{
|
||||
// filters out all the keys which are not working properly
|
||||
if (evt.GetKeyCode() == WXK_UP)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else if (evt.GetKeyCode() == WXK_DOWN)
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
evt.Skip();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void wxDataViewTreeCtrlComboPopup::OnDataViewTreeCtrlSelection(wxCommandEvent& evt)
|
||||
{
|
||||
wxComboCtrl* cmb = GetComboCtrl();
|
||||
auto selected = GetItemText(GetSelection());
|
||||
cmb->SetText(selected);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <wx/checklst.h>
|
||||
#include <wx/combo.h>
|
||||
#include <wx/dataview.h>
|
||||
|
||||
class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup
|
||||
{
|
||||
|
@ -25,4 +26,28 @@ public:
|
|||
void OnListBoxSelection(wxCommandEvent& evt);
|
||||
};
|
||||
|
||||
|
||||
// *** wxDataViewTreeCtrlComboBox ***
|
||||
|
||||
class wxDataViewTreeCtrlComboPopup: public wxDataViewTreeCtrl, public wxComboPopup
|
||||
{
|
||||
static const unsigned int DefaultWidth;
|
||||
static const unsigned int DefaultHeight;
|
||||
static const unsigned int DefaultItemHeight;
|
||||
|
||||
wxString m_text;
|
||||
int m_cnt_open_items{0};
|
||||
|
||||
public:
|
||||
virtual bool Create(wxWindow* parent);
|
||||
virtual wxWindow* GetControl() { return this; }
|
||||
virtual void SetStringValue(const wxString& value) { m_text = value; }
|
||||
virtual wxString GetStringValue() const { return m_text; }
|
||||
// virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight);
|
||||
|
||||
virtual void OnKeyEvent(wxKeyEvent& evt);
|
||||
void OnDataViewTreeCtrlSelection(wxCommandEvent& evt);
|
||||
void SetItemsCnt(int cnt) { m_cnt_open_items = cnt; }
|
||||
};
|
||||
|
||||
#endif // slic3r_GUI_wxExtensions_hpp_
|
||||
|
|
|
@ -84,7 +84,7 @@
|
|||
|
||||
std::vector<int> load_object(ModelObject *object, int obj_idx, std::vector<int> instance_idxs, std::string color_by, std::string select_by, std::string drag_by, bool use_VBOs);
|
||||
|
||||
int load_wipe_tower_preview(int obj_idx, float pos_x, float pos_y, float width, float depth, float height, bool use_VBOs);
|
||||
int load_wipe_tower_preview(int obj_idx, float pos_x, float pos_y, float width, float depth, float height, float rotation_angle, bool use_VBOs);
|
||||
|
||||
void erase()
|
||||
%code{% THIS->clear(); %};
|
||||
|
@ -105,6 +105,7 @@
|
|||
|
||||
void set_print_box(float min_x, float min_y, float min_z, float max_x, float max_y, float max_z);
|
||||
void update_outside_state(DynamicPrintConfig* config, bool all_inside);
|
||||
void update_colors_by_extruder(DynamicPrintConfig* config);
|
||||
|
||||
bool move_volume_up(int idx)
|
||||
%code%{
|
||||
|
|
|
@ -142,6 +142,8 @@ PresetCollection::arrayref()
|
|||
Ref<PresetCollection> print() %code%{ RETVAL = &THIS->prints; %};
|
||||
Ref<PresetCollection> filament() %code%{ RETVAL = &THIS->filaments; %};
|
||||
Ref<PresetCollection> printer() %code%{ RETVAL = &THIS->printers; %};
|
||||
Ref<DynamicPrintConfig> project_config() %code%{ RETVAL = &THIS->project_config; %};
|
||||
|
||||
bool has_defauls_only();
|
||||
|
||||
std::vector<std::string> filament_presets() %code%{ RETVAL = THIS->filament_presets; %};
|
||||
|
|
Loading…
Add table
Reference in a new issue