mirror of
https://github.com/cookiengineer/audacity
synced 2025-06-23 15:50:05 +02:00
Bug1443: Various odd behavior of label text editor, fixed...
... And label track selection code is simpler to understand, without delayed side effects happening during drawing. Left and right arrow keys collapse text range selection correctly Shift-click adjusts the end of selection nearest the pick Right (and middle) click and drag do not affect the selection Copying empty selection has no effect on the clipboard Left-drag behaves independently of previous selection state
This commit is contained in:
parent
5648023cf3
commit
cb3e5e6d4f
@ -269,7 +269,6 @@ void LabelTrack::WarpLabels(const TimeWarper &warper) {
|
|||||||
|
|
||||||
void LabelTrack::ResetFlags()
|
void LabelTrack::ResetFlags()
|
||||||
{
|
{
|
||||||
mDragXPos = -1;
|
|
||||||
mInitialCursorPos = 1;
|
mInitialCursorPos = 1;
|
||||||
mCurrentCursorPos = 1;
|
mCurrentCursorPos = 1;
|
||||||
mRightDragging = false;
|
mRightDragging = false;
|
||||||
@ -522,8 +521,6 @@ LabelStruct::LabelStruct(const SelectedRegion ®ion,
|
|||||||
: selectedRegion(region)
|
: selectedRegion(region)
|
||||||
, title(aTitle)
|
, title(aTitle)
|
||||||
{
|
{
|
||||||
changeInitialMouseXPos = true;
|
|
||||||
highlighted = false;
|
|
||||||
updated = false;
|
updated = false;
|
||||||
width = 0;
|
width = 0;
|
||||||
x = 0;
|
x = 0;
|
||||||
@ -541,8 +538,6 @@ LabelStruct::LabelStruct(const SelectedRegion ®ion,
|
|||||||
// Overwrite the times
|
// Overwrite the times
|
||||||
selectedRegion.setTimes(t0, t1);
|
selectedRegion.setTimes(t0, t1);
|
||||||
|
|
||||||
changeInitialMouseXPos = true;
|
|
||||||
highlighted = false;
|
|
||||||
updated = false;
|
updated = false;
|
||||||
width = 0;
|
width = 0;
|
||||||
x = 0;
|
x = 0;
|
||||||
@ -694,9 +689,6 @@ void LabelStruct::DrawTextBox(wxDC & dc, const wxRect & r) const
|
|||||||
void LabelStruct::DrawHighlight
|
void LabelStruct::DrawHighlight
|
||||||
( wxDC & dc, int xPos1, int xPos2, int charHeight) const
|
( wxDC & dc, int xPos1, int xPos2, int charHeight) const
|
||||||
{
|
{
|
||||||
highlighted = true;
|
|
||||||
changeInitialMouseXPos = false;
|
|
||||||
|
|
||||||
wxPen curPen = dc.GetPen();
|
wxPen curPen = dc.GetPen();
|
||||||
curPen.SetColour(wxString(wxT("BLUE")));
|
curPen.SetColour(wxString(wxT("BLUE")));
|
||||||
wxBrush curBrush = dc.GetBrush();
|
wxBrush curBrush = dc.GetBrush();
|
||||||
@ -826,7 +818,7 @@ void LabelTrack::Draw(wxDC & dc, const wxRect & r,
|
|||||||
}}
|
}}
|
||||||
|
|
||||||
// Draw highlights
|
// Draw highlights
|
||||||
if ((mDragXPos != -1) && (mSelIndex >= 0 ))
|
if ((mInitialCursorPos != mCurrentCursorPos) && (mSelIndex >= 0 ))
|
||||||
{
|
{
|
||||||
int xpos1, xpos2;
|
int xpos1, xpos2;
|
||||||
CalcHighlightXs(&xpos1, &xpos2);
|
CalcHighlightXs(&xpos1, &xpos2);
|
||||||
@ -866,11 +858,11 @@ void LabelTrack::Draw(wxDC & dc, const wxRect & r,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the cursor position according to x position of mouse
|
|
||||||
/// uses GetTextExtent to find the character position
|
/// uses GetTextExtent to find the character position
|
||||||
/// corresponding to the x pixel position.
|
/// corresponding to the x pixel position.
|
||||||
void LabelTrack::SetCurrentCursorPosition(int xPos)
|
int LabelTrack::FindCurrentCursorPosition(int xPos)
|
||||||
{
|
{
|
||||||
|
int result = -1;
|
||||||
wxMemoryDC dc;
|
wxMemoryDC dc;
|
||||||
if(msFont.Ok())
|
if(msFont.Ok())
|
||||||
dc.SetFont(msFont);
|
dc.SetFont(msFont);
|
||||||
@ -898,7 +890,7 @@ void LabelTrack::SetCurrentCursorPosition(int xPos)
|
|||||||
if (xPos <= bound)
|
if (xPos <= bound)
|
||||||
{
|
{
|
||||||
// Found
|
// Found
|
||||||
mCurrentCursorPos = charIndex - 1;
|
result = charIndex - 1;
|
||||||
finished = true;
|
finished = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -908,10 +900,16 @@ void LabelTrack::SetCurrentCursorPosition(int xPos)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!finished)
|
if (!finished)
|
||||||
{
|
|
||||||
// Cursor should be in the last position
|
// Cursor should be in the last position
|
||||||
mCurrentCursorPos = length;
|
result = length;
|
||||||
}
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the cursor position according to x position of mouse
|
||||||
|
void LabelTrack::SetCurrentCursorPosition(int xPos)
|
||||||
|
{
|
||||||
|
mCurrentCursorPos = FindCurrentCursorPosition(xPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LabelTrack::calculateFontHeight(wxDC & dc) const
|
void LabelTrack::calculateFontHeight(wxDC & dc) const
|
||||||
@ -936,8 +934,6 @@ bool LabelTrack::IsTextSelected()
|
|||||||
{
|
{
|
||||||
if (mSelIndex == -1)
|
if (mSelIndex == -1)
|
||||||
return false;
|
return false;
|
||||||
if (!mLabels[mSelIndex].highlighted)
|
|
||||||
return false;
|
|
||||||
if (mCurrentCursorPos == mInitialCursorPos)
|
if (mCurrentCursorPos == mInitialCursorPos)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
@ -993,14 +989,15 @@ bool LabelTrack::CopySelectedText()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto &labelStruct = mLabels[mSelIndex];
|
const auto &labelStruct = mLabels[mSelIndex];
|
||||||
if (!labelStruct.highlighted)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int init = mInitialCursorPos;
|
int init = mInitialCursorPos;
|
||||||
int cur = mCurrentCursorPos;
|
int cur = mCurrentCursorPos;
|
||||||
if (init > cur)
|
if (init > cur)
|
||||||
std::swap(init, cur);
|
std::swap(init, cur);
|
||||||
|
|
||||||
|
if (init == cur)
|
||||||
|
return false;
|
||||||
|
|
||||||
// data for copying
|
// data for copying
|
||||||
wxString data = labelStruct.title.Mid(init, cur-init);
|
wxString data = labelStruct.title.Mid(init, cur-init);
|
||||||
|
|
||||||
@ -1043,12 +1040,9 @@ bool LabelTrack::PasteSelectedText(double sel0, double sel1)
|
|||||||
|
|
||||||
auto &labelStruct = mLabels[mSelIndex];
|
auto &labelStruct = mLabels[mSelIndex];
|
||||||
auto &title = labelStruct.title;
|
auto &title = labelStruct.title;
|
||||||
int cur = mCurrentCursorPos, init = cur;
|
int cur = mCurrentCursorPos, init = mInitialCursorPos;
|
||||||
if (labelStruct.highlighted) {
|
if (init > cur)
|
||||||
init = mInitialCursorPos;
|
std::swap(init, cur);
|
||||||
if (init > cur)
|
|
||||||
std::swap(init, cur);
|
|
||||||
}
|
|
||||||
left = title.Left(init);
|
left = title.Left(init);
|
||||||
if (cur < (int)title.Length())
|
if (cur < (int)title.Length())
|
||||||
right = title.Mid(cur);
|
right = title.Mid(cur);
|
||||||
@ -1493,20 +1487,9 @@ void LabelTrack::HandleTextDragRelease(const wxMouseEvent & evt)
|
|||||||
|
|
||||||
if(evt.Dragging())
|
if(evt.Dragging())
|
||||||
{
|
{
|
||||||
// if dragging happens in text box
|
if (!mRightDragging)
|
||||||
// end dragging x position in pixels
|
// Update drag end
|
||||||
// set flag to update current cursor position
|
SetCurrentCursorPosition(evt.m_x);
|
||||||
mDragXPos = evt.m_x;
|
|
||||||
|
|
||||||
// for preventing dragging glygh from changing current cursor position
|
|
||||||
// set end dragging position to current cursor position
|
|
||||||
SetCurrentCursorPosition(mDragXPos);
|
|
||||||
|
|
||||||
// if it's an invalid dragging, disable displaying
|
|
||||||
if (mRightDragging) {
|
|
||||||
mDragXPos = -1;
|
|
||||||
mRightDragging = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1573,20 +1556,33 @@ void LabelTrack::HandleClick(const wxMouseEvent & evt,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable displaying if left button is down
|
|
||||||
if (evt.LeftDown())
|
|
||||||
mDragXPos = -1;
|
|
||||||
|
|
||||||
mSelIndex = OverATextBox(evt.m_x, evt.m_y);
|
mSelIndex = OverATextBox(evt.m_x, evt.m_y);
|
||||||
if (mSelIndex != -1) {
|
if (mSelIndex != -1) {
|
||||||
auto &labelStruct = mLabels[mSelIndex];
|
auto &labelStruct = mLabels[mSelIndex];
|
||||||
*newSel = labelStruct.selectedRegion;
|
*newSel = labelStruct.selectedRegion;
|
||||||
SetCurrentCursorPosition(evt.m_x);
|
|
||||||
|
|
||||||
// for preventing from resetting by shift+mouse left button
|
if (evt.LeftDown()) {
|
||||||
if (labelStruct.changeInitialMouseXPos)
|
// Find the NEW drag end
|
||||||
mInitialCursorPos = mCurrentCursorPos;
|
auto position = FindCurrentCursorPosition(evt.m_x);
|
||||||
mDrawCursor = true;
|
|
||||||
|
if (evt.ShiftDown()) {
|
||||||
|
// Set the drag anchor at the end of the previous selection
|
||||||
|
// that is farther from the NEW drag end
|
||||||
|
if (abs(position - mCurrentCursorPos) >
|
||||||
|
abs(position - mInitialCursorPos))
|
||||||
|
mInitialCursorPos = mCurrentCursorPos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mInitialCursorPos = position;
|
||||||
|
|
||||||
|
mCurrentCursorPos = position;
|
||||||
|
|
||||||
|
mDrawCursor = true;
|
||||||
|
mRightDragging = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// Actually this might be right or middle down
|
||||||
|
mRightDragging = true;
|
||||||
|
|
||||||
// reset the highlight indicator
|
// reset the highlight indicator
|
||||||
wxRect highlightedRect;
|
wxRect highlightedRect;
|
||||||
@ -1600,28 +1596,8 @@ void LabelTrack::HandleClick(const wxMouseEvent & evt,
|
|||||||
xpos1, labelStruct.y - mFontHeight / 2,
|
xpos1, labelStruct.y - mFontHeight / 2,
|
||||||
(int)(xpos2 - xpos1 + 0.5), mFontHeight
|
(int)(xpos2 - xpos1 + 0.5), mFontHeight
|
||||||
};
|
};
|
||||||
|
|
||||||
// reset when left button is down
|
|
||||||
if (evt.LeftDown())
|
|
||||||
labelStruct.highlighted = false;
|
|
||||||
// reset when right button is down outside text box
|
|
||||||
if (evt.RightDown())
|
|
||||||
{
|
|
||||||
if (!highlightedRect.Contains(evt.m_x, evt.m_y))
|
|
||||||
{
|
|
||||||
mCurrentCursorPos = mInitialCursorPos = 0;
|
|
||||||
labelStruct.highlighted = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// set changeInitialMouseXPos flag
|
|
||||||
labelStruct.changeInitialMouseXPos = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable displaying if right button is down outside text box
|
|
||||||
if (evt.RightDown()
|
|
||||||
&& !highlightedRect.Contains(evt.m_x, evt.m_y))
|
|
||||||
mDragXPos = -1;
|
|
||||||
|
|
||||||
// Middle click on GTK: paste from primary selection
|
// Middle click on GTK: paste from primary selection
|
||||||
#if defined(__WXGTK__) && (HAVE_GTK)
|
#if defined(__WXGTK__) && (HAVE_GTK)
|
||||||
if (evt.MiddleDown()) {
|
if (evt.MiddleDown()) {
|
||||||
@ -1634,16 +1610,6 @@ void LabelTrack::HandleClick(const wxMouseEvent & evt,
|
|||||||
*newSel = SelectedRegion(t, t);
|
*newSel = SelectedRegion(t, t);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// handle shift+mouse left button
|
|
||||||
if (evt.ShiftDown()) {
|
|
||||||
// if the mouse is clicked in text box, set flags
|
|
||||||
mDragXPos = evt.m_x;
|
|
||||||
|
|
||||||
// for preventing dragging glygh from changing current cursor position
|
|
||||||
// set end dragging position to current cursor position
|
|
||||||
SetCurrentCursorPosition(evt.m_x);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__WXGTK__) && (HAVE_GTK)
|
#if defined(__WXGTK__) && (HAVE_GTK)
|
||||||
@ -1732,9 +1698,8 @@ bool LabelTrack::OnKeyDown(SelectedRegion &newSel, wxKeyEvent & event)
|
|||||||
if (len > 0)
|
if (len > 0)
|
||||||
{
|
{
|
||||||
// IF there are some highlighted letters, THEN DELETE them
|
// IF there are some highlighted letters, THEN DELETE them
|
||||||
if (labelStruct.highlighted) {
|
if (mInitialCursorPos != mCurrentCursorPos)
|
||||||
RemoveSelectedText();
|
RemoveSelectedText();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// DELETE one letter
|
// DELETE one letter
|
||||||
@ -1763,9 +1728,8 @@ bool LabelTrack::OnKeyDown(SelectedRegion &newSel, wxKeyEvent & event)
|
|||||||
if (len > 0)
|
if (len > 0)
|
||||||
{
|
{
|
||||||
// if there are some highlighted letters, DELETE them
|
// if there are some highlighted letters, DELETE them
|
||||||
if (labelStruct.highlighted) {
|
if (mInitialCursorPos != mCurrentCursorPos)
|
||||||
RemoveSelectedText();
|
RemoveSelectedText();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// DELETE one letter
|
// DELETE one letter
|
||||||
@ -1789,11 +1753,9 @@ bool LabelTrack::OnKeyDown(SelectedRegion &newSel, wxKeyEvent & event)
|
|||||||
// Move cursor to beginning of label
|
// Move cursor to beginning of label
|
||||||
mCurrentCursorPos = 0;
|
mCurrentCursorPos = 0;
|
||||||
if (mods == wxMOD_SHIFT)
|
if (mods == wxMOD_SHIFT)
|
||||||
mDragXPos = 0;
|
;
|
||||||
else {
|
else
|
||||||
mDragXPos = -1;
|
|
||||||
mInitialCursorPos = mCurrentCursorPos;
|
mInitialCursorPos = mCurrentCursorPos;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WXK_END:
|
case WXK_END:
|
||||||
@ -1801,11 +1763,9 @@ bool LabelTrack::OnKeyDown(SelectedRegion &newSel, wxKeyEvent & event)
|
|||||||
// Move cursor to end of label
|
// Move cursor to end of label
|
||||||
mCurrentCursorPos = (int)title.length();
|
mCurrentCursorPos = (int)title.length();
|
||||||
if (mods == wxMOD_SHIFT)
|
if (mods == wxMOD_SHIFT)
|
||||||
mDragXPos = 0;
|
;
|
||||||
else {
|
else
|
||||||
mDragXPos = -1;
|
|
||||||
mInitialCursorPos = mCurrentCursorPos;
|
mInitialCursorPos = mCurrentCursorPos;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WXK_LEFT:
|
case WXK_LEFT:
|
||||||
@ -1814,11 +1774,10 @@ bool LabelTrack::OnKeyDown(SelectedRegion &newSel, wxKeyEvent & event)
|
|||||||
if (mCurrentCursorPos > 0) {
|
if (mCurrentCursorPos > 0) {
|
||||||
mCurrentCursorPos--;
|
mCurrentCursorPos--;
|
||||||
if (mods == wxMOD_SHIFT)
|
if (mods == wxMOD_SHIFT)
|
||||||
mDragXPos = 0;
|
;
|
||||||
else {
|
else
|
||||||
mDragXPos = -1;
|
mInitialCursorPos = mCurrentCursorPos =
|
||||||
mInitialCursorPos = mCurrentCursorPos;
|
std::min(mInitialCursorPos, mCurrentCursorPos);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1828,11 +1787,10 @@ bool LabelTrack::OnKeyDown(SelectedRegion &newSel, wxKeyEvent & event)
|
|||||||
if (mCurrentCursorPos < (int)title.length()) {
|
if (mCurrentCursorPos < (int)title.length()) {
|
||||||
mCurrentCursorPos++;
|
mCurrentCursorPos++;
|
||||||
if (mods == wxMOD_SHIFT)
|
if (mods == wxMOD_SHIFT)
|
||||||
mDragXPos = 0;
|
;
|
||||||
else {
|
else
|
||||||
mDragXPos = -1;
|
mInitialCursorPos = mCurrentCursorPos =
|
||||||
mInitialCursorPos = mCurrentCursorPos;
|
std::max(mInitialCursorPos, mCurrentCursorPos);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1984,9 +1942,8 @@ bool LabelTrack::OnChar(SelectedRegion &WXUNUSED(newSel), wxKeyEvent & event)
|
|||||||
auto &title = labelStruct.title;
|
auto &title = labelStruct.title;
|
||||||
|
|
||||||
// Test if cursor is in the end of string or not
|
// Test if cursor is in the end of string or not
|
||||||
if (labelStruct.highlighted) {
|
if (mInitialCursorPos != mCurrentCursorPos)
|
||||||
RemoveSelectedText();
|
RemoveSelectedText();
|
||||||
}
|
|
||||||
|
|
||||||
if (mCurrentCursorPos < (int)title.length()) {
|
if (mCurrentCursorPos < (int)title.length()) {
|
||||||
// Get substring on the righthand side of cursor
|
// Get substring on the righthand side of cursor
|
||||||
@ -2048,9 +2005,6 @@ void LabelTrack::ShowContextMenu()
|
|||||||
|
|
||||||
parent->PopupMenu(&menu, x, ls->y + (mIconHeight / 2) - 1);
|
parent->PopupMenu(&menu, x, ls->y + (mIconHeight / 2) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// it's an invalid dragging event
|
|
||||||
SetWrongDragging(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LabelTrack::OnContextMenu(wxCommandEvent & evt)
|
void LabelTrack::OnContextMenu(wxCommandEvent & evt)
|
||||||
@ -2126,8 +2080,6 @@ void LabelTrack::RemoveSelectedText()
|
|||||||
|
|
||||||
title = left + right;
|
title = left + right;
|
||||||
mInitialCursorPos = mCurrentCursorPos = left.Length();
|
mInitialCursorPos = mCurrentCursorPos = left.Length();
|
||||||
labelStruct.highlighted = false;
|
|
||||||
mDragXPos = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LabelTrack::Unselect()
|
void LabelTrack::Unselect()
|
||||||
|
@ -96,8 +96,6 @@ public:
|
|||||||
mutable int xText; /// Pixel position of left hand side of text box
|
mutable int xText; /// Pixel position of left hand side of text box
|
||||||
mutable int y; /// Pixel position of label.
|
mutable int y; /// Pixel position of label.
|
||||||
|
|
||||||
mutable bool highlighted; /// if the text is highlighted
|
|
||||||
mutable bool changeInitialMouseXPos; /// flag to change initial mouse X pos
|
|
||||||
bool updated; /// flag to tell if the label times were updated
|
bool updated; /// flag to tell if the label times were updated
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -180,9 +178,6 @@ class AUDACITY_DLL_API LabelTrack final : public Track
|
|||||||
bool PasteSelectedText(double sel0, double sel1);
|
bool PasteSelectedText(double sel0, double sel1);
|
||||||
static bool IsTextClipSupported();
|
static bool IsTextClipSupported();
|
||||||
|
|
||||||
// methods to set flags
|
|
||||||
void SetWrongDragging(bool rightFlag) { mRightDragging = rightFlag; }
|
|
||||||
|
|
||||||
void HandleClick(const wxMouseEvent & evt, const wxRect & r, const ZoomInfo &zoomInfo,
|
void HandleClick(const wxMouseEvent & evt, const wxRect & r, const ZoomInfo &zoomInfo,
|
||||||
SelectedRegion *newSel);
|
SelectedRegion *newSel);
|
||||||
bool HandleGlyphDragRelease(const wxMouseEvent & evt, wxRect & r, const ZoomInfo &zoomInfo,
|
bool HandleGlyphDragRelease(const wxMouseEvent & evt, wxRect & r, const ZoomInfo &zoomInfo,
|
||||||
@ -263,8 +258,6 @@ class AUDACITY_DLL_API LabelTrack final : public Track
|
|||||||
static int mFontHeight;
|
static int mFontHeight;
|
||||||
int mCurrentCursorPos; /// current cursor position
|
int mCurrentCursorPos; /// current cursor position
|
||||||
int mInitialCursorPos; /// initial cursor position
|
int mInitialCursorPos; /// initial cursor position
|
||||||
int mDragXPos; /// end X pos of dragging
|
|
||||||
/// in text box
|
|
||||||
|
|
||||||
bool mRightDragging; /// flag to tell if it's a valid dragging
|
bool mRightDragging; /// flag to tell if it's a valid dragging
|
||||||
bool mDrawCursor; /// flag to tell if drawing the
|
bool mDrawCursor; /// flag to tell if drawing the
|
||||||
@ -279,6 +272,7 @@ class AUDACITY_DLL_API LabelTrack final : public Track
|
|||||||
void ComputeTextPosition(const wxRect & r, int index) const;
|
void ComputeTextPosition(const wxRect & r, int index) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
int FindCurrentCursorPosition(int xPos);
|
||||||
void SetCurrentCursorPosition(int xPos);
|
void SetCurrentCursorPosition(int xPos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user