mirror of
https://github.com/MarlinFirmware/Marlin.git
synced 2024-11-22 18:25:18 +00:00
parent
593b734d18
commit
25521cb9b2
@ -31,6 +31,37 @@
|
|||||||
|
|
||||||
#if ENABLED(DWIN_LCD_PROUI)
|
#if ENABLED(DWIN_LCD_PROUI)
|
||||||
|
|
||||||
|
#if DISABLED(LIMITED_MAX_FR_EDITING)
|
||||||
|
#warning "LIMITED_MAX_FR_EDITING is recommended with ProUI."
|
||||||
|
#endif
|
||||||
|
#if DISABLED(LIMITED_MAX_ACCEL_EDITING)
|
||||||
|
#warning "LIMITED_MAX_ACCEL_EDITING is recommended with ProUI."
|
||||||
|
#endif
|
||||||
|
#if ENABLED(CLASSIC_JERK) && DISABLED(LIMITED_JERK_EDITING)
|
||||||
|
#warning "LIMITED_JERK_EDITING is recommended with ProUI."
|
||||||
|
#endif
|
||||||
|
#if DISABLED(INDIVIDUAL_AXIS_HOMING_SUBMENU)
|
||||||
|
#warning "INDIVIDUAL_AXIS_HOMING_SUBMENU is recommended with ProUI."
|
||||||
|
#endif
|
||||||
|
#if DISABLED(LCD_SET_PROGRESS_MANUALLY)
|
||||||
|
#warning "LCD_SET_PROGRESS_MANUALLY is recommended with ProUI."
|
||||||
|
#endif
|
||||||
|
#if DISABLED(STATUS_MESSAGE_SCROLLING)
|
||||||
|
#warning "STATUS_MESSAGE_SCROLLING is recommended with ProUI."
|
||||||
|
#endif
|
||||||
|
#if DISABLED(BAUD_RATE_GCODE)
|
||||||
|
#warning "BAUD_RATE_GCODE is recommended with ProUI."
|
||||||
|
#endif
|
||||||
|
#if DISABLED(SOUND_MENU_ITEM)
|
||||||
|
#warning "SOUND_MENU_ITEM is recommended with ProUI."
|
||||||
|
#endif
|
||||||
|
#if DISABLED(PRINTCOUNTER)
|
||||||
|
#warning "PRINTCOUNTER is recommended with ProUI."
|
||||||
|
#endif
|
||||||
|
#if HAS_MESH && DISABLED(MESH_EDIT_MENU)
|
||||||
|
#warning "MESH_EDIT_MENU is recommended with ProUI."
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "dwin.h"
|
#include "dwin.h"
|
||||||
#include "menus.h"
|
#include "menus.h"
|
||||||
#include "dwin_popup.h"
|
#include "dwin_popup.h"
|
||||||
@ -68,7 +99,7 @@
|
|||||||
#define HAS_ONESTEP_LEVELING 1
|
#define HAS_ONESTEP_LEVELING 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if HAS_MESH || HAS_ONESTEP_LEVELING
|
#if HAS_MESH || (HAS_LEVELING && HAS_ZOFFSET_ITEM)
|
||||||
#include "../../../feature/bedlevel/bedlevel.h"
|
#include "../../../feature/bedlevel/bedlevel.h"
|
||||||
#include "bedlevel_tools.h"
|
#include "bedlevel_tools.h"
|
||||||
#endif
|
#endif
|
||||||
@ -165,7 +196,12 @@
|
|||||||
#define DWIN_SCROLL_UPDATE_INTERVAL SEC_TO_MS(2)
|
#define DWIN_SCROLL_UPDATE_INTERVAL SEC_TO_MS(2)
|
||||||
#define DWIN_REMAIN_TIME_UPDATE_INTERVAL SEC_TO_MS(20)
|
#define DWIN_REMAIN_TIME_UPDATE_INTERVAL SEC_TO_MS(20)
|
||||||
|
|
||||||
#define BABY_Z_VAR TERN(HAS_BED_PROBE, probe.offset.z, HMI_data.ManualZOffset)
|
#if HAS_MESH
|
||||||
|
#define BABY_Z_VAR TERN(HAS_BED_PROBE, probe.offset.z, HMI_data.ManualZOffset)
|
||||||
|
#else
|
||||||
|
float z_offset = 0;
|
||||||
|
#define BABY_Z_VAR z_offset
|
||||||
|
#endif
|
||||||
|
|
||||||
// Structs
|
// Structs
|
||||||
HMI_value_t HMI_value;
|
HMI_value_t HMI_value;
|
||||||
@ -220,7 +256,13 @@ constexpr float max_acceleration_edit_values[] =
|
|||||||
;
|
;
|
||||||
|
|
||||||
#if HAS_CLASSIC_JERK
|
#if HAS_CLASSIC_JERK
|
||||||
constexpr float max_jerk_edit_values[] = MAX_JERK_EDIT_VALUES;
|
constexpr float max_jerk_edit_values[] =
|
||||||
|
#ifdef MAX_JERK_EDIT_VALUES
|
||||||
|
MAX_JERK_EDIT_VALUES
|
||||||
|
#else
|
||||||
|
{ DEFAULT_XJERK * 2, DEFAULT_YJERK * 2, DEFAULT_ZJERK * 2, DEFAULT_EJERK * 2 }
|
||||||
|
#endif
|
||||||
|
;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static uint8_t _percent_done = 0;
|
static uint8_t _percent_done = 0;
|
||||||
@ -834,6 +876,8 @@ void update_variable() {
|
|||||||
else
|
else
|
||||||
DWINUI::Draw_Icon(ICON_Zoffset, 187, 416);
|
DWINUI::Draw_Icon(ICON_Zoffset, 187, 416);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
DWINUI::Draw_Icon(ICON_Zoffset, 187, 416);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
_draw_xyz_position(false);
|
_draw_xyz_position(false);
|
||||||
@ -1781,7 +1825,7 @@ void DWIN_SetDataDefaults() {
|
|||||||
#endif
|
#endif
|
||||||
TERN_(BAUD_RATE_GCODE, SetBaud250K());
|
TERN_(BAUD_RATE_GCODE, SetBaud250K());
|
||||||
#if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS)
|
#if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS)
|
||||||
leds.set_default();
|
TERN_(LED_COLOR_PRESETS, leds.set_default());
|
||||||
ApplyLEDColor();
|
ApplyLEDColor();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -1799,10 +1843,10 @@ void DWIN_CopySettingsFrom(const char * const buff) {
|
|||||||
TERN_(BAUD_RATE_GCODE, HMI_SetBaudRate());
|
TERN_(BAUD_RATE_GCODE, HMI_SetBaudRate());
|
||||||
#if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS)
|
#if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS)
|
||||||
leds.set_color(
|
leds.set_color(
|
||||||
(HMI_data.LED_Color >> 16) & 0xFF,
|
HMI_data.Led_Color.r,
|
||||||
(HMI_data.LED_Color >> 8) & 0xFF,
|
HMI_data.Led_Color.g,
|
||||||
(HMI_data.LED_Color >> 0) & 0xFF
|
HMI_data.Led_Color.b
|
||||||
OPTARG(HAS_WHITE_LED, (HMI_data.LED_Color >> 24) & 0xFF)
|
OPTARG(HAS_WHITE_LED, HMI_data.Led_Color.w)
|
||||||
);
|
);
|
||||||
leds.update();
|
leds.update();
|
||||||
#endif
|
#endif
|
||||||
@ -2094,7 +2138,7 @@ void HomeZ() { queue.inject(F("G28Z")); }
|
|||||||
);
|
);
|
||||||
gcode.process_subcommands_now(cmd);
|
gcode.process_subcommands_now(cmd);
|
||||||
#else
|
#else
|
||||||
set_bed_leveling_enabled(false);
|
TERN_(HAS_LEVELING, set_bed_leveling_enabled(false));
|
||||||
gcode.process_subcommands_now(F("G28O\nG0Z0F300\nM400"));
|
gcode.process_subcommands_now(F("G28O\nG0Z0F300\nM400"));
|
||||||
#endif
|
#endif
|
||||||
ui.reset_status();
|
ui.reset_status();
|
||||||
@ -2182,10 +2226,9 @@ void SetPID(celsius_t t, heater_id_t h) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLED(BAUD_RATE_GCODE)
|
#if ENABLED(BAUD_RATE_GCODE)
|
||||||
void HMI_SetBaudRate() {
|
void HMI_SetBaudRate() { HMI_data.Baud115K ? SetBaud115K() : SetBaud250K(); }
|
||||||
if (HMI_data.Baud115K) SetBaud115K(); else SetBaud250K();
|
|
||||||
}
|
|
||||||
void SetBaudRate() {
|
void SetBaudRate() {
|
||||||
|
HMI_data.Baud115K ^= true;
|
||||||
HMI_SetBaudRate();
|
HMI_SetBaudRate();
|
||||||
Draw_Chkb_Line(CurrentMenu->line(), HMI_data.Baud115K);
|
Draw_Chkb_Line(CurrentMenu->line(), HMI_data.Baud115K);
|
||||||
DWIN_UpdateLCD();
|
DWIN_UpdateLCD();
|
||||||
@ -2223,7 +2266,9 @@ void SetPID(celsius_t t, heater_id_t h) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#if HAS_COLOR_LEDS
|
#if HAS_COLOR_LEDS
|
||||||
void ApplyLEDColor() { HMI_data.LED_Color = TERN0(HAS_WHITE_LED, (leds.color.w << 24)) | (leds.color.r << 16) | (leds.color.g << 8) | leds.color.b; }
|
void ApplyLEDColor() {
|
||||||
|
HMI_data.Led_Color = LEDColor( {leds.color.r, leds.color.g, leds.color.b OPTARG(HAS_WHITE_LED, HMI_data.Led_Color.w) } );
|
||||||
|
}
|
||||||
void LiveLEDColor(uint8_t *color) { *color = MenuData.Value; leds.update(); }
|
void LiveLEDColor(uint8_t *color) { *color = MenuData.Value; leds.update(); }
|
||||||
void LiveLEDColorR() { LiveLEDColor(&leds.color.r); }
|
void LiveLEDColorR() { LiveLEDColor(&leds.color.r); }
|
||||||
void LiveLEDColorG() { LiveLEDColor(&leds.color.g); }
|
void LiveLEDColorG() { LiveLEDColor(&leds.color.g); }
|
||||||
@ -2377,48 +2422,45 @@ void ApplyFlow() { planner.refresh_e_factor(0); }
|
|||||||
void SetFlow() { SetPIntOnClick(MIN_PRINT_FLOW, MAX_PRINT_FLOW, ApplyFlow); }
|
void SetFlow() { SetPIntOnClick(MIN_PRINT_FLOW, MAX_PRINT_FLOW, ApplyFlow); }
|
||||||
|
|
||||||
// Bed Tramming
|
// Bed Tramming
|
||||||
TERN(HAS_BED_PROBE, float, void) Tram(uint8_t point) {
|
|
||||||
|
void TramXY(const uint8_t point, const float &margin, float &x, float &y) {
|
||||||
|
switch (point) {
|
||||||
|
case 0:
|
||||||
|
LCD_MESSAGE(MSG_LEVBED_FL);
|
||||||
|
x = y = margin;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
LCD_MESSAGE(MSG_LEVBED_FR);
|
||||||
|
x = X_BED_SIZE - margin; y = margin;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
LCD_MESSAGE(MSG_LEVBED_BR);
|
||||||
|
x = X_BED_SIZE - margin; y = Y_BED_SIZE - margin;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
LCD_MESSAGE(MSG_LEVBED_BL);
|
||||||
|
x = margin; y = Y_BED_SIZE - margin;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
LCD_MESSAGE(MSG_LEVBED_C);
|
||||||
|
x = X_CENTER; y = Y_CENTER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if HAS_BED_PROBE
|
||||||
|
|
||||||
|
float Tram(const uint8_t point) {
|
||||||
char cmd[100] = "";
|
char cmd[100] = "";
|
||||||
#if HAS_BED_PROBE
|
|
||||||
static bool inLev = false;
|
static bool inLev = false;
|
||||||
float xpos = 0, ypos = 0, zval = 0, margin = 0;
|
float xpos = 0, ypos = 0, zval = 0, margin = 0;
|
||||||
char str_1[6] = "", str_2[6] = "", str_3[6] = "";
|
char str_1[6] = "", str_2[6] = "", str_3[6] = "";
|
||||||
if (inLev) return NAN;
|
if (inLev) return NAN;
|
||||||
margin = HMI_data.FullManualTramming ? 30 : PROBING_MARGIN;
|
margin = HMI_data.FullManualTramming ? 30 : PROBING_MARGIN;
|
||||||
#else
|
|
||||||
int16_t xpos = 0, ypos = 0;
|
|
||||||
int16_t margin = 30;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (point) {
|
TramXY(point, margin, xpos, ypos);
|
||||||
case 0:
|
|
||||||
LCD_MESSAGE(MSG_LEVBED_FL);
|
|
||||||
xpos = ypos = margin;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
LCD_MESSAGE(MSG_LEVBED_FR);
|
|
||||||
xpos = X_BED_SIZE - margin; ypos = margin;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
LCD_MESSAGE(MSG_LEVBED_BR);
|
|
||||||
xpos = X_BED_SIZE - margin; ypos = Y_BED_SIZE - margin;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
LCD_MESSAGE(MSG_LEVBED_BL);
|
|
||||||
xpos = margin; ypos = Y_BED_SIZE - margin;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
LCD_MESSAGE(MSG_LEVBED_C);
|
|
||||||
xpos = X_BED_SIZE / 2; ypos = Y_BED_SIZE / 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
planner.synchronize();
|
|
||||||
|
|
||||||
#if HAS_BED_PROBE
|
|
||||||
|
|
||||||
if (HMI_data.FullManualTramming) {
|
if (HMI_data.FullManualTramming) {
|
||||||
planner.synchronize();
|
|
||||||
sprintf_P(cmd, PSTR("M420S0\nG28O\nG90\nG0Z5F300\nG0X%sY%sF5000\nG0Z0F300"),
|
sprintf_P(cmd, PSTR("M420S0\nG28O\nG90\nG0Z5F300\nG0X%sY%sF5000\nG0Z0F300"),
|
||||||
dtostrf(xpos, 1, 1, str_1),
|
dtostrf(xpos, 1, 1, str_1),
|
||||||
dtostrf(ypos, 1, 1, str_2)
|
dtostrf(ypos, 1, 1, str_2)
|
||||||
@ -2426,6 +2468,20 @@ TERN(HAS_BED_PROBE, float, void) Tram(uint8_t point) {
|
|||||||
queue.inject(cmd);
|
queue.inject(cmd);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// AUTO_BED_LEVELING_BILINEAR does not define MESH_INSET
|
||||||
|
#ifndef MESH_MIN_X
|
||||||
|
#define MESH_MIN_X (_MAX(X_MIN_BED + PROBING_MARGIN, X_MIN_POS))
|
||||||
|
#endif
|
||||||
|
#ifndef MESH_MIN_Y
|
||||||
|
#define MESH_MIN_Y (_MAX(Y_MIN_BED + PROBING_MARGIN, Y_MIN_POS))
|
||||||
|
#endif
|
||||||
|
#ifndef MESH_MAX_X
|
||||||
|
#define MESH_MAX_X (_MIN(X_MAX_BED - (PROBING_MARGIN), X_MAX_POS))
|
||||||
|
#endif
|
||||||
|
#ifndef MESH_MAX_Y
|
||||||
|
#define MESH_MAX_Y (_MIN(Y_MAX_BED - (PROBING_MARGIN), Y_MAX_POS))
|
||||||
|
#endif
|
||||||
|
|
||||||
LIMIT(xpos, MESH_MIN_X, MESH_MAX_X);
|
LIMIT(xpos, MESH_MIN_X, MESH_MAX_X);
|
||||||
LIMIT(ypos, MESH_MIN_Y, MESH_MAX_Y);
|
LIMIT(ypos, MESH_MIN_Y, MESH_MAX_Y);
|
||||||
probe.stow();
|
probe.stow();
|
||||||
@ -2445,14 +2501,20 @@ TERN(HAS_BED_PROBE, float, void) Tram(uint8_t point) {
|
|||||||
inLev = false;
|
inLev = false;
|
||||||
}
|
}
|
||||||
return zval;
|
return zval;
|
||||||
|
}
|
||||||
|
|
||||||
#else // !HAS_BED_PROBE
|
#else
|
||||||
|
|
||||||
sprintf_P(cmd, PSTR("M420S0\nG28O\nG90\nG0Z5F300\nG0X%iY%iF5000\nG0Z0F300"), xpos, ypos);
|
void Tram(const uint8_t point) {
|
||||||
|
float xpos = 0, ypos = 0, margin = 30;
|
||||||
|
TramXY(point, margin, xpos, ypos);
|
||||||
|
|
||||||
|
char cmd[100] = "", str_1[6] = "", str_2[6] = "";
|
||||||
|
sprintf_P(cmd, PSTR("M420S0\nG28O\nG90\nG0Z5F300\nG0X%sY%sF5000\nG0Z0F300"), dtostrf(xpos, 1, 1, str_1), dtostrf(ypos, 1, 1, str_2));
|
||||||
queue.inject(cmd);
|
queue.inject(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
void TramFL() { Tram(0); }
|
void TramFL() { Tram(0); }
|
||||||
void TramFR() { Tram(1); }
|
void TramFR() { Tram(1); }
|
||||||
@ -3350,7 +3412,7 @@ void Draw_GetColor_Menu() {
|
|||||||
EDIT_ITEM_F(ICON_LedControl, MSG_COLORS_GREEN, onDrawPInt8Menu, SetLEDColorG, &leds.color.g);
|
EDIT_ITEM_F(ICON_LedControl, MSG_COLORS_GREEN, onDrawPInt8Menu, SetLEDColorG, &leds.color.g);
|
||||||
EDIT_ITEM_F(ICON_LedControl, MSG_COLORS_BLUE, onDrawPInt8Menu, SetLEDColorB, &leds.color.b);
|
EDIT_ITEM_F(ICON_LedControl, MSG_COLORS_BLUE, onDrawPInt8Menu, SetLEDColorB, &leds.color.b);
|
||||||
#if ENABLED(HAS_WHITE_LED)
|
#if ENABLED(HAS_WHITE_LED)
|
||||||
EDIT_ITEM_F(ICON_LedControl, MSG_COLORS_WHITE, onDrawPInt8Menu, SetLedColorW, &leds.color.w);
|
EDIT_ITEM_F(ICON_LedControl, MSG_COLORS_WHITE, onDrawPInt8Menu, SetLEDColorW, &leds.color.w);
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
@ -3763,6 +3825,7 @@ void Draw_Steps_Menu() {
|
|||||||
#endif // AUTO_BED_LEVELING_UBL
|
#endif // AUTO_BED_LEVELING_UBL
|
||||||
|
|
||||||
#if HAS_MESH
|
#if HAS_MESH
|
||||||
|
|
||||||
void Draw_MeshSet_Menu() {
|
void Draw_MeshSet_Menu() {
|
||||||
checkkey = Menu;
|
checkkey = Menu;
|
||||||
if (SetMenu(MeshMenu, GET_TEXT_F(MSG_MESH_LEVELING), 15)) {
|
if (SetMenu(MeshMenu, GET_TEXT_F(MSG_MESH_LEVELING), 15)) {
|
||||||
|
@ -239,9 +239,7 @@ void Draw_Tramming_Menu();
|
|||||||
#if HAS_BED_PROBE
|
#if HAS_BED_PROBE
|
||||||
void Draw_ProbeSet_Menu();
|
void Draw_ProbeSet_Menu();
|
||||||
#endif
|
#endif
|
||||||
#if HAS_FILAMENT_SENSOR
|
void Draw_FilSet_Menu();
|
||||||
void Draw_FilSet_Menu();
|
|
||||||
#endif
|
|
||||||
#if ENABLED(NOZZLE_PARK_FEATURE)
|
#if ENABLED(NOZZLE_PARK_FEATURE)
|
||||||
void Draw_ParkPos_Menu();
|
void Draw_ParkPos_Menu();
|
||||||
#endif
|
#endif
|
||||||
|
@ -37,6 +37,9 @@
|
|||||||
|
|
||||||
#include "../../../inc/MarlinConfigPre.h"
|
#include "../../../inc/MarlinConfigPre.h"
|
||||||
#include "../common/dwin_color.h"
|
#include "../common/dwin_color.h"
|
||||||
|
#if ENABLED(LED_CONTROL_MENU)
|
||||||
|
#include "../../../feature/leds/leds.h"
|
||||||
|
#endif
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#if defined(__STM32F1__) || defined(STM32F1)
|
#if defined(__STM32F1__) || defined(STM32F1)
|
||||||
@ -63,10 +66,7 @@
|
|||||||
#define Def_Coordinate_Color Color_White
|
#define Def_Coordinate_Color Color_White
|
||||||
#define Def_Button_Color RGB( 0, 23, 16)
|
#define Def_Button_Color RGB( 0, 23, 16)
|
||||||
#if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS)
|
#if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS)
|
||||||
#define Def_Leds_Color 0xFFFFFFFF
|
#define Def_Leds_Color LEDColorWhite()
|
||||||
#endif
|
|
||||||
#if ENABLED(CASELIGHT_USES_BRIGHTNESS)
|
|
||||||
#define Def_CaseLight_Brightness 255
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -109,12 +109,12 @@ typedef struct {
|
|||||||
bool Baud115K = false;
|
bool Baud115K = false;
|
||||||
#endif
|
#endif
|
||||||
bool FullManualTramming = false;
|
bool FullManualTramming = false;
|
||||||
// Led
|
|
||||||
#if ENABLED(MESH_BED_LEVELING)
|
#if ENABLED(MESH_BED_LEVELING)
|
||||||
float ManualZOffset = 0;
|
float ManualZOffset = 0;
|
||||||
#endif
|
#endif
|
||||||
|
// Led
|
||||||
#if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS)
|
#if BOTH(LED_CONTROL_MENU, HAS_COLOR_LEDS)
|
||||||
uint32_t LED_Color = Def_Leds_Color;
|
LEDColor Led_Color = Def_Leds_Color;
|
||||||
#endif
|
#endif
|
||||||
} HMI_data_t;
|
} HMI_data_t;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user