Merge branch 'master' of https://github.com/prusa3d/PrusaSlicer
This commit is contained in:
commit
f7e06ded67
6
deps/CGAL/CGAL.cmake
vendored
6
deps/CGAL/CGAL.cmake
vendored
@ -6,4 +6,10 @@ prusaslicer_add_cmake_project(
|
||||
# URL https://github.com/CGAL/cgal/archive/releases/CGAL-5.0.zip
|
||||
# URL_HASH SHA256=bd9327be903ab7ee379a8a7a0609eba0962f5078d2497cf8e13e8e1598584154
|
||||
DEPENDS dep_boost dep_GMP dep_MPFR
|
||||
)
|
||||
|
||||
ExternalProject_Add_Step(dep_CGAL dep_CGAL_relocation_fix
|
||||
DEPENDEES install
|
||||
COMMAND ${CMAKE_COMMAND} -E remove CGALConfig-installation-dirs.cmake
|
||||
WORKING_DIRECTORY "${DESTDIR}/usr/local/lib/cmake/CGAL"
|
||||
)
|
2
deps/GMP/GMP.cmake
vendored
2
deps/GMP/GMP.cmake
vendored
@ -20,7 +20,7 @@ else ()
|
||||
ExternalProject_Add(dep_GMP
|
||||
URL https://gmplib.org/download/gmp/gmp-6.1.2.tar.bz2
|
||||
BUILD_IN_SOURCE ON
|
||||
CONFIGURE_COMMAND ./configure --enable-shared=no --enable-static=yes "--prefix=${DESTDIR}/usr/local" --with-pic
|
||||
CONFIGURE_COMMAND ./configure --enable-shared=no --enable-cxx=yes --enable-static=yes "--prefix=${DESTDIR}/usr/local" --with-pic
|
||||
BUILD_COMMAND make -j
|
||||
INSTALL_COMMAND make install
|
||||
)
|
||||
|
@ -1000,13 +1000,13 @@ std::vector<std::pair<size_t, bool>> chain_extrusion_entities(std::vector<Extrus
|
||||
auto segment_end_point = [&entities](size_t idx, bool first_point) -> const Point& { return first_point ? entities[idx]->first_point() : entities[idx]->last_point(); };
|
||||
auto could_reverse = [&entities](size_t idx) { const ExtrusionEntity *ee = entities[idx]; return ee->is_loop() || ee->can_reverse(); };
|
||||
std::vector<std::pair<size_t, bool>> out = chain_segments_greedy_constrained_reversals<Point, decltype(segment_end_point), decltype(could_reverse)>(segment_end_point, could_reverse, entities.size(), start_near);
|
||||
for (size_t i = 0; i < entities.size(); ++ i) {
|
||||
ExtrusionEntity *ee = entities[i];
|
||||
for (std::pair<size_t, bool> &segment : out) {
|
||||
ExtrusionEntity *ee = entities[segment.first];
|
||||
if (ee->is_loop())
|
||||
// Ignore reversals for loops, as the start point equals the end point.
|
||||
out[i].second = false;
|
||||
segment.second = false;
|
||||
// Is can_reverse() respected by the reversals?
|
||||
assert(entities[i]->can_reverse() || ! out[i].second);
|
||||
assert(ee->can_reverse() || ! segment.second);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
@ -53,4 +53,7 @@
|
||||
// Enable selection for missing files in reload from disk command
|
||||
#define ENABLE_RELOAD_FROM_DISK_MISSING_SELECTION (1 && ENABLE_2_2_0_ALPHA1)
|
||||
|
||||
// Enable closing 3Dconnextion imgui settings dialog by clicking on [X] and [Close] buttons
|
||||
#define ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG (1 && ENABLE_2_2_0_ALPHA1)
|
||||
|
||||
#endif // _technologies_h_
|
||||
|
@ -1921,7 +1921,11 @@ void GLCanvas3D::render()
|
||||
m_camera.debug_render();
|
||||
#endif // ENABLE_CAMERA_STATISTICS
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog(*this);
|
||||
#else
|
||||
wxGetApp().plater()->get_mouse3d_controller().render_settings_dialog((unsigned int)cnv_size.get_width(), (unsigned int)cnv_size.get_height());
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
wxGetApp().imgui()->render();
|
||||
|
||||
@ -2629,8 +2633,8 @@ void GLCanvas3D::on_idle(wxIdleEvent& evt)
|
||||
if (m_extra_frame_requested || mouse3d_controller_applied)
|
||||
{
|
||||
m_dirty = true;
|
||||
evt.RequestMore();
|
||||
m_extra_frame_requested = false;
|
||||
evt.RequestMore();
|
||||
}
|
||||
else
|
||||
m_dirty = false;
|
||||
|
@ -254,6 +254,16 @@ bool ImGuiWrapper::begin(const wxString &name, int flags)
|
||||
return begin(into_u8(name), flags);
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::begin(const std::string& name, bool* close, int flags)
|
||||
{
|
||||
return ImGui::Begin(name.c_str(), close, (ImGuiWindowFlags)flags);
|
||||
}
|
||||
|
||||
bool ImGuiWrapper::begin(const wxString& name, bool* close, int flags)
|
||||
{
|
||||
return begin(into_u8(name), close, flags);
|
||||
}
|
||||
|
||||
void ImGuiWrapper::end()
|
||||
{
|
||||
ImGui::End();
|
||||
|
@ -56,6 +56,8 @@ public:
|
||||
|
||||
bool begin(const std::string &name, int flags = 0);
|
||||
bool begin(const wxString &name, int flags = 0);
|
||||
bool begin(const std::string& name, bool* close, int flags = 0);
|
||||
bool begin(const wxString& name, bool* close, int flags = 0);
|
||||
void end();
|
||||
|
||||
bool button(const wxString &label);
|
||||
|
@ -5,6 +5,9 @@
|
||||
#include "GUI_App.hpp"
|
||||
#include "PresetBundle.hpp"
|
||||
#include "AppConfig.hpp"
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
#include "GLCanvas3D.hpp"
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
#include <wx/glcanvas.h>
|
||||
|
||||
@ -184,7 +187,10 @@ Mouse3DController::Mouse3DController()
|
||||
, m_device(nullptr)
|
||||
, m_device_str("")
|
||||
, m_running(false)
|
||||
, m_settings_dialog(false)
|
||||
, m_show_settings_dialog(false)
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
, m_settings_dialog_closed_by_user(false)
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
{
|
||||
m_last_time = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
@ -229,8 +235,11 @@ bool Mouse3DController::apply(Camera& camera)
|
||||
if (!m_running && is_device_connected())
|
||||
{
|
||||
disconnect_device();
|
||||
// hides the settings dialog if the user re-plug the device
|
||||
m_settings_dialog = false;
|
||||
// hides the settings dialog if the user un-plug the device
|
||||
m_show_settings_dialog = false;
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
m_settings_dialog_closed_by_user = false;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
}
|
||||
|
||||
// check if the user plugged the device
|
||||
@ -240,88 +249,144 @@ bool Mouse3DController::apply(Camera& camera)
|
||||
return is_device_connected() ? m_state.apply(camera) : false;
|
||||
}
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
void Mouse3DController::render_settings_dialog(GLCanvas3D& canvas) const
|
||||
#else
|
||||
void Mouse3DController::render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
{
|
||||
if (!m_running || !m_settings_dialog)
|
||||
if (!m_running || !m_show_settings_dialog)
|
||||
return;
|
||||
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
|
||||
imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f);
|
||||
|
||||
imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
|
||||
|
||||
const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text(_(L("Device:")));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
imgui.text(m_device_str);
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text(_(L("Speed:")));
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale;
|
||||
if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.5f, 2.0f, "%.1f"))
|
||||
m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale);
|
||||
|
||||
float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale;
|
||||
if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.5f, 2.0f, "%.1f"))
|
||||
m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale);
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text(_(L("Deadzone:")));
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
float translation_deadzone = (float)m_state.get_translation_deadzone();
|
||||
if (imgui.slider_float(_(L("Translation")) + "##2", &translation_deadzone, 0.0f, (float)State::MaxTranslationDeadzone, "%.2f"))
|
||||
m_state.set_translation_deadzone((double)translation_deadzone);
|
||||
|
||||
float rotation_deadzone = m_state.get_rotation_deadzone();
|
||||
if (imgui.slider_float(_(L("Rotation")) + "##2", &rotation_deadzone, 0.0f, State::MaxRotationDeadzone, "%.2f"))
|
||||
m_state.set_rotation_deadzone(rotation_deadzone);
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
ImGui::Separator();
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text("DEBUG:");
|
||||
imgui.text("Vectors:");
|
||||
ImGui::PopStyleColor();
|
||||
Vec3f translation = m_state.get_translation().cast<float>();
|
||||
Vec3f rotation = m_state.get_rotation();
|
||||
ImGui::InputFloat3("Translation##3", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text("Queue size:");
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
int translation_size[2] = { (int)m_state.get_translation_queue_size(), (int)m_state.get_translation_queue_max_size() };
|
||||
int rotation_size[2] = { (int)m_state.get_rotation_queue_size(), (int)m_state.get_rotation_queue_max_size() };
|
||||
int buttons_size[2] = { (int)m_state.get_buttons_queue_size(), (int)m_state.get_buttons_queue_max_size() };
|
||||
|
||||
ImGui::InputInt2("Translation##4", translation_size, ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::InputInt2("Rotation##4", rotation_size, ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::InputInt2("Buttons", buttons_size, ImGuiInputTextFlags_ReadOnly);
|
||||
|
||||
int queue_size = (int)m_state.get_queues_max_size();
|
||||
if (ImGui::InputInt("Max size", &queue_size, 1, 1, ImGuiInputTextFlags_ReadOnly))
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
// when the user clicks on [X] or [Close] button we need to trigger
|
||||
// an extra frame to let the dialog disappear
|
||||
if (m_settings_dialog_closed_by_user)
|
||||
{
|
||||
if (queue_size > 0)
|
||||
m_state.set_queues_max_size(queue_size);
|
||||
m_show_settings_dialog = false;
|
||||
m_settings_dialog_closed_by_user = false;
|
||||
canvas.request_extra_frame();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text("Camera:");
|
||||
ImGui::PopStyleColor();
|
||||
Vec3f target = wxGetApp().plater()->get_camera().get_target().cast<float>();
|
||||
ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
|
||||
Size cnv_size = canvas.get_canvas_size();
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
ImGuiWrapper& imgui = *wxGetApp().imgui();
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
imgui.set_next_window_pos(0.5f * (float)cnv_size.get_width(), 0.5f * (float)cnv_size.get_height(), ImGuiCond_Always, 0.5f, 0.5f);
|
||||
#else
|
||||
imgui.set_next_window_pos(0.5f * (float)canvas_width, 0.5f * (float)canvas_height, ImGuiCond_Always, 0.5f, 0.5f);
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
static ImVec2 last_win_size(0.0f, 0.0f);
|
||||
bool shown = true;
|
||||
if (imgui.begin(_(L("3Dconnexion settings")), &shown, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse))
|
||||
{
|
||||
if (shown)
|
||||
{
|
||||
ImVec2 win_size = ImGui::GetWindowSize();
|
||||
if ((last_win_size.x != win_size.x) || (last_win_size.y != win_size.y))
|
||||
{
|
||||
// when the user clicks on [X] button, the next time the dialog is shown
|
||||
// has a dummy size, so we trigger an extra frame to let it have the correct size
|
||||
last_win_size = win_size;
|
||||
canvas.request_extra_frame();
|
||||
}
|
||||
#else
|
||||
imgui.begin(_(L("3Dconnexion settings")), ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse);
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
const ImVec4& color = ImGui::GetStyleColorVec4(ImGuiCol_Separator);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text(_(L("Device:")));
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine();
|
||||
imgui.text(m_device_str);
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text(_(L("Speed:")));
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
float translation_scale = (float)m_state.get_translation_scale() / State::DefaultTranslationScale;
|
||||
if (imgui.slider_float(_(L("Translation")) + "##1", &translation_scale, 0.5f, 2.0f, "%.1f"))
|
||||
m_state.set_translation_scale(State::DefaultTranslationScale * (double)translation_scale);
|
||||
|
||||
float rotation_scale = m_state.get_rotation_scale() / State::DefaultRotationScale;
|
||||
if (imgui.slider_float(_(L("Rotation")) + "##1", &rotation_scale, 0.5f, 2.0f, "%.1f"))
|
||||
m_state.set_rotation_scale(State::DefaultRotationScale * rotation_scale);
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text(_(L("Deadzone:")));
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
float translation_deadzone = (float)m_state.get_translation_deadzone();
|
||||
if (imgui.slider_float(_(L("Translation")) + "##2", &translation_deadzone, 0.0f, (float)State::MaxTranslationDeadzone, "%.2f"))
|
||||
m_state.set_translation_deadzone((double)translation_deadzone);
|
||||
|
||||
float rotation_deadzone = m_state.get_rotation_deadzone();
|
||||
if (imgui.slider_float(_(L("Rotation")) + "##2", &rotation_deadzone, 0.0f, State::MaxRotationDeadzone, "%.2f"))
|
||||
m_state.set_rotation_deadzone(rotation_deadzone);
|
||||
|
||||
#if ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
ImGui::Separator();
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text("DEBUG:");
|
||||
imgui.text("Vectors:");
|
||||
ImGui::PopStyleColor();
|
||||
Vec3f translation = m_state.get_translation().cast<float>();
|
||||
Vec3f rotation = m_state.get_rotation();
|
||||
ImGui::InputFloat3("Translation##3", translation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::InputFloat3("Rotation##3", rotation.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text("Queue size:");
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
int translation_size[2] = { (int)m_state.get_translation_queue_size(), (int)m_state.get_translation_queue_max_size() };
|
||||
int rotation_size[2] = { (int)m_state.get_rotation_queue_size(), (int)m_state.get_rotation_queue_max_size() };
|
||||
int buttons_size[2] = { (int)m_state.get_buttons_queue_size(), (int)m_state.get_buttons_queue_max_size() };
|
||||
|
||||
ImGui::InputInt2("Translation##4", translation_size, ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::InputInt2("Rotation##4", rotation_size, ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::InputInt2("Buttons", buttons_size, ImGuiInputTextFlags_ReadOnly);
|
||||
|
||||
int queue_size = (int)m_state.get_queues_max_size();
|
||||
if (ImGui::InputInt("Max size", &queue_size, 1, 1, ImGuiInputTextFlags_ReadOnly))
|
||||
{
|
||||
if (queue_size > 0)
|
||||
m_state.set_queues_max_size(queue_size);
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
||||
imgui.text("Camera:");
|
||||
ImGui::PopStyleColor();
|
||||
Vec3f target = wxGetApp().plater()->get_camera().get_target().cast<float>();
|
||||
ImGui::InputFloat3("Target", target.data(), "%.3f", ImGuiInputTextFlags_ReadOnly);
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_DEBUG_OUTPUT
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
ImGui::Separator();
|
||||
if (imgui.button(_(L("Close"))))
|
||||
{
|
||||
// the user clicked on the [Close] button
|
||||
m_settings_dialog_closed_by_user = true;
|
||||
canvas.set_as_dirty();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// the user clicked on the [X] button
|
||||
m_settings_dialog_closed_by_user = true;
|
||||
canvas.set_as_dirty();
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
imgui.end();
|
||||
}
|
||||
|
@ -18,6 +18,9 @@ namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
struct Camera;
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
class GLCanvas3D;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
class Mouse3DController
|
||||
{
|
||||
@ -130,7 +133,13 @@ class Mouse3DController
|
||||
hid_device* m_device;
|
||||
std::string m_device_str;
|
||||
bool m_running;
|
||||
bool m_settings_dialog;
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
mutable bool m_show_settings_dialog;
|
||||
// set to true when ther user closes the dialog by clicking on [X] or [Close] buttons
|
||||
mutable bool m_settings_dialog_closed_by_user;
|
||||
#else
|
||||
bool m_show_settings_dialog;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
std::chrono::time_point<std::chrono::high_resolution_clock> m_last_time;
|
||||
|
||||
public:
|
||||
@ -146,9 +155,13 @@ public:
|
||||
|
||||
bool apply(Camera& camera);
|
||||
|
||||
bool is_settings_dialog_shown() const { return m_settings_dialog; }
|
||||
void show_settings_dialog(bool show) { m_settings_dialog = show && is_running(); }
|
||||
bool is_settings_dialog_shown() const { return m_show_settings_dialog; }
|
||||
void show_settings_dialog(bool show) { m_show_settings_dialog = show && is_running(); }
|
||||
#if ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
void render_settings_dialog(GLCanvas3D& canvas) const;
|
||||
#else
|
||||
void render_settings_dialog(unsigned int canvas_width, unsigned int canvas_height) const;
|
||||
#endif // ENABLE_3DCONNEXION_DEVICES_CLOSE_SETTING_DIALOG
|
||||
|
||||
private:
|
||||
bool connect_device();
|
||||
|
Loading…
Reference in New Issue
Block a user