mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +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