1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-04-13 11:40:38 +02:00

Minor fixes and cleanup

This commit is contained in:
Ivan Savenko 2023-05-18 02:09:42 +03:00
parent 1f513fd280
commit d5d0ca96a8
11 changed files with 142 additions and 193 deletions

View File

@ -1513,7 +1513,6 @@ void CPlayerInterface::update()
assert(adventureInt);
// Handles mouse and key input
GH.updateTime();
GH.handleEvents();
GH.windows().simpleRedraw();
}

View File

@ -47,7 +47,6 @@ class KeyInterested;
class MotionInterested;
class PlayerLocalState;
class TimeInterested;
class IShowable;
namespace boost
{

View File

@ -90,13 +90,10 @@ void CGuiHandler::init()
pointerSpeedMultiplier = settings["general"]["relativePointerSpeedMultiplier"].Float();
}
void CGuiHandler::updateTime()
{
eventDispatcher().updateTime(framerateManager().getElapsedMilliseconds());
}
void CGuiHandler::handleEvents()
{
eventDispatcher().dispatchTimer(framerateManager().getElapsedMilliseconds());
//player interface may want special event handling
if(nullptr != LOCPLINT && LOCPLINT->capturedAllEvents())
return;
@ -104,7 +101,7 @@ void CGuiHandler::handleEvents()
boost::unique_lock<boost::mutex> lock(eventsM);
while(!SDLEventsQueue.empty())
{
continueEventHandling = true;
eventDispatcher().allowEventHandling(true);
SDL_Event currentEvent = SDLEventsQueue.front();
if (currentEvent.type == SDL_MOUSEMOTION)
@ -349,7 +346,10 @@ void CGuiHandler::handleEventMouseButtonDown(SDL_Event & current)
switch(current.button.button)
{
case SDL_BUTTON_LEFT:
eventDispatcher().dispatchMouseButtonPressed(MouseButton::LEFT, Point(current.button.x, current.button.y));
if (current.button.clicks > 1)
eventDispatcher().dispatchMouseDoubleClick(Point(current.button.x, current.button.y));
else
eventDispatcher().dispatchMouseButtonPressed(MouseButton::LEFT, Point(current.button.x, current.button.y));
break;
case SDL_BUTTON_RIGHT:
eventDispatcher().dispatchMouseButtonPressed(MouseButton::RIGHT, Point(current.button.x, current.button.y));
@ -460,7 +460,6 @@ void CGuiHandler::handleEventFingerUp(SDL_Event & current)
void CGuiHandler::renderFrame()
{
// Updating GUI requires locking pim mutex (that protects screen and GUI state).
// During game:
// When ending the game, the pim mutex might be hold by other thread,
@ -498,13 +497,10 @@ void CGuiHandler::renderFrame()
}
CGuiHandler::CGuiHandler()
: lastClick(-500, -500)
, lastClickTime(0)
, defActionsDef(0)
: defActionsDef(0)
, captureChildren(false)
, multifinger(false)
, mouseButtonsMask(0)
, continueEventHandling(true)
, curInt(nullptr)
, fakeStatusBar(std::make_shared<EmptyStatusBar>())
, terminate_cond (new CondSh<bool>(false))
@ -554,7 +550,7 @@ bool CGuiHandler::isKeyboardShiftDown() const
void CGuiHandler::breakEventHandling()
{
continueEventHandling = false;
eventDispatcher().allowEventHandling(false);
}
const Point & CGuiHandler::getCursorPosition() const

View File

@ -28,7 +28,6 @@ class IStatusBar;
class CIntObject;
class IUpdateable;
class IShowActivatable;
class IShowable;
class IScreenHandler;
class WindowHandler;
class InterfaceEventDispatcher;
@ -49,8 +48,6 @@ enum class EUserEvent
// Handles GUI logic and drawing
class CGuiHandler
{
friend class InterfaceEventDispatcher;
private:
/// Fake no-op version status bar, for use in windows that have no status bar
std::shared_ptr<IStatusBar> fakeStatusBar;
@ -64,8 +61,6 @@ private:
std::unique_ptr<ShortcutHandler> shortcutsHandlerInstance;
std::unique_ptr<WindowHandler> windowHandlerInstance;
std::atomic<bool> continueEventHandling;
std::unique_ptr<IScreenHandler> screenHandlerInstance;
std::unique_ptr<FramerateManager> framerateManagerInstance;
std::unique_ptr<InterfaceEventDispatcher> eventDispatcherInstance;
@ -129,8 +124,6 @@ public:
IUpdateable *curInt;
Point lastClick;
unsigned lastClickTime;
bool multifinger;
bool isPointerRelativeMode;
float pointerSpeedMultiplier;
@ -148,7 +141,6 @@ public:
/// called whenever user selects different resolution, requiring to center/resize all windows
void onScreenResize();
void updateTime();
void handleEvents(); //takes events from queue and calls interested objects
void fakeMouseMove();
void breakEventHandling(); //current event won't be propagated anymore

View File

@ -67,6 +67,23 @@ void AEventsReceiver::deactivateEvents(ui16 what)
GH.eventDispatcher().handleElementDeActivate(this, what & activeState);
}
void AEventsReceiver::click(MouseButton btn, tribool down, bool previousState)
{
switch(btn)
{
default:
case MouseButton::LEFT:
clickLeft(down, previousState);
break;
case MouseButton::MIDDLE:
clickMiddle(down, previousState);
break;
case MouseButton::RIGHT:
clickRight(down, previousState);
break;
}
}
CIntObject::CIntObject(int used_, Point pos_):
parent_m(nullptr),
parent(parent_m),
@ -150,41 +167,14 @@ void CIntObject::deactivate()
elem->deactivate();
}
void CIntObject::click(MouseButton btn, tribool down, bool previousState)
{
switch(btn)
{
default:
case MouseButton::LEFT:
clickLeft(down, previousState);
break;
case MouseButton::MIDDLE:
clickMiddle(down, previousState);
break;
case MouseButton::RIGHT:
clickRight(down, previousState);
break;
}
}
void CIntObject::printAtLoc(const std::string & text, int x, int y, EFonts font, SDL_Color kolor, SDL_Surface * dst)
{
graphics->fonts[font]->renderTextLeft(dst, text, kolor, Point(pos.x + x, pos.y + y));
}
void CIntObject::printAtMiddleLoc(const std::string & text, int x, int y, EFonts font, SDL_Color kolor, SDL_Surface * dst)
{
printAtMiddleLoc(text, Point(x,y), font, kolor, dst);
}
void CIntObject::printAtMiddleLoc(const std::string & text, const Point &p, EFonts font, SDL_Color kolor, SDL_Surface * dst)
{
graphics->fonts[font]->renderTextCenter(dst, text, kolor, pos.topLeft() + p);
}
void CIntObject::printAtMiddleWBLoc( const std::string & text, int x, int y, EFonts font, int charpr, SDL_Color kolor, SDL_Surface * dst)
void CIntObject::printAtMiddleWBLoc( const std::string & text, const Point &p, EFonts font, int charpr, SDL_Color kolor, SDL_Surface * dst)
{
graphics->fonts[font]->renderTextLinesCenter(dst, CMessage::breakText(text, charpr, font), kolor, Point(pos.x + x, pos.y + y));
graphics->fonts[font]->renderTextLinesCenter(dst, CMessage::breakText(text, charpr, font), kolor, pos.topLeft() + p);
}
void CIntObject::addUsedEvents(ui16 newActions)
@ -347,6 +337,7 @@ bool CIntObject::captureThisKey(EShortcut key)
CKeyShortcut::CKeyShortcut()
: assignedKey(EShortcut::NONE)
, shortcutPressed(false)
{}
CKeyShortcut::CKeyShortcut(EShortcut key)
@ -356,14 +347,20 @@ CKeyShortcut::CKeyShortcut(EShortcut key)
void CKeyShortcut::keyPressed(EShortcut key)
{
if( assignedKey == key && assignedKey != EShortcut::NONE)
if( assignedKey == key && assignedKey != EShortcut::NONE && !shortcutPressed)
{
shortcutPressed = true;
clickLeft(true, false);
}
}
void CKeyShortcut::keyReleased(EShortcut key)
{
if( assignedKey == key && assignedKey != EShortcut::NONE)
if( assignedKey == key && assignedKey != EShortcut::NONE && shortcutPressed)
{
shortcutPressed = false;
clickLeft(false, true);
}
}
WindowBase::WindowBase(int used_, Point pos_)

View File

@ -21,15 +21,6 @@ enum class EShortcut;
using boost::logic::tribool;
// Defines a activate/deactive method
class IActivatable
{
public:
virtual void activate()=0;
virtual void deactivate()=0;
virtual ~IActivatable() = default;
};
class IUpdateable
{
public:
@ -37,51 +28,21 @@ public:
virtual ~IUpdateable() = default;
};
// Defines a show method
class IShowable
class IShowActivatable
{
public:
virtual void activate()=0;
virtual void deactivate()=0;
virtual void redraw()=0;
virtual void show(SDL_Surface * to) = 0;
virtual void showAll(SDL_Surface * to)
{
show(to);
}
virtual ~IShowable() = default;
};
virtual void showAll(SDL_Surface * to) = 0;
class IShowActivatable : public IShowable, public IActivatable
{
public:
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
class AEventsReceiver
{
friend class InterfaceEventDispatcher;
@ -91,19 +52,39 @@ class AEventsReceiver : public IEventsReceiver
bool hoveredState; //for determining if object is hovered
bool strongInterestState; //if true - report all mouse movements, if not - only when hovered
void click(MouseButton btn, tribool down, bool previousState);
protected:
void setMoveEventStrongInterest(bool on);
void activateEvents(ui16 what);
void deactivateEvents(ui16 what);
virtual void clickLeft(tribool down, bool previousState) {}
virtual void clickRight(tribool down, bool previousState) {}
virtual void clickMiddle(tribool down, bool previousState) {}
virtual void textInputed(const std::string & enteredText) {}
virtual void textEdited(const std::string & enteredText) {}
virtual void tick(uint32_t msPassed) {}
virtual void wheelScrolled(bool down, bool in) {}
virtual void mouseMoved(const Point & cursorPosition) {}
virtual void hover(bool on) {}
virtual void onDoubleClick() {}
virtual void keyPressed(EShortcut key) {}
virtual void keyReleased(EShortcut key) {}
virtual bool captureThisKey(EShortcut key) = 0;
virtual bool isInside(const Point & position) = 0;
public:
AEventsReceiver();
virtual ~AEventsReceiver() = default;
// 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;
@ -113,7 +94,7 @@ public:
// Base UI element
class CIntObject : public IShowActivatable, public AEventsReceiver //interface object
{
ui16 used;//change via addUsed() or delUsed
ui16 used;
//non-const versions of fields to allow changing them in CIntObject
CIntObject *parent_m; //parent object
@ -122,17 +103,9 @@ 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
*/
std::vector<CIntObject *> children;
/*
* Public interface
*/
/// read-only parent access. May not be a "clean" solution but allows some compatibility
CIntObject * const & parent;
@ -142,35 +115,14 @@ public:
CIntObject(int used=0, Point offset=Point());
virtual ~CIntObject();
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
void hover (bool on) override{}
//keyboard handling
bool captureAllKeys; //if true, only this object should get info about pressed keys
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)
void textInputed(const std::string & enteredText) override{};
void textEdited(const std::string & enteredText) override{};
//mouse movement handling
void mouseMoved (const Point & cursorPosition) override{}
//time handling
void tick(uint32_t msPassed) override {}
//mouse wheel
void wheelScrolled(bool down, bool in) override {}
//double click
void onDoubleClick() override {}
void addUsedEvents(ui16 newActions);
void removeUsedEvents(ui16 newActions);
@ -185,7 +137,6 @@ public:
/// deactivates or activates UI element based on flag
void setEnabled(bool on);
// activate or deactivate object. Inactive object won't receive any input events (keyboard\mouse)
// usually used automatically by parent
void activate() override;
@ -213,26 +164,18 @@ public:
void addChild(CIntObject *child, bool adjustPosition = false);
void removeChild(CIntObject *child, bool adjustPosition = false);
//delChild - not needed, use normal "delete child" instead
//delChildNull - not needed, use "vstd::clear_pointer(child)" instead
/*
* Functions that should be used only by specific GUI elements. Don't use them unless you really know why they are here
*/
//functions for printing text. Use CLabel where possible instead
void printAtLoc(const std::string & text, int x, int y, EFonts font, SDL_Color color, SDL_Surface * dst);
void printAtMiddleLoc(const std::string & text, int x, int y, EFonts font, SDL_Color color, SDL_Surface * dst);
/// functions for printing text.
/// Deprecated. Use CLabel where possible instead
void printAtMiddleLoc(const std::string & text, const Point &p, EFonts font, SDL_Color color, SDL_Surface * dst);
void printAtMiddleWBLoc(const std::string & text, int x, int y, EFonts font, int charsPerLine, SDL_Color color, SDL_Surface * dst);
friend class CGuiHandler;
void printAtMiddleWBLoc(const std::string & text, const Point &p, EFonts font, int charsPerLine, SDL_Color color, SDL_Surface * dst);
};
/// Class for binding keys to left mouse button clicks
/// Classes wanting use it should have it as one of their base classes
class CKeyShortcut : public virtual CIntObject
{
bool shortcutPressed;
public:
EShortcut assignedKey;
CKeyShortcut();

View File

@ -13,6 +13,11 @@
#include "CGuiHandler.h"
#include "FramerateManager.h"
void InterfaceEventDispatcher::allowEventHandling(bool enable)
{
eventHandlingAllowed = enable;
}
void InterfaceEventDispatcher::processList(const ui16 mask, const ui16 flag, CIntObjectList *lst, std::function<void (CIntObjectList *)> cb)
{
if (mask & flag)
@ -51,7 +56,7 @@ void InterfaceEventDispatcher::handleElementDeActivate(AEventsReceiver * elem, u
elem->activeState &= ~activityFlag;
}
void InterfaceEventDispatcher::updateTime(uint32_t msPassed)
void InterfaceEventDispatcher::dispatchTimer(uint32_t msPassed)
{
CIntObjectList hlp = timeinterested;
for (auto & elem : hlp)
@ -65,34 +70,44 @@ void InterfaceEventDispatcher::dispatchShortcutPressed(const std::vector<EShortc
{
bool keysCaptured = false;
for(auto i = keyinterested.begin(); i != keyinterested.end() && GH.continueEventHandling; i++)
for(auto & i : keyinterested)
for(EShortcut shortcut : shortcutsVector)
if((*i)->captureThisKey(shortcut))
if(i->captureThisKey(shortcut))
keysCaptured = true;
CIntObjectList miCopy = keyinterested;
for(auto i = miCopy.begin(); i != miCopy.end() && GH.continueEventHandling; i++)
for(auto & i : miCopy)
{
if (!eventHandlingAllowed)
break;
for(EShortcut shortcut : shortcutsVector)
if(vstd::contains(keyinterested, *i) && (!keysCaptured || (*i)->captureThisKey(shortcut)))
(**i).keyPressed(shortcut);
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(auto & i : keyinterested)
for(EShortcut shortcut : shortcutsVector)
if((*i)->captureThisKey(shortcut))
if(i->captureThisKey(shortcut))
keysCaptured = true;
CIntObjectList miCopy = keyinterested;
for(auto i = miCopy.begin(); i != miCopy.end() && GH.continueEventHandling; i++)
for(auto & i : miCopy)
{
if (!eventHandlingAllowed)
break;
for(EShortcut shortcut : shortcutsVector)
if(vstd::contains(keyinterested, *i) && (!keysCaptured || (*i)->captureThisKey(shortcut)))
(**i).keyReleased(shortcut);
if(vstd::contains(keyinterested, i) && (!keysCaptured || i->captureThisKey(shortcut)))
i->keyReleased(shortcut);
}
}
InterfaceEventDispatcher::CIntObjectList & InterfaceEventDispatcher::getListForMouseButton(MouseButton button)
@ -109,32 +124,32 @@ InterfaceEventDispatcher::CIntObjectList & InterfaceEventDispatcher::getListForM
throw std::runtime_error("Invalid mouse button in getListForMouseButton");
}
void InterfaceEventDispatcher::dispatchMouseDoubleClick(const Point & position)
{
bool doubleClicked = false;
auto hlp = doubleClickInterested;
for(auto & i : hlp)
{
if(!vstd::contains(doubleClickInterested, i))
continue;
if (!eventHandlingAllowed)
break;
if(i->isInside(position))
{
i->onDoubleClick();
doubleClicked = true;
}
}
if(!doubleClicked)
dispatchMouseButtonPressed(MouseButton::LEFT, position);
}
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);
}
@ -146,28 +161,32 @@ void InterfaceEventDispatcher::dispatchMouseButtonReleased(const MouseButton & b
void InterfaceEventDispatcher::handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed)
{
auto hlp = interestedObjs;
for(auto i = hlp.begin(); i != hlp.end() && GH.continueEventHandling; i++)
for(auto & i : hlp)
{
if(!vstd::contains(interestedObjs, *i)) continue;
if(!vstd::contains(interestedObjs, i))
continue;
auto prev = (*i)->isMouseButtonPressed(btn);
if (!eventHandlingAllowed)
break;
auto prev = i->isMouseButtonPressed(btn);
if(!isPressed)
(*i)->currentMouseState[btn] = isPressed;
if((*i)->isInside(GH.getCursorPosition()))
i->currentMouseState[btn] = isPressed;
if(i->isInside(GH.getCursorPosition()))
{
if(isPressed)
(*i)->currentMouseState[btn] = isPressed;
(*i)->click(btn, isPressed, prev);
i->currentMouseState[btn] = isPressed;
i->click(btn, isPressed, prev);
}
else if(!isPressed)
(*i)->click(btn, boost::logic::indeterminate, prev);
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++)
for(auto i = hlp.begin(); i != hlp.end() && eventHandlingAllowed; i++)
{
if(!vstd::contains(wheelInterested,*i))
continue;

View File

@ -33,6 +33,8 @@ class InterfaceEventDispatcher
CIntObjectList doubleClickInterested;
CIntObjectList textInterested;
std::atomic<bool> eventHandlingAllowed = true;
CIntObjectList & getListForMouseButton(MouseButton button);
void handleMouseButtonClick(CIntObjectList & interestedObjs, MouseButton btn, bool isPressed);
@ -41,10 +43,12 @@ class InterfaceEventDispatcher
void processLists(ui16 activityFlag, std::function<void(CIntObjectList *)> cb);
public:
void allowEventHandling(bool enable);
void handleElementActivate(AEventsReceiver * elem, ui16 activityFlag);
void handleElementDeActivate(AEventsReceiver * elem, ui16 activityFlag);
void updateTime(uint32_t msPassed); //handles timeInterested
void dispatchTimer(uint32_t msPassed);
void dispatchShortcutPressed(const std::vector<EShortcut> & shortcuts);
void dispatchShortcutReleased(const std::vector<EShortcut> & shortcuts);
@ -52,6 +56,7 @@ public:
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 dispatchMouseDoubleClick(const Point & position);
void dispatchMouseMoved(const Point & position);
void dispatchTextInput(const std::string & text);

View File

@ -333,7 +333,6 @@ void CMainMenu::update()
}
// Handles mouse and key input
GH.updateTime();
GH.handleEvents();
// check for null othervice crash on finishing a campaign

View File

@ -1479,7 +1479,7 @@ void CAltarWindow::showAll(SDL_Surface * to)
int dmp, val;
market->getOffer(pickedArt->getTypeId(), 0, dmp, val, EMarketMode::ARTIFACT_EXP);
val = static_cast<int>(hero->calculateXp(val));
printAtMiddleLoc(std::to_string(val), 304, 498, FONT_SMALL, Colors::WHITE, to);
printAtMiddleLoc(std::to_string(val), Point(304, 498), FONT_SMALL, Colors::WHITE, to);
}
}
}

View File

@ -534,7 +534,7 @@ void CTavernWindow::show(SDL_Surface * to)
recruit->addHoverText(CButton::NORMAL, boost::str(boost::format(CGI->generaltexth->tavernInfo[3]) % sel->h->getNameTranslated() % sel->h->type->heroClass->getNameTranslated()));
}
printAtMiddleWBLoc(sel->description, 146, 395, FONT_SMALL, 200, Colors::WHITE, to);
printAtMiddleWBLoc(sel->description, Point(146, 395), FONT_SMALL, 200, Colors::WHITE, to);
CSDL_Ext::drawBorder(to,sel->pos.x-2,sel->pos.y-2,sel->pos.w+4,sel->pos.h+4,Colors::BRIGHT_YELLOW);
}
}