mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-14 21:25:53 +08:00
fix annoying check when setting big width with big nozzle
also fix error when setting a width too small
This commit is contained in:
parent
f6c663cc70
commit
77316cea73
@ -236,6 +236,7 @@ void PrintConfigDef::init_fff_params()
|
|||||||
def->tooltip = L("Do not use the 'Avoid crossing perimeters' on the first layer.");
|
def->tooltip = L("Do not use the 'Avoid crossing perimeters' on the first layer.");
|
||||||
def->mode = comExpert;
|
def->mode = comExpert;
|
||||||
def->set_default_value(new ConfigOptionBool(true));
|
def->set_default_value(new ConfigOptionBool(true));
|
||||||
|
|
||||||
def = this->add("avoid_crossing_perimeters_max_detour", coFloatOrPercent);
|
def = this->add("avoid_crossing_perimeters_max_detour", coFloatOrPercent);
|
||||||
def->label = L("Avoid crossing perimeters - Max detour length");
|
def->label = L("Avoid crossing perimeters - Max detour length");
|
||||||
def->category = OptionCategory::perimeter;
|
def->category = OptionCategory::perimeter;
|
||||||
@ -5945,9 +5946,118 @@ bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const
|
|||||||
double max_nozzle_diameter = 0;
|
double max_nozzle_diameter = 0;
|
||||||
for (double dmr : nozzle_diameter_option->values)
|
for (double dmr : nozzle_diameter_option->values)
|
||||||
max_nozzle_diameter = std::max(max_nozzle_diameter, dmr);
|
max_nozzle_diameter = std::max(max_nozzle_diameter, dmr);
|
||||||
if (opt_key == "extrusion_width") {
|
ConfigOptionFloatOrPercent* spacing_option = nullptr;
|
||||||
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("extrusion_spacing");
|
try {
|
||||||
if (width_option) {
|
if (opt_key == "extrusion_width") {
|
||||||
|
spacing_option = this->option<ConfigOptionFloatOrPercent>("extrusion_spacing");
|
||||||
|
if (width_option) {
|
||||||
|
width_option->set_phony(false);
|
||||||
|
spacing_option->set_phony(true);
|
||||||
|
Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
||||||
|
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
|
||||||
|
spacing_option->percent = width_option->percent;
|
||||||
|
something_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opt_key == "first_layer_extrusion_width") {
|
||||||
|
spacing_option = this->option<ConfigOptionFloatOrPercent>("first_layer_extrusion_spacing");
|
||||||
|
if (width_option) {
|
||||||
|
width_option->set_phony(false);
|
||||||
|
spacing_option->set_phony(true);
|
||||||
|
Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
||||||
|
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
|
||||||
|
spacing_option->percent = width_option->percent;
|
||||||
|
something_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opt_key == "perimeter_extrusion_width") {
|
||||||
|
const ConfigOptionPercent* perimeter_overlap_option = find_option<ConfigOptionPercent>("perimeter_overlap", this, config_collection);
|
||||||
|
spacing_option = this->option<ConfigOptionFloatOrPercent>("perimeter_extrusion_spacing");
|
||||||
|
if (width_option && perimeter_overlap_option) {
|
||||||
|
width_option->set_phony(false);
|
||||||
|
spacing_option->set_phony(true);
|
||||||
|
Flow flow = Flow::new_from_config_width(FlowRole::frExternalPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
||||||
|
flow.spacing_ratio = perimeter_overlap_option->get_abs_value(1);
|
||||||
|
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
|
||||||
|
spacing_option->percent = width_option->percent;
|
||||||
|
something_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opt_key == "external_perimeter_extrusion_width") {
|
||||||
|
const ConfigOptionPercent* external_perimeter_overlap_option = find_option<ConfigOptionPercent>("external_perimeter_overlap", this, config_collection);
|
||||||
|
spacing_option = this->option<ConfigOptionFloatOrPercent>("external_perimeter_extrusion_spacing");
|
||||||
|
if (width_option && external_perimeter_overlap_option) {
|
||||||
|
width_option->set_phony(false);
|
||||||
|
spacing_option->set_phony(true);
|
||||||
|
Flow ext_perimeter_flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
||||||
|
ext_perimeter_flow.spacing_ratio = external_perimeter_overlap_option->get_abs_value(0.5);
|
||||||
|
spacing_option->value = (width_option->percent) ? std::round(100 * ext_perimeter_flow.spacing() / max_nozzle_diameter) : (std::round(ext_perimeter_flow.spacing() * 10000) / 10000);
|
||||||
|
spacing_option->percent = width_option->percent;
|
||||||
|
something_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opt_key == "infill_extrusion_width") {
|
||||||
|
spacing_option = this->option<ConfigOptionFloatOrPercent>("infill_extrusion_spacing");
|
||||||
|
if (width_option) {
|
||||||
|
width_option->set_phony(false);
|
||||||
|
spacing_option->set_phony(true);
|
||||||
|
Flow flow = Flow::new_from_config_width(FlowRole::frInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
||||||
|
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
|
||||||
|
spacing_option->percent = width_option->percent;
|
||||||
|
something_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opt_key == "solid_infill_extrusion_width") {
|
||||||
|
spacing_option = this->option<ConfigOptionFloatOrPercent>("solid_infill_extrusion_spacing");
|
||||||
|
if (width_option) {
|
||||||
|
width_option->set_phony(false);
|
||||||
|
spacing_option->set_phony(true);
|
||||||
|
Flow flow = Flow::new_from_config_width(FlowRole::frSolidInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
||||||
|
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
|
||||||
|
spacing_option->percent = width_option->percent;
|
||||||
|
something_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opt_key == "top_infill_extrusion_width") {
|
||||||
|
spacing_option = this->option<ConfigOptionFloatOrPercent>("top_infill_extrusion_spacing");
|
||||||
|
if (width_option) {
|
||||||
|
width_option->set_phony(false);
|
||||||
|
spacing_option->set_phony(true);
|
||||||
|
Flow flow = Flow::new_from_config_width(FlowRole::frTopSolidInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
||||||
|
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
|
||||||
|
spacing_option->percent = width_option->percent;
|
||||||
|
something_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//if (opt_key == "support_material_extrusion_width") {
|
||||||
|
// Flow flow = Flow::new_from_config_width(FlowRole::frSupportMaterial, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
||||||
|
// if (width_option->percent)
|
||||||
|
// this->set_key_value("support_material_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(100 * flow.spacing() / max_nozzle_diameter), true));
|
||||||
|
// else
|
||||||
|
// this->set_key_value("support_material_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(flow.spacing() * 10000) / 10000, false));
|
||||||
|
// something_changed = true;
|
||||||
|
//}
|
||||||
|
//if (opt_key == "skirt_extrusion_width") {
|
||||||
|
// Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
||||||
|
// if (width_option->percent)
|
||||||
|
// this->set_key_value("skirt_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(100 * flow.spacing() / max_nozzle_diameter), true));
|
||||||
|
// else
|
||||||
|
// this->set_key_value("skirt_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(flow.spacing() * 10000) / 10000, false));
|
||||||
|
// something_changed = true;
|
||||||
|
//}
|
||||||
|
} catch (FlowErrorNegativeSpacing) {
|
||||||
|
if (spacing_option != nullptr) {
|
||||||
|
width_option->set_phony(true);
|
||||||
|
spacing_option->set_phony(false);
|
||||||
|
spacing_option->value = 100;
|
||||||
|
spacing_option->percent = true;
|
||||||
|
Flow flow = Flow::new_from_spacing(spacing_option->get_abs_value(max_nozzle_diameter), max_nozzle_diameter, layer_height_option->value, false);
|
||||||
|
width_option->value = (spacing_option->percent) ? std::round(100 * flow.width / max_nozzle_diameter) : (std::round(flow.width * 10000) / 10000);
|
||||||
|
width_option->percent = spacing_option->percent;
|
||||||
|
something_changed = true;
|
||||||
|
} else {
|
||||||
|
width_option->value = 100;
|
||||||
|
width_option->percent = true;
|
||||||
width_option->set_phony(false);
|
width_option->set_phony(false);
|
||||||
spacing_option->set_phony(true);
|
spacing_option->set_phony(true);
|
||||||
Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
||||||
@ -5956,92 +6066,6 @@ bool DynamicPrintConfig::value_changed(const t_config_option_key& opt_key, const
|
|||||||
something_changed = true;
|
something_changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (opt_key == "first_layer_extrusion_width") {
|
|
||||||
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("first_layer_extrusion_spacing");
|
|
||||||
if (width_option) {
|
|
||||||
width_option->set_phony(false);
|
|
||||||
spacing_option->set_phony(true);
|
|
||||||
Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
|
||||||
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
|
|
||||||
spacing_option->percent = width_option->percent;
|
|
||||||
something_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (opt_key == "perimeter_extrusion_width") {
|
|
||||||
const ConfigOptionPercent* perimeter_overlap_option = find_option<ConfigOptionPercent>("perimeter_overlap", this, config_collection);
|
|
||||||
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("perimeter_extrusion_spacing");
|
|
||||||
if (width_option && perimeter_overlap_option) {
|
|
||||||
width_option->set_phony(false);
|
|
||||||
spacing_option->set_phony(true);
|
|
||||||
Flow flow = Flow::new_from_config_width(FlowRole::frExternalPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
|
||||||
flow.spacing_ratio = perimeter_overlap_option->get_abs_value(1);
|
|
||||||
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
|
|
||||||
spacing_option->percent = width_option->percent;
|
|
||||||
something_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (opt_key == "external_perimeter_extrusion_width") {
|
|
||||||
const ConfigOptionPercent* external_perimeter_overlap_option = find_option<ConfigOptionPercent>("external_perimeter_overlap", this, config_collection);
|
|
||||||
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("external_perimeter_extrusion_spacing");
|
|
||||||
if (width_option && external_perimeter_overlap_option) {
|
|
||||||
width_option->set_phony(false);
|
|
||||||
spacing_option->set_phony(true);
|
|
||||||
Flow ext_perimeter_flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
|
||||||
ext_perimeter_flow.spacing_ratio = external_perimeter_overlap_option->get_abs_value(0.5);
|
|
||||||
spacing_option->value = (width_option->percent) ? std::round(100 * ext_perimeter_flow.spacing() / max_nozzle_diameter) : (std::round(ext_perimeter_flow.spacing() * 10000) / 10000);
|
|
||||||
spacing_option->percent = width_option->percent;
|
|
||||||
something_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (opt_key == "infill_extrusion_width") {
|
|
||||||
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("infill_extrusion_spacing");
|
|
||||||
if (width_option) {
|
|
||||||
width_option->set_phony(false);
|
|
||||||
spacing_option->set_phony(true);
|
|
||||||
Flow flow = Flow::new_from_config_width(FlowRole::frInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
|
||||||
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
|
|
||||||
spacing_option->percent = width_option->percent;
|
|
||||||
something_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (opt_key == "solid_infill_extrusion_width") {
|
|
||||||
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("solid_infill_extrusion_spacing");
|
|
||||||
if (width_option) {
|
|
||||||
width_option->set_phony(false);
|
|
||||||
spacing_option->set_phony(true);
|
|
||||||
Flow flow = Flow::new_from_config_width(FlowRole::frSolidInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
|
||||||
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
|
|
||||||
spacing_option->percent = width_option->percent;
|
|
||||||
something_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (opt_key == "top_infill_extrusion_width") {
|
|
||||||
ConfigOptionFloatOrPercent* spacing_option = this->option<ConfigOptionFloatOrPercent>("top_infill_extrusion_spacing");
|
|
||||||
if (width_option) {
|
|
||||||
width_option->set_phony(false);
|
|
||||||
spacing_option->set_phony(true);
|
|
||||||
Flow flow = Flow::new_from_config_width(FlowRole::frTopSolidInfill, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
|
||||||
spacing_option->value = (width_option->percent) ? std::round(100 * flow.spacing() / max_nozzle_diameter) : (std::round(flow.spacing() * 10000) / 10000);
|
|
||||||
spacing_option->percent = width_option->percent;
|
|
||||||
something_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//if (opt_key == "support_material_extrusion_width") {
|
|
||||||
// Flow flow = Flow::new_from_config_width(FlowRole::frSupportMaterial, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
|
||||||
// if (width_option->percent)
|
|
||||||
// this->set_key_value("support_material_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(100 * flow.spacing() / max_nozzle_diameter), true));
|
|
||||||
// else
|
|
||||||
// this->set_key_value("support_material_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(flow.spacing() * 10000) / 10000, false));
|
|
||||||
// something_changed = true;
|
|
||||||
//}
|
|
||||||
//if (opt_key == "skirt_extrusion_width") {
|
|
||||||
// Flow flow = Flow::new_from_config_width(FlowRole::frPerimeter, *width_option, max_nozzle_diameter, layer_height_option->value, 0);
|
|
||||||
// if (width_option->percent)
|
|
||||||
// this->set_key_value("skirt_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(100 * flow.spacing() / max_nozzle_diameter), true));
|
|
||||||
// else
|
|
||||||
// this->set_key_value("skirt_extrusion_spacing", new ConfigOptionFloatOrPercent(std::round(flow.spacing() * 10000) / 10000, false));
|
|
||||||
// something_changed = true;
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return something_changed;
|
return something_changed;
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "MainFrame.hpp"
|
#include "MainFrame.hpp"
|
||||||
#include "format.hpp"
|
#include "format.hpp"
|
||||||
|
|
||||||
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
#include "libslic3r/PrintConfig.hpp"
|
#include "libslic3r/PrintConfig.hpp"
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
@ -328,33 +329,50 @@ void Field::get_value_by_opt_type(wxString& str, const bool check_value/* = true
|
|||||||
} else if (((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) ||
|
} else if (((m_opt.sidetext.rfind("mm/s") != std::string::npos && val > m_opt.max) ||
|
||||||
(m_opt.sidetext.rfind("mm ") != std::string::npos && val > 1)) &&
|
(m_opt.sidetext.rfind("mm ") != std::string::npos && val > 1)) &&
|
||||||
(m_value.empty() || std::string(str.ToUTF8().data()) != boost::any_cast<std::string>(m_value)))
|
(m_value.empty() || std::string(str.ToUTF8().data()) != boost::any_cast<std::string>(m_value)))
|
||||||
{
|
{
|
||||||
if (!check_value) {
|
// exceptions
|
||||||
m_value.clear();
|
if (std::set<t_config_option_key>{"infill_anchor", "infill_anchor_max", "avoid_crossing_perimeters_max_detour"}.count(m_opt.opt_key) > 0) {
|
||||||
break;
|
m_value = std::string(str.ToUTF8().data());
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
|
if (m_opt.opt_key.find("extrusion_width") != std::string::npos || m_opt.opt_key.find("extrusion_spacing") != std::string::npos) {
|
||||||
|
const DynamicPrintConfig& printer_config = wxGetApp().preset_bundle->printers.get_edited_preset().config;
|
||||||
|
const std::vector<double> &nozzle_diameters = printer_config.option<ConfigOptionFloats>("nozzle_diameter")->values;
|
||||||
|
double nozzle_diameter = 0;
|
||||||
|
for(double diameter : nozzle_diameters)
|
||||||
|
nozzle_diameter = std::max(nozzle_diameter, diameter);
|
||||||
|
if (val < nozzle_diameter * 10) {
|
||||||
|
m_value = std::string(str.ToUTF8().data());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool infill_anchors = m_opt.opt_key == "infill_anchor" || m_opt.opt_key == "infill_anchor_max";
|
if (!check_value) {
|
||||||
|
m_value.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm";
|
bool infill_anchors = m_opt.opt_key == "infill_anchor" || m_opt.opt_key == "infill_anchor_max";
|
||||||
const wxString stVal = double_to_string(val, 2);
|
|
||||||
const wxString msg_text = from_u8((boost::format(_utf8(L("Do you mean %s%% instead of %s %s?\n"
|
const std::string sidetext = m_opt.sidetext.rfind("mm/s") != std::string::npos ? "mm/s" : "mm";
|
||||||
"Select YES if you want to change this value to %s%%, \n"
|
const wxString stVal = double_to_string(val, 2);
|
||||||
"or NO if you are sure that %s %s is a correct value."))) % stVal % stVal % sidetext % stVal % stVal % sidetext).str());
|
const wxString msg_text = from_u8((boost::format(_utf8(L("Do you mean %s%% instead of %s %s?\n"
|
||||||
wxMessageDialog dialog(m_parent, msg_text, _(L("Parameter validation")) + ": " + m_opt_id , wxICON_WARNING | wxYES | wxNO);
|
"Select YES if you want to change this value to %s%%, \n"
|
||||||
if ((!infill_anchors || val > 100) && dialog.ShowModal() == wxID_YES) {
|
"or NO if you are sure that %s %s is a correct value."))) % stVal % stVal % sidetext % stVal % stVal % sidetext).str());
|
||||||
set_value(from_u8((boost::format("%s%%") % stVal).str()), false/*true*/);
|
wxMessageDialog dialog(m_parent, msg_text, _(L("Parameter validation")) + ": " + m_opt_id , wxICON_WARNING | wxYES | wxNO);
|
||||||
str += "%%";
|
if ((!infill_anchors || val > 100) && dialog.ShowModal() == wxID_YES) {
|
||||||
|
set_value(from_u8((boost::format("%s%%") % stVal).str()), false/*true*/);
|
||||||
|
str += "%%";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
set_value(stVal, false); // it's no needed but can be helpful, when inputted value contained "," instead of "."
|
||||||
}
|
}
|
||||||
else
|
|
||||||
set_value(stVal, false); // it's no needed but can be helpful, when inputted value contained "," instead of "."
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
m_value = std::string(str.ToUTF8().data());
|
m_value = std::string(str.ToUTF8().data());
|
||||||
break; }
|
break;
|
||||||
|
}
|
||||||
case coPoints: {
|
case coPoints: {
|
||||||
std::vector<Vec2d> out_values;
|
std::vector<Vec2d> out_values;
|
||||||
str.Replace(" ", wxEmptyString, true);
|
str.Replace(" ", wxEmptyString, true);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user