diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 7f2fe4346..f9e9e668d 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -2044,4 +2044,11 @@ sub reset_legend_texture { Slic3r::GUI::_3DScene::reset_legend_texture(); } +sub get_current_print_zs { + my ($self) = @_; + + my $count = $self->volumes->get_current_print_zs(); + return $count; +} + 1; diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm index 554b9e35a..a8bda3e50 100644 --- a/lib/Slic3r/GUI/Plater/3DPreview.pm +++ b/lib/Slic3r/GUI/Plater/3DPreview.pm @@ -74,12 +74,8 @@ sub new { my $combochecklist_features = $self->{combochecklist_features} = Wx::ComboCtrl->new(); $combochecklist_features->Create($self, -1, "Feature types", wxDefaultPosition, [200, -1], wxCB_READONLY); - #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. - $combochecklist_features->UseAltPopupWindow(); - $combochecklist_features->EnablePopupAnimation(0); my $feature_text = "Feature types"; - my $feature_items = "Perimeter|External perimeter|Overhang perimeter|Internal infill|Solid infill|Top solid infill|Bridge infill|Gap fill|Skirt|Support material|Support material interface|Wipe tower"; + my $feature_items = "Perimeter|External perimeter|Overhang perimeter|Internal infill|Solid infill|Top solid infill|Bridge infill|Gap fill|Skirt|Support material|Support material interface|Wipe tower|Custom"; Slic3r::GUI::create_combochecklist($combochecklist_features, $feature_text, $feature_items, 1); my $checkbox_travel = $self->{checkbox_travel} = Wx::CheckBox->new($self, -1, "Travel"); @@ -255,6 +251,7 @@ sub new { 'Support material' => '00FF00', 'Support material interface' => '008000', 'Wipe tower' => 'B3E3AB', + 'Custom' => 'FFFF00', ); $self->gcode_preview_data->set_extrusion_paths_colors(\@extrusion_roles_colors); @@ -322,31 +319,9 @@ sub load_print { return; } - my $z_idx_low = $self->slider_low->GetValue; - my $z_idx_high = $self->slider_high->GetValue; - $self->enabled(1); - $self->slider_low->SetRange(0, $n_layers - 1); - $self->slider_high->SetRange(0, $n_layers - 1); - if ($z_idx_high < $n_layers && ($self->single_layer || $z_idx_high != 0)) { - # use $z_idx - } else { - # Out of range. Disable 'single layer' view. - $self->single_layer(0); - $self->{checkbox_singlelayer}->SetValue(0); - $z_idx_low = 0; - $z_idx_high = $n_layers - 1; - } - if ($self->single_layer) { - $z_idx_low = $z_idx_high; - } elsif ($z_idx_low > $z_idx_high) { - $z_idx_low = 0; - } - $self->slider_low->SetValue($z_idx_low); - $self->slider_high->SetValue($z_idx_high); - $self->slider_low->Show; - $self->slider_high->Show; - $self->Layout; - + # used to set the sliders to the extremes of the current zs range + $self->{force_sliders_full_range} = 0; + if ($self->{preferred_color_mode} eq 'tool_or_feature') { # It is left to Slic3r to decide whether the print shall be colored by the tool or by the feature. # Color by feature if it is a single extruder print. @@ -384,16 +359,58 @@ sub load_print { } $self->show_hide_ui_elements('simple'); } else { + $self->{force_sliders_full_range} = (scalar(@{$self->canvas->volumes}) == 0) && $self->auto_zoom; $self->canvas->load_gcode_preview($self->print, $self->gcode_preview_data, \@colors); $self->show_hide_ui_elements('full'); + + # recalculates zs and update sliders accordingly + $self->{layers_z} = $self->canvas->get_current_print_zs(); + $n_layers = scalar(@{$self->{layers_z}}); } + + $self->update_sliders($n_layers); + if ($self->auto_zoom) { $self->canvas->zoom_to_volumes; } $self->_loaded(1); } +} + +sub update_sliders +{ + my ($self, $n_layers) = @_; + + my $z_idx_low = $self->slider_low->GetValue; + my $z_idx_high = $self->slider_high->GetValue; + $self->enabled(1); + $self->slider_low->SetRange(0, $n_layers - 1); + $self->slider_high->SetRange(0, $n_layers - 1); + if ($self->{force_sliders_full_range}) { + $z_idx_low = 0; + $z_idx_high = $n_layers - 1; + } elsif ($z_idx_high < $n_layers && ($self->single_layer || $z_idx_high != 0)) { + # use $z_idx + } else { + # Out of range. Disable 'single layer' view. + $self->single_layer(0); + $self->{checkbox_singlelayer}->SetValue(0); + $z_idx_low = 0; + $z_idx_high = $n_layers - 1; + } + if ($self->single_layer) { + $z_idx_low = $z_idx_high; + } elsif ($z_idx_low > $z_idx_high) { + $z_idx_low = 0; + } + + $self->slider_low->SetValue($z_idx_low); + $self->slider_high->SetValue($z_idx_high); + $self->slider_low->Show; + $self->slider_high->Show; $self->set_z_range($self->{layers_z}[$z_idx_low], $self->{layers_z}[$z_idx_high]); + $self->Layout; } sub set_z_range diff --git a/xs/src/libslic3r/ExtrusionEntity.hpp b/xs/src/libslic3r/ExtrusionEntity.hpp index f5e243419..16ef51c1f 100644 --- a/xs/src/libslic3r/ExtrusionEntity.hpp +++ b/xs/src/libslic3r/ExtrusionEntity.hpp @@ -26,6 +26,7 @@ enum ExtrusionRole { erSupportMaterial, erSupportMaterialInterface, erWipeTower, + erCustom, // Extrusion role for a collection with multiple extrusion roles. erMixed, }; diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index 2c2df6ec3..28c03ba2c 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -587,6 +587,15 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true); // Set extruder(s) temperature before and after start G-code. this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, false); + + if (m_enable_analyzer) + { + // adds tag for analyzer + char buf[32]; + sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom); + _writeln(file, buf); + } + // Write the custom start G-code _writeln(file, start_gcode); // Process filament-specific gcode in extruder order. @@ -770,6 +779,15 @@ void GCode::_do_export(Print &print, FILE *file, GCodePreviewData *preview_data) // Write end commands to file. _write(file, this->retract()); _write(file, m_writer.set_fan(false)); + + if (m_enable_analyzer) + { + // adds tag for analyzer + char buf[32]; + sprintf(buf, ";%s%d\n", GCodeAnalyzer::Extrusion_Role_Tag.c_str(), erCustom); + _writeln(file, buf); + } + // Process filament-specific gcode in extruder order. if (print.config.single_extruder_multi_material) { // Process the end_filament_gcode for the active filament only. diff --git a/xs/src/libslic3r/GCode/Analyzer.cpp b/xs/src/libslic3r/GCode/Analyzer.cpp index f8d196f23..6530806c4 100644 --- a/xs/src/libslic3r/GCode/Analyzer.cpp +++ b/xs/src/libslic3r/GCode/Analyzer.cpp @@ -150,7 +150,13 @@ void GCodeAnalyzer::_process_gcode_line(GCodeReader&, const GCodeReader::GCodeLi { // processes 'special' comments contained in line if (_process_tags(line)) + { +#if 0 + // DEBUG ONLY: puts the line back into the gcode + m_process_output += line.raw() + "\n"; +#endif return; + } // sets new start position/extrusion _set_start_position(_get_end_position()); diff --git a/xs/src/libslic3r/GCode/PreviewData.cpp b/xs/src/libslic3r/GCode/PreviewData.cpp index 5a23d332d..183e10b2a 100644 --- a/xs/src/libslic3r/GCode/PreviewData.cpp +++ b/xs/src/libslic3r/GCode/PreviewData.cpp @@ -125,6 +125,7 @@ const GCodePreviewData::Color GCodePreviewData::Extrusion::Default_Extrusion_Rol Color(0.0f, 0.5f, 0.0f, 1.0f), // erSupportMaterial Color(0.0f, 0.0f, 0.5f, 1.0f), // erSupportMaterialInterface Color(0.7f, 0.89f, 0.67f, 1.0f), // erWipeTower + Color(1.0f, 1.0f, 0.0f, 1.0f), // erCustom Color(0.0f, 0.0f, 0.0f, 1.0f) // erMixed }; @@ -144,6 +145,7 @@ const std::string GCodePreviewData::Extrusion::Default_Extrusion_Role_Names[Num_ "Support material", "Support material interface", "Wipe tower", + "Custom", "Mixed" }; @@ -360,8 +362,11 @@ GCodePreviewData::LegendItemsList GCodePreviewData::get_legend_items(const std:: { case Extrusion::FeatureType: { - items.reserve(erMixed - erPerimeter + 1); - for (unsigned int i = (unsigned int)erPerimeter; i < (unsigned int)erMixed; ++i) + ExtrusionRole first_valid = erPerimeter; + ExtrusionRole last_valid = erCustom; + + items.reserve(last_valid - first_valid + 1); + for (unsigned int i = (unsigned int)first_valid; i <= (unsigned int)last_valid; ++i) { items.emplace_back(extrusion.role_names[i], extrusion.role_colors[i]); } diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index 3a8aa5ca7..f492ed342 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -450,6 +450,25 @@ void GLVolumeCollection::render_legacy() const glDisableClientState(GL_NORMAL_ARRAY); } +std::vector GLVolumeCollection::get_current_print_zs() const +{ + std::vector print_zs; + + for (GLVolume *vol : this->volumes) + { + for (coordf_t z : vol->print_zs) + { + double round_z = (double)round(z * 100000.0f) / 100000.0f; + if (std::find(print_zs.begin(), print_zs.end(), round_z) == print_zs.end()) + print_zs.push_back(round_z); + } + } + + std::sort(print_zs.begin(), print_zs.end()); + + return print_zs; +} + // caller is responsible for supplying NO lines with zero length static void thick_lines_to_indexed_vertex_array( const Lines &lines, @@ -2205,6 +2224,9 @@ void _3DScene::_update_gcode_volumes_visibility(const GCodePreviewData& preview_ { case GCodePreviewVolumeIndex::Extrusion: { + if ((ExtrusionRole)s_gcode_preview_volume_index.first_volumes[i].flag == erCustom) + volume->zoom_to_volumes = false; + volume->is_active = preview_data.extrusion.is_role_flag_set((ExtrusionRole)s_gcode_preview_volume_index.first_volumes[i].flag); break; } diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index 542be3ef6..3e26bf6d3 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -372,6 +372,9 @@ public: void set_render_interleaved_only_volumes(const RenderInterleavedOnlyVolumes& render_interleaved_only_volumes) { _render_interleaved_only_volumes = render_interleaved_only_volumes; } + // Returns a vector containing the sorted list of all the print_zs of the volumes contained in this collection + std::vector get_current_print_zs() const; + private: GLVolumeCollection(const GLVolumeCollection &other); GLVolumeCollection& operator=(const GLVolumeCollection &); diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 0d7d58e0f..0b122453f 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -487,10 +487,17 @@ void create_combochecklist(wxComboCtrl* comboCtrl, std::string text, std::string wxCheckListBoxComboPopup* popup = new wxCheckListBoxComboPopup; 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. + comboCtrl->UseAltPopupWindow(); + + comboCtrl->EnablePopupAnimation(false); comboCtrl->SetPopupControl(popup); popup->SetStringValue(text); - popup->Connect(wxID_ANY, wxEVT_CHECKLISTBOX, wxCommandEventHandler(wxCheckListBoxComboPopup::OnCheckListBox), nullptr, popup); - popup->Connect(wxID_ANY, wxEVT_LISTBOX, wxCommandEventHandler(wxCheckListBoxComboPopup::OnListBoxSelection), nullptr, popup); + popup->Bind(wxEVT_CHECKLISTBOX, [popup](wxCommandEvent& evt) { popup->OnCheckListBox(evt); }); + popup->Bind(wxEVT_LISTBOX, [popup](wxCommandEvent& evt) { popup->OnListBoxSelection(evt); }); + popup->Bind(wxEVT_KEY_DOWN, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); }); + popup->Bind(wxEVT_KEY_UP, [popup](wxKeyEvent& evt) { popup->OnKeyEvent(evt); }); std::vector items_str; boost::split(items_str, items, boost::is_any_of("|"), boost::token_compress_off); diff --git a/xs/src/slic3r/GUI/wxExtensions.cpp b/xs/src/slic3r/GUI/wxExtensions.cpp index b5f0595f8..1ebd7979e 100644 --- a/xs/src/slic3r/GUI/wxExtensions.cpp +++ b/xs/src/slic3r/GUI/wxExtensions.cpp @@ -1,6 +1,8 @@ #include "wxExtensions.hpp" -const unsigned int wxCheckListBoxComboPopup::Height = 210; +const unsigned int wxCheckListBoxComboPopup::DefaultWidth = 200; +const unsigned int wxCheckListBoxComboPopup::DefaultHeight = 200; +const unsigned int wxCheckListBoxComboPopup::DefaultItemHeight = 18; bool wxCheckListBoxComboPopup::Create(wxWindow* parent) { @@ -25,16 +27,55 @@ wxString wxCheckListBoxComboPopup::GetStringValue() const wxSize wxCheckListBoxComboPopup::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(); - size.SetHeight(Height); + + unsigned int count = GetCount(); + if (count > 0) + size.SetHeight(count * DefaultItemHeight); + else + size.SetHeight(DefaultHeight); + return size; } else - return wxSize(200, Height); + return wxSize(DefaultWidth, DefaultHeight); +} + +void wxCheckListBoxComboPopup::OnKeyEvent(wxKeyEvent& evt) +{ + // filters out all the keys which are not working properly + switch (evt.GetKeyCode()) + { + case WXK_LEFT: + case WXK_UP: + case WXK_RIGHT: + case WXK_DOWN: + case WXK_PAGEUP: + case WXK_PAGEDOWN: + case WXK_END: + case WXK_HOME: + case WXK_NUMPAD_LEFT: + case WXK_NUMPAD_UP: + case WXK_NUMPAD_RIGHT: + case WXK_NUMPAD_DOWN: + case WXK_NUMPAD_PAGEUP: + case WXK_NUMPAD_PAGEDOWN: + case WXK_NUMPAD_END: + case WXK_NUMPAD_HOME: + { + break; + } + default: + { + evt.Skip(); + break; + } + } } void wxCheckListBoxComboPopup::OnCheckListBox(wxCommandEvent& evt) @@ -48,6 +89,8 @@ void wxCheckListBoxComboPopup::OnCheckListBox(wxCommandEvent& evt) event.SetEventObject(cmb); cmb->ProcessWindowEvent(event); } + + evt.Skip(); } void wxCheckListBoxComboPopup::OnListBoxSelection(wxCommandEvent& evt) diff --git a/xs/src/slic3r/GUI/wxExtensions.hpp b/xs/src/slic3r/GUI/wxExtensions.hpp index 8e62f766c..e61c17bbc 100644 --- a/xs/src/slic3r/GUI/wxExtensions.hpp +++ b/xs/src/slic3r/GUI/wxExtensions.hpp @@ -6,7 +6,9 @@ class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup { - static const unsigned int Height; + static const unsigned int DefaultWidth; + static const unsigned int DefaultHeight; + static const unsigned int DefaultItemHeight; wxString m_text; @@ -17,6 +19,8 @@ public: virtual wxString GetStringValue() const; virtual wxSize GetAdjustedSize(int minWidth, int prefHeight, int maxHeight); + virtual void OnKeyEvent(wxKeyEvent& evt); + void OnCheckListBox(wxCommandEvent& evt); void OnListBoxSelection(wxCommandEvent& evt); }; diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index dbf171615..4670c5c7e 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -85,7 +85,11 @@ int count() %code{% RETVAL = THIS->volumes.size(); %}; + + std::vector get_current_print_zs() + %code{% RETVAL = THIS->get_current_print_zs(); %}; + void set_range(double low, double high); void render_VBOs() const;