Editing of the custom GCodes like ColorChange and PausePrint

This commit is contained in:
YuSanka 2020-06-03 10:42:47 +02:00
parent a4d30fc9bb
commit 629584e28f
17 changed files with 392 additions and 311 deletions

View file

@ -23,7 +23,7 @@ extern void update_custom_gcode_per_print_z_from_config(Info& info, DynamicPrint
info.gcodes.reserve(colorprint_values.size()); info.gcodes.reserve(colorprint_values.size());
int i = 0; int i = 0;
for (auto val : colorprint_values) for (auto val : colorprint_values)
info.gcodes.emplace_back(Item{ val, ColorChangeCode, 1, colors[(++i)%7] }); info.gcodes.emplace_back(Item{ val, ColorChange, 1, colors[(++i)%7] });
info.mode = SingleExtruder; info.mode = SingleExtruder;
} }
@ -43,11 +43,11 @@ extern void check_mode_for_custom_gcode_per_print_z(Info& info)
bool is_single_extruder = true; bool is_single_extruder = true;
for (auto item : info.gcodes) for (auto item : info.gcodes)
{ {
if (item.gcode == ToolChangeCode) { if (item.type == ToolChange) {
info.mode = MultiAsSingle; info.mode = MultiAsSingle;
return; return;
} }
if (item.gcode == ColorChangeCode && item.extruder > 1) if (item.type == ColorChange && item.extruder > 1)
is_single_extruder = false; is_single_extruder = false;
} }
@ -60,7 +60,7 @@ std::vector<std::pair<double, unsigned int>> custom_tool_changes(const Info& cus
{ {
std::vector<std::pair<double, unsigned int>> custom_tool_changes; std::vector<std::pair<double, unsigned int>> custom_tool_changes;
for (const Item& custom_gcode : custom_gcode_per_print_z.gcodes) for (const Item& custom_gcode : custom_gcode_per_print_z.gcodes)
if (custom_gcode.gcode == ToolChangeCode) { if (custom_gcode.type == ToolChange) {
// If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders // If extruder count in PrinterSettings was changed, use default (0) extruder for extruders, more than num_extruders
assert(custom_gcode.extruder >= 0); assert(custom_gcode.extruder >= 0);
custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast<unsigned int>(size_t(custom_gcode.extruder) > num_extruders ? 1 : custom_gcode.extruder)); custom_tool_changes.emplace_back(custom_gcode.print_z, static_cast<unsigned int>(size_t(custom_gcode.extruder) > num_extruders ? 1 : custom_gcode.extruder));

View file

@ -8,38 +8,40 @@ namespace Slic3r {
class DynamicPrintConfig; class DynamicPrintConfig;
// Additional Codes which can be set by user using DoubleSlider
static constexpr char ColorChangeCode[] = "M600";
static constexpr char PausePrintCode[] = "M601";
static constexpr char ToolChangeCode[] = "tool_change";
enum CustomGcodeType
{
cgtColorChange,
cgtPausePrint,
};
namespace CustomGCode { namespace CustomGCode {
enum Type
{
ColorChange,
PausePrint,
ToolChange,
Template,
Custom
};
struct Item struct Item
{ {
bool operator<(const Item& rhs) const { return this->print_z < rhs.print_z; } bool operator<(const Item& rhs) const { return this->print_z < rhs.print_z; }
bool operator==(const Item& rhs) const bool operator==(const Item& rhs) const
{ {
return (rhs.print_z == this->print_z ) && return (rhs.print_z == this->print_z ) &&
(rhs.gcode == this->gcode ) && (rhs.type == this->type ) &&
(rhs.extruder == this->extruder ) && (rhs.extruder == this->extruder ) &&
(rhs.color == this->color ); (rhs.color == this->color ) &&
(rhs.extra == this->extra );
} }
bool operator!=(const Item& rhs) const { return ! (*this == rhs); } bool operator!=(const Item& rhs) const { return ! (*this == rhs); }
double print_z; double print_z;
std::string gcode; Type type;
int extruder; // Informative value for ColorChangeCode and ToolChangeCode int extruder; // Informative value for ColorChangeCode and ToolChangeCode
// "gcode" == ColorChangeCode => M600 will be applied for "extruder" extruder // "gcode" == ColorChangeCode => M600 will be applied for "extruder" extruder
// "gcode" == ToolChangeCode => for whole print tool will be switched to "extruder" extruder // "gcode" == ToolChangeCode => for whole print tool will be switched to "extruder" extruder
std::string color; // if gcode is equal to PausePrintCode, std::string color; // if gcode is equal to PausePrintCode,
// this field is used for save a short message shown on Printer display // this field is used for save a short message shown on Printer display
std::string extra; // this field is used for the extra data like :
// - G-code text for the Type::Custom
// - message text for the Type::PausePrint
}; };
enum Mode enum Mode

View file

@ -1199,11 +1199,12 @@ namespace Slic3r {
continue; continue;
pt::ptree tree = code.second; pt::ptree tree = code.second;
double print_z = tree.get<double> ("<xmlattr>.print_z" ); double print_z = tree.get<double> ("<xmlattr>.print_z" );
std::string gcode = tree.get<std::string> ("<xmlattr>.gcode" ); CustomGCode::Type type = static_cast<CustomGCode::Type>(tree.get<int> ("<xmlattr>.type" ));
// std::string gcode = tree.get<std::string> ("<xmlattr>.gcode" );
int extruder = tree.get<int> ("<xmlattr>.extruder" ); int extruder = tree.get<int> ("<xmlattr>.extruder" );
std::string color = tree.get<std::string> ("<xmlattr>.color" ); std::string color = tree.get<std::string> ("<xmlattr>.color" );
m_model->custom_gcode_per_print_z.gcodes.push_back(CustomGCode::Item{print_z, gcode, extruder, color}) ; m_model->custom_gcode_per_print_z.gcodes.push_back(CustomGCode::Item{print_z, type, /*gcode, */extruder, color}) ;
} }
} }
} }
@ -2716,7 +2717,8 @@ bool _3MF_Exporter::_add_custom_gcode_per_print_z_file_to_archive( mz_zip_archiv
pt::ptree& code_tree = main_tree.add("code", ""); pt::ptree& code_tree = main_tree.add("code", "");
// store minX and maxZ // store minX and maxZ
code_tree.put("<xmlattr>.print_z" , code.print_z ); code_tree.put("<xmlattr>.print_z" , code.print_z );
code_tree.put("<xmlattr>.gcode" , code.gcode ); code_tree.put("<xmlattr>.gcode" , static_cast<int>(code.type));
// code_tree.put("<xmlattr>.gcode" , code.gcode );
code_tree.put("<xmlattr>.extruder" , code.extruder ); code_tree.put("<xmlattr>.extruder" , code.extruder );
code_tree.put("<xmlattr>.color" , code.color ); code_tree.put("<xmlattr>.color" , code.color );
} }

View file

@ -641,11 +641,12 @@ void AMFParserContext::endElement(const char * /* name */)
case NODE_TYPE_GCODE_PER_HEIGHT: { case NODE_TYPE_GCODE_PER_HEIGHT: {
double print_z = double(atof(m_value[0].c_str())); double print_z = double(atof(m_value[0].c_str()));
const std::string& gcode = m_value[1]; // const std::string& gcode = m_value[1];
CustomGCode::Type type = static_cast<CustomGCode::Type>(atoi(m_value[1].c_str()));
int extruder = atoi(m_value[2].c_str()); int extruder = atoi(m_value[2].c_str());
const std::string& color = m_value[3]; const std::string& color = m_value[3];
m_model.custom_gcode_per_print_z.gcodes.push_back(CustomGCode::Item{print_z, gcode, extruder, color}); m_model.custom_gcode_per_print_z.gcodes.push_back(CustomGCode::Item{print_z, type,/*gcode, */extruder, color});
for (std::string& val: m_value) for (std::string& val: m_value)
val.clear(); val.clear();
@ -1253,7 +1254,8 @@ bool store_amf(const char* path, Model* model, const DynamicPrintConfig* config,
pt::ptree& code_tree = main_tree.add("code", ""); pt::ptree& code_tree = main_tree.add("code", "");
// store custom_gcode_per_print_z gcodes information // store custom_gcode_per_print_z gcodes information
code_tree.put("<xmlattr>.print_z" , code.print_z ); code_tree.put("<xmlattr>.print_z" , code.print_z );
code_tree.put("<xmlattr>.gcode" , code.gcode ); // code_tree.put("<xmlattr>.gcode" , code.gcode );
code_tree.put("<xmlattr>.type" , code.type );
code_tree.put("<xmlattr>.extruder" , code.extruder ); code_tree.put("<xmlattr>.extruder" , code.extruder );
code_tree.put("<xmlattr>.color" , code.color ); code_tree.put("<xmlattr>.color" , code.color );
} }

View file

@ -1757,17 +1757,18 @@ namespace ProcessLayer
const CustomGCode::Item *custom_gcode, const CustomGCode::Item *custom_gcode,
// ID of the first extruder printing this layer. // ID of the first extruder printing this layer.
unsigned int first_extruder_id, unsigned int first_extruder_id,
bool single_extruder_printer) const PrintConfig &config)
{ {
std::string gcode; std::string gcode;
bool single_extruder_printer = config.nozzle_diameter.size() == 1;
if (custom_gcode != nullptr) { if (custom_gcode != nullptr) {
// Extruder switches are processed by LayerTools, they should be filtered out. // Extruder switches are processed by LayerTools, they should be filtered out.
assert(custom_gcode->gcode != ToolChangeCode); assert(custom_gcode->type != CustomGCode::ToolChange);
const std::string &custom_code = custom_gcode->gcode; CustomGCode::Type gcode_type = custom_gcode->type;
bool color_change = custom_code == ColorChangeCode; bool color_change = gcode_type == CustomGCode::ColorChange;
bool tool_change = custom_code == ToolChangeCode; bool tool_change = gcode_type == CustomGCode::ToolChange;
// Tool Change is applied as Color Change for a single extruder printer only. // Tool Change is applied as Color Change for a single extruder printer only.
assert(! tool_change || single_extruder_printer); assert(! tool_change || single_extruder_printer);
@ -1775,8 +1776,8 @@ namespace ProcessLayer
int m600_extruder_before_layer = -1; int m600_extruder_before_layer = -1;
if (color_change && custom_gcode->extruder > 0) if (color_change && custom_gcode->extruder > 0)
m600_extruder_before_layer = custom_gcode->extruder - 1; m600_extruder_before_layer = custom_gcode->extruder - 1;
else if (custom_code == PausePrintCode) else if (gcode_type == CustomGCode::PausePrint)
pause_print_msg = custom_gcode->color; pause_print_msg = custom_gcode->extra;
// we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count // we should add or not colorprint_change in respect to nozzle_diameter count instead of really used extruders count
if (color_change || tool_change) if (color_change || tool_change)
@ -1792,17 +1793,18 @@ namespace ProcessLayer
// && !MMU1 // && !MMU1
) { ) {
//! FIXME_in_fw show message during print pause //! FIXME_in_fw show message during print pause
gcode += "M601\n"; // pause print gcode += config.pause_print_gcode;// pause print
gcode += "\n";
gcode += "M117 Change filament for Extruder " + std::to_string(m600_extruder_before_layer) + "\n"; gcode += "M117 Change filament for Extruder " + std::to_string(m600_extruder_before_layer) + "\n";
} }
else { else {
gcode += ColorChangeCode; gcode += config.color_change_gcode;//ColorChangeCode;
gcode += "\n"; gcode += "\n";
} }
} }
else else
{ {
if (custom_code == PausePrintCode) // Pause print if (gcode_type == CustomGCode::PausePrint) // Pause print
{ {
// add tag for analyzer // add tag for analyzer
gcode += "; " + GCodeAnalyzer::Pause_Print_Tag + "\n"; gcode += "; " + GCodeAnalyzer::Pause_Print_Tag + "\n";
@ -1811,15 +1813,21 @@ namespace ProcessLayer
gcode += "M117 " + pause_print_msg + "\n"; gcode += "M117 " + pause_print_msg + "\n";
// add tag for time estimator // add tag for time estimator
gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n"; gcode += "; " + GCodeTimeEstimator::Pause_Print_Tag + "\n";
gcode += config.pause_print_gcode;
} }
else // custom Gcode else
{ {
// add tag for analyzer // add tag for analyzer
gcode += "; " + GCodeAnalyzer::Custom_Code_Tag + "\n"; gcode += "; " + GCodeAnalyzer::Custom_Code_Tag + "\n";
// add tag for time estimator // add tag for time estimator
//gcode += "; " + GCodeTimeEstimator::Custom_Code_Tag + "\n"; //gcode += "; " + GCodeTimeEstimator::Custom_Code_Tag + "\n";
if (gcode_type == CustomGCode::Template) // Template Cistom Gcode
gcode += config.template_custom_gcode;
else // custom Gcode
gcode += custom_gcode->extra;
} }
gcode += custom_code + "\n"; gcode += "\n";
} }
} }
@ -1996,7 +2004,7 @@ void GCode::process_layer(
if (single_object_instance_idx == size_t(-1)) { if (single_object_instance_idx == size_t(-1)) {
// Normal (non-sequential) print. // Normal (non-sequential) print.
gcode += ProcessLayer::emit_custom_gcode_per_print_z(layer_tools.custom_gcode, first_extruder_id, print.config().nozzle_diameter.size() == 1); gcode += ProcessLayer::emit_custom_gcode_per_print_z(layer_tools.custom_gcode, first_extruder_id, print.config());
} }
// Extrude skirt at the print_z of the raft layers and normal object layers // Extrude skirt at the print_z of the raft layers and normal object layers
// not at the print_z of the interlaced support material layers. // not at the print_z of the interlaced support material layers.

View file

@ -188,7 +188,7 @@ namespace Slic3r {
_calculate_time(0); _calculate_time(0);
if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f)) if (m_needs_custom_gcode_times && (m_custom_gcode_time_cache != 0.0f))
m_custom_gcode_times.push_back({ cgtColorChange, m_custom_gcode_time_cache }); m_custom_gcode_times.push_back({CustomGCode::ColorChange, m_custom_gcode_time_cache });
#if ENABLE_MOVE_STATS #if ENABLE_MOVE_STATS
_log_moves_stats(); _log_moves_stats();
@ -678,7 +678,7 @@ namespace Slic3r {
return _get_time_minutes(get_time()); return _get_time_minutes(get_time());
} }
std::vector<std::pair<CustomGcodeType, float>> GCodeTimeEstimator::get_custom_gcode_times() const std::vector<std::pair<CustomGCode::Type, float>> GCodeTimeEstimator::get_custom_gcode_times() const
{ {
return m_custom_gcode_times; return m_custom_gcode_times;
} }
@ -722,9 +722,9 @@ namespace Slic3r {
return ret; return ret;
} }
std::vector<std::pair<CustomGcodeType, std::string>> GCodeTimeEstimator::get_custom_gcode_times_dhm(bool include_remaining) const std::vector<std::pair<CustomGCode::Type, std::string>> GCodeTimeEstimator::get_custom_gcode_times_dhm(bool include_remaining) const
{ {
std::vector<std::pair<CustomGcodeType, std::string>> ret; std::vector<std::pair<CustomGCode::Type, std::string>> ret;
float total_time = 0.0f; float total_time = 0.0f;
for (auto t : m_custom_gcode_times) for (auto t : m_custom_gcode_times)
@ -1470,7 +1470,7 @@ namespace Slic3r {
size_t pos = comment.find(Color_Change_Tag); size_t pos = comment.find(Color_Change_Tag);
if (pos != comment.npos) if (pos != comment.npos)
{ {
_process_custom_gcode_tag(cgtColorChange); _process_custom_gcode_tag(CustomGCode::ColorChange);
return true; return true;
} }
@ -1478,14 +1478,14 @@ namespace Slic3r {
pos = comment.find(Pause_Print_Tag); pos = comment.find(Pause_Print_Tag);
if (pos != comment.npos) if (pos != comment.npos)
{ {
_process_custom_gcode_tag(cgtPausePrint); _process_custom_gcode_tag(CustomGCode::PausePrint);
return true; return true;
} }
return false; return false;
} }
void GCodeTimeEstimator::_process_custom_gcode_tag(CustomGcodeType code) void GCodeTimeEstimator::_process_custom_gcode_tag(CustomGCode::Type code)
{ {
PROFILE_FUNC(); PROFILE_FUNC();
m_needs_custom_gcode_times = true; m_needs_custom_gcode_times = true;

View file

@ -234,7 +234,7 @@ namespace Slic3r {
// data to calculate custom code times // data to calculate custom code times
bool m_needs_custom_gcode_times; bool m_needs_custom_gcode_times;
std::vector<std::pair<CustomGcodeType, float>> m_custom_gcode_times; std::vector<std::pair<CustomGCode::Type, float>> m_custom_gcode_times;
float m_custom_gcode_time_cache; float m_custom_gcode_time_cache;
#if ENABLE_MOVE_STATS #if ENABLE_MOVE_STATS
@ -358,7 +358,7 @@ namespace Slic3r {
std::string get_time_minutes() const; std::string get_time_minutes() const;
// Returns the estimated time, in seconds, for each custom gcode // Returns the estimated time, in seconds, for each custom gcode
std::vector<std::pair<CustomGcodeType, float>> get_custom_gcode_times() const; std::vector<std::pair<CustomGCode::Type, float>> get_custom_gcode_times() const;
// Returns the estimated time, in format DDd HHh MMm SSs, for each color // Returns the estimated time, in format DDd HHh MMm SSs, for each color
// If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)" // If include_remaining==true the strings will be formatted as: "time for color (remaining time at color start)"
@ -370,7 +370,7 @@ namespace Slic3r {
// Returns the estimated time, in format DDd HHh MMm, for each custom_gcode // Returns the estimated time, in format DDd HHh MMm, for each custom_gcode
// If include_remaining==true the strings will be formatted as: "time for custom_gcode (remaining time at color start)" // If include_remaining==true the strings will be formatted as: "time for custom_gcode (remaining time at color start)"
std::vector<std::pair<CustomGcodeType, std::string>> get_custom_gcode_times_dhm(bool include_remaining) const; std::vector<std::pair<CustomGCode::Type, std::string>> get_custom_gcode_times_dhm(bool include_remaining) const;
// Return an estimate of the memory consumed by the time estimator. // Return an estimate of the memory consumed by the time estimator.
size_t memory_used() const; size_t memory_used() const;
@ -453,7 +453,7 @@ namespace Slic3r {
bool _process_tags(const GCodeReader::GCodeLine& line); bool _process_tags(const GCodeReader::GCodeLine& line);
// Processes ColorChangeTag and PausePrintTag // Processes ColorChangeTag and PausePrintTag
void _process_custom_gcode_tag(CustomGcodeType code); void _process_custom_gcode_tag(CustomGCode::Type code);
// Simulates firmware st_synchronize() call // Simulates firmware st_synchronize() call
void _simulate_st_synchronize(float additional_time); void _simulate_st_synchronize(float additional_time);

View file

@ -500,12 +500,12 @@ static bool custom_per_printz_gcodes_tool_changes_differ(const std::vector<Custo
auto it_a = va.begin(); auto it_a = va.begin();
auto it_b = vb.begin(); auto it_b = vb.begin();
while (it_a != va.end() || it_b != vb.end()) { while (it_a != va.end() || it_b != vb.end()) {
if (it_a != va.end() && it_a->gcode != ToolChangeCode) { if (it_a != va.end() && it_a->type != CustomGCode::ToolChange) {
// Skip any CustomGCode items, which are not tool changes. // Skip any CustomGCode items, which are not tool changes.
++ it_a; ++ it_a;
continue; continue;
} }
if (it_b != vb.end() && it_b->gcode != ToolChangeCode) { if (it_b != vb.end() && it_b->type != CustomGCode::ToolChange) {
// Skip any CustomGCode items, which are not tool changes. // Skip any CustomGCode items, which are not tool changes.
++ it_b; ++ it_b;
continue; continue;
@ -513,8 +513,8 @@ static bool custom_per_printz_gcodes_tool_changes_differ(const std::vector<Custo
if (it_a == va.end() || it_b == vb.end()) if (it_a == va.end() || it_b == vb.end())
// va or vb contains more Tool Changes than the other. // va or vb contains more Tool Changes than the other.
return true; return true;
assert(it_a->gcode == ToolChangeCode); assert(it_a->type == CustomGCode::ToolChange);
assert(it_b->gcode == ToolChangeCode); assert(it_b->type == CustomGCode::ToolChange);
if (*it_a != *it_b) if (*it_a != *it_b)
// The two Tool Changes differ. // The two Tool Changes differ.
return true; return true;

View file

@ -300,8 +300,8 @@ struct PrintStatistics
PrintStatistics() { clear(); } PrintStatistics() { clear(); }
std::string estimated_normal_print_time; std::string estimated_normal_print_time;
std::string estimated_silent_print_time; std::string estimated_silent_print_time;
std::vector<std::pair<CustomGcodeType, std::string>> estimated_normal_custom_gcode_print_times; std::vector<std::pair<CustomGCode::Type, std::string>> estimated_normal_custom_gcode_print_times;
std::vector<std::pair<CustomGcodeType, std::string>> estimated_silent_custom_gcode_print_times; std::vector<std::pair<CustomGCode::Type, std::string>> estimated_silent_custom_gcode_print_times;
double total_used_filament; double total_used_filament;
double total_extruded_volume; double total_extruded_volume;
double total_cost; double total_cost;

View file

@ -1909,6 +1909,33 @@ void PrintConfigDef::init_fff_params()
def->mode = comExpert; def->mode = comExpert;
def->set_default_value(new ConfigOptionStrings { "; Filament gcode\n" }); def->set_default_value(new ConfigOptionStrings { "; Filament gcode\n" });
def = this->add("color_change_gcode", coString);
def->label = L("Color change G-code");
def->tooltip = L("This G-code will be used as a code for the color change");
def->multiline = true;
def->full_width = true;
def->height = 12;
def->mode = comExpert;
def->set_default_value(new ConfigOptionString("M600"));
def = this->add("pause_print_gcode", coString);
def->label = L("Pause Print G-code");
def->tooltip = L("This G-code will be used as a code for the pause print");
def->multiline = true;
def->full_width = true;
def->height = 12;
def->mode = comExpert;
def->set_default_value(new ConfigOptionString("M601"));
def = this->add("template_custom_gcode", coString);
def->label = L("Custom G-code");
def->tooltip = L("This G-code will be used as a custom code");
def->multiline = true;
def->full_width = true;
def->height = 12;
def->mode = comExpert;
def->set_default_value(new ConfigOptionString(""));
def = this->add("single_extruder_multi_material", coBool); def = this->add("single_extruder_multi_material", coBool);
def->label = L("Single Extruder Multi Material"); def->label = L("Single Extruder Multi Material");
def->tooltip = L("The printer multiplexes filaments into a single hot end."); def->tooltip = L("The printer multiplexes filaments into a single hot end.");

View file

@ -699,6 +699,9 @@ public:
ConfigOptionBool remaining_times; ConfigOptionBool remaining_times;
ConfigOptionBool silent_mode; ConfigOptionBool silent_mode;
ConfigOptionFloat extra_loading_move; ConfigOptionFloat extra_loading_move;
ConfigOptionString color_change_gcode;
ConfigOptionString pause_print_gcode;
ConfigOptionString template_custom_gcode;
std::string get_extrusion_axis() const std::string get_extrusion_axis() const
{ {
@ -772,6 +775,9 @@ protected:
OPT_PTR(remaining_times); OPT_PTR(remaining_times);
OPT_PTR(silent_mode); OPT_PTR(silent_mode);
OPT_PTR(extra_loading_move); OPT_PTR(extra_loading_move);
OPT_PTR(color_change_gcode);
OPT_PTR(pause_print_gcode);
OPT_PTR(template_custom_gcode);
} }
}; };

View file

@ -33,6 +33,21 @@ namespace DoubleSlider {
wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent); wxDEFINE_EVENT(wxCUSTOMEVT_TICKSCHANGED, wxEvent);
static std::string gcode(Type type)
{
const PrintConfig& config = GUI::wxGetApp().plater()->fff_print().config();
switch (type) {
case ColorChange:
return config.color_change_gcode;
case PausePrint:
return config.pause_print_gcode;
case Template:
return config.template_custom_gcode;
default:
return "";
}
}
Control::Control( wxWindow *parent, Control::Control( wxWindow *parent,
wxWindowID id, wxWindowID id,
int lowerValue, int lowerValue,
@ -284,18 +299,17 @@ double Control::get_double_value(const SelectedSlider& selection)
return m_values[selection == ssLower ? m_lower_value : m_higher_value]; return m_values[selection == ssLower ? m_lower_value : m_higher_value];
} }
using t_custom_code = CustomGCode::Item; Info Control::GetTicksValues() const
CustomGCode::Info Control::GetTicksValues() const
{ {
CustomGCode::Info custom_gcode_per_print_z; Info custom_gcode_per_print_z;
std::vector<t_custom_code>& values = custom_gcode_per_print_z.gcodes; std::vector<Item>& values = custom_gcode_per_print_z.gcodes;
const int val_size = m_values.size(); const int val_size = m_values.size();
if (!m_values.empty()) if (!m_values.empty())
for (const TickCode& tick : m_ticks.ticks) { for (const TickCode& tick : m_ticks.ticks) {
if (tick.tick > val_size) if (tick.tick > val_size)
break; break;
values.emplace_back(t_custom_code{m_values[tick.tick], tick.gcode, tick.extruder, tick.color}); values.emplace_back(Item{m_values[tick.tick], tick.type, tick.extruder, tick.color, tick.extra});
} }
if (m_force_mode_apply) if (m_force_mode_apply)
@ -304,7 +318,7 @@ CustomGCode::Info Control::GetTicksValues() const
return custom_gcode_per_print_z; return custom_gcode_per_print_z;
} }
void Control::SetTicksValues(const CustomGCode::Info& custom_gcode_per_print_z) void Control::SetTicksValues(const Info& custom_gcode_per_print_z)
{ {
if (m_values.empty()) if (m_values.empty())
{ {
@ -315,14 +329,14 @@ void Control::SetTicksValues(const CustomGCode::Info& custom_gcode_per_print_z)
const bool was_empty = m_ticks.empty(); const bool was_empty = m_ticks.empty();
m_ticks.ticks.clear(); m_ticks.ticks.clear();
const std::vector<t_custom_code>& heights = custom_gcode_per_print_z.gcodes; const std::vector<Item>& heights = custom_gcode_per_print_z.gcodes;
for (auto h : heights) { for (auto h : heights) {
auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon()); auto it = std::lower_bound(m_values.begin(), m_values.end(), h.print_z - epsilon());
if (it == m_values.end()) if (it == m_values.end())
continue; continue;
m_ticks.ticks.emplace(TickCode{int(it-m_values.begin()), h.gcode, h.extruder, h.color}); m_ticks.ticks.emplace(TickCode{int(it-m_values.begin()), h.type, h.extruder, h.color, h.extra});
} }
if (!was_empty && m_ticks.empty()) if (!was_empty && m_ticks.empty())
@ -345,14 +359,14 @@ void Control::SetDrawMode(bool is_sla_print, bool is_sequential_print)
void Control::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder) void Control::SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder)
{ {
m_mode = !is_one_extruder_printed_model ? t_mode::MultiExtruder : m_mode = !is_one_extruder_printed_model ? MultiExtruder :
only_extruder < 0 ? t_mode::SingleExtruder : only_extruder < 0 ? SingleExtruder :
t_mode::MultiAsSingle; MultiAsSingle;
if (!m_ticks.mode) if (!m_ticks.mode)
m_ticks.mode = m_mode; m_ticks.mode = m_mode;
m_only_extruder = only_extruder; m_only_extruder = only_extruder;
UseDefaultColors(m_mode == t_mode::SingleExtruder); UseDefaultColors(m_mode == SingleExtruder);
} }
void Control::SetExtruderColors( const std::vector<std::string>& extruder_colors) void Control::SetExtruderColors( const std::vector<std::string>& extruder_colors)
@ -653,11 +667,11 @@ void Control::draw_ticks(wxDC& dc)
// if we have non-regular draw mode, all ticks should be marked with error icon // if we have non-regular draw mode, all ticks should be marked with error icon
if (m_draw_mode != dmRegular) if (m_draw_mode != dmRegular)
icon_name = focused_tick ? "error_tick_f" : "error_tick"; icon_name = focused_tick ? "error_tick_f" : "error_tick";
else if (tick.gcode == ColorChangeCode || tick.gcode == ToolChangeCode) { else if (tick.type == ColorChange || tick.type == ToolChange) {
if (m_ticks.is_conflict_tick(tick, m_mode, m_only_extruder, m_values[tick.tick])) if (m_ticks.is_conflict_tick(tick, m_mode, m_only_extruder, m_values[tick.tick]))
icon_name = focused_tick ? "error_tick_f" : "error_tick"; icon_name = focused_tick ? "error_tick_f" : "error_tick";
} }
else if (tick.gcode == PausePrintCode) else if (tick.type == PausePrint)
icon_name = focused_tick ? "pause_print_f" : "pause_print"; icon_name = focused_tick ? "pause_print_f" : "pause_print";
else else
icon_name = focused_tick ? "edit_gcode_f" : "edit_gcode"; icon_name = focused_tick ? "edit_gcode_f" : "edit_gcode";
@ -682,7 +696,7 @@ std::string Control::get_color_for_tool_change_tick(std::set<TickCode>::const_it
auto it_n = it; auto it_n = it;
while (it_n != m_ticks.ticks.begin()) { while (it_n != m_ticks.ticks.begin()) {
--it_n; --it_n;
if (it_n->gcode == ColorChangeCode && it_n->extruder == current_extruder) if (it_n->type == ColorChange && it_n->extruder == current_extruder)
return it_n->color; return it_n->color;
} }
@ -696,13 +710,13 @@ std::string Control::get_color_for_color_change_tick(std::set<TickCode>::const_i
bool is_tool_change = false; bool is_tool_change = false;
while (it_n != m_ticks.ticks.begin()) { while (it_n != m_ticks.ticks.begin()) {
--it_n; --it_n;
if (it_n->gcode == ToolChangeCode) { if (it_n->type == ToolChange) {
is_tool_change = true; is_tool_change = true;
if (it_n->extruder == it->extruder) if (it_n->extruder == it->extruder)
return it->color; return it->color;
break; break;
} }
if (it_n->gcode == ColorChangeCode && it_n->extruder == it->extruder) if (it_n->type == ColorChange && it_n->extruder == it->extruder)
return it->color; return it->color;
} }
if (!is_tool_change && it->extruder == def_extruder) if (!is_tool_change && it->extruder == def_extruder)
@ -740,28 +754,28 @@ void Control::draw_colored_band(wxDC& dc)
wxRect main_band = get_colored_band_rect(); wxRect main_band = get_colored_band_rect();
// don't color a band for MultiExtruder mode // don't color a band for MultiExtruder mode
if (m_ticks.empty() || m_mode == t_mode::MultiExtruder) if (m_ticks.empty() || m_mode == MultiExtruder)
{ {
draw_band(dc, GetParent()->GetBackgroundColour(), main_band); draw_band(dc, GetParent()->GetBackgroundColour(), main_band);
return; return;
} }
const int default_color_idx = m_mode==t_mode::MultiAsSingle ? std::max<int>(m_only_extruder - 1, 0) : 0; const int default_color_idx = m_mode==MultiAsSingle ? std::max<int>(m_only_extruder - 1, 0) : 0;
draw_band(dc, wxColour(m_extruder_colors[default_color_idx]), main_band); draw_band(dc, wxColour(m_extruder_colors[default_color_idx]), main_band);
std::set<TickCode>::const_iterator tick_it = m_ticks.ticks.begin(); std::set<TickCode>::const_iterator tick_it = m_ticks.ticks.begin();
while (tick_it != m_ticks.ticks.end()) while (tick_it != m_ticks.ticks.end())
{ {
if ( (m_mode == t_mode::SingleExtruder && tick_it->gcode == ColorChangeCode ) || if ( (m_mode == SingleExtruder && tick_it->type == ColorChange ) ||
(m_mode == t_mode::MultiAsSingle && (tick_it->gcode == ToolChangeCode || tick_it->gcode == ColorChangeCode)) ) (m_mode == MultiAsSingle && (tick_it->type == ToolChange || tick_it->type == ColorChange)) )
{ {
const wxCoord pos = get_position_from_value(tick_it->tick); const wxCoord pos = get_position_from_value(tick_it->tick);
is_horizontal() ? main_band.SetLeft(SLIDER_MARGIN + pos) : is_horizontal() ? main_band.SetLeft(SLIDER_MARGIN + pos) :
main_band.SetBottom(pos - 1); main_band.SetBottom(pos - 1);
const std::string clr_str = m_mode == t_mode::SingleExtruder ? tick_it->color : const std::string clr_str = m_mode == SingleExtruder ? tick_it->color :
tick_it->gcode == ToolChangeCode ? tick_it->type == ToolChange ?
get_color_for_tool_change_tick(tick_it) : get_color_for_tool_change_tick(tick_it) :
get_color_for_color_change_tick(tick_it); get_color_for_color_change_tick(tick_it);
@ -950,17 +964,17 @@ wxString Control::get_tooltip(int tick/*=-1*/)
if (m_focus == fiNone) if (m_focus == fiNone)
return ""; return "";
if (m_focus == fiOneLayerIcon) if (m_focus == fiOneLayerIcon)
return _(L("One layer mode")); return _L("One layer mode");
if (m_focus == fiRevertIcon) if (m_focus == fiRevertIcon)
return _(L("Discard all custom changes")); return _L("Discard all custom changes");
if (m_focus == fiCogIcon) if (m_focus == fiCogIcon)
return m_mode == t_mode::MultiAsSingle ? return m_mode == MultiAsSingle ?
GUI::from_u8((boost::format(_utf8(L("Jump to height %s or " GUI::from_u8((boost::format(_u8L("Jump to height %s or "
"Set extruder sequence for the entire print"))) % " (Shift + G)\n").str()) : "Set extruder sequence for the entire print")) % " (Shift + G)\n").str()) :
_(L("Jump to height")) + " (Shift + G)"; _L("Jump to height") + " (Shift + G)";
if (m_focus == fiColorBand) if (m_focus == fiColorBand)
return m_mode != t_mode::SingleExtruder ? "" : return m_mode != SingleExtruder ? "" :
_(L("Edit current color - Right click the colored slider segment")); _L("Edit current color - Right click the colored slider segment");
if (m_draw_mode == dmSlaPrint) if (m_draw_mode == dmSlaPrint)
return ""; // no drawn ticks and no tooltips for them in SlaPrinting mode return ""; // no drawn ticks and no tooltips for them in SlaPrinting mode
@ -970,10 +984,10 @@ wxString Control::get_tooltip(int tick/*=-1*/)
if (tick_code_it == m_ticks.ticks.end() && m_focus == fiActionIcon) // tick doesn't exist if (tick_code_it == m_ticks.ticks.end() && m_focus == fiActionIcon) // tick doesn't exist
{ {
// Show mode as a first string of tooltop // Show mode as a first string of tooltop
tooltip = " " + _(L("Print mode")) + ": "; tooltip = " " + _L("Print mode") + ": ";
tooltip += (m_mode == t_mode::SingleExtruder ? CustomGCode::SingleExtruderMode : tooltip += (m_mode == SingleExtruder ? SingleExtruderMode :
m_mode == t_mode::MultiAsSingle ? CustomGCode::MultiAsSingleMode : m_mode == MultiAsSingle ? MultiAsSingleMode :
CustomGCode::MultiExtruderMode ); MultiExtruderMode );
tooltip += "\n\n"; tooltip += "\n\n";
/* Note: just on OSX!!! /* Note: just on OSX!!!
@ -983,68 +997,70 @@ wxString Control::get_tooltip(int tick/*=-1*/)
* */ * */
// Show list of actions with new tick // Show list of actions with new tick
tooltip += ( m_mode == t_mode::MultiAsSingle ? tooltip += ( m_mode == MultiAsSingle ?
_(L("Add extruder change - Left click")) : _L("Add extruder change - Left click") :
m_mode == t_mode::SingleExtruder ? m_mode == SingleExtruder ?
_(L("Add color change - Left click for predefined color or " _L("Add color change - Left click for predefined color or "
"Shift + Left click for custom color selection")) : "Shift + Left click for custom color selection") :
_(L("Add color change - Left click")) ) + " " + _L("Add color change - Left click") ) + " " +
_(L("or press \"+\" key")) + "\n" + ( _L("or press \"+\" key") + "\n" + (
is_osx ? is_osx ?
_(L("Add another code - Ctrl + Left click")) : _L("Add another code - Ctrl + Left click") :
_(L("Add another code - Right click")) ); _L("Add another code - Right click") );
} }
if (tick_code_it != m_ticks.ticks.end()) // tick exists if (tick_code_it != m_ticks.ticks.end()) // tick exists
{ {
if (m_draw_mode == dmSequentialFffPrint) if (m_draw_mode == dmSequentialFffPrint)
return _(L("The sequential print is on.\n" return _L("The sequential print is on.\n"
"It's impossible to apply any custom G-code for objects printing sequentually.\n" "It's impossible to apply any custom G-code for objects printing sequentually.\n"
"This code won't be processed during G-code generation.")); "This code won't be processed during G-code generation.");
// Show custom Gcode as a first string of tooltop // Show custom Gcode as a first string of tooltop
tooltip = " "; tooltip = " ";
tooltip += tooltip +=
tick_code_it->gcode == ColorChangeCode ? tick_code_it->type == ColorChange ?
(m_mode == t_mode::SingleExtruder ? (m_mode == SingleExtruder ?
format_wxstr(_L("Color change (\"%1%\")"), tick_code_it->gcode) : format_wxstr(_L("Color change (\"%1%\")"), gcode(ColorChange)) :
format_wxstr(_L("Color change (\"%1%\") for Extruder %2%"), tick_code_it->gcode, tick_code_it->extruder)) : format_wxstr(_L("Color change (\"%1%\") for Extruder %2%"), gcode(ColorChange), tick_code_it->extruder)) :
tick_code_it->gcode == PausePrintCode ? tick_code_it->type == PausePrint ?
format_wxstr(_L("Pause print (\"%1%\")"), tick_code_it->gcode) : format_wxstr(_L("Pause print (\"%1%\")"), gcode(PausePrint)) :
tick_code_it->gcode == ToolChangeCode ? tick_code_it->type == Template ?
format_wxstr(_L("Extruder (tool) is changed to Extruder \"%1%\""), tick_code_it->extruder) : format_wxstr(_L("Custom template (\"%1%\")"), gcode(Template)) :
from_u8(tick_code_it->gcode); tick_code_it->type == ToolChange ?
format_wxstr(_L("Extruder (tool) is changed to Extruder \"%1%\""), tick_code_it->extruder) :
from_u8(tick_code_it->extra);// tick_code_it->type == Custom
// If tick is marked as a conflict (exclamation icon), // If tick is marked as a conflict (exclamation icon),
// we should to explain why // we should to explain why
ConflictType conflict = m_ticks.is_conflict_tick(*tick_code_it, m_mode, m_only_extruder, m_values[tick]); ConflictType conflict = m_ticks.is_conflict_tick(*tick_code_it, m_mode, m_only_extruder, m_values[tick]);
if (conflict != ctNone) if (conflict != ctNone)
tooltip += "\n\n" + _(L("Note")) + "! "; tooltip += "\n\n" + _L("Note") + "! ";
if (conflict == ctModeConflict) if (conflict == ctModeConflict)
tooltip += _(L("G-code associated to this tick mark is in a conflict with print mode.\n" tooltip += _L("G-code associated to this tick mark is in a conflict with print mode.\n"
"Editing it will cause changes of Slider data.")); "Editing it will cause changes of Slider data.");
else if (conflict == ctMeaninglessColorChange) else if (conflict == ctMeaninglessColorChange)
tooltip += _(L("There is a color change for extruder that won't be used till the end of print job.\n" tooltip += _L("There is a color change for extruder that won't be used till the end of print job.\n"
"This code won't be processed during G-code generation.")); "This code won't be processed during G-code generation.");
else if (conflict == ctMeaninglessToolChange) else if (conflict == ctMeaninglessToolChange)
tooltip += _(L("There is an extruder change set to the same extruder.\n" tooltip += _L("There is an extruder change set to the same extruder.\n"
"This code won't be processed during G-code generation.")); "This code won't be processed during G-code generation.");
else if (conflict == ctRedundant) else if (conflict == ctRedundant)
tooltip += _(L("There is a color change for extruder that has not been used before.\n" tooltip += _L("There is a color change for extruder that has not been used before.\n"
"Check your settings to avoid redundant color changes.")); "Check your settings to avoid redundant color changes.");
// Show list of actions with existing tick // Show list of actions with existing tick
if (m_focus == fiActionIcon) if (m_focus == fiActionIcon)
tooltip += "\n\n" + _(L("Delete tick mark - Left click or press \"-\" key")) + "\n" + ( tooltip += "\n\n" + _L("Delete tick mark - Left click or press \"-\" key") + "\n" + (
is_osx ? is_osx ?
_(L("Edit tick mark - Ctrl + Left click")) : _L("Edit tick mark - Ctrl + Left click") :
_(L("Edit tick mark - Right click")) ); _L("Edit tick mark - Right click") );
} }
return tooltip; return tooltip;
} }
int Control::get_edited_tick_for_position(const wxPoint pos, const std::string& gcode /*= ColorChangeCode*/) int Control::get_edited_tick_for_position(const wxPoint pos, Type type /*= ColorChange*/)
{ {
if (m_ticks.empty()) if (m_ticks.empty())
return -1; return -1;
@ -1054,7 +1070,7 @@ int Control::get_edited_tick_for_position(const wxPoint pos, const std::string&
while (it != m_ticks.ticks.begin()) { while (it != m_ticks.ticks.begin()) {
--it; --it;
if (it->gcode == gcode) if (it->type == type)
return it->tick; return it->tick;
} }
@ -1080,7 +1096,7 @@ void Control::OnMotion(wxMouseEvent& event)
m_focus = fiRevertIcon; m_focus = fiRevertIcon;
else if (is_point_in_rect(pos, m_rect_cog_icon)) else if (is_point_in_rect(pos, m_rect_cog_icon))
m_focus = fiCogIcon; m_focus = fiCogIcon;
else if (m_mode == t_mode::SingleExtruder && is_point_in_rect(pos, get_colored_band_rect()) && else if (m_mode == SingleExtruder && is_point_in_rect(pos, get_colored_band_rect()) &&
get_edited_tick_for_position(pos) >= 0 ) get_edited_tick_for_position(pos) >= 0 )
m_focus = fiColorBand; m_focus = fiColorBand;
else { else {
@ -1137,21 +1153,21 @@ void Control::append_change_extruder_menu_item(wxMenu* menu, bool switch_current
const wxString item_name = wxString::Format(_(L("Extruder %d")), i) + const wxString item_name = wxString::Format(_(L("Extruder %d")), i) +
(is_active_extruder ? " (" + _(L("active")) + ")" : ""); (is_active_extruder ? " (" + _(L("active")) + ")" : "");
if (m_mode == t_mode::MultiAsSingle) if (m_mode == MultiAsSingle)
append_menu_item(change_extruder_menu, wxID_ANY, item_name, "", append_menu_item(change_extruder_menu, wxID_ANY, item_name, "",
[this, i](wxCommandEvent&) { add_code_as_tick(ToolChangeCode, i); }, *icons[i-1], menu, [this, i](wxCommandEvent&) { add_code_as_tick(ToolChange, i); }, *icons[i-1], menu,
[is_active_extruder]() { return !is_active_extruder; }, GUI::wxGetApp().plater()); [is_active_extruder]() { return !is_active_extruder; }, GUI::wxGetApp().plater());
} }
const wxString change_extruder_menu_name = m_mode == t_mode::MultiAsSingle ? const wxString change_extruder_menu_name = m_mode == MultiAsSingle ?
(switch_current_code ? _(L("Switch code to Change extruder")) : _(L("Change extruder")) ) : (switch_current_code ? _L("Switch code to Change extruder") : _L("Change extruder") ) :
_(L("Change extruder (N/A)")); _L("Change extruder (N/A)");
wxMenuItem* change_extruder_menu_item = menu->AppendSubMenu(change_extruder_menu, change_extruder_menu_name, _(L("Use another extruder"))); wxMenuItem* change_extruder_menu_item = menu->AppendSubMenu(change_extruder_menu, change_extruder_menu_name, _(L("Use another extruder")));
change_extruder_menu_item->SetBitmap(create_scaled_bitmap(active_extruders[1] > 0 ? "edit_uni" : "change_extruder")); change_extruder_menu_item->SetBitmap(create_scaled_bitmap(active_extruders[1] > 0 ? "edit_uni" : "change_extruder"));
GUI::wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this, change_extruder_menu_item](wxUpdateUIEvent& evt) { GUI::wxGetApp().plater()->Bind(wxEVT_UPDATE_UI, [this, change_extruder_menu_item](wxUpdateUIEvent& evt) {
enable_menu_item(evt, [this]() {return m_mode == t_mode::MultiAsSingle; }, change_extruder_menu_item, this); }, enable_menu_item(evt, [this]() {return m_mode == MultiAsSingle; }, change_extruder_menu_item, this); },
change_extruder_menu_item->GetId()); change_extruder_menu_item->GetId());
} }
} }
@ -1174,13 +1190,13 @@ void Control::append_add_color_change_menu_item(wxMenu* menu, bool switch_curren
(is_used_extruder ? " (" + _(L("used")) + ")" : ""); (is_used_extruder ? " (" + _(L("used")) + ")" : "");
append_menu_item(add_color_change_menu, wxID_ANY, item_name, "", append_menu_item(add_color_change_menu, wxID_ANY, item_name, "",
[this, i](wxCommandEvent&) { add_code_as_tick(ColorChangeCode, i); }, "", menu, [this, i](wxCommandEvent&) { add_code_as_tick(ColorChange, i); }, "", menu,
[]() { return true; }, GUI::wxGetApp().plater()); []() { return true; }, GUI::wxGetApp().plater());
} }
const wxString menu_name = switch_current_code ? const wxString menu_name = switch_current_code ?
format_wxstr(_L("Switch code to Color change (%1%) for:"), ColorChangeCode) : format_wxstr(_L("Switch code to Color change (%1%) for:"), gcode(ColorChange)) :
format_wxstr(_L("Add color change (%1%) for:"), ColorChangeCode); format_wxstr(_L("Add color change (%1%) for:"), gcode(ColorChange));
wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, ""); wxMenuItem* add_color_change_menu_item = menu->AppendSubMenu(add_color_change_menu, menu_name, "");
add_color_change_menu_item->SetBitmap(create_scaled_bitmap("colorchange_add_m")); add_color_change_menu_item->SetBitmap(create_scaled_bitmap("colorchange_add_m"));
} }
@ -1204,7 +1220,7 @@ void Control::OnLeftUp(wxMouseEvent& event)
add_current_tick(); add_current_tick();
break; break;
case maCogIconClick : case maCogIconClick :
if (m_mode == t_mode::MultiAsSingle && m_draw_mode == dmRegular) if (m_mode == MultiAsSingle && m_draw_mode == dmRegular)
show_cog_icon_context_menu(); show_cog_icon_context_menu();
else else
jump_to_print_z(); jump_to_print_z();
@ -1362,9 +1378,9 @@ void Control::OnRightDown(wxMouseEvent& event)
m_mouse = m_ticks.ticks.find(TickCode{ tick }) == m_ticks.ticks.end() ? m_mouse = m_ticks.ticks.find(TickCode{ tick }) == m_ticks.ticks.end() ?
maAddMenu : maEditMenu; maAddMenu : maEditMenu;
} }
else if (m_mode == t_mode::SingleExtruder && !detect_selected_slider(pos) && is_point_in_rect(pos, get_colored_band_rect())) else if (m_mode == SingleExtruder && !detect_selected_slider(pos) && is_point_in_rect(pos, get_colored_band_rect()))
m_mouse = maForceColorEdit; m_mouse = maForceColorEdit;
else if (m_mode == t_mode::MultiAsSingle && is_point_in_rect(pos, m_rect_cog_icon)) else if (m_mode == MultiAsSingle && is_point_in_rect(pos, m_rect_cog_icon))
m_mouse = maCogIconMenu; m_mouse = maCogIconMenu;
} }
if (m_mouse != maNone || !detect_selected_slider(pos)) if (m_mouse != maNone || !detect_selected_slider(pos))
@ -1385,11 +1401,11 @@ void Control::OnRightDown(wxMouseEvent& event)
// Get active extruders for tick. // Get active extruders for tick.
// Means one current extruder for not existing tick OR // Means one current extruder for not existing tick OR
// 2 extruders - for existing tick (extruder before ToolChangeCode and extruder of current existing tick) // 2 extruders - for existing tick (extruder before ToolChange and extruder of current existing tick)
// Use those values to disable selection of active extruders // Use those values to disable selection of active extruders
std::array<int, 2> Control::get_active_extruders_for_tick(int tick) const std::array<int, 2> Control::get_active_extruders_for_tick(int tick) const
{ {
int default_initial_extruder = m_mode == t_mode::MultiAsSingle ? std::max<int>(1, m_only_extruder) : 1; int default_initial_extruder = m_mode == MultiAsSingle ? std::max<int>(1, m_only_extruder) : 1;
std::array<int, 2> extruders = { default_initial_extruder, -1 }; std::array<int, 2> extruders = { default_initial_extruder, -1 };
if (m_ticks.empty()) if (m_ticks.empty())
return extruders; return extruders;
@ -1401,7 +1417,7 @@ std::array<int, 2> Control::get_active_extruders_for_tick(int tick) const
while (it != m_ticks.ticks.begin()) { while (it != m_ticks.ticks.begin()) {
--it; --it;
if(it->gcode == ToolChangeCode) { if(it->type == ToolChange) {
extruders[0] = it->extruder; extruders[0] = it->extruder;
break; break;
} }
@ -1412,11 +1428,11 @@ std::array<int, 2> Control::get_active_extruders_for_tick(int tick) const
// Get used extruders for tick. // Get used extruders for tick.
// Means all extruders(tools) which will be used during printing from current tick to the end // Means all extruders(tools) which will be used during printing from current tick to the end
std::set<int> TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extruder, double print_z, t_mode force_mode/* = t_mode::Undef*/) const std::set<int> TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extruder, double print_z, Mode force_mode/* = Undef*/) const
{ {
t_mode e_mode = !force_mode ? mode : force_mode; Mode e_mode = !force_mode ? mode : force_mode;
if (e_mode == t_mode::MultiExtruder) if (e_mode == MultiExtruder)
{ {
// #ys_FIXME: get tool ordering from _correct_ place // #ys_FIXME: get tool ordering from _correct_ place
const ToolOrdering& tool_ordering = GUI::wxGetApp().plater()->fff_print().get_tool_ordering(); const ToolOrdering& tool_ordering = GUI::wxGetApp().plater()->fff_print().get_tool_ordering();
@ -1437,15 +1453,15 @@ std::set<int> TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extru
return used_extruders; return used_extruders;
} }
const int default_initial_extruder = e_mode == t_mode::MultiAsSingle ? std::max(only_extruder, 1) : 1; const int default_initial_extruder = e_mode == MultiAsSingle ? std::max(only_extruder, 1) : 1;
if (ticks.empty() || e_mode == t_mode::SingleExtruder) if (ticks.empty() || e_mode == SingleExtruder)
return {default_initial_extruder}; return {default_initial_extruder};
std::set<int> used_extruders; std::set<int> used_extruders;
auto it_start = ticks.lower_bound(TickCode{tick}); auto it_start = ticks.lower_bound(TickCode{tick});
auto it = it_start; auto it = it_start;
if (it == ticks.begin() && it->gcode == ToolChangeCode && if (it == ticks.begin() && it->type == ToolChange &&
tick != it->tick ) // In case of switch of ToolChange to ColorChange, when tick exists, tick != it->tick ) // In case of switch of ToolChange to ColorChange, when tick exists,
// we shouldn't change color for extruder, which will be deleted // we shouldn't change color for extruder, which will be deleted
{ {
@ -1456,7 +1472,7 @@ std::set<int> TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extru
while (it != ticks.begin()) { while (it != ticks.begin()) {
--it; --it;
if (it->gcode == ToolChangeCode && tick != it->tick) { if (it->type == ToolChange && tick != it->tick) {
used_extruders.emplace(it->extruder); used_extruders.emplace(it->extruder);
break; break;
} }
@ -1466,7 +1482,7 @@ std::set<int> TickCodeInfo::get_used_extruders_for_tick(int tick, int only_extru
used_extruders.emplace(default_initial_extruder); used_extruders.emplace(default_initial_extruder);
for (it = it_start; it != ticks.end(); ++it) for (it = it_start; it != ticks.end(); ++it)
if (it->gcode == ToolChangeCode && tick != it->tick) if (it->type == ToolChange && tick != it->tick)
used_extruders.emplace(it->extruder); used_extruders.emplace(it->extruder);
return used_extruders; return used_extruders;
@ -1476,9 +1492,9 @@ void Control::show_add_context_menu()
{ {
wxMenu menu; wxMenu menu;
if (m_mode == t_mode::SingleExtruder) { if (m_mode == SingleExtruder) {
append_menu_item(&menu, wxID_ANY, _(L("Add color change")) + " (M600)", "", append_menu_item(&menu, wxID_ANY, _L("Add color change") + " (" + gcode(ColorChange) + ")", "",
[this](wxCommandEvent&) { add_code_as_tick(ColorChangeCode); }, "colorchange_add_m", &menu); [this](wxCommandEvent&) { add_code_as_tick(ColorChange); }, "colorchange_add_m", &menu);
UseDefaultColors(false); UseDefaultColors(false);
} }
@ -1487,11 +1503,14 @@ void Control::show_add_context_menu()
append_add_color_change_menu_item(&menu); append_add_color_change_menu_item(&menu);
} }
append_menu_item(&menu, wxID_ANY, _(L("Add pause print")) + " (M601)", "", append_menu_item(&menu, wxID_ANY, _L("Add pause print") + " (" + gcode(PausePrint) + ")", "",
[this](wxCommandEvent&) { add_code_as_tick(PausePrintCode); }, "pause_print", &menu); [this](wxCommandEvent&) { add_code_as_tick(PausePrint); }, "pause_print", &menu);
append_menu_item(&menu, wxID_ANY, _(L("Add custom G-code")), "", append_menu_item(&menu, wxID_ANY, _L("Add custom template") + " (" + gcode(Template) + ")", "",
[this](wxCommandEvent&) { add_code_as_tick(""); }, "edit_gcode", &menu); [this](wxCommandEvent&) { add_code_as_tick(Template); }, "edit_gcode", &menu);
append_menu_item(&menu, wxID_ANY, _L("Add custom G-code"), "",
[this](wxCommandEvent&) { add_code_as_tick(Custom); }, "edit_gcode", &menu);
GUI::wxGetApp().plater()->PopupMenu(&menu); GUI::wxGetApp().plater()->PopupMenu(&menu);
} }
@ -1502,23 +1521,23 @@ void Control::show_edit_context_menu()
std::set<TickCode>::iterator it = m_ticks.ticks.find(TickCode{ m_selection == ssLower ? m_lower_value : m_higher_value }); std::set<TickCode>::iterator it = m_ticks.ticks.find(TickCode{ m_selection == ssLower ? m_lower_value : m_higher_value });
if (it->gcode == ToolChangeCode) { if (it->type == ToolChange) {
if (m_mode == t_mode::MultiAsSingle) if (m_mode == MultiAsSingle)
append_change_extruder_menu_item(&menu); append_change_extruder_menu_item(&menu);
append_add_color_change_menu_item(&menu, true); append_add_color_change_menu_item(&menu, true);
} }
else else
append_menu_item(&menu, wxID_ANY, it->gcode == ColorChangeCode ? _(L("Edit color")) : append_menu_item(&menu, wxID_ANY, it->type == ColorChange ? _(L("Edit color")) :
it->gcode == PausePrintCode ? _(L("Edit pause print message")) : it->type == PausePrint ? _(L("Edit pause print message")) :
_(L("Edit custom G-code")), "", _(L("Edit custom G-code")), "",
[this](wxCommandEvent&) { edit_tick(); }, "edit_uni", &menu); [this](wxCommandEvent&) { edit_tick(); }, "edit_uni", &menu);
if (it->gcode == ColorChangeCode && m_mode == t_mode::MultiAsSingle) if (it->type == ColorChange && m_mode == MultiAsSingle)
append_change_extruder_menu_item(&menu, true); append_change_extruder_menu_item(&menu, true);
append_menu_item(&menu, wxID_ANY, it->gcode == ColorChangeCode ? _(L("Delete color change")) : append_menu_item(&menu, wxID_ANY, it->type == ColorChange ? _(L("Delete color change")) :
it->gcode == ToolChangeCode ? _(L("Delete tool change")) : it->type == ToolChange ? _(L("Delete tool change")) :
it->gcode == PausePrintCode ? _(L("Delete pause print")) : it->type == PausePrint ? _(L("Delete pause print")) :
_(L("Delete custom G-code")), "", _(L("Delete custom G-code")), "",
[this](wxCommandEvent&) { delete_current_tick();}, "colorchange_del_f", &menu); [this](wxCommandEvent&) { delete_current_tick();}, "colorchange_del_f", &menu);
@ -1665,13 +1684,13 @@ static double get_print_z_to_jump(double active_print_z, double min_z, double ma
return dlg.GetValue().ToCDouble(&value) ? value : -1.0; return dlg.GetValue().ToCDouble(&value) ? value : -1.0;
} }
void Control::add_code_as_tick(std::string code, int selected_extruder/* = -1*/) void Control::add_code_as_tick(Type type, int selected_extruder/* = -1*/)
{ {
if (m_selection == ssUndef) if (m_selection == ssUndef)
return; return;
const int tick = m_selection == ssLower ? m_lower_value : m_higher_value; const int tick = m_selection == ssLower ? m_lower_value : m_higher_value;
if ( !check_ticks_changed_event(code) ) if ( !check_ticks_changed_event(type) )
return; return;
const int extruder = selected_extruder > 0 ? selected_extruder : std::max<int>(1, m_only_extruder); const int extruder = selected_extruder > 0 ? selected_extruder : std::max<int>(1, m_only_extruder);
@ -1679,18 +1698,18 @@ void Control::add_code_as_tick(std::string code, int selected_extruder/* = -1*/)
if ( it == m_ticks.ticks.end() ) { if ( it == m_ticks.ticks.end() ) {
// try to add tick // try to add tick
if (!m_ticks.add_tick(tick, code, extruder, m_values[tick])) if (!m_ticks.add_tick(tick, type, extruder, m_values[tick]))
return; return;
} }
else if (code == ToolChangeCode || code == ColorChangeCode) { else if (type == ToolChange || type == ColorChange) {
// try to switch tick code to ToolChangeCode or ColorChangeCode accordingly // try to switch tick code to ToolChange or ColorChange accordingly
if (!m_ticks.switch_code_for_tick(it, code, extruder)) if (!m_ticks.switch_code_for_tick(it, type, extruder))
return; return;
} }
else else
return; return;
post_ticks_changed_event(code); post_ticks_changed_event(type);
} }
void Control::add_current_tick(bool call_from_keyboard /*= false*/) void Control::add_current_tick(bool call_from_keyboard /*= false*/)
@ -1701,16 +1720,16 @@ void Control::add_current_tick(bool call_from_keyboard /*= false*/)
auto it = m_ticks.ticks.find(TickCode{ tick }); auto it = m_ticks.ticks.find(TickCode{ tick });
if (it != m_ticks.ticks.end() || // this tick is already exist if (it != m_ticks.ticks.end() || // this tick is already exist
!check_ticks_changed_event(m_mode == t_mode::MultiAsSingle ? ToolChangeCode : ColorChangeCode)) !check_ticks_changed_event(m_mode == MultiAsSingle ? ToolChange : ColorChange))
return; return;
if (m_mode == t_mode::SingleExtruder) if (m_mode == SingleExtruder)
add_code_as_tick(ColorChangeCode); add_code_as_tick(ColorChange);
else else
{ {
wxMenu menu; wxMenu menu;
if (m_mode == t_mode::MultiAsSingle) if (m_mode == MultiAsSingle)
append_change_extruder_menu_item(&menu); append_change_extruder_menu_item(&menu);
else else
append_add_color_change_menu_item(&menu); append_add_color_change_menu_item(&menu);
@ -1743,12 +1762,12 @@ void Control::delete_current_tick()
auto it = m_ticks.ticks.find(TickCode{ m_selection == ssLower ? m_lower_value : m_higher_value }); auto it = m_ticks.ticks.find(TickCode{ m_selection == ssLower ? m_lower_value : m_higher_value });
if (it == m_ticks.ticks.end() || if (it == m_ticks.ticks.end() ||
!check_ticks_changed_event(it->gcode)) !check_ticks_changed_event(it->type))
return; return;
const std::string code = it->gcode; Type type = it->type;
m_ticks.ticks.erase(it); m_ticks.ticks.erase(it);
post_ticks_changed_event(code); post_ticks_changed_event(type);
} }
void Control::edit_tick(int tick/* = -1*/) void Control::edit_tick(int tick/* = -1*/)
@ -1758,12 +1777,12 @@ void Control::edit_tick(int tick/* = -1*/)
const std::set<TickCode>::iterator it = m_ticks.ticks.find(TickCode{ tick }); const std::set<TickCode>::iterator it = m_ticks.ticks.find(TickCode{ tick });
if (it == m_ticks.ticks.end() || if (it == m_ticks.ticks.end() ||
!check_ticks_changed_event(it->gcode)) !check_ticks_changed_event(it->type))
return; return;
const std::string code = it->gcode; Type type = it->type;
if (m_ticks.edit_tick(it, m_values[it->tick])) if (m_ticks.edit_tick(it, m_values[it->tick]))
post_ticks_changed_event(code); post_ticks_changed_event(type);
} }
// switch on/off one layer mode // switch on/off one layer mode
@ -1818,7 +1837,7 @@ void Control::move_current_thumb_to_pos(wxPoint pos)
void Control::edit_extruder_sequence() void Control::edit_extruder_sequence()
{ {
if (!check_ticks_changed_event(ToolChangeCode)) if (!check_ticks_changed_event(ToolChange))
return; return;
GUI::ExtruderSequenceDialog dlg(m_extruders_sequence); GUI::ExtruderSequenceDialog dlg(m_extruders_sequence);
@ -1826,7 +1845,7 @@ void Control::edit_extruder_sequence()
return; return;
m_extruders_sequence = dlg.GetValue(); m_extruders_sequence = dlg.GetValue();
m_ticks.erase_all_ticks_with_code(ToolChangeCode); m_ticks.erase_all_ticks_with_code(ToolChange);
int tick = 0; int tick = 0;
double value = 0.0; double value = 0.0;
@ -1839,7 +1858,7 @@ void Control::edit_extruder_sequence()
bool meaningless_tick = tick == 0.0 && cur_extruder == extruder; bool meaningless_tick = tick == 0.0 && cur_extruder == extruder;
if (!meaningless_tick) if (!meaningless_tick)
m_ticks.ticks.emplace(TickCode{tick, ToolChangeCode, cur_extruder + 1, m_extruder_colors[cur_extruder]}); m_ticks.ticks.emplace(TickCode{tick, ToolChange,cur_extruder + 1, m_extruder_colors[cur_extruder]});
extruder++; extruder++;
if (extruder == extr_cnt) if (extruder == extr_cnt)
@ -1858,7 +1877,7 @@ void Control::edit_extruder_sequence()
tick += m_extruders_sequence.interval_by_layers; tick += m_extruders_sequence.interval_by_layers;
} }
post_ticks_changed_event(ToolChangeCode); post_ticks_changed_event(ToolChange);
} }
void Control::jump_to_print_z() void Control::jump_to_print_z()
@ -1877,64 +1896,64 @@ void Control::jump_to_print_z()
SetHigherValue(tick_value); SetHigherValue(tick_value);
} }
void Control::post_ticks_changed_event(const std::string& gcode /*= ""*/) void Control::post_ticks_changed_event(Type type /*= Custom*/)
{ {
m_force_mode_apply = (gcode.empty() || gcode == ColorChangeCode || gcode == ToolChangeCode); m_force_mode_apply = (type == Custom || type == ColorChange || type == ToolChange);
wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED)); wxPostEvent(this->GetParent(), wxCommandEvent(wxCUSTOMEVT_TICKSCHANGED));
} }
bool Control::check_ticks_changed_event(const std::string& gcode) bool Control::check_ticks_changed_event(Type type)
{ {
if ( m_ticks.mode == m_mode || if ( m_ticks.mode == m_mode ||
(gcode != ColorChangeCode && gcode != ToolChangeCode) || (type != ColorChange && type != ToolChange) ||
(m_ticks.mode == t_mode::SingleExtruder && m_mode == t_mode::MultiAsSingle) || // All ColorChanges will be applied for 1st extruder (m_ticks.mode == SingleExtruder && m_mode == MultiAsSingle) || // All ColorChanges will be applied for 1st extruder
(m_ticks.mode == t_mode::MultiExtruder && m_mode == t_mode::MultiAsSingle) ) // Just mark ColorChanges for all unused extruders (m_ticks.mode == MultiExtruder && m_mode == MultiAsSingle) ) // Just mark ColorChanges for all unused extruders
return true; return true;
if ((m_ticks.mode == t_mode::SingleExtruder && m_mode == t_mode::MultiExtruder ) || if ((m_ticks.mode == SingleExtruder && m_mode == MultiExtruder ) ||
(m_ticks.mode == t_mode::MultiExtruder && m_mode == t_mode::SingleExtruder) ) (m_ticks.mode == MultiExtruder && m_mode == SingleExtruder) )
{ {
if (!m_ticks.has_tick_with_code(ColorChangeCode)) if (!m_ticks.has_tick_with_code(ColorChange))
return true; return true;
wxString message = (m_ticks.mode == t_mode::SingleExtruder ? wxString message = (m_ticks.mode == SingleExtruder ?
_(L("The last color change data was saved for a single extruder printing.")) : _L("The last color change data was saved for a single extruder printing.") :
_(L("The last color change data was saved for a multi extruder printing.")) _L("The last color change data was saved for a multi extruder printing.")
) + "\n" + ) + "\n" +
_(L("Your current changes will delete all saved color changes.")) + "\n\n\t" + _L("Your current changes will delete all saved color changes.") + "\n\n\t" +
_(L("Are you sure you want to continue?")); _L("Are you sure you want to continue?");
wxMessageDialog msg(this, message, _(L("Notice")), wxYES_NO); wxMessageDialog msg(this, message, _L("Notice"), wxYES_NO);
if (msg.ShowModal() == wxID_YES) { if (msg.ShowModal() == wxID_YES) {
m_ticks.erase_all_ticks_with_code(ColorChangeCode); m_ticks.erase_all_ticks_with_code(ColorChange);
post_ticks_changed_event(ColorChangeCode); post_ticks_changed_event(ColorChange);
} }
return false; return false;
} }
// m_ticks_mode == t_mode::MultiAsSingle // m_ticks_mode == MultiAsSingle
if( m_ticks.has_tick_with_code(ToolChangeCode) ) if( m_ticks.has_tick_with_code(ToolChange) )
{ {
wxString message = m_mode == t_mode::SingleExtruder ? ( wxString message = m_mode == SingleExtruder ? (
_(L("The last color change data was saved for a multi extruder printing.")) + "\n\n" + _L("The last color change data was saved for a multi extruder printing.") + "\n\n" +
_(L("Select YES if you want to delete all saved tool changes, \n" _L("Select YES if you want to delete all saved tool changes, \n"
"NO if you want all tool changes switch to color changes, \n" "NO if you want all tool changes switch to color changes, \n"
"or CANCEL to leave it unchanged.")) + "\n\n\t" + "or CANCEL to leave it unchanged.") + "\n\n\t" +
_(L("Do you want to delete all saved tool changes?")) _L("Do you want to delete all saved tool changes?")
) : ( // t_mode::MultiExtruder ): ( // MultiExtruder
_(L("The last color change data was saved for a multi extruder printing with tool changes for whole print.")) + "\n\n" + _L("The last color change data was saved for a multi extruder printing with tool changes for whole print.") + "\n\n" +
_(L("Your current changes will delete all saved extruder (tool) changes.")) + "\n\n\t" + _L("Your current changes will delete all saved extruder (tool) changes.") + "\n\n\t" +
_(L("Are you sure you want to continue?")) ) ; _L("Are you sure you want to continue?") ) ;
wxMessageDialog msg(this, message, _(L("Notice")), wxYES_NO | (m_mode == t_mode::SingleExtruder ? wxCANCEL : 0)); wxMessageDialog msg(this, message, _L("Notice"), wxYES_NO | (m_mode == SingleExtruder ? wxCANCEL : 0));
const int answer = msg.ShowModal(); const int answer = msg.ShowModal();
if (answer == wxID_YES) { if (answer == wxID_YES) {
m_ticks.erase_all_ticks_with_code(ToolChangeCode); m_ticks.erase_all_ticks_with_code(ToolChange);
post_ticks_changed_event(ToolChangeCode); post_ticks_changed_event(ToolChange);
} }
else if (m_mode == t_mode::SingleExtruder && answer == wxID_NO) { else if (m_mode == SingleExtruder && answer == wxID_NO) {
m_ticks.switch_code(ToolChangeCode, ColorChangeCode); m_ticks.switch_code(ToolChange, ColorChange);
post_ticks_changed_event(ColorChangeCode); post_ticks_changed_event(ColorChange);
} }
return false; return false;
} }
@ -1942,9 +1961,9 @@ bool Control::check_ticks_changed_event(const std::string& gcode)
return true; return true;
} }
std::string TickCodeInfo::get_color_for_tick(TickCode tick, const std::string& code, const int extruder) std::string TickCodeInfo::get_color_for_tick(TickCode tick, Type type, const int extruder)
{ {
if (mode == t_mode::SingleExtruder && code == ColorChangeCode && m_use_default_colors) if (mode == SingleExtruder && type == ColorChange && m_use_default_colors)
{ {
const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors(); const std::vector<std::string>& colors = GCodePreviewData::ColorPrintColors();
if (ticks.empty()) if (ticks.empty())
@ -1956,14 +1975,14 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, const std::string& c
std::string color = (*m_colors)[extruder - 1]; std::string color = (*m_colors)[extruder - 1];
if (code == ColorChangeCode) if (type == ColorChange)
{ {
if (!ticks.empty()) if (!ticks.empty())
{ {
auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), tick ); auto before_tick_it = std::lower_bound(ticks.begin(), ticks.end(), tick );
while (before_tick_it != ticks.begin()) { while (before_tick_it != ticks.begin()) {
--before_tick_it; --before_tick_it;
if (before_tick_it->gcode == ColorChangeCode && before_tick_it->extruder == extruder) { if (before_tick_it->type == ColorChange && before_tick_it->extruder == extruder) {
color = before_tick_it->color; color = before_tick_it->color;
break; break;
} }
@ -1975,63 +1994,61 @@ std::string TickCodeInfo::get_color_for_tick(TickCode tick, const std::string& c
return color; return color;
} }
bool TickCodeInfo::add_tick(const int tick, std::string& code, const int extruder, double print_z) bool TickCodeInfo::add_tick(const int tick, Type type, const int extruder, double print_z)
{ {
std::string color; std::string color;
if (code.empty()) // custom Gcode std::string extra;
if (type == Custom) // custom Gcode
{ {
code = get_custom_code(custom_gcode, print_z); extra = get_custom_code(custom_gcode, print_z);
if (code.empty()) if (extra.empty())
return false; return false;
custom_gcode = code; custom_gcode = extra;
} }
else if (code == PausePrintCode) else if (type == PausePrint)
{ {
/* PausePrintCode doesn't need a color, so extra = get_pause_print_msg(pause_print_msg, print_z);
* this field is used for save a short message shown on Printer display if (extra.empty())
* */
color = get_pause_print_msg(pause_print_msg, print_z);
if (color.empty())
return false; return false;
pause_print_msg = color; pause_print_msg = extra;
} }
else else
{ {
color = get_color_for_tick(TickCode{ tick }, code, extruder); color = get_color_for_tick(TickCode{ tick }, type, extruder);
if (color.empty()) if (color.empty())
return false; return false;
} }
if (mode == t_mode::SingleExtruder) if (mode == SingleExtruder)
m_use_default_colors = true; m_use_default_colors = true;
ticks.emplace(TickCode{ tick, code, extruder, color }); ticks.emplace(TickCode{ tick, type, extruder, color, extra });
return true; return true;
} }
bool TickCodeInfo::edit_tick(std::set<TickCode>::iterator it, double print_z) bool TickCodeInfo::edit_tick(std::set<TickCode>::iterator it, double print_z)
{ {
std::string edited_value; std::string edited_value;
if (it->gcode == ColorChangeCode) if (it->type == ColorChange)
edited_value = get_new_color(it->color); edited_value = get_new_color(it->color);
else if (it->gcode == PausePrintCode) else if (it->type == PausePrint)
edited_value = get_pause_print_msg(it->color, print_z); edited_value = get_pause_print_msg(it->extra, print_z);
else else
edited_value = get_custom_code(it->gcode, print_z); edited_value = get_custom_code(it->extra, print_z);
if (edited_value.empty()) if (edited_value.empty())
return false; return false;
TickCode changed_tick = *it; TickCode changed_tick = *it;
if (it->gcode == ColorChangeCode || it->gcode == PausePrintCode) { if (it->type == ColorChange) {
if (it->color == edited_value) if (it->color == edited_value)
return false; return false;
changed_tick.color = edited_value; changed_tick.color = edited_value;
} }
else { else if (it->type == Custom || it->type == PausePrint){
if (it->gcode == edited_value) if (it->extra == edited_value)
return false; return false;
changed_tick.gcode = edited_value; changed_tick.extra = edited_value;
} }
ticks.erase(it); ticks.erase(it);
@ -2040,13 +2057,13 @@ bool TickCodeInfo::edit_tick(std::set<TickCode>::iterator it, double print_z)
return true; return true;
} }
void TickCodeInfo::switch_code(const std::string& code_from, const std::string& code_to) void TickCodeInfo::switch_code(Type type_from, Type type_to)
{ {
for (auto it{ ticks.begin() }, end{ ticks.end() }; it != end; ) for (auto it{ ticks.begin() }, end{ ticks.end() }; it != end; )
if (it->gcode == code_from) if (it->type == type_from)
{ {
TickCode tick = *it; TickCode tick = *it;
tick.gcode = code_to; tick.type = type_to;
tick.extruder = 1; tick.extruder = 1;
ticks.erase(it); ticks.erase(it);
it = ticks.emplace(tick).first; it = ticks.emplace(tick).first;
@ -2055,14 +2072,14 @@ void TickCodeInfo::switch_code(const std::string& code_from, const std::string&
++it; ++it;
} }
bool TickCodeInfo::switch_code_for_tick(std::set<TickCode>::iterator it, const std::string& code_to, const int extruder) bool TickCodeInfo::switch_code_for_tick(std::set<TickCode>::iterator it, Type type_to, const int extruder)
{ {
const std::string color = get_color_for_tick(*it, code_to, extruder); const std::string color = get_color_for_tick(*it, type_to, extruder);
if (color.empty()) if (color.empty())
return false; return false;
TickCode changed_tick = *it; TickCode changed_tick = *it;
changed_tick.gcode = code_to; changed_tick.type = type_to;
changed_tick.extruder = extruder; changed_tick.extruder = extruder;
changed_tick.color = color; changed_tick.color = color;
@ -2072,36 +2089,36 @@ bool TickCodeInfo::switch_code_for_tick(std::set<TickCode>::iterator it, const s
return true; return true;
} }
void TickCodeInfo::erase_all_ticks_with_code(const std::string& gcode) void TickCodeInfo::erase_all_ticks_with_code(Type type)
{ {
for (auto it{ ticks.begin() }, end{ ticks.end() }; it != end; ) { for (auto it{ ticks.begin() }, end{ ticks.end() }; it != end; ) {
if (it->gcode == gcode) if (it->type == type)
it = ticks.erase(it); it = ticks.erase(it);
else else
++it; ++it;
} }
} }
bool TickCodeInfo::has_tick_with_code(const std::string& gcode) bool TickCodeInfo::has_tick_with_code(Type type)
{ {
for (const TickCode& tick : ticks) for (const TickCode& tick : ticks)
if (tick.gcode == gcode) if (tick.type == type)
return true; return true;
return false; return false;
} }
ConflictType TickCodeInfo::is_conflict_tick(const TickCode& tick, t_mode out_mode, int only_extruder, double print_z) ConflictType TickCodeInfo::is_conflict_tick(const TickCode& tick, Mode out_mode, int only_extruder, double print_z)
{ {
if ((tick.gcode == ColorChangeCode && ( if ((tick.type == ColorChange && (
(mode == t_mode::SingleExtruder && out_mode == t_mode::MultiExtruder ) || (mode == SingleExtruder && out_mode == MultiExtruder ) ||
(mode == t_mode::MultiExtruder && out_mode == t_mode::SingleExtruder) )) || (mode == MultiExtruder && out_mode == SingleExtruder) )) ||
(tick.gcode == ToolChangeCode && (tick.type == ToolChange &&
(mode == t_mode::MultiAsSingle && out_mode != t_mode::MultiAsSingle)) ) (mode == MultiAsSingle && out_mode != MultiAsSingle)) )
return ctModeConflict; return ctModeConflict;
// check ColorChange tick // check ColorChange tick
if (tick.gcode == ColorChangeCode) if (tick.type == ColorChange)
{ {
// We should mark a tick as a "MeaninglessColorChange", // We should mark a tick as a "MeaninglessColorChange",
// if it has a ColorChange for unused extruder from current print to end of the print // if it has a ColorChange for unused extruder from current print to end of the print
@ -2112,15 +2129,15 @@ ConflictType TickCodeInfo::is_conflict_tick(const TickCode& tick, t_mode out_mod
// We should mark a tick as a "Redundant", // We should mark a tick as a "Redundant",
// if it has a ColorChange for extruder that has not been used before // if it has a ColorChange for extruder that has not been used before
if (mode == t_mode::MultiAsSingle && tick.extruder != std::max<int>(only_extruder, 1) ) if (mode == MultiAsSingle && tick.extruder != std::max<int>(only_extruder, 1) )
{ {
auto it = ticks.lower_bound( tick ); auto it = ticks.lower_bound( tick );
if (it == ticks.begin() && it->gcode == ToolChangeCode && tick.extruder == it->extruder) if (it == ticks.begin() && it->type == ToolChange && tick.extruder == it->extruder)
return ctNone; return ctNone;
while (it != ticks.begin()) { while (it != ticks.begin()) {
--it; --it;
if (it->gcode == ToolChangeCode && tick.extruder == it->extruder) if (it->type == ToolChange && tick.extruder == it->extruder)
return ctNone; return ctNone;
} }
@ -2129,7 +2146,7 @@ ConflictType TickCodeInfo::is_conflict_tick(const TickCode& tick, t_mode out_mod
} }
// check ToolChange tick // check ToolChange tick
if (mode == t_mode::MultiAsSingle && tick.gcode == ToolChangeCode) if (mode == MultiAsSingle && tick.type == ToolChange)
{ {
// We should mark a tick as a "MeaninglessToolChange", // We should mark a tick as a "MeaninglessToolChange",
// if it has a ToolChange to the same extruder // if it has a ToolChange to the same extruder
@ -2139,7 +2156,7 @@ ConflictType TickCodeInfo::is_conflict_tick(const TickCode& tick, t_mode out_mod
while (it != ticks.begin()) { while (it != ticks.begin()) {
--it; --it;
if (it->gcode == ToolChangeCode) if (it->type == ToolChange)
return tick.extruder == it->extruder ? ctMeaninglessToolChange : ctNone; return tick.extruder == it->extruder ? ctMeaninglessToolChange : ctNone;
} }
} }

View file

@ -17,6 +17,8 @@ class wxMenu;
namespace Slic3r { namespace Slic3r {
using namespace CustomGCode;
namespace DoubleSlider { namespace DoubleSlider {
/* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values. /* For exporting GCode in GCodeWriter is used XYZF_NUM(val) = PRECISION(val, 3) for XYZ values.
@ -73,17 +75,16 @@ enum DrawMode
dmSequentialFffPrint, dmSequentialFffPrint,
}; };
using t_mode = CustomGCode::Mode;
struct TickCode struct TickCode
{ {
bool operator<(const TickCode& other) const { return other.tick > this->tick; } bool operator<(const TickCode& other) const { return other.tick > this->tick; }
bool operator>(const TickCode& other) const { return other.tick < this->tick; } bool operator>(const TickCode& other) const { return other.tick < this->tick; }
int tick = 0; int tick = 0;
std::string gcode = ColorChangeCode; Type type = ColorChange;
int extruder = 0; int extruder = 0;
std::string color; std::string color;
std::string extra;
}; };
class TickCodeInfo class TickCodeInfo
@ -97,27 +98,27 @@ class TickCodeInfo
std::vector<std::string>* m_colors {nullptr}; std::vector<std::string>* m_colors {nullptr};
std::string get_color_for_tick(TickCode tick, const std::string& code, const int extruder); std::string get_color_for_tick(TickCode tick, Type type, const int extruder);
public: public:
std::set<TickCode> ticks {}; std::set<TickCode> ticks {};
t_mode mode = t_mode::Undef; Mode mode = Undef;
bool empty() const { return ticks.empty(); } bool empty() const { return ticks.empty(); }
void set_pause_print_msg(const std::string& message) { pause_print_msg = message; } void set_pause_print_msg(const std::string& message) { pause_print_msg = message; }
bool add_tick(const int tick, std::string& code, int extruder, double print_z); bool add_tick(const int tick, Type type, int extruder, double print_z);
bool edit_tick(std::set<TickCode>::iterator it, double print_z); bool edit_tick(std::set<TickCode>::iterator it, double print_z);
void switch_code(const std::string& code_from, const std::string& code_to); void switch_code(Type type_from, Type type_to);
bool switch_code_for_tick(std::set<TickCode>::iterator it, const std::string& code_to, const int extruder); bool switch_code_for_tick(std::set<TickCode>::iterator it, Type type_to, const int extruder);
void erase_all_ticks_with_code(const std::string& gcode); void erase_all_ticks_with_code(Type type);
bool has_tick_with_code(const std::string& gcode); bool has_tick_with_code(Type type);
ConflictType is_conflict_tick(const TickCode& tick, t_mode out_mode, int only_extruder, double print_z); ConflictType is_conflict_tick(const TickCode& tick, Mode out_mode, int only_extruder, double print_z);
// Get used extruders for tick. // Get used extruders for tick.
// Means all extruders(tools) which will be used during printing from current tick to the end // Means all extruders(tools) which will be used during printing from current tick to the end
std::set<int> get_used_extruders_for_tick(int tick, int only_extruder, double print_z, t_mode force_mode = t_mode::Undef) const; std::set<int> get_used_extruders_for_tick(int tick, int only_extruder, double print_z, Mode force_mode = Undef) const;
void suppress_plus (bool suppress) { m_suppress_plus = suppress; } void suppress_plus (bool suppress) { m_suppress_plus = suppress; }
void suppress_minus(bool suppress) { m_suppress_minus = suppress; } void suppress_minus(bool suppress) { m_suppress_minus = suppress; }
@ -205,13 +206,13 @@ public:
void SetSliderValues(const std::vector<double>& values) { m_values = values; } void SetSliderValues(const std::vector<double>& values) { m_values = values; }
void ChangeOneLayerLock(); void ChangeOneLayerLock();
CustomGCode::Info GetTicksValues() const; Info GetTicksValues() const;
void SetTicksValues(const Slic3r::CustomGCode::Info &custom_gcode_per_print_z); void SetTicksValues(const Info &custom_gcode_per_print_z);
void SetDrawMode(bool is_sla_print, bool is_sequential_print); void SetDrawMode(bool is_sla_print, bool is_sequential_print);
void SetManipulationMode(t_mode mode) { m_mode = mode; } void SetManipulationMode(Mode mode) { m_mode = mode; }
t_mode GetManipulationMode() const { return m_mode; } Mode GetManipulationMode() const { return m_mode; }
void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder); void SetModeAndOnlyExtruder(const bool is_one_extruder_printed_model, const int only_extruder);
void SetExtruderColors(const std::vector<std::string>& extruder_colors); void SetExtruderColors(const std::vector<std::string>& extruder_colors);
@ -235,7 +236,7 @@ public:
void OnRightDown(wxMouseEvent& event); void OnRightDown(wxMouseEvent& event);
void OnRightUp(wxMouseEvent& event); void OnRightUp(wxMouseEvent& event);
void add_code_as_tick(std::string code, int selected_extruder = -1); void add_code_as_tick(Type type, int selected_extruder = -1);
// add default action for tick, when press "+" // add default action for tick, when press "+"
void add_current_tick(bool call_from_keyboard = false); void add_current_tick(bool call_from_keyboard = false);
// delete current tick, when press "-" // delete current tick, when press "-"
@ -293,7 +294,7 @@ private:
void get_size(int *w, int *h); void get_size(int *w, int *h);
double get_double_value(const SelectedSlider& selection); double get_double_value(const SelectedSlider& selection);
wxString get_tooltip(int tick = -1); wxString get_tooltip(int tick = -1);
int get_edited_tick_for_position(wxPoint pos, const std::string& gcode = ColorChangeCode); int get_edited_tick_for_position(wxPoint pos, Type type = ColorChange);
std::string get_color_for_tool_change_tick(std::set<TickCode>::const_iterator it) const; std::string get_color_for_tool_change_tick(std::set<TickCode>::const_iterator it) const;
std::string get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const; std::string get_color_for_color_change_tick(std::set<TickCode>::const_iterator it) const;
@ -305,8 +306,8 @@ private:
// Use those values to disable selection of active extruders // Use those values to disable selection of active extruders
std::array<int, 2> get_active_extruders_for_tick(int tick) const; std::array<int, 2> get_active_extruders_for_tick(int tick) const;
void post_ticks_changed_event(const std::string& gcode = ""); void post_ticks_changed_event(Type type = Custom);
bool check_ticks_changed_event(const std::string& gcode); bool check_ticks_changed_event(Type type);
void append_change_extruder_menu_item (wxMenu*, bool switch_current_code = false); void append_change_extruder_menu_item (wxMenu*, bool switch_current_code = false);
void append_add_color_change_menu_item(wxMenu*, bool switch_current_code = false); void append_add_color_change_menu_item(wxMenu*, bool switch_current_code = false);
@ -338,7 +339,7 @@ private:
DrawMode m_draw_mode = dmRegular; DrawMode m_draw_mode = dmRegular;
t_mode m_mode = t_mode::SingleExtruder; Mode m_mode = SingleExtruder;
int m_only_extruder = -1; int m_only_extruder = -1;
MouseAction m_mouse = maNone; MouseAction m_mouse = maNone;

View file

@ -916,7 +916,7 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
std::vector<double> print_zs = canvas.get_current_print_zs(true); std::vector<double> print_zs = canvas.get_current_print_zs(true);
for (auto custom_code : custom_gcode_per_print_z) for (auto custom_code : custom_gcode_per_print_z)
{ {
if (custom_code.gcode != ColorChangeCode) if (custom_code.type != CustomGCode::ColorChange)
continue; continue;
auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), custom_code.print_z - Slic3r::DoubleSlider::epsilon()); auto lower_b = std::lower_bound(print_zs.begin(), print_zs.end(), custom_code.print_z - Slic3r::DoubleSlider::epsilon());
@ -989,7 +989,7 @@ void GLCanvas3D::LegendTexture::fill_color_print_legend_items( const GLCanvas3D
int cnt = custom_gcode_per_print_z.size(); int cnt = custom_gcode_per_print_z.size();
int color_change_idx = color_cnt - extruders_cnt; int color_change_idx = color_cnt - extruders_cnt;
for (int i = cnt-1; i >= 0; --i) for (int i = cnt-1; i >= 0; --i)
if (custom_gcode_per_print_z[i].gcode == ColorChangeCode) { if (custom_gcode_per_print_z[i].type == CustomGCode::ColorChange) {
::memcpy((void*)(colors.data() + color_pos), (const void*)(colors_in.data() + color_in_pos), 4 * sizeof(float)); ::memcpy((void*)(colors.data() + color_pos), (const void*)(colors_in.data() + color_in_pos), 4 * sizeof(float));
color_pos += 4; color_pos += 4;
color_in_pos -= 4; color_in_pos -= 4;
@ -6052,7 +6052,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
// For coloring by a color_print(M600), return a parsed color. // For coloring by a color_print(M600), return a parsed color.
bool color_by_color_print() const { return color_print_values!=nullptr; } bool color_by_color_print() const { return color_print_values!=nullptr; }
const size_t color_print_color_idx_by_layer_idx(const size_t layer_idx) const { const size_t color_print_color_idx_by_layer_idx(const size_t layer_idx) const {
const CustomGCode::Item value{layers[layer_idx]->print_z + EPSILON, "", 0, ""}; const CustomGCode::Item value{layers[layer_idx]->print_z + EPSILON, CustomGCode::Custom, 0, ""};
auto it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value); auto it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value);
return (it - color_print_values->begin()) % number_tools(); return (it - color_print_values->begin()) % number_tools();
} }
@ -6066,36 +6066,36 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
{ return fabs(code.print_z - print_z) < EPSILON; }); { return fabs(code.print_z - print_z) < EPSILON; });
if (it != color_print_values->end()) if (it != color_print_values->end())
{ {
const std::string& code = it->gcode; CustomGCode::Type type = it->type;
// pause print or custom Gcode // pause print or custom Gcode
if (code == PausePrintCode || if (type == CustomGCode::PausePrint ||
(code != ColorChangeCode && code != ToolChangeCode)) (type != CustomGCode::ColorChange && type != CustomGCode::ToolChange))
return number_tools()-1; // last color item is a gray color for pause print or custom G-code return number_tools()-1; // last color item is a gray color for pause print or custom G-code
// change tool (extruder) // change tool (extruder)
if (code == ToolChangeCode) if (type == CustomGCode::ToolChange)
return get_color_idx_for_tool_change(it, extruder); return get_color_idx_for_tool_change(it, extruder);
// change color for current extruder // change color for current extruder
if (code == ColorChangeCode) { if (type == CustomGCode::ColorChange) {
int color_idx = get_color_idx_for_color_change(it, extruder); int color_idx = get_color_idx_for_color_change(it, extruder);
if (color_idx >= 0) if (color_idx >= 0)
return color_idx; return color_idx;
} }
} }
const CustomGCode::Item value{print_z + EPSILON, "", 0, ""}; const CustomGCode::Item value{print_z + EPSILON, CustomGCode::Custom, 0, ""};
it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value); it = std::lower_bound(color_print_values->begin(), color_print_values->end(), value);
while (it != color_print_values->begin()) while (it != color_print_values->begin())
{ {
--it; --it;
// change color for current extruder // change color for current extruder
if (it->gcode == ColorChangeCode) { if (it->type == CustomGCode::ColorChange) {
int color_idx = get_color_idx_for_color_change(it, extruder); int color_idx = get_color_idx_for_color_change(it, extruder);
if (color_idx >= 0) if (color_idx >= 0)
return color_idx; return color_idx;
} }
// change tool (extruder) // change tool (extruder)
if (it->gcode == ToolChangeCode) if (it->type == CustomGCode::ToolChange)
return get_color_idx_for_tool_change(it, extruder); return get_color_idx_for_tool_change(it, extruder);
} }
@ -6108,7 +6108,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
int shift = 0; int shift = 0;
while (it != color_print_values->begin()) { while (it != color_print_values->begin()) {
--it; --it;
if (it->gcode == ColorChangeCode) if (it->type == CustomGCode::ColorChange)
shift++; shift++;
} }
return extruders_cnt + shift; return extruders_cnt + shift;
@ -6123,7 +6123,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
auto it_n = it; auto it_n = it;
while (it_n != color_print_values->begin()) { while (it_n != color_print_values->begin()) {
--it_n; --it_n;
if (it_n->gcode == ColorChangeCode && it_n->extruder == current_extruder) if (it_n->type == CustomGCode::ColorChange && it_n->extruder == current_extruder)
return get_m600_color_idx(it_n); return get_m600_color_idx(it_n);
} }
@ -6139,7 +6139,7 @@ void GLCanvas3D::_load_print_object_toolpaths(const PrintObject& print_object, c
bool is_tool_change = false; bool is_tool_change = false;
while (it_n != color_print_values->begin()) { while (it_n != color_print_values->begin()) {
--it_n; --it_n;
if (it_n->gcode == ToolChangeCode) { if (it_n->type == CustomGCode::ToolChange) {
is_tool_change = true; is_tool_change = true;
if (it_n->extruder == it->extruder || (it_n->extruder == 0 && it->extruder == extruder)) if (it_n->extruder == it->extruder || (it_n->extruder == 0 && it->extruder == extruder))
return get_m600_color_idx(it); return get_m600_color_idx(it);

View file

@ -1324,22 +1324,22 @@ void Sidebar::update_sliced_info_sizer()
wxString str_color = _L("Color"); wxString str_color = _L("Color");
wxString str_pause = _L("Pause"); wxString str_pause = _L("Pause");
auto fill_labels = [str_color, str_pause](const std::vector<std::pair<CustomGcodeType, std::string>>& times, auto fill_labels = [str_color, str_pause](const std::vector<std::pair<CustomGCode::Type, std::string>>& times,
wxString& new_label, wxString& info_text) wxString& new_label, wxString& info_text)
{ {
int color_change_count = 0; int color_change_count = 0;
for (auto time : times) for (auto time : times)
if (time.first == cgtColorChange) if (time.first == CustomGCode::ColorChange)
color_change_count++; color_change_count++;
for (int i = (int)times.size() - 1; i >= 0; --i) for (int i = (int)times.size() - 1; i >= 0; --i)
{ {
if (i == 0 || times[i - 1].first == cgtPausePrint) if (i == 0 || times[i - 1].first == CustomGCode::PausePrint)
new_label += format_wxstr("\n - %1%%2%", str_color + " ", color_change_count); new_label += format_wxstr("\n - %1%%2%", str_color + " ", color_change_count);
else if (times[i - 1].first == cgtColorChange) else if (times[i - 1].first == CustomGCode::ColorChange)
new_label += format_wxstr("\n - %1%%2%", str_color + " ", color_change_count--); new_label += format_wxstr("\n - %1%%2%", str_color + " ", color_change_count--);
if (i != (int)times.size() - 1 && times[i].first == cgtPausePrint) if (i != (int)times.size() - 1 && times[i].first == CustomGCode::PausePrint)
new_label += format_wxstr(" -> %1%", str_pause); new_label += format_wxstr(" -> %1%", str_pause);
info_text += format_wxstr("\n%1%", times[i].second); info_text += format_wxstr("\n%1%", times[i].second);
@ -5288,7 +5288,7 @@ std::vector<std::string> Plater::get_colors_for_color_print() const
colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.gcodes.size()); colors.reserve(colors.size() + p->model.custom_gcode_per_print_z.gcodes.size());
for (const CustomGCode::Item& code : p->model.custom_gcode_per_print_z.gcodes) for (const CustomGCode::Item& code : p->model.custom_gcode_per_print_z.gcodes)
if (code.gcode == ColorChangeCode) if (code.type == CustomGCode::ColorChange)
colors.emplace_back(code.color); colors.emplace_back(code.color);
return colors; return colors;

View file

@ -461,6 +461,7 @@ const std::vector<std::string>& Preset::printer_options()
"use_firmware_retraction", "use_volumetric_e", "variable_layer_height", "use_firmware_retraction", "use_volumetric_e", "variable_layer_height",
"host_type", "print_host", "printhost_apikey", "printhost_cafile", "host_type", "print_host", "printhost_apikey", "printhost_cafile",
"single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode", "single_extruder_multi_material", "start_gcode", "end_gcode", "before_layer_gcode", "layer_gcode", "toolchange_gcode",
"color_change_gcode", "pause_print_gcode", "template_custom_gcode",
"between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction", "between_objects_gcode", "printer_vendor", "printer_model", "printer_variant", "printer_notes", "cooling_tube_retraction",
"cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "max_print_height", "cooling_tube_length", "high_current_on_filament_swap", "parking_pos_retraction", "extra_loading_move", "max_print_height",
"default_print_profile", "inherits", "default_print_profile", "inherits",

View file

@ -2218,6 +2218,21 @@ void TabPrinter::build_fff()
option.opt.height = gcode_field_height;//150; option.opt.height = gcode_field_height;//150;
optgroup->append_single_option_line(option); optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Color Change G-code"), 0);
option = optgroup->get_option("color_change_gcode");
option.opt.height = gcode_field_height;//150;
optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Pause Print G-code"), 0);
option = optgroup->get_option("pause_print_gcode");
option.opt.height = gcode_field_height;//150;
optgroup->append_single_option_line(option);
optgroup = page->new_optgroup(L("Template Custom G-code"), 0);
option = optgroup->get_option("template_custom_gcode");
option.opt.height = gcode_field_height;//150;
optgroup->append_single_option_line(option);
page = add_options_page(L("Notes"), "note.png"); page = add_options_page(L("Notes"), "note.png");
optgroup = page->new_optgroup(L("Notes"), 0); optgroup = page->new_optgroup(L("Notes"), 0);
option = optgroup->get_option("printer_notes"); option = optgroup->get_option("printer_notes");