2017-07-13 10:26:03 +02:00
|
|
|
/*
|
|
|
|
* AdventureMapClasses.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
|
|
|
|
*
|
|
|
|
*/
|
2012-06-13 16:04:06 +03:00
|
|
|
#include "StdInc.h"
|
|
|
|
#include "AdventureMapClasses.h"
|
|
|
|
|
2023-01-18 16:54:53 +02:00
|
|
|
#include <SDL_timer.h>
|
2014-07-15 10:14:49 +03:00
|
|
|
|
2014-07-13 20:53:37 +03:00
|
|
|
#include "MiscWidgets.h"
|
2014-07-15 10:14:49 +03:00
|
|
|
#include "CComponent.h"
|
2022-09-18 14:47:49 +02:00
|
|
|
#include "Images.h"
|
2014-07-13 20:53:37 +03:00
|
|
|
|
|
|
|
#include "../CGameInfo.h"
|
|
|
|
#include "../CMusicHandler.h"
|
|
|
|
#include "../CPlayerInterface.h"
|
2018-01-05 19:21:07 +02:00
|
|
|
#include "../mainmenu/CMainMenu.h"
|
2014-07-13 20:53:37 +03:00
|
|
|
|
|
|
|
#include "../gui/CGuiHandler.h"
|
2023-01-30 20:06:08 +02:00
|
|
|
#include "../gui/SDL_PixelAccess.h"
|
2023-01-30 18:25:47 +02:00
|
|
|
#include "../gui/CAnimation.h"
|
2014-07-13 20:53:37 +03:00
|
|
|
|
2014-07-15 10:14:49 +03:00
|
|
|
#include "../windows/InfoWindows.h"
|
2014-07-13 20:53:37 +03:00
|
|
|
#include "../windows/CAdvmapInterface.h"
|
|
|
|
|
2022-12-09 13:38:46 +02:00
|
|
|
#include "../battle/BattleInterfaceClasses.h"
|
|
|
|
#include "../battle/BattleInterface.h"
|
2014-07-13 20:53:37 +03:00
|
|
|
|
|
|
|
#include "../../CCallback.h"
|
|
|
|
#include "../../lib/StartInfo.h"
|
|
|
|
#include "../../lib/CGameState.h"
|
|
|
|
#include "../../lib/CGeneralTextHandler.h"
|
|
|
|
#include "../../lib/CHeroHandler.h"
|
|
|
|
#include "../../lib/CModHandler.h"
|
|
|
|
#include "../../lib/CTownHandler.h"
|
2023-01-09 01:17:37 +02:00
|
|
|
#include "../../lib/TerrainHandler.h"
|
2014-07-13 20:53:37 +03:00
|
|
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
|
|
|
#include "../../lib/mapping/CMap.h"
|
2023-01-06 22:01:00 +02:00
|
|
|
#include "ClientCommandManager.h"
|
2012-06-13 16:04:06 +03:00
|
|
|
|
2023-01-30 19:55:32 +02:00
|
|
|
#include <SDL_surface.h>
|
|
|
|
#include <SDL_keyboard.h>
|
|
|
|
#include <SDL_events.h>
|
|
|
|
|
2018-04-07 13:34:11 +02:00
|
|
|
CInGameConsole::CInGameConsole()
|
|
|
|
: CIntObject(KEYBOARD | TEXTINPUT),
|
|
|
|
prevEntDisp(-1),
|
|
|
|
defaultTimeout(10000),
|
|
|
|
maxDisplayedTexts(10)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-07-13 18:39:45 +03:00
|
|
|
void CInGameConsole::show(SDL_Surface * to)
|
|
|
|
{
|
|
|
|
int number = 0;
|
|
|
|
|
2023-01-30 19:55:32 +02:00
|
|
|
std::vector<std::list< std::pair< std::string, uint32_t > >::iterator> toDel;
|
2014-07-13 18:39:45 +03:00
|
|
|
|
|
|
|
boost::unique_lock<boost::mutex> lock(texts_mx);
|
|
|
|
for(auto it = texts.begin(); it != texts.end(); ++it, ++number)
|
|
|
|
{
|
2022-12-21 17:02:53 +02:00
|
|
|
Point leftBottomCorner(0, pos.h);
|
|
|
|
|
2014-07-13 18:39:45 +03:00
|
|
|
graphics->fonts[FONT_MEDIUM]->renderTextLeft(to, it->first, Colors::GREEN,
|
2020-10-01 10:38:06 +02:00
|
|
|
Point(leftBottomCorner.x + 50, leftBottomCorner.y - (int)texts.size() * 20 - 80 + number*20));
|
2014-07-13 18:39:45 +03:00
|
|
|
|
2020-10-01 10:38:06 +02:00
|
|
|
if((int)(SDL_GetTicks() - it->second) > defaultTimeout)
|
2014-07-13 18:39:45 +03:00
|
|
|
{
|
|
|
|
toDel.push_back(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(auto & elem : toDel)
|
|
|
|
{
|
|
|
|
texts.erase(elem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CInGameConsole::print(const std::string &txt)
|
|
|
|
{
|
|
|
|
boost::unique_lock<boost::mutex> lock(texts_mx);
|
|
|
|
int lineLen = conf.go()->ac.outputLineLength;
|
|
|
|
|
|
|
|
if(txt.size() < lineLen)
|
|
|
|
{
|
|
|
|
texts.push_back(std::make_pair(txt, SDL_GetTicks()));
|
|
|
|
if(texts.size() > maxDisplayedTexts)
|
|
|
|
{
|
|
|
|
texts.pop_front();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
assert(lineLen);
|
|
|
|
for(int g=0; g<txt.size() / lineLen + 1; ++g)
|
|
|
|
{
|
|
|
|
std::string part = txt.substr(g * lineLen, lineLen);
|
|
|
|
if(part.size() == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
texts.push_back(std::make_pair(part, SDL_GetTicks()));
|
|
|
|
if(texts.size() > maxDisplayedTexts)
|
|
|
|
{
|
|
|
|
texts.pop_front();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CInGameConsole::keyPressed (const SDL_KeyboardEvent & key)
|
|
|
|
{
|
|
|
|
if(key.type != SDL_KEYDOWN) return;
|
|
|
|
|
|
|
|
if(!captureAllKeys && key.keysym.sym != SDLK_TAB) return; //because user is not entering any text
|
|
|
|
|
|
|
|
switch(key.keysym.sym)
|
|
|
|
{
|
|
|
|
case SDLK_TAB:
|
|
|
|
case SDLK_ESCAPE:
|
|
|
|
{
|
|
|
|
if(captureAllKeys)
|
|
|
|
{
|
|
|
|
endEnteringText(false);
|
|
|
|
}
|
2017-10-29 17:23:30 +02:00
|
|
|
else if(SDLK_TAB == key.keysym.sym)
|
2014-07-13 18:39:45 +03:00
|
|
|
{
|
|
|
|
startEnteringText();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SDLK_RETURN: //enter key
|
|
|
|
{
|
2023-01-22 02:14:28 +02:00
|
|
|
if(!enteredText.empty() && captureAllKeys)
|
2014-07-13 18:39:45 +03:00
|
|
|
{
|
2023-01-22 02:14:28 +02:00
|
|
|
bool anyTextExceptCaret = enteredText.size() > 1;
|
|
|
|
endEnteringText(anyTextExceptCaret);
|
|
|
|
|
|
|
|
if(anyTextExceptCaret)
|
|
|
|
{
|
|
|
|
CCS->soundh->playSound("CHAT");
|
|
|
|
}
|
2014-07-13 18:39:45 +03:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SDLK_BACKSPACE:
|
|
|
|
{
|
|
|
|
if(enteredText.size() > 1)
|
|
|
|
{
|
|
|
|
Unicode::trimRight(enteredText,2);
|
|
|
|
enteredText += '_';
|
|
|
|
refreshEnteredText();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SDLK_UP: //up arrow
|
|
|
|
{
|
|
|
|
if(previouslyEntered.size() == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(prevEntDisp == -1)
|
|
|
|
{
|
2020-10-01 10:38:06 +02:00
|
|
|
prevEntDisp = static_cast<int>(previouslyEntered.size() - 1);
|
2014-07-13 18:39:45 +03:00
|
|
|
enteredText = previouslyEntered[prevEntDisp] + "_";
|
|
|
|
refreshEnteredText();
|
|
|
|
}
|
|
|
|
else if( prevEntDisp > 0)
|
|
|
|
{
|
|
|
|
--prevEntDisp;
|
|
|
|
enteredText = previouslyEntered[prevEntDisp] + "_";
|
|
|
|
refreshEnteredText();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SDLK_DOWN: //down arrow
|
|
|
|
{
|
|
|
|
if(prevEntDisp != -1 && prevEntDisp+1 < previouslyEntered.size())
|
|
|
|
{
|
|
|
|
++prevEntDisp;
|
|
|
|
enteredText = previouslyEntered[prevEntDisp] + "_";
|
|
|
|
refreshEnteredText();
|
|
|
|
}
|
|
|
|
else if(prevEntDisp+1 == previouslyEntered.size()) //useful feature
|
|
|
|
{
|
|
|
|
prevEntDisp = -1;
|
|
|
|
enteredText = "_";
|
|
|
|
refreshEnteredText();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CInGameConsole::textInputed(const SDL_TextInputEvent & event)
|
|
|
|
{
|
|
|
|
if(!captureAllKeys || enteredText.size() == 0)
|
|
|
|
return;
|
|
|
|
enteredText.resize(enteredText.size()-1);
|
|
|
|
|
|
|
|
enteredText += event.text;
|
|
|
|
enteredText += "_";
|
|
|
|
|
|
|
|
refreshEnteredText();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CInGameConsole::textEdited(const SDL_TextEditingEvent & event)
|
|
|
|
{
|
|
|
|
//do nothing here
|
|
|
|
}
|
|
|
|
|
|
|
|
void CInGameConsole::startEnteringText()
|
|
|
|
{
|
2022-12-19 22:53:31 +02:00
|
|
|
if (!active)
|
|
|
|
return;
|
|
|
|
|
2022-12-19 22:04:50 +02:00
|
|
|
if (captureAllKeys)
|
|
|
|
return;
|
2022-11-20 11:53:46 +02:00
|
|
|
|
2022-12-12 18:23:41 +02:00
|
|
|
assert(GH.statusbar);
|
2022-12-19 22:53:31 +02:00
|
|
|
assert(currentStatusBar.expired());//effectively, nullptr check
|
2014-07-13 18:39:45 +03:00
|
|
|
|
2022-12-19 22:53:31 +02:00
|
|
|
currentStatusBar = GH.statusbar;
|
|
|
|
|
2022-12-12 18:23:41 +02:00
|
|
|
captureAllKeys = true;
|
2014-07-13 18:39:45 +03:00
|
|
|
enteredText = "_";
|
|
|
|
|
2022-12-12 18:23:41 +02:00
|
|
|
GH.statusbar->setEnteringMode(true);
|
|
|
|
GH.statusbar->setEnteredText(enteredText);
|
2014-07-13 18:39:45 +03:00
|
|
|
}
|
|
|
|
|
2023-01-06 22:01:00 +02:00
|
|
|
void CInGameConsole::endEnteringText(bool processEnteredText)
|
2014-07-13 18:39:45 +03:00
|
|
|
{
|
2022-11-20 11:53:46 +02:00
|
|
|
captureAllKeys = false;
|
2014-07-13 18:39:45 +03:00
|
|
|
prevEntDisp = -1;
|
2023-01-06 22:01:00 +02:00
|
|
|
if(processEnteredText)
|
2014-07-13 18:39:45 +03:00
|
|
|
{
|
|
|
|
std::string txt = enteredText.substr(0, enteredText.size()-1);
|
|
|
|
previouslyEntered.push_back(txt);
|
2023-01-06 22:01:00 +02:00
|
|
|
|
2023-01-06 23:53:10 +02:00
|
|
|
if(txt.at(0) == '/')
|
|
|
|
{
|
|
|
|
//some commands like gosolo don't work when executed from GUI thread
|
2023-01-15 02:09:58 +02:00
|
|
|
auto threadFunction = [=]()
|
|
|
|
{
|
|
|
|
ClientCommandManager commandController;
|
|
|
|
commandController.processCommand(txt.substr(1), true);
|
|
|
|
};
|
|
|
|
|
|
|
|
boost::thread clientCommandThread(threadFunction);
|
2023-01-07 16:42:34 +02:00
|
|
|
clientCommandThread.detach();
|
2023-01-06 23:53:10 +02:00
|
|
|
}
|
2023-01-08 21:30:57 +02:00
|
|
|
else
|
|
|
|
LOCPLINT->cb->sendMessage(txt, LOCPLINT->getSelection());
|
2014-07-13 18:39:45 +03:00
|
|
|
}
|
2022-11-15 02:20:55 +02:00
|
|
|
enteredText.clear();
|
2022-12-19 22:53:31 +02:00
|
|
|
|
|
|
|
auto statusbar = currentStatusBar.lock();
|
|
|
|
assert(statusbar);
|
|
|
|
|
|
|
|
if (statusbar)
|
|
|
|
statusbar->setEnteringMode(false);
|
|
|
|
|
|
|
|
currentStatusBar.reset();
|
2014-07-13 18:39:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void CInGameConsole::refreshEnteredText()
|
|
|
|
{
|
2022-12-19 22:53:31 +02:00
|
|
|
auto statusbar = currentStatusBar.lock();
|
|
|
|
assert(statusbar);
|
|
|
|
|
|
|
|
if (statusbar)
|
|
|
|
statusbar->setEnteredText(enteredText);
|
2014-07-13 18:39:45 +03:00
|
|
|
}
|
|
|
|
|