mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 01:05:48 +01:00 
			
		
		
		
	Replace all uses of core::list with std::list (#12313)
This commit is contained in:
		@@ -54,25 +54,10 @@ GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env,
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GUIConfirmRegistration::~GUIConfirmRegistration()
 | 
			
		||||
{
 | 
			
		||||
	removeChildren();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIConfirmRegistration::removeChildren()
 | 
			
		||||
{
 | 
			
		||||
	const core::list<gui::IGUIElement *> &children = getChildren();
 | 
			
		||||
	core::list<gui::IGUIElement *> children_copy;
 | 
			
		||||
	for (gui::IGUIElement *i : children)
 | 
			
		||||
		children_copy.push_back(i);
 | 
			
		||||
	for (gui::IGUIElement *i : children_copy)
 | 
			
		||||
		i->remove();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIConfirmRegistration::regenerateGui(v2u32 screensize)
 | 
			
		||||
{
 | 
			
		||||
	acceptInput();
 | 
			
		||||
	removeChildren();
 | 
			
		||||
	removeAllChildren();
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		Calculate new sizes and positions
 | 
			
		||||
 
 | 
			
		||||
@@ -34,9 +34,6 @@ public:
 | 
			
		||||
			s32 id, IMenuManager *menumgr, Client *client,
 | 
			
		||||
			const std::string &playername, const std::string &password,
 | 
			
		||||
			bool *aborted, ISimpleTextureSource *tsrc);
 | 
			
		||||
	~GUIConfirmRegistration();
 | 
			
		||||
 | 
			
		||||
	void removeChildren();
 | 
			
		||||
	/*
 | 
			
		||||
		Remove and re-add (or reposition) stuff
 | 
			
		||||
	*/
 | 
			
		||||
 
 | 
			
		||||
@@ -127,7 +127,8 @@ GUIFormSpecMenu::GUIFormSpecMenu(JoystickController *joystick,
 | 
			
		||||
 | 
			
		||||
GUIFormSpecMenu::~GUIFormSpecMenu()
 | 
			
		||||
{
 | 
			
		||||
	removeChildren();
 | 
			
		||||
	removeAllChildren();
 | 
			
		||||
	removeTooltip();
 | 
			
		||||
 | 
			
		||||
	for (auto &table_it : m_tables)
 | 
			
		||||
		table_it.second->drop();
 | 
			
		||||
@@ -174,14 +175,8 @@ void GUIFormSpecMenu::create(GUIFormSpecMenu *&cur_formspec, Client *client,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIFormSpecMenu::removeChildren()
 | 
			
		||||
void GUIFormSpecMenu::removeTooltip()
 | 
			
		||||
{
 | 
			
		||||
	const core::list<gui::IGUIElement*> &children = getChildren();
 | 
			
		||||
 | 
			
		||||
	while (!children.empty()) {
 | 
			
		||||
		(*children.getLast())->remove();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (m_tooltip_element) {
 | 
			
		||||
		m_tooltip_element->remove();
 | 
			
		||||
		m_tooltip_element->drop();
 | 
			
		||||
@@ -199,16 +194,7 @@ void GUIFormSpecMenu::setInitialFocus()
 | 
			
		||||
	// 5. first focusable (not statictext, not tabheader)
 | 
			
		||||
	// 6. first child element
 | 
			
		||||
 | 
			
		||||
	core::list<gui::IGUIElement*> children = getChildren();
 | 
			
		||||
 | 
			
		||||
	// in case "children" contains any NULL elements, remove them
 | 
			
		||||
	for (core::list<gui::IGUIElement*>::Iterator it = children.begin();
 | 
			
		||||
			it != children.end();) {
 | 
			
		||||
		if (*it)
 | 
			
		||||
			++it;
 | 
			
		||||
		else
 | 
			
		||||
			it = children.erase(it);
 | 
			
		||||
	}
 | 
			
		||||
	const auto& children = getChildren();
 | 
			
		||||
 | 
			
		||||
	// 1. first empty editbox
 | 
			
		||||
	for (gui::IGUIElement *it : children) {
 | 
			
		||||
@@ -236,8 +222,7 @@ void GUIFormSpecMenu::setInitialFocus()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 4. last button
 | 
			
		||||
	for (core::list<gui::IGUIElement*>::Iterator it = children.getLast();
 | 
			
		||||
			it != children.end(); --it) {
 | 
			
		||||
	for (auto it = children.rbegin(); it != children.rend(); ++it) {
 | 
			
		||||
		if ((*it)->getType() == gui::EGUIET_BUTTON) {
 | 
			
		||||
			Environment->setFocus(*it);
 | 
			
		||||
			return;
 | 
			
		||||
@@ -257,7 +242,7 @@ void GUIFormSpecMenu::setInitialFocus()
 | 
			
		||||
	if (children.empty())
 | 
			
		||||
		Environment->setFocus(this);
 | 
			
		||||
	else
 | 
			
		||||
		Environment->setFocus(*(children.begin()));
 | 
			
		||||
		Environment->setFocus(children.front());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GUITable* GUIFormSpecMenu::getTable(const std::string &tablename)
 | 
			
		||||
@@ -3045,7 +3030,8 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Remove children
 | 
			
		||||
	removeChildren();
 | 
			
		||||
	removeAllChildren();
 | 
			
		||||
	removeTooltip();
 | 
			
		||||
 | 
			
		||||
	for (auto &table_it : m_tables)
 | 
			
		||||
		table_it.second->drop();
 | 
			
		||||
@@ -3341,7 +3327,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
 | 
			
		||||
	pos_offset = v2f32();
 | 
			
		||||
 | 
			
		||||
	// used for formspec versions < 3
 | 
			
		||||
	core::list<IGUIElement *>::Iterator legacy_sort_start = Children.getLast();
 | 
			
		||||
	std::list<IGUIElement *>::iterator legacy_sort_start = std::prev(Children.end()); // last element
 | 
			
		||||
 | 
			
		||||
	if (enable_prepends) {
 | 
			
		||||
		// Backup the coordinates so that prepends can use the coordinates of choice.
 | 
			
		||||
@@ -3356,7 +3342,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
 | 
			
		||||
		// legacy sorting for formspec versions < 3
 | 
			
		||||
		if (m_formspec_version >= 3)
 | 
			
		||||
			// prepends do not need to be reordered
 | 
			
		||||
			legacy_sort_start = Children.getLast();
 | 
			
		||||
			legacy_sort_start = std::prev(Children.end()); // last element
 | 
			
		||||
		else if (version_backup >= 3)
 | 
			
		||||
			// only prepends elements have to be reordered
 | 
			
		||||
			legacySortElements(legacy_sort_start);
 | 
			
		||||
@@ -3437,7 +3423,7 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator from)
 | 
			
		||||
void GUIFormSpecMenu::legacySortElements(std::list<IGUIElement *>::iterator from)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
		Draw order for formspec_version <= 2:
 | 
			
		||||
@@ -3454,17 +3440,16 @@ void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator fro
 | 
			
		||||
	if (from == Children.end())
 | 
			
		||||
		from = Children.begin();
 | 
			
		||||
	else
 | 
			
		||||
		from++;
 | 
			
		||||
		++from;
 | 
			
		||||
 | 
			
		||||
	core::list<IGUIElement *>::Iterator to = Children.end();
 | 
			
		||||
	std::list<IGUIElement *>::iterator to = Children.end();
 | 
			
		||||
	// 1: Copy into a sortable container
 | 
			
		||||
	std::vector<IGUIElement *> elements;
 | 
			
		||||
	for (auto it = from; it != to; ++it)
 | 
			
		||||
		elements.emplace_back(*it);
 | 
			
		||||
	std::vector<IGUIElement *> elements(from, to);
 | 
			
		||||
 | 
			
		||||
	// 2: Sort the container
 | 
			
		||||
	std::stable_sort(elements.begin(), elements.end(),
 | 
			
		||||
			[this] (const IGUIElement *a, const IGUIElement *b) -> bool {
 | 
			
		||||
		// TODO: getSpecByID is a linear search. It should made O(1), or cached here.
 | 
			
		||||
		const FieldSpec *spec_a = getSpecByID(a->getID());
 | 
			
		||||
		const FieldSpec *spec_b = getSpecByID(b->getID());
 | 
			
		||||
		return spec_a && spec_b &&
 | 
			
		||||
@@ -3472,10 +3457,7 @@ void GUIFormSpecMenu::legacySortElements(core::list<IGUIElement *>::Iterator fro
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	// 3: Re-assign the pointers
 | 
			
		||||
	for (auto e : elements) {
 | 
			
		||||
		*from = e;
 | 
			
		||||
		from++;
 | 
			
		||||
	}
 | 
			
		||||
	reorderChildren(from, to, elements);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __ANDROID__
 | 
			
		||||
@@ -3600,12 +3582,11 @@ void GUIFormSpecMenu::drawMenu()
 | 
			
		||||
	/*
 | 
			
		||||
		This is where all the drawing happens.
 | 
			
		||||
	*/
 | 
			
		||||
	core::list<IGUIElement*>::Iterator it = Children.begin();
 | 
			
		||||
	for (; it != Children.end(); ++it)
 | 
			
		||||
		if ((*it)->isNotClipped() ||
 | 
			
		||||
	for (auto child : Children)
 | 
			
		||||
		if (child->isNotClipped() ||
 | 
			
		||||
				AbsoluteClippingRect.isRectCollided(
 | 
			
		||||
						(*it)->getAbsolutePosition()))
 | 
			
		||||
			(*it)->draw();
 | 
			
		||||
						child->getAbsolutePosition()))
 | 
			
		||||
			child->draw();
 | 
			
		||||
 | 
			
		||||
	for (gui::IGUIElement *e : m_clickthrough_elements)
 | 
			
		||||
		e->setVisible(false);
 | 
			
		||||
 
 | 
			
		||||
@@ -212,7 +212,7 @@ public:
 | 
			
		||||
		m_lockscreensize = basescreensize;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void removeChildren();
 | 
			
		||||
	void removeTooltip();
 | 
			
		||||
	void setInitialFocus();
 | 
			
		||||
 | 
			
		||||
	void setFocus(const std::string &elementname)
 | 
			
		||||
@@ -467,7 +467,7 @@ private:
 | 
			
		||||
	 * types were drawn before others.
 | 
			
		||||
	 * This function sorts the elements in the old order for backwards compatibility.
 | 
			
		||||
	 */
 | 
			
		||||
	void legacySortElements(core::list<IGUIElement *>::Iterator from);
 | 
			
		||||
	void legacySortElements(std::list<IGUIElement *>::iterator from);
 | 
			
		||||
 | 
			
		||||
	int m_btn_height;
 | 
			
		||||
	gui::IGUIFont *m_font = nullptr;
 | 
			
		||||
 
 | 
			
		||||
@@ -93,7 +93,8 @@ GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env,
 | 
			
		||||
 | 
			
		||||
GUIKeyChangeMenu::~GUIKeyChangeMenu()
 | 
			
		||||
{
 | 
			
		||||
	removeChildren();
 | 
			
		||||
	removeAllChildren();
 | 
			
		||||
	key_used_text = nullptr;
 | 
			
		||||
 | 
			
		||||
	for (key_setting *ks : key_settings) {
 | 
			
		||||
		delete[] ks->button_name;
 | 
			
		||||
@@ -102,23 +103,10 @@ GUIKeyChangeMenu::~GUIKeyChangeMenu()
 | 
			
		||||
	key_settings.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIKeyChangeMenu::removeChildren()
 | 
			
		||||
{
 | 
			
		||||
	const core::list<gui::IGUIElement*> &children = getChildren();
 | 
			
		||||
	core::list<gui::IGUIElement*> children_copy;
 | 
			
		||||
	for (gui::IGUIElement*i : children) {
 | 
			
		||||
		children_copy.push_back(i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (gui::IGUIElement *i : children_copy) {
 | 
			
		||||
		i->remove();
 | 
			
		||||
	}
 | 
			
		||||
	key_used_text = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIKeyChangeMenu::regenerateGui(v2u32 screensize)
 | 
			
		||||
{
 | 
			
		||||
	removeChildren();
 | 
			
		||||
	removeAllChildren();
 | 
			
		||||
	key_used_text = nullptr;
 | 
			
		||||
 | 
			
		||||
	const float s = m_gui_scale;
 | 
			
		||||
	DesiredRect = core::rect<s32>(
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,6 @@ public:
 | 
			
		||||
			IMenuManager *menumgr, ISimpleTextureSource *tsrc);
 | 
			
		||||
	~GUIKeyChangeMenu();
 | 
			
		||||
 | 
			
		||||
	void removeChildren();
 | 
			
		||||
	/*
 | 
			
		||||
	 Remove and re-add (or reposition) stuff
 | 
			
		||||
	 */
 | 
			
		||||
 
 | 
			
		||||
@@ -51,23 +51,6 @@ GUIPasswordChange::GUIPasswordChange(gui::IGUIEnvironment* env,
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GUIPasswordChange::~GUIPasswordChange()
 | 
			
		||||
{
 | 
			
		||||
	removeChildren();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIPasswordChange::removeChildren()
 | 
			
		||||
{
 | 
			
		||||
	const core::list<gui::IGUIElement *> &children = getChildren();
 | 
			
		||||
	core::list<gui::IGUIElement *> children_copy;
 | 
			
		||||
	for (gui::IGUIElement *i : children) {
 | 
			
		||||
		children_copy.push_back(i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (gui::IGUIElement *i : children_copy) {
 | 
			
		||||
		i->remove();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
void GUIPasswordChange::regenerateGui(v2u32 screensize)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
@@ -78,7 +61,7 @@ void GUIPasswordChange::regenerateGui(v2u32 screensize)
 | 
			
		||||
	/*
 | 
			
		||||
		Remove stuff
 | 
			
		||||
	*/
 | 
			
		||||
	removeChildren();
 | 
			
		||||
	removeAllChildren();
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		Calculate new sizes and positions
 | 
			
		||||
 
 | 
			
		||||
@@ -31,9 +31,7 @@ public:
 | 
			
		||||
	GUIPasswordChange(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id,
 | 
			
		||||
			IMenuManager *menumgr, Client *client,
 | 
			
		||||
			ISimpleTextureSource *tsrc);
 | 
			
		||||
	~GUIPasswordChange();
 | 
			
		||||
 | 
			
		||||
	void removeChildren();
 | 
			
		||||
	/*
 | 
			
		||||
		Remove and re-add (or reposition) stuff
 | 
			
		||||
	*/
 | 
			
		||||
 
 | 
			
		||||
@@ -32,13 +32,12 @@ GUIFileSelectMenu::GUIFileSelectMenu(gui::IGUIEnvironment* env,
 | 
			
		||||
 | 
			
		||||
GUIFileSelectMenu::~GUIFileSelectMenu()
 | 
			
		||||
{
 | 
			
		||||
	removeChildren();
 | 
			
		||||
	setlocale(LC_NUMERIC, "C");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIFileSelectMenu::regenerateGui(v2u32 screensize)
 | 
			
		||||
{
 | 
			
		||||
	removeChildren();
 | 
			
		||||
	removeAllChildren();
 | 
			
		||||
	m_fileOpenDialog = 0;
 | 
			
		||||
 | 
			
		||||
	core::dimension2du size(600 * m_gui_scale, 400 * m_gui_scale);
 | 
			
		||||
 
 | 
			
		||||
@@ -59,12 +59,11 @@ bool GUIScrollContainer::OnEvent(const SEvent &event)
 | 
			
		||||
void GUIScrollContainer::draw()
 | 
			
		||||
{
 | 
			
		||||
	if (isVisible()) {
 | 
			
		||||
		core::list<IGUIElement *>::Iterator it = Children.begin();
 | 
			
		||||
		for (; it != Children.end(); ++it)
 | 
			
		||||
			if ((*it)->isNotClipped() ||
 | 
			
		||||
		for (auto child : Children)
 | 
			
		||||
			if (child->isNotClipped() ||
 | 
			
		||||
					AbsoluteClippingRect.isRectCollided(
 | 
			
		||||
							(*it)->getAbsolutePosition()))
 | 
			
		||||
				(*it)->draw();
 | 
			
		||||
							child->getAbsolutePosition()))
 | 
			
		||||
				child->draw();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -45,32 +45,12 @@ GUIVolumeChange::GUIVolumeChange(gui::IGUIEnvironment* env,
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GUIVolumeChange::~GUIVolumeChange()
 | 
			
		||||
{
 | 
			
		||||
	removeChildren();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIVolumeChange::removeChildren()
 | 
			
		||||
{
 | 
			
		||||
	if (gui::IGUIElement *e = getElementFromId(ID_soundText))
 | 
			
		||||
		e->remove();
 | 
			
		||||
 | 
			
		||||
	if (gui::IGUIElement *e = getElementFromId(ID_soundExitButton))
 | 
			
		||||
		e->remove();
 | 
			
		||||
 | 
			
		||||
	if (gui::IGUIElement *e = getElementFromId(ID_soundSlider))
 | 
			
		||||
		e->remove();
 | 
			
		||||
 | 
			
		||||
	if (gui::IGUIElement *e = getElementFromId(ID_soundMuteButton))
 | 
			
		||||
		e->remove();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIVolumeChange::regenerateGui(v2u32 screensize)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
		Remove stuff
 | 
			
		||||
	*/
 | 
			
		||||
	removeChildren();
 | 
			
		||||
	removeAllChildren();
 | 
			
		||||
	/*
 | 
			
		||||
		Calculate new sizes and positions
 | 
			
		||||
	*/
 | 
			
		||||
 
 | 
			
		||||
@@ -31,9 +31,6 @@ public:
 | 
			
		||||
	GUIVolumeChange(gui::IGUIEnvironment* env,
 | 
			
		||||
			gui::IGUIElement* parent, s32 id,
 | 
			
		||||
			IMenuManager *menumgr, ISimpleTextureSource *tsrc);
 | 
			
		||||
	~GUIVolumeChange();
 | 
			
		||||
 | 
			
		||||
	void removeChildren();
 | 
			
		||||
	/*
 | 
			
		||||
		Remove and re-add (or reposition) stuff
 | 
			
		||||
	*/
 | 
			
		||||
 
 | 
			
		||||
@@ -64,10 +64,6 @@ public:
 | 
			
		||||
		// Remove all entries if there are duplicates
 | 
			
		||||
		m_stack.remove(menu);
 | 
			
		||||
 | 
			
		||||
		/*core::list<GUIModalMenu*>::Iterator i = m_stack.getLast();
 | 
			
		||||
		assert(*i == menu);
 | 
			
		||||
		m_stack.erase(i);*/
 | 
			
		||||
 | 
			
		||||
		if(!m_stack.empty())
 | 
			
		||||
			m_stack.back()->setVisible(true);
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -108,19 +108,6 @@ void GUIModalMenu::quitMenu()
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void GUIModalMenu::removeChildren()
 | 
			
		||||
{
 | 
			
		||||
	const core::list<gui::IGUIElement *> &children = getChildren();
 | 
			
		||||
	core::list<gui::IGUIElement *> children_copy;
 | 
			
		||||
	for (gui::IGUIElement *i : children) {
 | 
			
		||||
		children_copy.push_back(i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (gui::IGUIElement *i : children_copy) {
 | 
			
		||||
		i->remove();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// clang-format off
 | 
			
		||||
bool GUIModalMenu::DoubleClickDetection(const SEvent &event)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,6 @@ public:
 | 
			
		||||
	bool canTakeFocus(gui::IGUIElement *e);
 | 
			
		||||
	void draw();
 | 
			
		||||
	void quitMenu();
 | 
			
		||||
	void removeChildren();
 | 
			
		||||
 | 
			
		||||
	virtual void regenerateGui(v2u32 screensize) = 0;
 | 
			
		||||
	virtual void drawMenu() = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -360,7 +360,7 @@ struct TestMapBlock: public TestBase
 | 
			
		||||
 | 
			
		||||
		MapNode node;
 | 
			
		||||
		bool position_valid;
 | 
			
		||||
		core::list<v3s16> validity_exceptions;
 | 
			
		||||
		std::list<v3s16> validity_exceptions;
 | 
			
		||||
 | 
			
		||||
		TC()
 | 
			
		||||
		{
 | 
			
		||||
@@ -371,7 +371,7 @@ struct TestMapBlock: public TestBase
 | 
			
		||||
		{
 | 
			
		||||
			//return position_valid ^ (p==position_valid_exception);
 | 
			
		||||
			bool exception = false;
 | 
			
		||||
			for(core::list<v3s16>::Iterator i=validity_exceptions.begin();
 | 
			
		||||
			for(std::list<v3s16>::iterator i=validity_exceptions.begin();
 | 
			
		||||
					i != validity_exceptions.end(); i++)
 | 
			
		||||
			{
 | 
			
		||||
				if(p == *i)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user