diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 65264c9cd..b5ef3da5b 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -870,8 +870,11 @@ void GCode::_do_export(Print &print, FILE *file) this->apply_print_config(print.config()); this->set_extruders(print.extruders()); - // Initialize colorprint. + // #ys_FIXME_COLOR // Initialize colorprint. m_colorprint_heights = cast(print.config().colorprint_heights.values); + // Initialize custom gcode + Model* model = print.get_object(0)->model_object()->get_model(); + m_custom_g_code_heights = model->custom_gcode_per_height; // Initialize autospeed. { @@ -1676,8 +1679,15 @@ void GCode::process_layer( // In case there are more toolchange requests that weren't done yet and should happen simultaneously, erase them all. // (Layers can be close to each other, model could have been resliced with bigger layer height, ...). bool colorprint_change = false; - while (!m_colorprint_heights.empty() && m_colorprint_heights.front()-EPSILON < layer.print_z) { - m_colorprint_heights.erase(m_colorprint_heights.begin()); + // #ys_FIXME_COLOR + // while (!m_colorprint_heights.empty() && m_colorprint_heights.front()-EPSILON < layer.print_z) { + // m_colorprint_heights.erase(m_colorprint_heights.begin()); + // colorprint_change = true; + // } + std::string custom_code = ""; + while (!m_custom_g_code_heights.empty() && m_custom_g_code_heights.front().height-EPSILON < layer.print_z) { + custom_code = m_custom_g_code_heights.front().gcode; + m_custom_g_code_heights.erase(m_custom_g_code_heights.begin()); colorprint_change = true; } @@ -1688,7 +1698,9 @@ void GCode::process_layer( gcode += "; " + GCodeAnalyzer::Color_Change_Tag + "\n"; // add tag for time estimator gcode += "; " + GCodeTimeEstimator::Color_Change_Tag + "\n"; - gcode += "M600\n"; + // #ys_FIXME_COLOR + // gcode += "M600\n"; + gcode += custom_code + "\n"; } diff --git a/src/libslic3r/GCode.hpp b/src/libslic3r/GCode.hpp index 45ff7eda6..a1a83983e 100644 --- a/src/libslic3r/GCode.hpp +++ b/src/libslic3r/GCode.hpp @@ -353,6 +353,8 @@ protected: // Layer heights for colorprint - updated before the export and erased during the process // so no toolchange occurs twice. std::vector m_colorprint_heights; + // extensions for colorprint - now it's not a just color_print, there can be some custom gcode + std::vector m_custom_g_code_heights; // Time estimators GCodeTimeEstimator m_normal_time_estimator; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 410c2d3ef..2a1edd0ca 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -745,6 +745,32 @@ public: ModelObjectPtrs objects; // Wipe tower object. ModelWipeTower wipe_tower; + + // Extensions for + struct CustomGCode + { + CustomGCode(double height, const std::string& code, int extruder) : + height(height), gcode(code), extruder(extruder) {} + + bool operator<(const CustomGCode& other) const { return other.height > this->height; } + bool operator==(const CustomGCode& other) const + { + return (other.height == this->height) && + (other.gcode == this->gcode) && + (other.extruder == this->extruder ); + } + bool operator!=(const CustomGCode& other) const + { + return (other.height != this->height) || + (other.gcode != this->gcode) || + (other.extruder != this->extruder ); + } + + double height; + std::string gcode; + int extruder; + }; + std::vector custom_gcode_per_height; // Default constructor assigns a new ID to the model. Model() { assert(this->id().valid()); } diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp index 88645df15..3212082a3 100644 --- a/src/libslic3r/Print.cpp +++ b/src/libslic3r/Print.cpp @@ -749,6 +749,11 @@ Print::ApplyStatus Print::apply(const Model &model, DynamicPrintConfig new_full_ delete model_object; } } + if (model.custom_gcode_per_height != m_model.custom_gcode_per_height) + { + update_apply_status(this->invalidate_step(psGCodeExport)); + m_model.custom_gcode_per_height = model.custom_gcode_per_height; + } } // 2) Map print objects including their transformation matrices. diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index c55d64b47..2aa10a9bb 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -839,6 +839,8 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_values(const GCodePrevie if (preview_data.extrusion.view_type == GCodePreviewData::Extrusion::ColorPrint && wxGetApp().extruders_edited_cnt() == 1) // show color change legend only for single-material presets { + /* + // #ys_FIXME_COLOR auto& config = wxGetApp().preset_bundle->project_config; const std::vector& color_print_values = config.option("colorprint_heights")->values; @@ -854,6 +856,27 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_values(const GCodePrevie double current_z = *lower_b; double previous_z = lower_b == print_zs.begin() ? 0.0 : *(--lower_b); + // to avoid duplicate values, check adding values + if (cp_legend_values.empty() || + !(cp_legend_values.back().first == previous_z && cp_legend_values.back().second == current_z) ) + cp_legend_values.push_back(std::pair(previous_z, current_z)); + } + } + */ + std::vector custom_gcode_per_height = wxGetApp().plater()->model().custom_gcode_per_height; + + if (!custom_gcode_per_height.empty()) { + std::vector print_zs = canvas.get_current_print_zs(true); + for (auto custom_code : custom_gcode_per_height) + { + auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), custom_code.height - DoubleSlider::epsilon()); + + if (lower_b == print_zs.end()) + continue; + + double current_z = *lower_b; + double previous_z = lower_b == print_zs.begin() ? 0.0 : *(--lower_b); + // to avoid duplicate values, check adding values if (cp_legend_values.empty() || !(cp_legend_values.back().first == previous_z && cp_legend_values.back().second == current_z) ) diff --git a/src/slic3r/GUI/GUI_Preview.cpp b/src/slic3r/GUI/GUI_Preview.cpp index 98f6a8ee6..df7b5cf54 100644 --- a/src/slic3r/GUI/GUI_Preview.cpp +++ b/src/slic3r/GUI/GUI_Preview.cpp @@ -562,12 +562,22 @@ void Preview::update_view_type() { const DynamicPrintConfig& config = wxGetApp().preset_bundle->project_config; + /* + // #ys_FIXME_COLOR const wxString& choice = !config.option("colorprint_heights")->values.empty() && wxGetApp().extruders_edited_cnt()==1 ? _(L("Color Print")) : config.option("wiping_volumes_matrix")->values.size() > 1 ? _(L("Tool")) : _(L("Feature type")); + */ + + const wxString& choice = !wxGetApp().plater()->model().custom_gcode_per_height.empty() && + wxGetApp().extruders_edited_cnt()==1 ? + _(L("Color Print")) : + config.option("wiping_volumes_matrix")->values.size() > 1 ? + _(L("Tool")) : + _(L("Feature type")); int type = m_choice_view_type->FindString(choice); if (m_choice_view_type->GetSelection() != type) { @@ -609,7 +619,11 @@ void Preview::create_double_slider() Bind(wxCUSTOMEVT_TICKSCHANGED, [this](wxEvent&) { - wxGetApp().preset_bundle->project_config.option("colorprint_heights")->values = m_slider->GetTicksValues(); + // #ys_FIXME_COLOR + // wxGetApp().preset_bundle->project_config.option("colorprint_heights")->values = m_slider->GetTicksValues(); + + Model& model = wxGetApp().plater()->model(); + model.custom_gcode_per_height = m_slider->GetTicksValues_(); m_schedule_background_process(); update_view_type(); @@ -645,6 +659,24 @@ static int find_close_layer_idx(const std::vector& zs, double &z, double return -1; } +void Preview::check_slider_values(std::vector& ticks_from_model, + const std::vector& layers_z) +{ + // All ticks that would end up outside the slider range should be erased. + // TODO: this should be placed into more appropriate part of code, + // this function is e.g. not called when the last object is deleted + unsigned int old_size = ticks_from_model.size(); + ticks_from_model.erase(std::remove_if(ticks_from_model.begin(), ticks_from_model.end(), + [layers_z](Model::CustomGCode val) + { + auto it = std::lower_bound(layers_z.begin(), layers_z.end(), val.height - DoubleSlider::epsilon()); + return it == layers_z.end(); + }), + ticks_from_model.end()); + if (ticks_from_model.size() != old_size) + m_schedule_background_process(); +} + void Preview::update_double_slider(const std::vector& layers_z, bool keep_z_range) { // Save the initial slider span. @@ -660,8 +692,11 @@ void Preview::update_double_slider(const std::vector& layers_z, bool kee bool snap_to_min = force_sliders_full_range || m_slider->is_lower_at_min(); bool snap_to_max = force_sliders_full_range || m_slider->is_higher_at_max(); - std::vector &ticks_from_config = (wxGetApp().preset_bundle->project_config.option("colorprint_heights"))->values; - check_slider_values(ticks_from_config, layers_z); + // #ys_FIXME_COLOR + // std::vector &ticks_from_config = (wxGetApp().preset_bundle->project_config.option("colorprint_heights"))->values; + // check_slider_values(ticks_from_config, layers_z); + std::vector &ticks_from_model = wxGetApp().plater()->model().custom_gcode_per_height; + check_slider_values(ticks_from_model, layers_z); m_slider->SetSliderValues(layers_z); assert(m_slider->GetMinValue() == 0); @@ -683,7 +718,9 @@ void Preview::update_double_slider(const std::vector& layers_z, bool kee } m_slider->SetSelectionSpan(idx_low, idx_high); - m_slider->SetTicksValues(ticks_from_config); + // #ys_FIXME_COLOR + // m_slider->SetTicksValues(ticks_from_config); + m_slider->SetTicksValues_(ticks_from_model); bool color_print_enable = (wxGetApp().plater()->printer_technology() == ptFFF); if (color_print_enable) { @@ -693,7 +730,7 @@ void Preview::update_double_slider(const std::vector& layers_z, bool kee } m_slider->EnableTickManipulation(color_print_enable); } - +// #ys_FIXME_COLOR void Preview::check_slider_values(std::vector& ticks_from_config, const std::vector &layers_z) { @@ -799,10 +836,13 @@ void Preview::load_print_as_fff(bool keep_z_range) { colors = GCodePreviewData::ColorPrintColors(); if (! gcode_preview_data_valid) { - //FIXME accessing full_config() is pretty expensive. - // Only initialize color_print_values for the initial preview, not for the full preview where the color_print_values is extracted from the G-code. - const auto& config = wxGetApp().preset_bundle->project_config; - color_print_values = config.option("colorprint_heights")->values; + // #ys_FIXME_COLOR + // const auto& config = wxGetApp().preset_bundle->project_config; + // color_print_values = config.option("colorprint_heights")->values; + const std::vector& custom_codes = wxGetApp().plater()->model().custom_gcode_per_height; + color_print_values.reserve(custom_codes.size()); + for (const Model::CustomGCode& code : custom_codes) + color_print_values.push_back(code.height); } } else if (gcode_preview_data_valid || (m_gcode_preview_data->extrusion.view_type == GCodePreviewData::Extrusion::Tool) ) diff --git a/src/slic3r/GUI/GUI_Preview.hpp b/src/slic3r/GUI/GUI_Preview.hpp index 08d5991b4..551900277 100644 --- a/src/slic3r/GUI/GUI_Preview.hpp +++ b/src/slic3r/GUI/GUI_Preview.hpp @@ -5,6 +5,7 @@ #include "libslic3r/Point.hpp" #include +#include "libslic3r/Model.hpp" class wxNotebook; class wxGLCanvas; @@ -154,9 +155,11 @@ private: // Create/Update/Reset double slider on 3dPreview void create_double_slider(); + void check_slider_values(std::vector &ticks_from_model, + const std::vector &layers_z); void update_double_slider(const std::vector& layers_z, bool keep_z_range = false); void check_slider_values(std::vector &ticks_from_config, - const std::vector &layers_z); + const std::vector &layers_z); // #ys_FIXME_COLOR void reset_double_slider(); // update DoubleSlider after keyDown in canvas void update_double_slider_from_canvas(wxKeyEvent& event); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 50621caa8..6812c2b81 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2688,8 +2688,10 @@ void Plater::priv::reset() // The hiding of the slicing results, if shown, is not taken care by the background process, so we do it here this->sidebar->show_sliced_info_sizer(false); - auto& config = wxGetApp().preset_bundle->project_config; - config.option("colorprint_heights")->values.clear(); + // #ys_FIXME_COLOR + // auto& config = wxGetApp().preset_bundle->project_config; + // config.option("colorprint_heights")->values.clear(); + model.custom_gcode_per_height.clear(); } void Plater::priv::mirror(Axis axis) diff --git a/src/slic3r/GUI/wxExtensions.cpp b/src/slic3r/GUI/wxExtensions.cpp index 9536e3560..aaa8c86fd 100644 --- a/src/slic3r/GUI/wxExtensions.cpp +++ b/src/slic3r/GUI/wxExtensions.cpp @@ -2469,6 +2469,44 @@ std::vector DoubleSlider::GetTicksValues() const return values; } +using t_custom_code = Slic3r::Model::CustomGCode; +std::vector DoubleSlider::GetTicksValues_() const +{ + std::vector values; + + const int val_size = m_values.size(); + if (!m_values.empty()) + for (const TICK_CODE& tick : m_ticks_) { + if (tick.tick > val_size) + break; + values.push_back(t_custom_code(m_values[tick.tick], tick.gcode, tick.extruder)); + } + + return values; +} + +void DoubleSlider::SetTicksValues_(const std::vector& heights) +{ + if (m_values.empty()) + return; + + const bool was_empty = m_ticks_.empty(); + + m_ticks_.clear(); + for (auto h : heights) { + auto it = std::lower_bound(m_values.begin(), m_values.end(), h.height - epsilon()); + + if (it == m_values.end()) + continue; + + m_ticks_.insert(TICK_CODE(it-m_values.begin(), h.gcode, h.extruder)); + } + + if (!was_empty && m_ticks_.empty()) + // Switch to the "Feature type"/"Tool" from the very beginning of a new object slicing after deleting of the old one + wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); +} + void DoubleSlider::SetTicksValues(const std::vector& heights) { if (m_values.empty()) @@ -2577,19 +2615,12 @@ void DoubleSlider::draw_action_icon(wxDC& dc, const wxPoint pt_beg, const wxPoin if (tick == 0) return; + wxBitmap* icon = m_is_action_icon_focesed ? &m_bmp_add_tick_off.bmp() : &m_bmp_add_tick_on.bmp(); // #ys_FIXME_COLOR - // wxBitmap* icon = m_is_action_icon_focesed ? &m_bmp_add_tick_off.bmp() : &m_bmp_add_tick_on.bmp(); // if (m_ticks.find(tick) != m_ticks.end()) // icon = m_is_action_icon_focesed ? &m_bmp_del_tick_off.bmp() : &m_bmp_del_tick_on.bmp(); - wxBitmap* icon = m_action_icon_focesed > 0 ? &m_bmp_add_tick_off.bmp() : &m_bmp_add_tick_on.bmp(); - auto tick_code_it = m_ticks_.find(tick); - if (tick_code_it != m_ticks_.end()) { - icon = m_action_icon_focesed > 0 ? &m_bmp_del_tick_off.bmp() : &m_bmp_del_tick_on.bmp(); - - if (m_action_icon_focesed > 0) - m_action_icon_focesed = tick_code_it->gcode == "M600" ? fiDelColorChange : - tick_code_it->gcode == "M25" ? fiDelPause : fiDelCustomCode; - } + if (m_ticks_.find(tick) != m_ticks_.end()) + icon = m_is_action_icon_focesed ? &m_bmp_del_tick_off.bmp() : &m_bmp_del_tick_on.bmp(); wxCoord x_draw, y_draw; is_horizontal() ? x_draw = pt_beg.x - 0.5*m_tick_icon_dim : y_draw = pt_beg.y - 0.5*m_tick_icon_dim; @@ -3017,10 +3048,9 @@ void DoubleSlider::OnMotion(wxMouseEvent& event) bool is_revert_icon_focused = false; if (!m_is_left_down && !m_is_one_layer) { + m_is_action_icon_focesed = is_point_in_rect(pos, m_rect_tick_action); // #ys_FIXME_COLOR - // m_is_action_icon_focesed = is_point_in_rect(pos, m_rect_tick_action); // is_revert_icon_focused = !m_ticks.empty() && is_point_in_rect(pos, m_rect_revert_icon); - m_action_icon_focesed = is_point_in_rect(pos, m_rect_tick_action) ? fiAdd : fiNone; is_revert_icon_focused = !m_ticks_.empty() && is_point_in_rect(pos, m_rect_revert_icon); } else if (m_is_left_down || m_is_right_down) { @@ -3042,13 +3072,25 @@ void DoubleSlider::OnMotion(wxMouseEvent& event) event.Skip(); // Set tooltips with information for each icon - const wxString tooltip = m_is_one_layer_icon_focesed ? _(L("One layer mode")) : - // m_is_action_icon_focesed ? _(L("Add/Del color change")) : - m_action_icon_focesed == fiAdd ? _(L("Add color change")) : - m_action_icon_focesed == fiDelColorChange ? _(L("Delete color change")) : - m_action_icon_focesed == fiDelPause ? _(L("Delete pause")) : - m_action_icon_focesed == fiDelCustomCode ? _(L("Delete custom code")) : - is_revert_icon_focused ? _(L("Discard all color changes")) : ""; + // #ys_FIXME_COLOR + // const wxString tooltip = m_is_one_layer_icon_focesed ? _(L("One layer mode")) : + // m_is_action_icon_focesed ? _(L("Add/Del color change")) : + // is_revert_icon_focused ? _(L("Discard all color changes")) : ""; + wxString tooltip(wxEmptyString); + if (m_is_one_layer_icon_focesed) + tooltip = _(L("One layer mode")); + if (is_revert_icon_focused) + tooltip = _(L("Discard all custom changes")); + else if (m_is_action_icon_focesed) + { + const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; + const auto tick_code_it = m_ticks_.find(tick); + tooltip = tick_code_it == m_ticks_.end() ? _(L("Add color change")) : + tick_code_it->gcode == "M600" ? _(L("Delete color change")) : + tick_code_it->gcode == "M25" ? _(L("Delete pause")) : + from_u8((boost::format(_utf8(L("Delete \"%1%\" code"))) % tick_code_it->gcode).str()); + } + this->SetToolTip(tooltip); if (action) diff --git a/src/slic3r/GUI/wxExtensions.hpp b/src/slic3r/GUI/wxExtensions.hpp index a41fe1379..0ee451f44 100644 --- a/src/slic3r/GUI/wxExtensions.hpp +++ b/src/slic3r/GUI/wxExtensions.hpp @@ -16,6 +16,7 @@ #include #include #include +#include "libslic3r/Model.hpp" namespace Slic3r { enum class ModelVolumeType : int; @@ -795,6 +796,8 @@ public: } void ChangeOneLayerLock(); std::vector GetTicksValues() const; + std::vector GetTicksValues_() const; + void SetTicksValues_(const std::vector &heights); void SetTicksValues(const std::vector& heights); void EnableTickManipulation(bool enable = true) { m_is_enabled_tick_manipulation = enable; @@ -883,14 +886,6 @@ private: bool m_is_one_layer = false; bool m_is_focused = false; bool m_is_action_icon_focesed = false; - enum FocusedIcon - { - fiNone = 0, - fiAdd, - fiDelColorChange, - fiDelPause, - fiDelCustomCode - } m_action_icon_focesed { fiNone }; bool m_is_one_layer_icon_focesed = false; bool m_is_enabled_tick_manipulation = true; bool m_show_context_menu = false;