mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Extracted event management from GuiHandler and CIntObject
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
| @@ -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) | ||||
| 	{ | ||||
|   | ||||
| @@ -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'); | ||||
|   | ||||
| @@ -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(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -211,7 +211,7 @@ void CInGameConsole::textEdited(const std::string & inputtedText) | ||||
|  | ||||
| void CInGameConsole::startEnteringText() | ||||
| { | ||||
| 	if (!active) | ||||
| 	if (!isActive()) | ||||
| 		return; | ||||
|  | ||||
| 	if (captureAllKeys) | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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(); | ||||
| 		} | ||||
|   | ||||
| @@ -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(¤t); | ||||
| 		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(¤t); | ||||
| 		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); | ||||
|   | ||||
| @@ -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 ¤t); | ||||
| 	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 | ||||
|   | ||||
| @@ -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_) | ||||
|   | ||||
| @@ -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; | ||||
| }; | ||||
|  | ||||
| class IEventsReceiver | ||||
| { | ||||
| 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; | ||||
|  | ||||
| 	bool hoveredState; //for determining if object is hovered | ||||
| 	bool strongInterestState; //if true - report all mouse movements, if not - only when hovered | ||||
|  | ||||
| protected: | ||||
| 	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 //interface object | ||||
| class CIntObject : public IShowActivatable, public AEventsReceiver //interface object | ||||
| { | ||||
| 	ui16 used;//change via addUsed() or delUsed | ||||
|  | ||||
| 	std::map<MouseButton, bool> currentMouseState; | ||||
|  | ||||
| 	//non-const versions of fields to allow changing them in CIntObject | ||||
| 	CIntObject *parent_m; //parent object | ||||
| 	ui16 active_m; | ||||
|  | ||||
| protected: | ||||
| 	//activate or deactivate specific action (LCLICK, RCLICK...) | ||||
| 	void activate(ui16 what); | ||||
| 	void deactivate(ui16 what); | ||||
|  | ||||
| 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
									
								
								client/gui/InterfaceEventDispatcher.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								client/gui/InterfaceEventDispatcher.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								client/gui/InterfaceEventDispatcher.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								client/gui/InterfaceEventDispatcher.h
									
									
									
									
									
										Normal file
									
								
							| @@ -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); | ||||
| }; | ||||
| @@ -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(); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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 *); | ||||
| 	 | ||||
|   | ||||
| @@ -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()); | ||||
|   | ||||
| @@ -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); | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -169,7 +169,7 @@ void CArtifactsOfHeroBase::scrollBackpackForArtSet(int offset, const CArtifactSe | ||||
|  | ||||
| void CArtifactsOfHeroBase::safeRedraw() | ||||
| { | ||||
| 	if(active) | ||||
| 	if(isActive()) | ||||
| 	{ | ||||
| 		if(parent) | ||||
| 			parent->redraw(); | ||||
|   | ||||
| @@ -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) | ||||
| 				{ | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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; | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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(); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user