| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 | /* * EventDispatcher.cpp, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */#include "StdInc.h"#include "EventDispatcher.h"#include "EventsReceiver.h"#include "FramerateManager.h"#include "CGuiHandler.h"#include "MouseButton.h"#include "../../lib/Point.h"template<typename Functor>void EventDispatcher::processLists(ui16 activityFlag, const Functor & cb){	auto processList = [&](ui16 mask, EventReceiversList & lst)	{		if(mask & activityFlag)			cb(lst);	};	processList(AEventsReceiver::LCLICK, lclickable);	processList(AEventsReceiver::RCLICK, rclickable);	processList(AEventsReceiver::MCLICK, mclickable);	processList(AEventsReceiver::HOVER, hoverable);	processList(AEventsReceiver::MOVE, motioninterested);	processList(AEventsReceiver::KEYBOARD, keyinterested);	processList(AEventsReceiver::TIME, timeinterested);	processList(AEventsReceiver::WHEEL, wheelInterested);	processList(AEventsReceiver::DOUBLECLICK, doubleClickInterested);	processList(AEventsReceiver::TEXTINPUT, textInterested);}void EventDispatcher::activateElement(AEventsReceiver * elem, ui16 activityFlag){	processLists(activityFlag,[&](EventReceiversList & lst){		lst.push_front(elem);	});	elem->activeState |= activityFlag;}void EventDispatcher::deactivateElement(AEventsReceiver * elem, ui16 activityFlag){	processLists(activityFlag,[&](EventReceiversList & lst){		auto hlp = std::find(lst.begin(),lst.end(),elem);		assert(hlp != lst.end());		lst.erase(hlp);	});	elem->activeState &= ~activityFlag;}void EventDispatcher::dispatchTimer(uint32_t msPassed){	EventReceiversList hlp = timeinterested;	for (auto & elem : hlp)	{		if(!vstd::contains(timeinterested,elem)) continue;		(elem)->tick(msPassed);	}}void EventDispatcher::dispatchShortcutPressed(const std::vector<EShortcut> & shortcutsVector){	bool keysCaptured = false;	for(auto & i : keyinterested)		for(EShortcut shortcut : shortcutsVector)			if(i->captureThisKey(shortcut))				keysCaptured = true;	EventReceiversList miCopy = keyinterested;	for(auto & i : miCopy)	{		for(EShortcut shortcut : shortcutsVector)			if(vstd::contains(keyinterested, i) && (!keysCaptured || i->captureThisKey(shortcut)))			{				i->keyPressed(shortcut);				if (keysCaptured)					return;			}	}}void EventDispatcher::dispatchShortcutReleased(const std::vector<EShortcut> & shortcutsVector){	bool keysCaptured = false;	for(auto & i : keyinterested)		for(EShortcut shortcut : shortcutsVector)			if(i->captureThisKey(shortcut))				keysCaptured = true;	EventReceiversList miCopy = keyinterested;	for(auto & i : miCopy)	{		for(EShortcut shortcut : shortcutsVector)			if(vstd::contains(keyinterested, i) && (!keysCaptured || i->captureThisKey(shortcut)))			{				i->keyReleased(shortcut);				if (keysCaptured)					return;			}	}}EventDispatcher::EventReceiversList & EventDispatcher::getListForMouseButton(MouseButton button){	switch (button)	{		case MouseButton::LEFT:			return lclickable;		case MouseButton::RIGHT:			return rclickable;		case MouseButton::MIDDLE:			return mclickable;	}	throw std::runtime_error("Invalid mouse button in getListForMouseButton");}void EventDispatcher::dispatchMouseDoubleClick(const Point & position){	bool doubleClicked = false;	auto hlp = doubleClickInterested;	for(auto & i : hlp)	{		if(!vstd::contains(doubleClickInterested, i))			continue;		if(i->isInside(position))		{			i->onDoubleClick();			doubleClicked = true;		}	}	if(!doubleClicked)		dispatchMouseButtonPressed(MouseButton::LEFT, position);}void EventDispatcher::dispatchMouseButtonPressed(const MouseButton & button, const Point & position){	handleMouseButtonClick(getListForMouseButton(button), button, true);}void EventDispatcher::dispatchMouseButtonReleased(const MouseButton & button, const Point & position){	handleMouseButtonClick(getListForMouseButton(button), button, false);}void EventDispatcher::handleMouseButtonClick(EventReceiversList & interestedObjs, MouseButton btn, bool isPressed){	auto hlp = interestedObjs;	for(auto & i : hlp)	{		if(!vstd::contains(interestedObjs, i))			continue;		auto prev = i->isMouseButtonPressed(btn);		if(!isPressed)			i->currentMouseState[btn] = isPressed;		if(i->isInside(GH.getCursorPosition()))		{			if(isPressed)				i->currentMouseState[btn] = isPressed;			i->click(btn, isPressed, prev);		}		else if(!isPressed)			i->click(btn, boost::logic::indeterminate, prev);	}}void EventDispatcher::dispatchMouseScrolled(const Point & distance, const Point & position){	EventReceiversList hlp = wheelInterested;	for(auto & i : hlp)	{		if(!vstd::contains(wheelInterested,i))			continue;		i->wheelScrolled(distance.y < 0, i->isInside(position));	}}void EventDispatcher::dispatchTextInput(const std::string & text){	for(auto it : textInterested)	{		it->textInputed(text);	}}void EventDispatcher::dispatchTextEditing(const std::string & text){	for(auto it : textInterested)	{		it->textEdited(text);	}}void EventDispatcher::dispatchMouseMoved(const Point & position){	//sending active, hovered hoverable objects hover() call	EventReceiversList hlp;	auto hoverableCopy = hoverable;	for(auto & elem : hoverableCopy)	{		if(elem->isInside(GH.getCursorPosition()))		{			if (!(elem)->isHovered())				hlp.push_back((elem));		}		else if ((elem)->isHovered())		{			(elem)->hover(false);			(elem)->hoveredState = false;		}	}	for(auto & elem : hlp)	{		elem->hover(true);		elem->hoveredState = true;	}	//sending active, MotionInterested objects mouseMoved() call	EventReceiversList miCopy = motioninterested;	for(auto & elem : miCopy)	{		if(elem->strongInterestState || elem->isInside(position)) //checking bounds including border fixes bug #2476		{			(elem)->mouseMoved(position);		}	}}
 |