/* * 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 "CGuiHandler.h" #include "../lib/CondSh.h" #include "CIntObject.h" #include "CursorHandler.h" #include "ShortcutHandler.h" #include "FramerateManager.h" #include "WindowHandler.h" #include "EventDispatcher.h" #include "../eventsSDL/InputHandler.h" #include "../CGameInfo.h" #include "../render/Colors.h" #include "../renderSDL/ScreenHandler.h" #include "../CMT.h" #include "../CPlayerInterface.h" #include "../battle/BattleInterface.h" #include "../../lib/CThreadHelper.h" #include "../../lib/CConfigHandler.h" #include CGuiHandler GH; boost::thread_specific_ptr inGuiThread; SObjectConstruction::SObjectConstruction(CIntObject *obj) :myObj(obj) { GH.createdObj.push_front(obj); GH.captureChildren = true; } SObjectConstruction::~SObjectConstruction() { assert(GH.createdObj.size()); assert(GH.createdObj.front() == myObj); GH.createdObj.pop_front(); GH.captureChildren = GH.createdObj.size(); } SSetCaptureState::SSetCaptureState(bool allow, ui8 actions) { previousCapture = GH.captureChildren; GH.captureChildren = false; prevActions = GH.defActionsDef; GH.defActionsDef = actions; } SSetCaptureState::~SSetCaptureState() { GH.captureChildren = previousCapture; GH.defActionsDef = prevActions; } void CGuiHandler::init() { inputHandlerInstance = std::make_unique(); eventDispatcherInstance = std::make_unique(); windowHandlerInstance = std::make_unique(); screenHandlerInstance = std::make_unique(); shortcutsHandlerInstance = std::make_unique(); framerateManagerInstance = std::make_unique(settings["video"]["targetfps"].Integer()); } void CGuiHandler::handleEvents() { events().dispatchTimer(framerate().getElapsedMilliseconds()); //player interface may want special event handling if(nullptr != LOCPLINT && LOCPLINT->capturedAllEvents()) return; input().processEvents(); } void CGuiHandler::fakeMouseMove() { pushUserEvent(EUserEvent::FAKE_MOUSE_MOVE); } void CGuiHandler::startTextInput(const Rect & whereInput) { input().startTextInput(whereInput); } void CGuiHandler::stopTextInput() { input().stopTextInput(); } 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, // that will notify us about the ending game by setting terminate_cond flag. //in PreGame terminate_cond stay false bool acquiredTheLockOnPim = false; //for tracking whether pim mutex locking succeeded while(!terminate_cond->get() && !(acquiredTheLockOnPim = CPlayerInterface::pim->try_lock())) //try acquiring long until it succeeds or we are told to terminate boost::this_thread::sleep(boost::posix_time::milliseconds(1)); if(acquiredTheLockOnPim) { // If we are here, pim mutex has been successfully locked - let's store it in a safe RAII lock. boost::unique_lock un(*CPlayerInterface::pim, boost::adopt_lock); if(nullptr != curInt) curInt->update(); if(settings["video"]["showfps"].Bool()) drawFPSCounter(); SDL_UpdateTexture(screenTexture, nullptr, screen->pixels, screen->pitch); SDL_RenderClear(mainRenderer); SDL_RenderCopy(mainRenderer, screenTexture, nullptr, nullptr); CCS->curh->render(); SDL_RenderPresent(mainRenderer); windows().onFrameRendered(); } framerate().framerateDelay(); // holds a constant FPS } CGuiHandler::CGuiHandler() : defActionsDef(0) , captureChildren(false) , curInt(nullptr) , fakeStatusBar(std::make_shared()) , terminate_cond (new CondSh(false)) { } CGuiHandler::~CGuiHandler() { delete terminate_cond; } ShortcutHandler & CGuiHandler::shortcuts() { assert(shortcutsHandlerInstance); return *shortcutsHandlerInstance; } FramerateManager & CGuiHandler::framerate() { assert(framerateManagerInstance); return *framerateManagerInstance; } bool CGuiHandler::isKeyboardCtrlDown() const { return inputHandlerInstance->isKeyboardCtrlDown(); } bool CGuiHandler::isKeyboardAltDown() const { return inputHandlerInstance->isKeyboardAltDown(); } bool CGuiHandler::isKeyboardShiftDown() const { return inputHandlerInstance->isKeyboardShiftDown(); } const Point & CGuiHandler::getCursorPosition() const { return inputHandlerInstance->getCursorPosition(); } Point CGuiHandler::screenDimensions() const { return Point(screen->w, screen->h); } void CGuiHandler::drawFPSCounter() { static SDL_Rect overlay = { 0, 0, 64, 32}; uint32_t black = SDL_MapRGB(screen->format, 10, 10, 10); SDL_FillRect(screen, &overlay, black); std::string fps = std::to_string(framerate().getFramerate()); graphics->fonts[FONT_BIG]->renderTextLeft(screen, fps, Colors::YELLOW, Point(10, 10)); } bool CGuiHandler::amIGuiThread() { return inGuiThread.get() && *inGuiThread; } void CGuiHandler::pushUserEvent(EUserEvent usercode) { inputHandlerInstance->pushUserEvent(usercode, nullptr); } void CGuiHandler::pushUserEvent(EUserEvent usercode, void * userdata) { inputHandlerInstance->pushUserEvent(usercode, userdata); } IScreenHandler & CGuiHandler::screenHandler() { return *screenHandlerInstance; } EventDispatcher & CGuiHandler::events() { return *eventDispatcherInstance; } InputHandler & CGuiHandler::input() { return *inputHandlerInstance; } WindowHandler & CGuiHandler::windows() { assert(windowHandlerInstance); return *windowHandlerInstance; } std::shared_ptr CGuiHandler::statusbar() { auto locked = currentStatusBar.lock(); if (!locked) return fakeStatusBar; return locked; } void CGuiHandler::setStatusbar(std::shared_ptr newStatusBar) { currentStatusBar = newStatusBar; } void CGuiHandler::onScreenResize() { screenHandler().onScreenResize(); windows().onScreenResize(); }