You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/apps/openmw/mwmp/GUI/GUIChat.cpp

501 lines
14 KiB
C++

//
// Created by koncord on 04.03.16.
//
#include "GUIChat.hpp"
#include <MyGUI_EditBox.h>
#include "apps/openmw/mwbase/environment.hpp"
#include "apps/openmw/mwgui/windowmanagerimp.hpp"
#include "apps/openmw/mwinput/inputmanagerimp.hpp"
#include <MyGUI_InputManager.h>
#include <components/openmw-mp/Log.hpp>
#include <boost/tokenizer.hpp>
#include <string>
#include "../Networking.hpp"
#include "../Main.hpp"
#include "../LocalPlayer.hpp"
#include "../../mwbase/world.hpp"
#include "../../mwworld/timestamp.hpp"
#include "../GUIController.hpp"
namespace mwmp
{
GUIChat::GUIChat(int x, int y, int w, int h)
: WindowBase("tes3mp_chat.layout")
{
netStat = false;
setCoord(x, y, w, h);
getWidget(mCommandLine, "edit_Command");
getWidget(mHistory, "list_History");
getWidget(mChannelPrevBtn, "btn_prev_ch");
mChannelPrevBtn->eventMouseButtonClick += MyGUI::newDelegate(this, &GUIChat::prevChannel);
getWidget(mChannelNextBtn, "btn_next_ch");
mChannelNextBtn->eventMouseButtonClick += MyGUI::newDelegate(this, &GUIChat::nextChannel);
getWidget(mBoxChannels, "box_channels");
for (int i = 0; i < 3; ++i)
{
getWidget(mChannelBtns[i], "btn_ch" + std::to_string(i + 1));
mChannelBtns[i]->eventMouseButtonClick += MyGUI::newDelegate(this, &GUIChat::onClickChannel);
}
// Set up the command line box
mCommandLine->eventEditSelectAccept +=
newDelegate(this, &GUIChat::acceptCommand);
mCommandLine->eventKeyButtonPressed +=
newDelegate(this, &GUIChat::keyPress);
mHistory->setOverflowToTheLeft(true);
mHistory->setEditWordWrap(true);
mHistory->setTextShadow(true);
mHistory->setTextShadowColour(MyGUI::Colour::Black);
mHistory->setNeedKeyFocus(false);
windowState = 0;
mCommandLine->setVisible(false);
mBoxChannels->setVisible(false);
delay = 3; // 3 sec.
page = 0;
currentChannel = 0;
addChannel(0, "Default");
setChannel(0);
redrawChannels();
defaultColor = mChannelPrevBtn->getTextColour();
}
void GUIChat::onOpen()
{
// Give keyboard focus to the combo box whenever the console is
// turned on
setEditState(0);
windowState = CHAT_ENABLED;
}
void GUIChat::onClose()
{
// Apparently, hidden widgets can retain key focus
// Remove for MyGUI 3.2.2
windowState = CHAT_DISABLED;
setEditState(0);
}
bool GUIChat::exit()
{
//WindowBase::exit();
return true;
}
void GUIChat::acceptCommand(MyGUI::EditBox *_sender)
{
const std::string &cm = MyGUI::TextIterator::toTagsString(mCommandLine->getCaption());
// If they enter nothing, then it should be canceled.
// Otherwise, there's no way of closing without having text.
if (cm.empty())
{
mCommandLine->setCaption("");
setEditState(false);
return;
}
if (cm.find("//", 0, 2) == 0) //clientside commands
{
typedef boost::char_separator<char> csep;
csep sep(" ");
boost::tokenizer<csep> tokens(cm, sep);
std::vector<std::string> cmd;
for (const auto& t : tokens)
cmd.push_back(t);
if (cmd[0] == "//channel")
{
if (cmd[1] == "close")
{
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Closed \"%d\" channel", currentChannel);
closeChannel(currentChannel);
}
}
}
else
{
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "Player: %s", cm);
send (cm);
}
// Add the command to the history, and set the current pointer to
// the end of the list
if (mCommandHistory.empty() || mCommandHistory.back() != cm)
mCommandHistory.push_back(cm);
mCurrent = mCommandHistory.end();
mEditString.clear();
mCommandLine->setCaption("");
setEditState(false);
}
void GUIChat::onResChange(int width, int height)
{
setCoord(10,10, width-10, height/2);
}
void GUIChat::setFont(const std::string &fntName)
{
mHistory->setFontName(fntName);
mCommandLine->setFontName(fntName);
}
void GUIChat::print(unsigned channelId, const std::string &msg, const std::string &color)
{
if (windowState == 2 && !isVisible())
{
setVisible(true);
}
if (channelId != currentChannel)
{
try
{
auto it = getChannel(channelId);
if (it != channels.end())
{
it->channelText = color + msg;
it->newMessages = true;
}
}
catch(std::out_of_range &e) {}
}
else
mHistory->addText(color + msg);
LOG_MESSAGE_SIMPLE(Log::LOG_INFO, "%s", msg.c_str());
}
void GUIChat::send(const std::string &str)
{
LocalPlayer *localPlayer = Main::get().getLocalPlayer();
Networking *networking = Main::get().getNetworking();
localPlayer->chat.action = Chat::Action::print;
localPlayer->chat.channel = currentChannel;
localPlayer->chat.message = str;
networking->getPlayerPacket(ID_CHAT_MESSAGE)->setPlayer(localPlayer);
networking->getPlayerPacket(ID_CHAT_MESSAGE)->Send();
}
void GUIChat::clean(unsigned channelId)
{
if (channelId == currentChannel)
mHistory->setCaption("");
else
{
auto it = getChannel(channelId);
if (it != channels.end())
{
it->channelText.clear();
}
}
}
void GUIChat::pressedChatMode()
{
windowState++;
if (windowState == 3) windowState = 0;
std::string chatMode = windowState == CHAT_DISABLED ? "Chat disabled" :
windowState == CHAT_ENABLED ? "Chat enabled" :
"Chat in hidden mode";
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Switch chat mode to %s", chatMode.c_str());
MWBase::Environment::get().getWindowManager()->messageBox(chatMode);
switch (windowState)
{
case CHAT_DISABLED:
this->mMainWidget->setVisible(false);
setEditState(false);
break;
case CHAT_ENABLED:
this->mMainWidget->setVisible(true);
break;
default: //CHAT_HIDDENMODE
this->mMainWidget->setVisible(true);
curTime = 0;
}
}
void GUIChat::setEditState(bool state)
{
editState = state;
mCommandLine->setVisible(editState);
mBoxChannels->setVisible(editState);
MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(editState ? mCommandLine : nullptr);
}
void GUIChat::pressedSay()
{
if (windowState == CHAT_DISABLED)
return;
if (!mCommandLine->getVisible())
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Opening chat.");
if (windowState == CHAT_HIDDENMODE)
{
setVisible(true);
curTime = 0;
}
setEditState(true);
}
void GUIChat::keyPress(MyGUI::Widget *_sender, MyGUI::KeyCode key, MyGUI::Char _char)
{
if (mCommandHistory.empty()) return;
// Traverse history with up and down arrows
if (key == MyGUI::KeyCode::ArrowUp)
{
// If the user was editing a string, store it for later
if (mCurrent == mCommandHistory.end())
mEditString = mCommandLine->getOnlyText();
if (mCurrent != mCommandHistory.begin())
{
--mCurrent;
mCommandLine->setCaption(*mCurrent);
}
}
else if (key == MyGUI::KeyCode::ArrowDown)
{
if (mCurrent != mCommandHistory.end())
{
++mCurrent;
if (mCurrent != mCommandHistory.end())
mCommandLine->setCaption(*mCurrent);
else
// Restore the edit string
mCommandLine->setCaption(mEditString);
}
}
}
void GUIChat::update(float dt)
{
if (windowState == CHAT_HIDDENMODE && !editState && isVisible())
{
curTime += dt;
if (curTime >= delay)
{
setEditState(false);
this->mMainWidget->setVisible(false);
}
}
if (netStat)
{
auto rss = Main::get().getNetworking()->getNetworkStatistics();
mHistory->setCaption(rss);
}
static float time = 0;
time += dt;
if (time >= 1)
{
time = 0;
static bool phase = false;
phase = !phase;
auto color = phase ? MyGUI::Colour::Blue : defaultColor;
for (auto it = channels.begin(); it != channels.end(); ++it)
{
if (!it->newMessages || it->channel == currentChannel)
continue;
long pos = it - channels.begin();
if (pos < page * pageM)
mChannelPrevBtn->setTextColour(color);
else if (pos >= page * pageM + 3)
mChannelNextBtn->setTextColour(color);
else
{
for (auto &btn : mChannelBtns)
{
if (it->channelName != btn->getCaption().asUTF8())
continue;
btn->setTextColour(color);
break;
}
}
}
}
}
void GUIChat::setCaption(const std::string &str)
{
mHistory->setCaption(str);
}
void GUIChat::setDelay(float delay)
{
this->delay = delay;
}
void GUIChat::switchNetstat()
{
netStat = !netStat;
}
void GUIChat::addChannel(unsigned ch, const std::string &name)
{
auto channel = getChannel(ch);
if (channel == channels.end())
{
LOG_MESSAGE_SIMPLE(Log::LOG_VERBOSE, "Adding channel id: %d %s", ch, name);
channels.push_back(ChannelData{ch, name.substr(0, 9), "", false});
}
redrawChannels();
}
void GUIChat::renameChannel(unsigned ch, const std::string &newName)
{
auto it = getChannel(ch);
if (it != channels.end())
{
it->channelName = newName.substr(0, 9);
redrawChannels();
}
}
void GUIChat::setChannel(const std::string &channel, bool saveHistory)
{
auto ch = channel.substr(0, 9);
auto it = std::find_if(channels.begin(), channels.end(), [&ch](const ChannelData &item) {
return item.channelName == ch;
});
if (it != channels.end())
setChannel(it, saveHistory);
}
void GUIChat::setChannel(unsigned ch, bool saveHistory)
{
auto it = getChannel(ch);
if (it != channels.end())
setChannel(it, saveHistory);
}
void GUIChat::setChannel(ChannelIter it, bool saveHistory)
{
if (saveHistory && !mHistory->getCaption().empty())
getChannel(currentChannel)->channelText = mHistory->getCaption();
it->newMessages = false;
mHistory->setCaption(it->channelText);
currentChannel = it->channel;
redrawChannels();
}
void GUIChat::closeChannel(unsigned ch)
{
if (ch == 0) // that's impossible
return;
auto it = getChannel(ch);
if (it != channels.end())
{
if (ch == it->channel)
setChannel(0, false); // reset to default channel
channels.erase(it);
}
redrawChannels();
}
void GUIChat::redrawChannels()
{
mChannelPrevBtn->setVisible(page != 0);
mChannelNextBtn->setVisible(channels.size() > 3 && page != lastPage());
mChannelPrevBtn->setTextColour(defaultColor);
mChannelNextBtn->setTextColour(defaultColor);
if (page >=lastPage())
page = lastPage();
unsigned showElems = page * pageM + 3;
if (showElems > channels.size())
showElems = static_cast<unsigned>(channels.size());
auto it = channels.begin() + page * pageM;
auto endIt = channels.begin() + showElems;
for (auto &btn : mChannelBtns)
{
if (it == endIt)
btn->setVisible(false);
else
{
btn->setVisible(true);
if (currentChannel == it->channel)
{
setTitle("Chat: " + it->channelName + "(" + std::to_string(it->channel) + ")");
btn->setEnabled(false);
btn->setStateSelected(true);
btn->setTextColour(MyGUI::Colour::Red);
}
else
{
btn->setEnabled(true);
btn->setTextColour(defaultColor);
}
btn->setCaption(it++->channelName);
}
}
}
void GUIChat::nextChannel(MyGUI::Widget* _sender)
{
page++;
if (page > lastPage())
page = lastPage();
redrawChannels();
}
void GUIChat::prevChannel(MyGUI::Widget* _sender)
{
if (page > 0)
page--;
redrawChannels();
}
void GUIChat::onClickChannel(MyGUI::Widget *_sender)
{
auto sender = dynamic_cast<MyGUI::Button*>(_sender);
setChannel(sender->getCaption().asUTF8());
}
unsigned GUIChat::lastPage()
{
return static_cast<unsigned>(channels.size() / pageM + channels.size() % pageM - 1);
}
GUIChat::ChannelIter GUIChat::getChannel(unsigned ch)
{
return std::find_if(channels.begin(), channels.end(), [&ch](const ChannelData &data){
return data.channel == ch;
});
}
}