Browse Source

Extracted event management from GuiHandler and CIntObject

Ivan Savenko 2 years ago
parent
commit
1f513fd280

+ 2 - 0
client/CMakeLists.txt

@@ -30,6 +30,7 @@ set(client_SRCS
 	gui/CGuiHandler.cpp
 	gui/CIntObject.cpp
 	gui/CursorHandler.cpp
+	gui/InterfaceEventDispatcher.cpp
 	gui/InterfaceObjectConfigurable.cpp
 	gui/FramerateManager.cpp
 	gui/NotificationHandler.cpp
@@ -164,6 +165,7 @@ set(client_HEADERS
 	gui/CIntObject.h
 	gui/CursorHandler.h
 	gui/InterfaceObjectConfigurable.h
+	gui/InterfaceEventDispatcher.h
 	gui/FramerateManager.h
 	gui/MouseButton.h
 	gui/NotificationHandler.h

+ 1 - 1
client/CPlayerInterface.cpp

@@ -1872,7 +1872,7 @@ bool CPlayerInterface::capturedAllEvents()
 		return true;
 	}
 
-	bool needToLockAdventureMap = adventureInt && adventureInt->active && CGI->mh->hasOngoingAnimations();
+	bool needToLockAdventureMap = adventureInt && adventureInt->isActive() && CGI->mh->hasOngoingAnimations();
 
 	if (ignoreEvents || needToLockAdventureMap || isAutoFightOn)
 	{

+ 2 - 2
client/ClientCommandManager.cpp

@@ -493,9 +493,9 @@ void ClientCommandManager::printInfoAboutInterfaceObject(const CIntObject *obj,
 	sbuffer << std::string(level, '\t');
 
 	sbuffer << typeid(*obj).name() << " *** ";
-	if (obj->active)
+	if (obj->isActive())
 	{
-#define PRINT(check, text) if (obj->active & CIntObject::check) sbuffer << text
+#define PRINT(check, text) if (obj->isActive(CIntObject::check)) sbuffer << text
 		PRINT(LCLICK, 'L');
 		PRINT(RCLICK, 'R');
 		PRINT(HOVER, 'H');

+ 8 - 8
client/adventureMap/AdventureMapInterface.cpp

@@ -52,7 +52,7 @@ AdventureMapInterface::AdventureMapInterface():
 	pos.x = pos.y = 0;
 	pos.w = GH.screenDimensions().x;
 	pos.h = GH.screenDimensions().y;
-	strongInterest = true; // handle all mouse move events to prevent dead mouse move space in fullscreen mode
+	setMoveEventStrongInterest(true); // handle all mouse move events to prevent dead mouse move space in fullscreen mode
 
 	shortcuts = std::make_shared<AdventureMapShortcuts>(*this);
 
@@ -179,7 +179,7 @@ void AdventureMapInterface::handleMapScrollingUpdate(uint32_t timePassed)
 	Point scrollDelta = scrollDirection * scrollDistance;
 
 	bool cursorInScrollArea = scrollDelta != Point(0,0);
-	bool scrollingActive = cursorInScrollArea && active && shortcuts->optionSidePanelActive() && !scrollingWasBlocked;
+	bool scrollingActive = cursorInScrollArea && isActive() && shortcuts->optionSidePanelActive() && !scrollingWasBlocked;
 	bool scrollingBlocked = GH.isKeyboardCtrlDown();
 
 	if (!scrollingWasActive && scrollingBlocked)
@@ -323,19 +323,19 @@ void AdventureMapInterface::setState(EAdventureState state)
 
 void AdventureMapInterface::adjustActiveness()
 {
-	bool widgetMustBeActive = active && shortcuts->optionSidePanelActive();
-	bool mapViewMustBeActive = active && (shortcuts->optionMapViewActive());
+	bool widgetMustBeActive = isActive() && shortcuts->optionSidePanelActive();
+	bool mapViewMustBeActive = isActive() && (shortcuts->optionMapViewActive());
 
-	if (widgetMustBeActive && !widget->active)
+	if (widgetMustBeActive && !widget->isActive())
 		widget->activate();
 
-	if (!widgetMustBeActive && widget->active)
+	if (!widgetMustBeActive && widget->isActive())
 		widget->deactivate();
 
-	if (mapViewMustBeActive && !widget->getMapView()->active)
+	if (mapViewMustBeActive && !widget->getMapView()->isActive())
 		widget->getMapView()->activate();
 
-	if (!mapViewMustBeActive && widget->getMapView()->active)
+	if (!mapViewMustBeActive && widget->getMapView()->isActive())
 		widget->getMapView()->deactivate();
 }
 

+ 1 - 1
client/adventureMap/CInGameConsole.cpp

@@ -211,7 +211,7 @@ void CInGameConsole::textEdited(const std::string & inputtedText)
 
 void CInGameConsole::startEnteringText()
 {
-	if (!active)
+	if (!isActive())
 		return;
 
 	if (captureAllKeys)

+ 1 - 2
client/adventureMap/CInfoBar.cpp

@@ -316,8 +316,7 @@ CInfoBar::CInfoBar(const Point & position): CInfoBar(Rect(position.x, position.y
 
 void CInfoBar::setTimer(uint32_t msToTrigger)
 {
-	if (!(active & TIME))
-		addUsedEvents(TIME);
+	addUsedEvents(TIME);
 	timerCounter = msToTrigger;
 }
 

+ 2 - 2
client/adventureMap/CMinimap.cpp

@@ -131,7 +131,7 @@ void CMinimap::moveAdvMapSelection()
 	int3 newLocation = pixelToTile(GH.getCursorPosition() - pos.topLeft());
 	adventureInt->centerOnTile(newLocation);
 
-	if (!(adventureInt->active & GENERAL))
+	if (!(adventureInt->isActive() & GENERAL))
 		GH.windows().totalRedraw(); //redraw this as well as inactive adventure map
 	else
 		redraw();//redraw only this
@@ -159,7 +159,7 @@ void CMinimap::hover(bool on)
 
 void CMinimap::mouseMoved(const Point & cursorPosition)
 {
-	if(mouseState(MouseButton::LEFT))
+	if(isMouseButtonPressed(MouseButton::LEFT))
 		moveAdvMapSelection();
 }
 

+ 1 - 1
client/battle/BattleFieldController.cpp

@@ -39,7 +39,7 @@ BattleFieldController::BattleFieldController(BattleInterface & owner):
 	owner(owner)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
-	strongInterest = true;
+	setMoveEventStrongInterest(true);
 
 	//preparing cells and hexes
 	cellBorder = IImage::createFromFile("CCELLGRD.BMP", EImageBlitMode::COLORKEY);

+ 1 - 1
client/battle/BattleInterfaceClasses.cpp

@@ -692,7 +692,7 @@ std::optional<uint32_t> StackQueue::getHoveredUnitIdIfAny() const
 {
 	for(const auto & stackBox : stackBoxes)
 	{
-		if(stackBox->hovered || stackBox->mouseState(MouseButton::RIGHT))
+		if(stackBox->isHovered() || stackBox->isMouseButtonPressed(MouseButton::RIGHT))
 		{
 			return stackBox->getBoundUnitID();
 		}

+ 29 - 188
client/gui/CGuiHandler.cpp

@@ -16,6 +16,7 @@
 #include "ShortcutHandler.h"
 #include "FramerateManager.h"
 #include "WindowHandler.h"
+#include "InterfaceEventDispatcher.h"
 
 #include "../CGameInfo.h"
 #include "../render/Colors.h"
@@ -77,29 +78,9 @@ SSetCaptureState::~SSetCaptureState()
 	GH.defActionsDef = prevActions;
 }
 
-static inline void
-processList(const ui16 mask, const ui16 flag, std::list<CIntObject*> *lst, std::function<void (std::list<CIntObject*> *)> cb)
-{
-	if (mask & flag)
-		cb(lst);
-}
-
-void CGuiHandler::processLists(const ui16 activityFlag, std::function<void (std::list<CIntObject*> *)> cb)
-{
-	processList(CIntObject::LCLICK,activityFlag,&lclickable,cb);
-	processList(CIntObject::RCLICK,activityFlag,&rclickable,cb);
-	processList(CIntObject::MCLICK,activityFlag,&mclickable,cb);
-	processList(CIntObject::HOVER,activityFlag,&hoverable,cb);
-	processList(CIntObject::MOVE,activityFlag,&motioninterested,cb);
-	processList(CIntObject::KEYBOARD,activityFlag,&keyinterested,cb);
-	processList(CIntObject::TIME,activityFlag,&timeinterested,cb);
-	processList(CIntObject::WHEEL,activityFlag,&wheelInterested,cb);
-	processList(CIntObject::DOUBLECLICK,activityFlag,&doubleClickInterested,cb);
-	processList(CIntObject::TEXTINPUT,activityFlag,&textInterested,cb);
-}
-
 void CGuiHandler::init()
 {
+	eventDispatcherInstance = std::make_unique<InterfaceEventDispatcher>();
 	windowHandlerInstance = std::make_unique<WindowHandler>();
 	screenHandlerInstance = std::make_unique<ScreenHandler>();
 	shortcutsHandlerInstance = std::make_unique<ShortcutHandler>();
@@ -109,33 +90,9 @@ void CGuiHandler::init()
 	pointerSpeedMultiplier = settings["general"]["relativePointerSpeedMultiplier"].Float();
 }
 
-void CGuiHandler::handleElementActivate(CIntObject * elem, ui16 activityFlag)
-{
-	processLists(activityFlag,[&](std::list<CIntObject*> * lst){
-		lst->push_front(elem);
-	});
-	elem->active_m |= activityFlag;
-}
-
-void CGuiHandler::handleElementDeActivate(CIntObject * elem, ui16 activityFlag)
-{
-	processLists(activityFlag,[&](std::list<CIntObject*> * lst){
-		auto hlp = std::find(lst->begin(),lst->end(),elem);
-		assert(hlp != lst->end());
-		lst->erase(hlp);
-	});
-	elem->active_m &= ~activityFlag;
-}
-
 void CGuiHandler::updateTime()
 {
-	int ms = framerateManager().getElapsedMilliseconds();
-	std::list<CIntObject*> hlp = timeinterested;
-	for (auto & elem : hlp)
-	{
-		if(!vstd::contains(timeinterested,elem)) continue;
-		(elem)->tick(ms);
-	}
+	eventDispatcher().updateTime(framerateManager().getElapsedMilliseconds());
 }
 
 void CGuiHandler::handleEvents()
@@ -365,18 +322,7 @@ void CGuiHandler::handleEventKeyDown(SDL_Event & current)
 
 	auto shortcutsVector = shortcutsHandler().translateKeycode(key.keysym.sym);
 
-	bool keysCaptured = false;
-	for(auto i = keyinterested.begin(); i != keyinterested.end() && continueEventHandling; i++)
-		for(EShortcut shortcut : shortcutsVector)
-			if((*i)->captureThisKey(shortcut))
-				keysCaptured = true;
-
-	std::list<CIntObject *> miCopy = keyinterested;
-
-	for(auto i = miCopy.begin(); i != miCopy.end() && continueEventHandling; i++)
-		for(EShortcut shortcut : shortcutsVector)
-			if(vstd::contains(keyinterested, *i) && (!keysCaptured || (*i)->captureThisKey(shortcut)))
-					(**i).keyPressed(shortcut);
+	eventDispatcher().dispatchShortcutPressed(shortcutsVector);
 }
 
 void CGuiHandler::handleEventKeyUp(SDL_Event & current)
@@ -390,24 +336,12 @@ void CGuiHandler::handleEventKeyUp(SDL_Event & current)
 
 	auto shortcutsVector = shortcutsHandler().translateKeycode(key.keysym.sym);
 
-	bool keysCaptured = false;
-
-	for(auto i = keyinterested.begin(); i != keyinterested.end() && continueEventHandling; i++)
-		for(EShortcut shortcut : shortcutsVector)
-			if((*i)->captureThisKey(shortcut))
-				keysCaptured = true;
-
-	std::list<CIntObject *> miCopy = keyinterested;
-
-	for(auto i = miCopy.begin(); i != miCopy.end() && continueEventHandling; i++)
-		for(EShortcut shortcut : shortcutsVector)
-			if(vstd::contains(keyinterested, *i) && (!keysCaptured || (*i)->captureThisKey(shortcut)))
-				(**i).keyReleased(shortcut);
+	eventDispatcher().dispatchShortcutReleased(shortcutsVector);
 }
 
 void CGuiHandler::handleEventMouseMotion(SDL_Event & current)
 {
-	handleMouseMotion(current);
+	eventDispatcher().dispatchMouseMoved(Point(current.motion.x, current.motion.y));
 }
 
 void CGuiHandler::handleEventMouseButtonDown(SDL_Event & current)
@@ -415,68 +349,34 @@ void CGuiHandler::handleEventMouseButtonDown(SDL_Event & current)
 	switch(current.button.button)
 	{
 		case SDL_BUTTON_LEFT:
-		{
-			auto doubleClicked = false;
-			if(lastClick == getCursorPosition() && (SDL_GetTicks() - lastClickTime) < 300)
-			{
-				std::list<CIntObject*> hlp = doubleClickInterested;
-				for(auto i = hlp.begin(); i != hlp.end() && continueEventHandling; i++)
-				{
-					if(!vstd::contains(doubleClickInterested, *i)) continue;
-					if((*i)->pos.isInside(current.motion.x, current.motion.y))
-					{
-						(*i)->onDoubleClick();
-						doubleClicked = true;
-					}
-				}
-
-			}
-
-			lastClick = current.motion;
-			lastClickTime = SDL_GetTicks();
-
-			if(!doubleClicked)
-				handleMouseButtonClick(lclickable, MouseButton::LEFT, true);
+			eventDispatcher().dispatchMouseButtonPressed(MouseButton::LEFT, Point(current.button.x, current.button.y));
 			break;
-		}
 		case SDL_BUTTON_RIGHT:
-			handleMouseButtonClick(rclickable, MouseButton::RIGHT, true);
+			eventDispatcher().dispatchMouseButtonPressed(MouseButton::RIGHT, Point(current.button.x, current.button.y));
 			break;
 		case SDL_BUTTON_MIDDLE:
-			handleMouseButtonClick(mclickable, MouseButton::MIDDLE, true);
-			break;
-		default:
+			eventDispatcher().dispatchMouseButtonPressed(MouseButton::MIDDLE, Point(current.button.x, current.button.y));
 			break;
 	}
 }
 
 void CGuiHandler::handleEventMouseWheel(SDL_Event & current)
 {
-	std::list<CIntObject*> hlp = wheelInterested;
-	for(auto i = hlp.begin(); i != hlp.end() && continueEventHandling; i++)
-	{
-		if(!vstd::contains(wheelInterested,*i)) continue;
-		// SDL doesn't have the proper values for mouse positions on SDL_MOUSEWHEEL, refetch them
-		int x = 0, y = 0;
-		SDL_GetMouseState(&x, &y);
-		(*i)->wheelScrolled(current.wheel.y < 0, (*i)->pos.isInside(x, y));
-	}
+	// SDL doesn't have the proper values for mouse positions on SDL_MOUSEWHEEL, refetch them
+	int x = 0, y = 0;
+	SDL_GetMouseState(&x, &y);
+
+	eventDispatcher().dispatchMouseScrolled(Point(current.wheel.x, current.wheel.y), Point(x, y));
 }
 
 void CGuiHandler::handleEventTextInput(SDL_Event & current)
 {
-	for(auto it : textInterested)
-	{
-		it->textInputed(current.text.text);
-	}
+	eventDispatcher().dispatchTextInput(current.text.text);
 }
 
 void CGuiHandler::handleEventTextEditing(SDL_Event & current)
 {
-	for(auto it : textInterested)
-	{
-		it->textEdited(current.edit.text);
-	}
+	eventDispatcher().dispatchTextEditing(current.text.text);
 }
 
 void CGuiHandler::handleEventMouseButtonUp(SDL_Event & current)
@@ -486,13 +386,13 @@ void CGuiHandler::handleEventMouseButtonUp(SDL_Event & current)
 		switch(current.button.button)
 		{
 			case SDL_BUTTON_LEFT:
-				handleMouseButtonClick(lclickable, MouseButton::LEFT, false);
+				eventDispatcher().dispatchMouseButtonReleased(MouseButton::LEFT, Point(current.button.x, current.button.y));
 				break;
 			case SDL_BUTTON_RIGHT:
-				handleMouseButtonClick(rclickable, MouseButton::RIGHT, false);
+				eventDispatcher().dispatchMouseButtonReleased(MouseButton::RIGHT, Point(current.button.x, current.button.y));
 				break;
 			case SDL_BUTTON_MIDDLE:
-				handleMouseButtonClick(mclickable, MouseButton::MIDDLE, false);
+				eventDispatcher().dispatchMouseButtonReleased(MouseButton::MIDDLE, Point(current.button.x, current.button.y));
 				break;
 		}
 	}
@@ -525,8 +425,9 @@ void CGuiHandler::handleEventFingerDown(SDL_Event & current)
 	else if(fingerCount == 2)
 	{
 		convertTouchToMouse(&current);
-		handleMouseMotion(current);
-		handleMouseButtonClick(rclickable, MouseButton::RIGHT, true);
+
+		eventDispatcher().dispatchMouseMoved(Point(current.button.x, current.button.y));
+		eventDispatcher().dispatchMouseButtonPressed(MouseButton::RIGHT, Point(current.button.x, current.button.y));
 	}
 #endif //VCMI_IOS
 }
@@ -550,78 +451,13 @@ void CGuiHandler::handleEventFingerUp(SDL_Event & current)
 	else if(multifinger)
 	{
 		convertTouchToMouse(&current);
-		handleMouseMotion(current);
-		handleMouseButtonClick(rclickable, MouseButton::RIGHT, false);
+		eventDispatcher().dispatchMouseMoved(Point(current.button.x, current.button.y));
+		eventDispatcher().dispatchMouseButtonReleased(MouseButton::RIGHT, Point(current.button.x, current.button.y));
 		multifinger = fingerCount != 0;
 	}
 #endif //VCMI_IOS
 }
 
-void CGuiHandler::handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed)
-{
-	auto hlp = interestedObjs;
-	for(auto i = hlp.begin(); i != hlp.end() && continueEventHandling; i++)
-	{
-		if(!vstd::contains(interestedObjs, *i)) continue;
-
-		auto prev = (*i)->mouseState(btn);
-		if(!isPressed)
-			(*i)->updateMouseState(btn, isPressed);
-		if((*i)->pos.isInside(getCursorPosition()))
-		{
-			if(isPressed)
-				(*i)->updateMouseState(btn, isPressed);
-			(*i)->click(btn, isPressed, prev);
-		}
-		else if(!isPressed)
-			(*i)->click(btn, boost::logic::indeterminate, prev);
-	}
-}
-
-void CGuiHandler::handleMouseMotion(const SDL_Event & current)
-{
-	//sending active, hovered hoverable objects hover() call
-	std::vector<CIntObject*> hlp;
-
-	auto hoverableCopy = hoverable;
-	for(auto & elem : hoverableCopy)
-	{
-		if(elem->pos.isInside(getCursorPosition()))
-		{
-			if (!(elem)->hovered)
-				hlp.push_back((elem));
-		}
-		else if ((elem)->hovered)
-		{
-			(elem)->hover(false);
-			(elem)->hovered = false;
-		}
-	}
-
-	for(auto & elem : hlp)
-	{
-		elem->hover(true);
-		elem->hovered = true;
-	}
-
-	// do not send motion events for events outside our window
-	//if (current.motion.windowID == 0)
-		handleMoveInterested(current.motion);
-}
-
-void CGuiHandler::handleMoveInterested(const SDL_MouseMotionEvent & motion)
-{
-	//sending active, MotionInterested objects mouseMoved() call
-	std::list<CIntObject*> miCopy = motioninterested;
-	for(auto & elem : miCopy)
-	{
-		if(elem->strongInterest || Rect::createAround(elem->pos, 1).isInside( motion.x, motion.y)) //checking bounds including border fixes bug #2476
-		{
-			(elem)->mouseMoved(Point(motion.x, motion.y));
-		}
-	}
-}
-
 void CGuiHandler::renderFrame()
 {
 
@@ -781,6 +617,11 @@ IScreenHandler & CGuiHandler::screenHandler()
 	return *screenHandlerInstance;
 }
 
+InterfaceEventDispatcher & CGuiHandler::eventDispatcher()
+{
+	return *eventDispatcherInstance;
+}
+
 WindowHandler & CGuiHandler::windows()
 {
 	assert(windowHandlerInstance);

+ 5 - 23
client/gui/CGuiHandler.h

@@ -31,6 +31,7 @@ class IShowActivatable;
 class IShowable;
 class IScreenHandler;
 class WindowHandler;
+class InterfaceEventDispatcher;
 
 // TODO: event handling need refactoring
 enum class EUserEvent
@@ -48,8 +49,7 @@ enum class EUserEvent
 // Handles GUI logic and drawing
 class CGuiHandler
 {
-public:
-
+	friend class InterfaceEventDispatcher;
 
 private:
 	/// Fake no-op version status bar, for use in windows that have no status bar
@@ -65,28 +65,12 @@ private:
 	std::unique_ptr<WindowHandler> windowHandlerInstance;
 
 	std::atomic<bool> continueEventHandling;
-	using CIntObjectList = std::list<CIntObject *>;
-
-	//active GUI elements (listening for events
-	CIntObjectList lclickable;
-	CIntObjectList rclickable;
-	CIntObjectList mclickable;
-	CIntObjectList hoverable;
-	CIntObjectList keyinterested;
-	CIntObjectList motioninterested;
-	CIntObjectList timeinterested;
-	CIntObjectList wheelInterested;
-	CIntObjectList doubleClickInterested;
-	CIntObjectList textInterested;
 
 	std::unique_ptr<IScreenHandler> screenHandlerInstance;
 	std::unique_ptr<FramerateManager> framerateManagerInstance;
+	std::unique_ptr<InterfaceEventDispatcher> eventDispatcherInstance;
 
-	void handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed);
-	void processLists(const ui16 activityFlag, std::function<void (std::list<CIntObject*> *)> cb);
 	void handleCurrentEvent(SDL_Event &current);
-	void handleMouseMotion(const SDL_Event & current);
-	void handleMoveInterested( const SDL_MouseMotionEvent & motion );
 	void convertTouchToMouse(SDL_Event * current);
 	void fakeMoveCursor(float dx, float dy);
 	void fakeMouseButtonEventRelativeMode(bool down, bool right);
@@ -103,9 +87,6 @@ private:
 	void handleEventFingerDown(SDL_Event & current);
 	void handleEventFingerUp(SDL_Event & current);
 
-public:
-	void handleElementActivate(CIntObject * elem, ui16 activityFlag);
-	void handleElementDeActivate(CIntObject * elem, ui16 activityFlag);
 public:
 
 	/// returns current position of mouse cursor, relative to vcmi window
@@ -113,6 +94,7 @@ public:
 
 	ShortcutHandler & shortcutsHandler();
 	FramerateManager & framerateManager();
+	InterfaceEventDispatcher & eventDispatcher();
 
 	/// Returns current logical screen dimensions
 	/// May not match size of window if user has UI scaling different from 100%
@@ -166,7 +148,7 @@ public:
 	/// called whenever user selects different resolution, requiring to center/resize all windows
 	void onScreenResize();
 
-	void updateTime(); //handles timeInterested
+	void updateTime();
 	void handleEvents(); //takes events from queue and calls interested objects
 	void fakeMouseMove();
 	void breakEventHandling(); //current event won't be propagated anymore

+ 71 - 54
client/gui/CIntObject.cpp

@@ -11,6 +11,7 @@
 #include "CIntObject.h"
 
 #include "CGuiHandler.h"
+#include "InterfaceEventDispatcher.h"
 #include "WindowHandler.h"
 #include "Shortcut.h"
 #include "../renderSDL/SDL_Extensions.h"
@@ -19,18 +20,59 @@
 
 #include <SDL_pixels.h>
 
-IShowActivatable::IShowActivatable()
+AEventsReceiver::AEventsReceiver()
+	: activeState(0)
+	, hoveredState(false)
+	, strongInterestState(false)
 {
-	type = 0;
+}
+
+bool AEventsReceiver::isHovered() const
+{
+	return hoveredState;
+}
+
+bool AEventsReceiver::isActive() const
+{
+	return activeState;
+}
+
+bool AEventsReceiver::isActive(int flags) const
+{
+	return activeState & flags;
+}
+
+bool AEventsReceiver::isMouseButtonPressed(MouseButton btn) const
+{
+	return currentMouseState.count(btn) ? currentMouseState.at(btn) : false;
+}
+
+void AEventsReceiver::setMoveEventStrongInterest(bool on)
+{
+	strongInterestState = on;
+}
+
+void AEventsReceiver::activateEvents(ui16 what)
+{
+	assert((what & GENERAL) || (activeState & GENERAL));
+
+	activeState |= GENERAL;
+	GH.eventDispatcher().handleElementActivate(this, what);
+}
+
+void AEventsReceiver::deactivateEvents(ui16 what)
+{
+	if (what & GENERAL)
+		activeState &= ~GENERAL;
+	GH.eventDispatcher().handleElementDeActivate(this, what & activeState);
 }
 
 CIntObject::CIntObject(int used_, Point pos_):
 	parent_m(nullptr),
-	active_m(0),
 	parent(parent_m),
-	active(active_m)
+	type(0)
 {
-	hovered = captureAllKeys = strongInterest = false;
+	captureAllKeys = false;
 	used = used_;
 
 	recActions = defActions = GH.defActionsDef;
@@ -46,7 +88,7 @@ CIntObject::CIntObject(int used_, Point pos_):
 
 CIntObject::~CIntObject()
 {
-	if(active_m)
+	if(isActive())
 		deactivate();
 
 	while(!children.empty())
@@ -76,25 +118,16 @@ void CIntObject::showAll(SDL_Surface * to)
 		for(auto & elem : children)
 			if(elem->recActions & SHOWALL)
 				elem->showAll(to);
-
 	}
 }
 
 void CIntObject::activate()
 {
-	if (active_m)
-	{
-		if ((used | GENERAL) == active_m)
-			return;
-		else
-		{
-			logGlobal->warn("Warning: IntObject re-activated with mismatching used and active");
-			deactivate(); //FIXME: better to avoid such possibility at all
-		}
-	}
+	if (isActive())
+		return;
 
-	active_m |= GENERAL;
-	activate(used);
+	activateEvents(used | GENERAL);
+	assert(isActive());
 
 	if(defActions & ACTIVATE)
 		for(auto & elem : children)
@@ -102,20 +135,14 @@ void CIntObject::activate()
 				elem->activate();
 }
 
-void CIntObject::activate(ui16 what)
-{
-	GH.handleElementActivate(this, what);
-}
-
 void CIntObject::deactivate()
 {
-	if (!active_m)
+	if (!isActive())
 		return;
 
-	active_m &= ~ GENERAL;
-	deactivate(active_m);
+	deactivateEvents(ALL);
 
-	assert(!active_m);
+	assert(!isActive());
 
 	if(defActions & DEACTIVATE)
 		for(auto & elem : children)
@@ -123,11 +150,6 @@ void CIntObject::deactivate()
 				elem->deactivate();
 }
 
-void CIntObject::deactivate(ui16 what)
-{
-	GH.handleElementDeActivate(this, what);
-}
-
 void CIntObject::click(MouseButton btn, tribool down, bool previousState)
 {
 	switch(btn)
@@ -167,21 +189,21 @@ void CIntObject::printAtMiddleWBLoc( const std::string & text, int x, int y, EFo
 
 void CIntObject::addUsedEvents(ui16 newActions)
 {
-	if (active_m)
-		activate(~used & newActions);
+	if (isActive())
+		activateEvents(~used & newActions);
 	used |= newActions;
 }
 
 void CIntObject::removeUsedEvents(ui16 newActions)
 {
-	if (active_m)
-		deactivate(used & newActions);
+	if (isActive())
+		deactivateEvents(used & newActions);
 	used &= ~newActions;
 }
 
 void CIntObject::disable()
 {
-	if(active)
+	if(isActive())
 		deactivate();
 
 	recActions = DISPOSE;
@@ -189,7 +211,7 @@ void CIntObject::disable()
 
 void CIntObject::enable()
 {
-	if(!active_m && (!parent_m || parent_m->active))
+	if(!isActive() && (!parent_m || parent_m->isActive()))
 	{
 		activate();
 		redraw();
@@ -246,9 +268,9 @@ void CIntObject::addChild(CIntObject * child, bool adjustPosition)
 	if(adjustPosition)
 		child->moveBy(pos.topLeft(), adjustPosition);
 
-	if (!active && child->active)
+	if (!isActive() && child->isActive())
 		child->deactivate();
-	if (active && !child->active)
+	if (isActive()&& !child->isActive())
 		child->activate();
 }
 
@@ -273,7 +295,7 @@ void CIntObject::redraw()
 {
 	//currently most of calls come from active objects so this check won't affect them
 	//it should fix glitches when called by inactive elements located below active window
-	if (active)
+	if (isActive())
 	{
 		if (parent_m && (type & REDRAW_PARENT))
 		{
@@ -288,6 +310,11 @@ void CIntObject::redraw()
 	}
 }
 
+bool CIntObject::isInside(const Point & position)
+{
+	return pos.isInside(position);
+}
+
 void CIntObject::onScreenResize()
 {
 	center(pos, true);
@@ -330,23 +357,13 @@ CKeyShortcut::CKeyShortcut(EShortcut key)
 void CKeyShortcut::keyPressed(EShortcut key)
 {
 	if( assignedKey == key && assignedKey != EShortcut::NONE)
-	{
-		bool prev = mouseState(MouseButton::LEFT);
-		updateMouseState(MouseButton::LEFT, true);
-		clickLeft(true, prev);
-
-	}
+		clickLeft(true, false);
 }
 
 void CKeyShortcut::keyReleased(EShortcut key)
 {
 	if( assignedKey == key && assignedKey != EShortcut::NONE)
-	{
-		bool prev = mouseState(MouseButton::LEFT);
-		updateMouseState(MouseButton::LEFT, false);
-		clickLeft(false, prev);
-
-	}
+		clickLeft(false, true);
 }
 
 WindowBase::WindowBase(int used_, Point pos_)

+ 80 - 40
client/gui/CIntObject.h

@@ -16,6 +16,7 @@
 struct SDL_Surface;
 class CGuiHandler;
 class CPicture;
+class InterfaceEventDispatcher;
 enum class EShortcut;
 
 using boost::logic::tribool;
@@ -26,14 +27,14 @@ class IActivatable
 public:
 	virtual void activate()=0;
 	virtual void deactivate()=0;
-	virtual ~IActivatable(){};
+	virtual ~IActivatable() = default;
 };
 
 class IUpdateable
 {
 public:
 	virtual void update()=0;
-	virtual ~IUpdateable(){};
+	virtual ~IUpdateable() = default;
 };
 
 // Defines a show method
@@ -46,36 +47,81 @@ public:
 	{
 		show(to);
 	}
-	virtual ~IShowable(){};
+	virtual ~IShowable() = default;
 };
 
 class IShowActivatable : public IShowable, public IActivatable
 {
 public:
-	//redraw parent flag - this int may be semi-transparent and require redraw of parent window
-	enum {REDRAW_PARENT=8};
-	int type; //bin flags using etype
-	IShowActivatable();
-	virtual ~IShowActivatable(){};
+	virtual void onScreenResize() = 0;
+	virtual ~IShowActivatable() = default;
 };
 
-// Base UI element
-class CIntObject : public IShowActivatable //interface object
+class IEventsReceiver
 {
-	ui16 used;//change via addUsed() or delUsed
+public:
+	virtual void keyPressed(EShortcut key) = 0;
+	virtual void keyReleased(EShortcut key) = 0;
+	virtual bool captureThisKey(EShortcut key) = 0;
+
+	virtual void click(MouseButton btn, tribool down, bool previousState) = 0;
+	virtual void clickLeft(tribool down, bool previousState) = 0;
+	virtual void clickRight(tribool down, bool previousState) = 0;
+	virtual void clickMiddle(tribool down, bool previousState) = 0;
+
+	virtual void textInputed(const std::string & enteredText) = 0;
+	virtual void textEdited(const std::string & enteredText) = 0;
 
+	virtual void tick(uint32_t msPassed) = 0;
+	virtual void wheelScrolled(bool down, bool in) = 0;
+	virtual void mouseMoved(const Point & cursorPosition) = 0;
+	virtual void hover(bool on) = 0;
+	virtual void onDoubleClick() = 0;
+
+	virtual ~IEventsReceiver() = default;
+};
+
+class AEventsReceiver : public IEventsReceiver
+{
+	friend class InterfaceEventDispatcher;
+
+	ui16 activeState;
 	std::map<MouseButton, bool> currentMouseState;
 
-	//non-const versions of fields to allow changing them in CIntObject
-	CIntObject *parent_m; //parent object
-	ui16 active_m;
+	bool hoveredState; //for determining if object is hovered
+	bool strongInterestState; //if true - report all mouse movements, if not - only when hovered
 
 protected:
-	//activate or deactivate specific action (LCLICK, RCLICK...)
-	void activate(ui16 what);
-	void deactivate(ui16 what);
+	void setMoveEventStrongInterest(bool on);
+
+	void activateEvents(ui16 what);
+	void deactivateEvents(ui16 what);
 
 public:
+	AEventsReceiver();
+
+	// These are the arguments that can be used to determine what kind of input the CIntObject will receive
+	enum {LCLICK=1, RCLICK=2, HOVER=4, MOVE=8, KEYBOARD=16, TIME=32, GENERAL=64, WHEEL=128, DOUBLECLICK=256, TEXTINPUT=512, MCLICK=1024, ALL=0xffff};
+
+	virtual bool isInside(const Point & position) = 0;
+	bool isHovered() const;
+	bool isActive() const;
+	bool isActive(int flags) const;
+	bool isMouseButtonPressed(MouseButton btn) const;
+};
+
+// Base UI element
+class CIntObject : public IShowActivatable, public AEventsReceiver //interface object
+{
+	ui16 used;//change via addUsed() or delUsed
+
+	//non-const versions of fields to allow changing them in CIntObject
+	CIntObject *parent_m; //parent object
+
+public:
+	//redraw parent flag - this int may be semi-transparent and require redraw of parent window
+	enum {REDRAW_PARENT=8};
+	int type; //bin flags using etype
 /*
  * Functions and fields that supposed to be private but are not for now.
  * Don't use them unless you really know what they are for
@@ -96,43 +142,35 @@ public:
 	CIntObject(int used=0, Point offset=Point());
 	virtual ~CIntObject();
 
-	void updateMouseState(MouseButton btn, bool state) { currentMouseState[btn] = state; }
-	bool mouseState(MouseButton btn) const { return currentMouseState.count(btn) ? currentMouseState.at(btn) : false; }
-
-	virtual void click(MouseButton btn, tribool down, bool previousState);
-	virtual void clickLeft(tribool down, bool previousState) {}
-	virtual void clickRight(tribool down, bool previousState) {}
-	virtual void clickMiddle(tribool down, bool previousState) {}
+	void click(MouseButton btn, tribool down, bool previousState) final;
+	void clickLeft(tribool down, bool previousState) override {}
+	void clickRight(tribool down, bool previousState) override {}
+	void clickMiddle(tribool down, bool previousState) override {}
 
 	//hover handling
-	/*const*/ bool hovered;  //for determining if object is hovered
-	virtual void hover (bool on){}
+	void hover (bool on) override{}
 
 	//keyboard handling
 	bool captureAllKeys; //if true, only this object should get info about pressed keys
-	virtual void keyPressed(EShortcut key){}
-	virtual void keyReleased(EShortcut key){}
-	virtual bool captureThisKey(EShortcut key); //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
+	void keyPressed(EShortcut key) override {}
+	void keyReleased(EShortcut key) override {}
+	bool captureThisKey(EShortcut key) override; //allows refining captureAllKeys against specific events (eg. don't capture ENTER)
 
-	virtual void textInputed(const std::string & enteredText){};
-	virtual void textEdited(const std::string & enteredText){};
+	void textInputed(const std::string & enteredText) override{};
+	void textEdited(const std::string & enteredText) override{};
 
 	//mouse movement handling
-	bool strongInterest; //if true - report all mouse movements, if not - only when hovered
-	virtual void mouseMoved (const Point & cursorPosition){}
+	void mouseMoved (const Point & cursorPosition) override{}
 
 	//time handling
-	virtual void tick(uint32_t msPassed){}
+	void tick(uint32_t msPassed) override {}
 
 	//mouse wheel
-	virtual void wheelScrolled(bool down, bool in){}
+	void wheelScrolled(bool down, bool in) override {}
 
 	//double click
-	virtual void onDoubleClick(){}
+	void onDoubleClick() override {}
 
-	// These are the arguments that can be used to determine what kind of input the CIntObject will receive
-	enum {LCLICK=1, RCLICK=2, HOVER=4, MOVE=8, KEYBOARD=16, TIME=32, GENERAL=64, WHEEL=128, DOUBLECLICK=256, TEXTINPUT=512, MCLICK=1024, ALL=0xffff};
-	const ui16 & active;
 	void addUsedEvents(ui16 newActions);
 	void removeUsedEvents(ui16 newActions);
 
@@ -162,7 +200,9 @@ public:
 
 	/// called only for windows whenever screen size changes
 	/// default behavior is to re-center, can be overriden
-	virtual void onScreenResize();
+	void onScreenResize() override;
+
+	bool isInside(const Point & position) override;
 
 	const Rect & center(const Rect &r, bool propagate = true); //sets pos so that r will be in the center of screen, assigns sizes of r to pos, returns new position
 	const Rect & center(const Point &p, bool propagate = true);  //moves object so that point p will be in its center

+ 229 - 0
client/gui/InterfaceEventDispatcher.cpp

@@ -0,0 +1,229 @@
+/*
+ * CGuiHandler.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 "InterfaceEventDispatcher.h"
+#include "CIntObject.h"
+#include "CGuiHandler.h"
+#include "FramerateManager.h"
+
+void InterfaceEventDispatcher::processList(const ui16 mask, const ui16 flag, CIntObjectList *lst, std::function<void (CIntObjectList *)> cb)
+{
+	if (mask & flag)
+		cb(lst);
+}
+
+void InterfaceEventDispatcher::processLists(ui16 activityFlag, std::function<void (CIntObjectList *)> cb)
+{
+	processList(AEventsReceiver::LCLICK,activityFlag,&lclickable,cb);
+	processList(AEventsReceiver::RCLICK,activityFlag,&rclickable,cb);
+	processList(AEventsReceiver::MCLICK,activityFlag,&mclickable,cb);
+	processList(AEventsReceiver::HOVER,activityFlag,&hoverable,cb);
+	processList(AEventsReceiver::MOVE,activityFlag,&motioninterested,cb);
+	processList(AEventsReceiver::KEYBOARD,activityFlag,&keyinterested,cb);
+	processList(AEventsReceiver::TIME,activityFlag,&timeinterested,cb);
+	processList(AEventsReceiver::WHEEL,activityFlag,&wheelInterested,cb);
+	processList(AEventsReceiver::DOUBLECLICK,activityFlag,&doubleClickInterested,cb);
+	processList(AEventsReceiver::TEXTINPUT,activityFlag,&textInterested,cb);
+}
+
+void InterfaceEventDispatcher::handleElementActivate(AEventsReceiver * elem, ui16 activityFlag)
+{
+	processLists(activityFlag,[&](CIntObjectList * lst){
+		lst->push_front(elem);
+	});
+	elem->activeState |= activityFlag;
+}
+
+void InterfaceEventDispatcher::handleElementDeActivate(AEventsReceiver * elem, ui16 activityFlag)
+{
+	processLists(activityFlag,[&](CIntObjectList * lst){
+		auto hlp = std::find(lst->begin(),lst->end(),elem);
+		assert(hlp != lst->end());
+		lst->erase(hlp);
+	});
+	elem->activeState &= ~activityFlag;
+}
+
+void InterfaceEventDispatcher::updateTime(uint32_t msPassed)
+{
+	CIntObjectList hlp = timeinterested;
+	for (auto & elem : hlp)
+	{
+		if(!vstd::contains(timeinterested,elem)) continue;
+		(elem)->tick(msPassed);
+	}
+}
+
+void InterfaceEventDispatcher::dispatchShortcutPressed(const std::vector<EShortcut> & shortcutsVector)
+{
+	bool keysCaptured = false;
+
+	for(auto i = keyinterested.begin(); i != keyinterested.end() && GH.continueEventHandling; i++)
+		for(EShortcut shortcut : shortcutsVector)
+			if((*i)->captureThisKey(shortcut))
+				keysCaptured = true;
+
+	CIntObjectList miCopy = keyinterested;
+
+	for(auto i = miCopy.begin(); i != miCopy.end() && GH.continueEventHandling; i++)
+		for(EShortcut shortcut : shortcutsVector)
+			if(vstd::contains(keyinterested, *i) && (!keysCaptured || (*i)->captureThisKey(shortcut)))
+					(**i).keyPressed(shortcut);
+}
+
+void InterfaceEventDispatcher::dispatchShortcutReleased(const std::vector<EShortcut> & shortcutsVector)
+{
+	bool keysCaptured = false;
+
+	for(auto i = keyinterested.begin(); i != keyinterested.end() && GH.continueEventHandling; i++)
+		for(EShortcut shortcut : shortcutsVector)
+			if((*i)->captureThisKey(shortcut))
+				keysCaptured = true;
+
+	CIntObjectList miCopy = keyinterested;
+
+	for(auto i = miCopy.begin(); i != miCopy.end() && GH.continueEventHandling; i++)
+		for(EShortcut shortcut : shortcutsVector)
+			if(vstd::contains(keyinterested, *i) && (!keysCaptured || (*i)->captureThisKey(shortcut)))
+				(**i).keyReleased(shortcut);
+}
+
+InterfaceEventDispatcher::CIntObjectList & InterfaceEventDispatcher::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 InterfaceEventDispatcher::dispatchMouseButtonPressed(const MouseButton & button, const Point & position)
+{
+//	if (button == MouseButton::LEFT)
+//	{
+//		auto doubleClicked = false;
+//		if(lastClick == getCursorPosition() && (SDL_GetTicks() - lastClickTime) < 300)
+//		{
+//			std::list<CIntObject*> hlp = doubleClickInterested;
+//			for(auto i = hlp.begin(); i != hlp.end() && continueEventHandling; i++)
+//			{
+//				if(!vstd::contains(doubleClickInterested, *i)) continue;
+//				if((*i)->pos.isInside(current.motion.x, current.motion.y))
+//				{
+//					(*i)->onDoubleClick();
+//					doubleClicked = true;
+//				}
+//			}
+//		}
+//
+//		lastClick = current.motion;
+//		lastClickTime = SDL_GetTicks();
+//
+//		if(doubleClicked)
+//			return;
+//	}
+
+	handleMouseButtonClick(getListForMouseButton(button), button, true);
+}
+
+void InterfaceEventDispatcher::dispatchMouseButtonReleased(const MouseButton & button, const Point & position)
+{
+	handleMouseButtonClick(getListForMouseButton(button), button, false);
+}
+
+void InterfaceEventDispatcher::handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed)
+{
+	auto hlp = interestedObjs;
+	for(auto i = hlp.begin(); i != hlp.end() && GH.continueEventHandling; i++)
+	{
+		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 InterfaceEventDispatcher::dispatchMouseScrolled(const Point & distance, const Point & position)
+{
+	CIntObjectList hlp = wheelInterested;
+	for(auto i = hlp.begin(); i != hlp.end() && GH.continueEventHandling; i++)
+	{
+		if(!vstd::contains(wheelInterested,*i))
+			continue;
+		(*i)->wheelScrolled(distance.y < 0, (*i)->isInside(position));
+	}
+}
+
+void InterfaceEventDispatcher::dispatchTextInput(const std::string & text)
+{
+	for(auto it : textInterested)
+	{
+		it->textInputed(text);
+	}
+}
+
+void InterfaceEventDispatcher::dispatchTextEditing(const std::string & text)
+{
+	for(auto it : textInterested)
+	{
+		it->textEdited(text);
+	}
+}
+
+void InterfaceEventDispatcher::dispatchMouseMoved(const Point & position)
+{
+	//sending active, hovered hoverable objects hover() call
+	CIntObjectList 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
+	CIntObjectList miCopy = motioninterested;
+	for(auto & elem : miCopy)
+	{
+		if(elem->strongInterestState || elem->isInside(position)) //checking bounds including border fixes bug #2476
+		{
+			(elem)->mouseMoved(position);
+		}
+	}
+}

+ 59 - 0
client/gui/InterfaceEventDispatcher.h

@@ -0,0 +1,59 @@
+/*
+ * CGuiHandler.h, 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
+ *
+ */
+#pragma once
+
+VCMI_LIB_NAMESPACE_BEGIN
+class Point;
+VCMI_LIB_NAMESPACE_END
+
+class AEventsReceiver;
+enum class MouseButton;
+enum class EShortcut;
+
+class InterfaceEventDispatcher
+{
+	using CIntObjectList = std::list<AEventsReceiver *>;
+
+	//active GUI elements (listening for events
+	CIntObjectList lclickable;
+	CIntObjectList rclickable;
+	CIntObjectList mclickable;
+	CIntObjectList hoverable;
+	CIntObjectList keyinterested;
+	CIntObjectList motioninterested;
+	CIntObjectList timeinterested;
+	CIntObjectList wheelInterested;
+	CIntObjectList doubleClickInterested;
+	CIntObjectList textInterested;
+
+	CIntObjectList & getListForMouseButton(MouseButton button);
+
+	void handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed);
+
+	void processList(const ui16 mask, const ui16 flag, CIntObjectList * lst, std::function<void(CIntObjectList *)> cb);
+	void processLists(ui16 activityFlag, std::function<void(CIntObjectList *)> cb);
+
+public:
+	void handleElementActivate(AEventsReceiver * elem, ui16 activityFlag);
+	void handleElementDeActivate(AEventsReceiver * elem, ui16 activityFlag);
+
+	void updateTime(uint32_t msPassed); //handles timeInterested
+
+	void dispatchShortcutPressed(const std::vector<EShortcut> & shortcuts);
+	void dispatchShortcutReleased(const std::vector<EShortcut> & shortcuts);
+
+	void dispatchMouseButtonPressed(const MouseButton & button, const Point & position);
+	void dispatchMouseButtonReleased(const MouseButton & button, const Point & position);
+	void dispatchMouseScrolled(const Point & distance, const Point & position);
+	void dispatchMouseMoved(const Point & position);
+
+	void dispatchTextInput(const std::string & text);
+	void dispatchTextEditing(const std::string & text);
+};

+ 1 - 5
client/gui/WindowHandler.cpp

@@ -109,12 +109,8 @@ void WindowHandler::simpleRedraw()
 void WindowHandler::onScreenResize()
 {
 	for(const auto & entry : windowsStack)
-	{
-		auto intObject = std::dynamic_pointer_cast<CIntObject>(entry);
+		entry->onScreenResize();
 
-		if(intObject)
-			intObject->onScreenResize();
-	}
 	totalRedraw();
 }
 

+ 1 - 1
client/lobby/CSelectionBase.cpp

@@ -90,7 +90,7 @@ CSelectionBase::CSelectionBase(ESelectionScreen type)
 
 void CSelectionBase::toggleTab(std::shared_ptr<CIntObject> tab)
 {
-	if(curTab && curTab->active)
+	if(curTab && curTab->isActive())
 	{
 		curTab->deactivate();
 		curTab->recActions = 0;

+ 3 - 13
client/lobby/RandomMapTab.cpp

@@ -397,21 +397,16 @@ void TemplatesDropBox::ListItem::hover(bool on)
 	if(h && w)
 	{
 		if(w->getText().empty())
-		{
-			hovered = false;
 			h->visible = false;
-		}
 		else
-		{
 			h->visible = on;
-		}
 	}
 	redraw();
 }
 
 void TemplatesDropBox::ListItem::clickLeft(tribool down, bool previousState)
 {
-	if(down && hovered)
+	if(down && isHovered())
 	{
 		dropBox.setTemplate(item);
 	}
@@ -469,19 +464,14 @@ void TemplatesDropBox::sliderMove(int slidPos)
 	redraw();
 }
 
-void TemplatesDropBox::hover(bool on)
-{
-	hovered = on;
-}
-
 void TemplatesDropBox::clickLeft(tribool down, bool previousState)
 {
-	if(down && !hovered)
+	if(down && !isActive())
 	{
 		auto w = widget<CSlider>("slider");
 
 		// pop the interface only if the mouse is not clicking on the slider
-		if (!w || !w->mouseState(MouseButton::LEFT))
+		if (!w || !w->isMouseButtonPressed(MouseButton::LEFT))
 		{
 			assert(GH.windows().isTopWindow(this));
 			GH.windows().popWindows(1);

+ 0 - 1
client/lobby/RandomMapTab.h

@@ -70,7 +70,6 @@ class TemplatesDropBox : public InterfaceObjectConfigurable
 public:
 	TemplatesDropBox(RandomMapTab & randomMapTab, int3 size);
 	
-	void hover(bool on) override;
 	void clickLeft(tribool down, bool previousState) override;
 	void setTemplate(const CRmgTemplate *);
 	

+ 1 - 1
client/lobby/SelectionTab.cpp

@@ -408,7 +408,7 @@ void SelectionTab::select(int position)
 
 	rememberCurrentSelection();
 
-	if(inputName && inputName->active)
+	if(inputName && inputName->isActive())
 	{
 		auto filename = *CResourceHandler::get("local")->getResourceName(ResourceID(curItems[py]->fileURI, EResType::CLIENT_SAVEGAME));
 		inputName->setText(filename.stem().string());

+ 1 - 1
client/mainmenu/CCampaignScreen.cpp

@@ -119,7 +119,7 @@ void CCampaignScreen::CCampaignButton::show(SDL_Surface * to)
 	CIntObject::show(to);
 
 	// Play the campaign button video when the mouse cursor is placed over the button
-	if(hovered)
+	if(isHovered())
 	{
 		if(CCS->videoh->fname != video)
 			CCS->videoh->open(video);

+ 7 - 7
client/widgets/Buttons.cpp

@@ -54,7 +54,7 @@ void CButton::update()
 		newPos = (int)image->size()-1;
 	image->setFrame(newPos);
 
-	if (active)
+	if (isActive())
 		redraw();
 }
 
@@ -177,7 +177,7 @@ void CButton::clickLeft(tribool down, bool previousState)
 			CCS->soundh->playSound(soundBase::button);
 		setState(PRESSED);
 	}
-	else if(hoverable && hovered)
+	else if(hoverable && isHovered())
 		setState(HIGHLIGHTED);
 	else
 		setState(NORMAL);
@@ -492,7 +492,7 @@ void CVolumeSlider::moveTo(int id)
 	vstd::abetween<int>(id, 0, animImage->size() - 1);
 	animImage->setFrame(id);
 	animImage->moveTo(Point(pos.x + (animImage->pos.w + 1) * id, pos.y));
-	if (active)
+	if (isActive())
 		redraw();
 }
 
@@ -550,7 +550,7 @@ void CVolumeSlider::wheelScrolled(bool down, bool in)
 
 void CSlider::sliderClicked()
 {
-	if(!(active & MOVE))
+	if(!isActive(MOVE))
 		addUsedEvents(MOVE);
 }
 
@@ -688,11 +688,11 @@ void CSlider::clickLeft(tribool down, bool previousState)
 			return;
 		// 		if (rw>1) return;
 		// 		if (rw<0) return;
-		slider->clickLeft(true, slider->mouseState(MouseButton::LEFT));
+		slider->clickLeft(true, slider->isMouseButtonPressed(MouseButton::LEFT));
 		moveTo((int)(rw * positions  +  0.5));
 		return;
 	}
-	if(active & MOVE)
+	if(isActive(MOVE))
 		removeUsedEvents(MOVE);
 }
 
@@ -710,7 +710,7 @@ CSlider::CSlider(Point position, int totalw, std::function<void(int)> Moved, int
 	vstd::amax(value, 0);
 	vstd::amin(value, positions);
 
-	strongInterest = true;
+	setMoveEventStrongInterest(true);
 
 	pos.x += position.x;
 	pos.y += position.y;

+ 1 - 1
client/widgets/CArtifactHolder.cpp

@@ -213,7 +213,7 @@ void CHeroArtPlace::showAll(SDL_Surface* to)
 		CIntObject::showAll(to);
 	}
 
-	if(marked && active)
+	if(marked && isActive())
 	{
 		// Draw vertical bars.
 		for(int i = 0; i < pos.h; ++i)

+ 1 - 1
client/widgets/CArtifactsOfHeroBase.cpp

@@ -169,7 +169,7 @@ void CArtifactsOfHeroBase::scrollBackpackForArtSet(int offset, const CArtifactSe
 
 void CArtifactsOfHeroBase::safeRedraw()
 {
-	if(active)
+	if(isActive())
 	{
 		if(parent)
 			parent->redraw();

+ 1 - 1
client/widgets/CWindowWithArtifacts.cpp

@@ -238,7 +238,7 @@ void CWindowWithArtifacts::artifactMoved(const ArtifactLocation & srcLoc, const
 		if(artSetPtr)
 		{
 			const auto hero = artSetPtr->getHero();
-			if(artSetPtr->active)
+			if(artSetPtr->isActive())
 			{
 				if(pickedArtInst)
 				{

+ 3 - 3
client/widgets/ObjectLists.cpp

@@ -35,7 +35,7 @@ std::shared_ptr<CIntObject> CObjectList::createItem(size_t index)
 
 	item->recActions = defActions;
 	addChild(item.get());
-	if (active)
+	if (isActive())
 		item->activate();
 	return item;
 }
@@ -70,7 +70,7 @@ void CTabbedInt::reset()
 	activeTab = createItem(activeID);
 	activeTab->moveTo(pos.topLeft());
 
-	if(active)
+	if(isActive())
 		redraw();
 }
 
@@ -107,7 +107,7 @@ void CListBox::updatePositions()
 		(elem)->moveTo(itemPos);
 		itemPos += itemOffset;
 	}
-	if (active)
+	if (isActive())
 	{
 		redraw();
 		if (slider)

+ 2 - 2
client/widgets/TextControls.cpp

@@ -446,7 +446,7 @@ void CGStatusBar::clickLeft(tribool down, bool previousState)
 {
 	if(!down)
 	{
-		if(LOCPLINT && LOCPLINT->cingconsole->active)
+		if(LOCPLINT && LOCPLINT->cingconsole->isActive())
 			LOCPLINT->cingconsole->startEnteringText();
 	}
 }
@@ -749,7 +749,7 @@ void CFocusable::moveFocus()
 		if(i == focusables.end())
 			i = focusables.begin();
 
-		if((*i)->active)
+		if((*i)->isActive())
 		{
 			(*i)->giveFocus();
 			break;

+ 3 - 4
client/windows/CCastleInterface.cpp

@@ -115,12 +115,12 @@ void CBuildingRect::hover(bool on)
 {
 	if(on)
 	{
-		if(!(active & MOVE))
+		if(!isActive(MOVE))
 			addUsedEvents(MOVE);
 	}
 	else
 	{
-		if(active & MOVE)
+		if(isActive(MOVE))
 			removeUsedEvents(MOVE);
 
 		if(parent->selectedBuilding == this)
@@ -218,7 +218,7 @@ void CBuildingRect::showAll(SDL_Surface * to)
 		return;
 
 	CShowableAnim::showAll(to);
-	if(!active && parent->selectedBuilding == this && border)
+	if(!isActive() && parent->selectedBuilding == this && border)
 		border->draw(to, pos.x, pos.y);
 }
 
@@ -1577,7 +1577,6 @@ void LabeledValue::hover(bool on)
 	else
 	{
 		GH.statusbar()->clear();
-		parent->hovered = false;
 	}
 }
 

+ 1 - 1
client/windows/CKingdomInterface.cpp

@@ -972,6 +972,6 @@ std::shared_ptr<CIntObject> CHeroItem::onTabSelected(size_t index)
 void CHeroItem::onArtChange(int tabIndex)
 {
 	//redraw item after background change
-	if(active)
+	if(isActive())
 		redraw();
 }