mirror of
https://git.lyx.org/repos/lyx.git
synced 2025-01-03 08:28:25 +00:00
toolbar cleanup. JMarc, Lars, please see the fIXME. I haven't introduced the problem
but we are leaking icons on every vector resize ... git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@4751 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
parent
3c22b7dc3b
commit
c43fc67eff
@ -20,6 +20,12 @@
|
||||
* buffer.C (readFile): Run the lyxconvert script in order to read
|
||||
old files.
|
||||
|
||||
2002-07-22 John Levon <moz@compsoc.man.ac.uk>
|
||||
|
||||
* LyXAction.C:
|
||||
* commandtags.h:
|
||||
* lyxfunc.C: remove LFUN_ADD_TO_TOOLBAR
|
||||
|
||||
2002-07-22 John Levon <moz@compsoc.man.ac.uk>
|
||||
|
||||
* LyXAction.C:
|
||||
|
@ -382,7 +382,6 @@ void LyXAction::init()
|
||||
{ LFUN_TOGGLECURSORFOLLOW, "toggle-cursor-follows-scrollbar",
|
||||
N_("Toggle cursor does/doesn't follow the scrollbar"),
|
||||
ReadOnly },
|
||||
{ LFUN_ADD_TO_TOOLBAR, "toolbar-add-to", "", NoBuffer },
|
||||
{ LFUN_UNDO, "undo", N_("Undo"), Noop },
|
||||
{ LFUN_UP, "up", "", ReadOnly },
|
||||
{ LFUN_UPSEL, "up-select", "", ReadOnly },
|
||||
|
@ -175,7 +175,6 @@ enum kb_action {
|
||||
LFUN_CAPITALIZE_WORD,
|
||||
LFUN_INSERT_LABEL,
|
||||
LFUN_REF_INSERT,
|
||||
LFUN_ADD_TO_TOOLBAR,
|
||||
LFUN_DEPTH_MIN, // 150 // RVDK_PATCH_5
|
||||
LFUN_DEPTH_PLUS, // RVDK_PATCH_5
|
||||
LFUN_MENU_OPEN_BY_NAME, // RVDK_PATCH_5
|
||||
|
@ -2,6 +2,11 @@
|
||||
|
||||
* lyx_gui.h: add exit()
|
||||
|
||||
2002-07-22 John Levon <moz@compsoc.man.ac.uk>
|
||||
|
||||
* Toolbar.h:
|
||||
* Toolbar.C: remove other unused code
|
||||
|
||||
2002-07-22 John Levon <moz@compsoc.man.ac.uk>
|
||||
|
||||
* Toolbar.h:
|
||||
|
@ -29,14 +29,11 @@ Toolbar::Toolbar(LyXView * o, Dialogs & d,
|
||||
{
|
||||
pimpl_ = new Pimpl(o, d, x, y);
|
||||
|
||||
pimpl_->reset();
|
||||
|
||||
// extracts the toolbar actions from tbd
|
||||
for (ToolbarDefaults::const_iterator cit = tbd.begin();
|
||||
cit != tbd.end(); ++cit) {
|
||||
pimpl_->add((*cit));
|
||||
lyxerr[Debug::GUI] << "tool action: "
|
||||
<< (*cit) << endl;
|
||||
lyxerr[Debug::GUI] << "tool action: " << (*cit) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,12 +44,6 @@ Toolbar::~Toolbar()
|
||||
}
|
||||
|
||||
|
||||
void Toolbar::set(bool doingmain)
|
||||
{
|
||||
pimpl_->set(doingmain);
|
||||
}
|
||||
|
||||
|
||||
void Toolbar::update()
|
||||
{
|
||||
pimpl_->update();
|
||||
@ -90,16 +81,3 @@ void Toolbar::clearLayoutList()
|
||||
{
|
||||
pimpl_->clearLayoutList();
|
||||
}
|
||||
|
||||
|
||||
void Toolbar::add(string const & func, bool doclean)
|
||||
{
|
||||
int const tf = lyxaction.LookupFunc(func);
|
||||
|
||||
if (tf == -1) {
|
||||
lyxerr << "Toolbar::add: no LyX command called`"
|
||||
<< func << "'exists!" << endl;
|
||||
} else {
|
||||
pimpl_->add(tf, doclean);
|
||||
}
|
||||
}
|
||||
|
@ -36,16 +36,6 @@ public:
|
||||
///
|
||||
~Toolbar();
|
||||
|
||||
/// (re)sets the toolbar
|
||||
void set(bool doingmain = false);
|
||||
|
||||
/** this is to be the entry point to the toolbar
|
||||
frame, where you can change the toolbar realtime. */
|
||||
void edit();
|
||||
/// add a new button to the toolbar.
|
||||
void add(int , bool doclean = true);
|
||||
/// name of func instead of kb_action
|
||||
void add(string const & , bool doclean = true);
|
||||
/// update the state of the icons
|
||||
void update();
|
||||
|
||||
|
@ -1,3 +1,11 @@
|
||||
2002-07-22 John Levon <moz@compsoc.man.ac.uk>
|
||||
|
||||
* XFormsView.C: don't call toolbar_->set()
|
||||
|
||||
* Toolbar_pimpl.h:
|
||||
* Toolbar_pimpl.C: rationalise code, remove half-working
|
||||
update stuff into simple add()
|
||||
|
||||
2002-07-22 John Levon <moz@compsoc.man.ac.uk>
|
||||
|
||||
* lyx_gui.C: add lyx_gui::exit()
|
||||
|
@ -46,21 +46,22 @@ const int buttonwidth = 30; // the standard button width
|
||||
const int height = 30; // the height of all items in the toolbar
|
||||
|
||||
Toolbar::Pimpl::toolbarItem::toolbarItem()
|
||||
: action(LFUN_NOACTION), icon(0)
|
||||
{
|
||||
action = LFUN_NOACTION;
|
||||
icon = 0;
|
||||
}
|
||||
|
||||
|
||||
Toolbar::Pimpl::toolbarItem::~toolbarItem()
|
||||
{
|
||||
// It seems that now this is taken care of
|
||||
// in the XFormsView destructor. (Lgb)
|
||||
// clean();
|
||||
// Lars said here that ~XFormsView() dealt with the icons.
|
||||
// This is not true. But enabling this causes crashes,
|
||||
// because somehow we kill the same icon twice :(
|
||||
// FIXME
|
||||
//kill_icon();
|
||||
}
|
||||
|
||||
|
||||
void Toolbar::Pimpl::toolbarItem::clean()
|
||||
void Toolbar::Pimpl::toolbarItem::kill_icon()
|
||||
{
|
||||
if (icon) {
|
||||
fl_delete_object(icon);
|
||||
@ -73,16 +74,14 @@ void Toolbar::Pimpl::toolbarItem::clean()
|
||||
Toolbar::Pimpl::toolbarItem &
|
||||
Toolbar::Pimpl::toolbarItem::operator=(toolbarItem const & ti)
|
||||
{
|
||||
// Are we assigning the object onto itself?
|
||||
if (this == &ti)
|
||||
return *this;
|
||||
|
||||
// If we already have an icon, release it.
|
||||
clean();
|
||||
// But we don't copy the icon from ti
|
||||
kill_icon();
|
||||
|
||||
// do we have to check icon too?
|
||||
action = ti.action;
|
||||
icon = 0; // locally we need to get the icon anew
|
||||
|
||||
return *this;
|
||||
}
|
||||
@ -90,27 +89,45 @@ Toolbar::Pimpl::toolbarItem::operator=(toolbarItem const & ti)
|
||||
|
||||
|
||||
Toolbar::Pimpl::Pimpl(LyXView * o, Dialogs & d, int x, int y)
|
||||
: owner(static_cast<XFormsView *>(o)), sxpos(x), sypos(y)
|
||||
: owner_(static_cast<XFormsView *>(o)), xpos(x), ypos(y)
|
||||
{
|
||||
combox = 0;
|
||||
combox_ = 0;
|
||||
tooltip_ = new Tooltips(d);
|
||||
}
|
||||
|
||||
|
||||
Toolbar::Pimpl::~Pimpl()
|
||||
{
|
||||
clean();
|
||||
fl_freeze_form(owner_->getForm());
|
||||
|
||||
// G++ vector does not have clear defined
|
||||
//toollist.clear();
|
||||
toollist_.erase(toollist_.begin(), toollist_.end());
|
||||
|
||||
delete combox_;
|
||||
|
||||
fl_unfreeze_form(owner_->getForm());
|
||||
delete tooltip_;
|
||||
}
|
||||
|
||||
|
||||
void Toolbar::Pimpl::update()
|
||||
{
|
||||
ToolbarList::const_iterator p = toollist.begin();
|
||||
ToolbarList::const_iterator end = toollist.end();
|
||||
ToolbarList::const_iterator p = toollist_.begin();
|
||||
ToolbarList::const_iterator end = toollist_.end();
|
||||
for (; p != end; ++p) {
|
||||
if (p->icon) {
|
||||
FuncStatus status = owner->getLyXFunc()->getStatus(p->action);
|
||||
if (p->action == ToolbarDefaults::LAYOUTS && combox_) {
|
||||
if (owner_->getLyXFunc()->getStatus(LFUN_LAYOUT).disabled())
|
||||
combox_->deactivate();
|
||||
else
|
||||
combox_->activate();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!p->icon)
|
||||
continue;
|
||||
|
||||
FuncStatus const status = owner_->getLyXFunc()->getStatus(p->action);
|
||||
if (status.onoff(true)) {
|
||||
// I'd like to use a different color
|
||||
// here, but then the problem is to
|
||||
@ -131,12 +148,6 @@ void Toolbar::Pimpl::update()
|
||||
}
|
||||
else
|
||||
fl_activate_object(p->icon);
|
||||
} else if (p->action == ToolbarDefaults::LAYOUTS && combox) {
|
||||
if (owner->getLyXFunc()->getStatus(LFUN_LAYOUT).disabled())
|
||||
combox->deactivate();
|
||||
else
|
||||
combox->activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,15 +163,15 @@ void Toolbar::Pimpl::layoutSelectedCB(int, void * arg, Combox *)
|
||||
|
||||
void Toolbar::Pimpl::layoutSelected()
|
||||
{
|
||||
string const & layoutguiname = combox->getline();
|
||||
string const & layoutguiname = combox_->getline();
|
||||
LyXTextClass const & tc =
|
||||
owner->buffer()->params.getLyXTextClass();
|
||||
owner_->buffer()->params.getLyXTextClass();
|
||||
|
||||
LyXTextClass::const_iterator end = tc.end();
|
||||
for (LyXTextClass::const_iterator cit = tc.begin();
|
||||
cit != end; ++cit) {
|
||||
if (_((*cit)->name()) == layoutguiname) {
|
||||
owner->getLyXFunc()->dispatch(LFUN_LAYOUT, (*cit)->name());
|
||||
owner_->getLyXFunc()->dispatch(LFUN_LAYOUT, (*cit)->name());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -171,10 +182,10 @@ void Toolbar::Pimpl::layoutSelected()
|
||||
|
||||
void Toolbar::Pimpl::setLayout(string const & layout)
|
||||
{
|
||||
if (combox) {
|
||||
if (combox_) {
|
||||
LyXTextClass const & tc =
|
||||
owner->buffer()->params.getLyXTextClass();
|
||||
combox->select(_(tc[layout]->name()));
|
||||
owner_->buffer()->params.getLyXTextClass();
|
||||
combox_->select(_(tc[layout]->name()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,39 +193,39 @@ void Toolbar::Pimpl::setLayout(string const & layout)
|
||||
void Toolbar::Pimpl::updateLayoutList(bool force)
|
||||
{
|
||||
// Update the layout display
|
||||
if (!combox) return;
|
||||
if (!combox_) return;
|
||||
|
||||
// If textclass is different, we need to update the list
|
||||
if (combox->empty() || force) {
|
||||
combox->clear();
|
||||
if (combox_->empty() || force) {
|
||||
combox_->clear();
|
||||
LyXTextClass const & tc =
|
||||
owner->buffer()->params.getLyXTextClass();
|
||||
owner_->buffer()->params.getLyXTextClass();
|
||||
LyXTextClass::const_iterator end = tc.end();
|
||||
for (LyXTextClass::const_iterator cit = tc.begin();
|
||||
cit != end; ++cit) {
|
||||
// ignore obsolete entries
|
||||
if ((*cit)->obsoleted_by().empty())
|
||||
combox->addline(_((*cit)->name()));
|
||||
combox_->addline(_((*cit)->name()));
|
||||
}
|
||||
}
|
||||
// we need to do this.
|
||||
combox->redraw();
|
||||
combox_->redraw();
|
||||
}
|
||||
|
||||
|
||||
void Toolbar::Pimpl::clearLayoutList()
|
||||
{
|
||||
if (combox) {
|
||||
combox->clear();
|
||||
combox->redraw();
|
||||
if (combox_) {
|
||||
combox_->clear();
|
||||
combox_->redraw();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Toolbar::Pimpl::openLayoutList()
|
||||
{
|
||||
if (combox)
|
||||
combox->show();
|
||||
if (combox_)
|
||||
combox_->show();
|
||||
}
|
||||
|
||||
|
||||
@ -285,22 +296,14 @@ void setPixmap(FL_OBJECT * obj, int action, int buttonwidth, int height)
|
||||
} // namespace anon
|
||||
|
||||
|
||||
void Toolbar::Pimpl::set(bool doingmain)
|
||||
void Toolbar::Pimpl::add(int action)
|
||||
{
|
||||
// we shouldn't set if we have not cleaned
|
||||
if (!cleaned) return;
|
||||
|
||||
FL_OBJECT * obj;
|
||||
|
||||
if (!doingmain) {
|
||||
fl_freeze_form(owner->getForm());
|
||||
fl_addto_form(owner->getForm());
|
||||
}
|
||||
toolbarItem item;
|
||||
item.action = action;
|
||||
|
||||
ToolbarList::iterator item = toollist.begin();
|
||||
ToolbarList::iterator end = toollist.end();
|
||||
for (; item != end; ++item) {
|
||||
switch (item->action) {
|
||||
switch (action) {
|
||||
case ToolbarDefaults::SEPARATOR:
|
||||
xpos += sepspace;
|
||||
break;
|
||||
@ -309,17 +312,17 @@ void Toolbar::Pimpl::set(bool doingmain)
|
||||
break;
|
||||
case ToolbarDefaults::LAYOUTS:
|
||||
xpos += standardspacing;
|
||||
if (!combox)
|
||||
combox = new Combox(FL_COMBOX_DROPLIST);
|
||||
combox->add(xpos, ypos, 135, height, 400);
|
||||
combox->setcallback(layoutSelectedCB, this);
|
||||
combox->resize(FL_RESIZE_ALL);
|
||||
combox->gravity(NorthWestGravity, NorthWestGravity);
|
||||
if (!combox_)
|
||||
combox_ = new Combox(FL_COMBOX_DROPLIST);
|
||||
combox_->add(xpos, ypos, 135, height, 400);
|
||||
combox_->setcallback(layoutSelectedCB, this);
|
||||
combox_->resize(FL_RESIZE_ALL);
|
||||
combox_->gravity(NorthWestGravity, NorthWestGravity);
|
||||
xpos += 135;
|
||||
break;
|
||||
default:
|
||||
xpos += standardspacing;
|
||||
item->icon = obj =
|
||||
item.icon = obj =
|
||||
fl_add_pixmapbutton(FL_NORMAL_BUTTON,
|
||||
xpos, ypos,
|
||||
buttonwidth,
|
||||
@ -329,7 +332,7 @@ void Toolbar::Pimpl::set(bool doingmain)
|
||||
NorthWestGravity,
|
||||
NorthWestGravity);
|
||||
fl_set_object_callback(obj, C_Toolbar_ToolbarCB,
|
||||
static_cast<long>(item->action));
|
||||
static_cast<long>(action));
|
||||
// Remove the blue feedback rectangle
|
||||
fl_set_pixmapbutton_focus_outline(obj, 0);
|
||||
|
||||
@ -338,9 +341,9 @@ void Toolbar::Pimpl::set(bool doingmain)
|
||||
tooltip_->init(obj, tip);
|
||||
|
||||
// The view that this object belongs to.
|
||||
obj->u_vdata = owner;
|
||||
obj->u_vdata = owner_;
|
||||
|
||||
setPixmap(obj, item->action, buttonwidth, height);
|
||||
setPixmap(obj, action, buttonwidth, height);
|
||||
// we must remember to update the positions
|
||||
xpos += buttonwidth;
|
||||
// ypos is constant
|
||||
@ -350,95 +353,6 @@ void Toolbar::Pimpl::set(bool doingmain)
|
||||
*/
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!doingmain) {
|
||||
fl_end_form();
|
||||
fl_unfreeze_form(owner->getForm());
|
||||
// Should be safe to do this here.
|
||||
owner->updateLayoutChoice();
|
||||
}
|
||||
|
||||
// set the state of the icons
|
||||
//update();
|
||||
|
||||
cleaned = false;
|
||||
}
|
||||
|
||||
|
||||
void Toolbar::Pimpl::add(int action, bool doclean)
|
||||
{
|
||||
if (doclean && !cleaned) clean();
|
||||
|
||||
// this is what we do if we want to add to an existing
|
||||
// toolbar.
|
||||
if (!doclean && owner) {
|
||||
// first "hide" the toolbar buttons. This is not a real hide
|
||||
// actually it deletes and frees the button altogether.
|
||||
lyxerr << "Toolbar::add: \"hide\" the toolbar buttons."
|
||||
<< endl;
|
||||
|
||||
lightReset();
|
||||
|
||||
fl_freeze_form(owner->getForm());
|
||||
|
||||
ToolbarList::iterator p = toollist.begin();
|
||||
ToolbarList::iterator end = toollist.end();
|
||||
for (; p != end; ++p) {
|
||||
p->clean();
|
||||
}
|
||||
|
||||
if (combox) {
|
||||
delete combox;
|
||||
combox = 0;
|
||||
}
|
||||
fl_unfreeze_form(owner->getForm());
|
||||
cleaned = true; // this is not completely true, but OK anyway
|
||||
}
|
||||
|
||||
// there exist some special actions not part of
|
||||
// kb_action: SEPARATOR, LAYOUTS
|
||||
|
||||
toolbarItem newItem;
|
||||
newItem.action = action;
|
||||
toollist.push_back(newItem);
|
||||
}
|
||||
|
||||
|
||||
void Toolbar::Pimpl::clean()
|
||||
{
|
||||
//reset(); // I do not understand what this reset() is, anyway
|
||||
|
||||
//now delete all the objects..
|
||||
if (owner)
|
||||
fl_freeze_form(owner->getForm());
|
||||
|
||||
// G++ vector does not have clear defined
|
||||
//toollist.clear();
|
||||
toollist.erase(toollist.begin(), toollist.end());
|
||||
|
||||
lyxerr[Debug::GUI] << "Combox: " << combox << endl;
|
||||
if (combox) {
|
||||
delete combox;
|
||||
combox = 0;
|
||||
}
|
||||
|
||||
if (owner)
|
||||
fl_unfreeze_form(owner->getForm());
|
||||
lyxerr[Debug::GUI] << "toolbar cleaned" << endl;
|
||||
cleaned = true;
|
||||
}
|
||||
|
||||
|
||||
void Toolbar::Pimpl::reset()
|
||||
{
|
||||
//toollist = 0; // what is this supposed to do?
|
||||
cleaned = false;
|
||||
lightReset();
|
||||
}
|
||||
|
||||
|
||||
void Toolbar::Pimpl::lightReset() {
|
||||
xpos = sxpos - standardspacing;
|
||||
ypos = sypos;
|
||||
toollist_.push_back(item);
|
||||
}
|
||||
|
@ -31,20 +31,15 @@ struct Toolbar::Pimpl {
|
||||
public:
|
||||
/// called when user selects a layout from combox
|
||||
static void layoutSelectedCB(int, void *, Combox *);
|
||||
///
|
||||
|
||||
/// create an empty toolbar
|
||||
Pimpl(LyXView * o, Dialogs &, int x, int y);
|
||||
///
|
||||
|
||||
~Pimpl();
|
||||
|
||||
/// (re)sets the toolbar
|
||||
void set(bool doingmain = false);
|
||||
|
||||
/** this is to be the entry point to the toolbar
|
||||
frame, where you can change the toolbar realtime.
|
||||
*/
|
||||
void edit();
|
||||
/// add a new button to the toolbar.
|
||||
void add(int, bool doclean = true);
|
||||
void add(int action);
|
||||
|
||||
/// update the state of the icons
|
||||
void update();
|
||||
|
||||
@ -59,51 +54,38 @@ public:
|
||||
/// the non-static version of layoutSelectedCB
|
||||
void layoutSelected();
|
||||
|
||||
///
|
||||
/// an item on the toolbar
|
||||
struct toolbarItem
|
||||
{
|
||||
///
|
||||
int action;
|
||||
///
|
||||
FL_OBJECT * icon;
|
||||
///
|
||||
toolbarItem();
|
||||
///
|
||||
void clean();
|
||||
///
|
||||
|
||||
~toolbarItem();
|
||||
///
|
||||
|
||||
toolbarItem & operator=(toolbarItem const & ti);
|
||||
|
||||
/// deallocate icon
|
||||
void kill_icon();
|
||||
|
||||
/// lyx action number
|
||||
int action;
|
||||
/// icon for this item
|
||||
FL_OBJECT * icon;
|
||||
};
|
||||
|
||||
/// typedef to simplify things
|
||||
typedef std::vector<toolbarItem> ToolbarList;
|
||||
|
||||
/// The list containing all the buttons
|
||||
ToolbarList toollist;
|
||||
///
|
||||
XFormsView * owner;
|
||||
///
|
||||
ToolbarList toollist_;
|
||||
/// owning view
|
||||
XFormsView * owner_;
|
||||
/// tooltips manager
|
||||
Tooltips * tooltip_;
|
||||
///
|
||||
Combox * combox;
|
||||
/// Starting position
|
||||
int sxpos;
|
||||
///
|
||||
int sypos;
|
||||
///
|
||||
/// layout combo
|
||||
Combox * combox_;
|
||||
/// x position of end of toolbar
|
||||
int xpos;
|
||||
///
|
||||
/// y position of end of toolbar
|
||||
int ypos;
|
||||
///
|
||||
bool cleaned;
|
||||
|
||||
/// removes all toolbar buttons from the toolbar.
|
||||
void clean();
|
||||
|
||||
/// more...
|
||||
void reset();
|
||||
|
||||
/// more...
|
||||
void lightReset();
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif // TOOLBAR_PIMPL_H
|
||||
|
@ -148,7 +148,6 @@ void XFormsView::create_form_form_main(Dialogs & dia, int width, int height)
|
||||
|
||||
toolbar_.reset(new Toolbar(this, dia,
|
||||
air, 30 + air + bw, toolbardefaults));
|
||||
toolbar_->set(true);
|
||||
|
||||
int const ywork = 60 + 2 * air + bw;
|
||||
int const workheight = height - ywork - (25 + 2 * air);
|
||||
|
@ -1329,24 +1329,6 @@ void LyXFunc::dispatch(kb_action action, string argument, bool verbose)
|
||||
}
|
||||
break;
|
||||
|
||||
case LFUN_ADD_TO_TOOLBAR:
|
||||
{
|
||||
if (lyxerr.debugging(Debug::GUI)) {
|
||||
lyxerr << "LFUN_ADD_TO_TOOLBAR:"
|
||||
"argument = `" << argument << '\'' << endl;
|
||||
}
|
||||
string tmp(argument);
|
||||
//lyxerr <<string("Argument: ") + argument);
|
||||
//lyxerr <<string("Tmp : ") + tmp);
|
||||
if (tmp.empty()) {
|
||||
setErrorMessage(N_("Usage: toolbar-add-to <LyX command>"));
|
||||
} else {
|
||||
owner->getToolbar()->add(argument, false);
|
||||
owner->getToolbar()->set();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// --- insert characters ----------------------------------------
|
||||
|
||||
// --- Mathed stuff. If we are here, there is no locked inset yet.
|
||||
|
Loading…
Reference in New Issue
Block a user