mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-30 12:32:36 +00:00
28131fd62b
These warnings were always enabled, but we didn't see them due to https://gitlab.com/OpenMW/openmw/-/issues/7882. I do not fully understand the cause of 7822 as I can't repro it in a minimal CMake project. Some of these fixes are thought through. Some are sensible best guesses. Some are kind of a stab in the dark as I don't know whether there was a possible bug the warning was telling me about that I've done nothing to help by introducing a static_cast. Nearly all of these warnings were about some kind of narrowing conversion, so I'm not sure why they weren't firing with GCC and Clang, which have -Wall -Wextra -pedantic set, which should imply -Wnarrowing, and they can't have been affected by 7882. There were also some warnings being triggered from Boost code. The vast majority of library headers that do questionable things weren't firing warnings off, but for some reason, /external:I wasn't putting these Boost headers into external mode. We need these warnings dealt with one way or another so we can switch the default Windows CI from MSBuild (which doesn't do ccache) to Ninja (which does). I have the necessary magic for that on a branch, but the branch won't build because of these warnings.
435 lines
14 KiB
C++
435 lines
14 KiB
C++
#include "messagebox.hpp"
|
|
|
|
#include <MyGUI_Button.h>
|
|
#include <MyGUI_EditBox.h>
|
|
#include <MyGUI_LanguageManager.h>
|
|
#include <MyGUI_RenderManager.h>
|
|
#include <MyGUI_UString.h>
|
|
|
|
#include <components/debug/debuglog.hpp>
|
|
#include <components/misc/strings/algorithm.hpp>
|
|
|
|
#include "../mwbase/environment.hpp"
|
|
#include "../mwbase/inputmanager.hpp"
|
|
#include "../mwbase/windowmanager.hpp"
|
|
|
|
namespace MWGui
|
|
{
|
|
|
|
MessageBoxManager::MessageBoxManager(float timePerChar)
|
|
{
|
|
mStaticMessageBox = nullptr;
|
|
mLastButtonPressed = -1;
|
|
mMessageBoxSpeed = timePerChar;
|
|
}
|
|
|
|
MessageBoxManager::~MessageBoxManager()
|
|
{
|
|
MessageBoxManager::clear();
|
|
}
|
|
|
|
std::size_t MessageBoxManager::getMessagesCount()
|
|
{
|
|
return mMessageBoxes.size();
|
|
}
|
|
|
|
void MessageBoxManager::clear()
|
|
{
|
|
if (mInterMessageBoxe)
|
|
{
|
|
mInterMessageBoxe->setVisible(false);
|
|
mInterMessageBoxe.reset();
|
|
}
|
|
|
|
mMessageBoxes.clear();
|
|
mStaticMessageBox = nullptr;
|
|
|
|
mLastButtonPressed = -1;
|
|
}
|
|
|
|
void MessageBoxManager::resetInteractiveMessageBox()
|
|
{
|
|
if (mInterMessageBoxe)
|
|
{
|
|
mInterMessageBoxe->setVisible(false);
|
|
mInterMessageBoxe.reset();
|
|
}
|
|
}
|
|
|
|
void MessageBoxManager::setLastButtonPressed(int index)
|
|
{
|
|
mLastButtonPressed = index;
|
|
}
|
|
|
|
void MessageBoxManager::onFrame(float frameDuration)
|
|
{
|
|
for (auto it = mMessageBoxes.begin(); it != mMessageBoxes.end();)
|
|
{
|
|
(*it)->mCurrentTime += frameDuration;
|
|
if ((*it)->mCurrentTime >= (*it)->mMaxTime && it->get() != mStaticMessageBox)
|
|
{
|
|
it = mMessageBoxes.erase(it);
|
|
}
|
|
else
|
|
++it;
|
|
}
|
|
|
|
float height = 0;
|
|
auto it = mMessageBoxes.begin();
|
|
while (it != mMessageBoxes.end())
|
|
{
|
|
(*it)->update(static_cast<int>(height));
|
|
height += (*it)->getHeight();
|
|
++it;
|
|
}
|
|
|
|
if (mInterMessageBoxe != nullptr && mInterMessageBoxe->mMarkedToDelete)
|
|
{
|
|
mLastButtonPressed = mInterMessageBoxe->readPressedButton();
|
|
mInterMessageBoxe->setVisible(false);
|
|
mInterMessageBoxe.reset();
|
|
MWBase::Environment::get().getInputManager()->changeInputMode(
|
|
MWBase::Environment::get().getWindowManager()->isGuiMode());
|
|
}
|
|
}
|
|
|
|
void MessageBoxManager::createMessageBox(std::string_view message, bool stat)
|
|
{
|
|
auto box = std::make_unique<MessageBox>(*this, message);
|
|
box->mCurrentTime = 0;
|
|
auto realMessage = MyGUI::LanguageManager::getInstance().replaceTags({ message.data(), message.size() });
|
|
box->mMaxTime = realMessage.length() * mMessageBoxSpeed;
|
|
|
|
if (stat)
|
|
mStaticMessageBox = box.get();
|
|
|
|
box->setVisible(mVisible);
|
|
|
|
mMessageBoxes.push_back(std::move(box));
|
|
|
|
if (mMessageBoxes.size() > 3)
|
|
{
|
|
mMessageBoxes.erase(mMessageBoxes.begin());
|
|
}
|
|
|
|
int height = 0;
|
|
for (const auto& messageBox : mMessageBoxes)
|
|
{
|
|
messageBox->update(height);
|
|
height += messageBox->getHeight();
|
|
}
|
|
}
|
|
|
|
void MessageBoxManager::removeStaticMessageBox()
|
|
{
|
|
removeMessageBox(mStaticMessageBox);
|
|
mStaticMessageBox = nullptr;
|
|
}
|
|
|
|
bool MessageBoxManager::createInteractiveMessageBox(
|
|
std::string_view message, const std::vector<std::string>& buttons, bool immediate, int defaultFocus)
|
|
{
|
|
if (mInterMessageBoxe != nullptr)
|
|
{
|
|
Log(Debug::Warning) << "Warning: replacing an interactive message box that was not answered yet";
|
|
mInterMessageBoxe->setVisible(false);
|
|
}
|
|
|
|
mInterMessageBoxe
|
|
= std::make_unique<InteractiveMessageBox>(*this, std::string{ message }, buttons, immediate, defaultFocus);
|
|
mLastButtonPressed = -1;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool MessageBoxManager::isInteractiveMessageBox()
|
|
{
|
|
return mInterMessageBoxe != nullptr;
|
|
}
|
|
|
|
bool MessageBoxManager::removeMessageBox(MessageBox* msgbox)
|
|
{
|
|
for (auto it = mMessageBoxes.begin(); it != mMessageBoxes.end(); ++it)
|
|
{
|
|
if (it->get() == msgbox)
|
|
{
|
|
mMessageBoxes.erase(it);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const std::vector<std::unique_ptr<MessageBox>>& MessageBoxManager::getActiveMessageBoxes() const
|
|
{
|
|
return mMessageBoxes;
|
|
}
|
|
|
|
int MessageBoxManager::readPressedButton(bool reset)
|
|
{
|
|
int pressed = mLastButtonPressed;
|
|
if (reset)
|
|
mLastButtonPressed = -1;
|
|
return pressed;
|
|
}
|
|
|
|
void MessageBoxManager::setVisible(bool value)
|
|
{
|
|
mVisible = value;
|
|
for (const auto& messageBox : mMessageBoxes)
|
|
messageBox->setVisible(value);
|
|
}
|
|
|
|
MessageBox::MessageBox(MessageBoxManager& parMessageBoxManager, std::string_view message)
|
|
: Layout("openmw_messagebox.layout")
|
|
, mCurrentTime(0)
|
|
, mMaxTime(0)
|
|
, mMessageBoxManager(parMessageBoxManager)
|
|
, mMessage(message)
|
|
{
|
|
// defines
|
|
mBottomPadding = 48;
|
|
mNextBoxPadding = 4;
|
|
|
|
getWidget(mMessageWidget, "message");
|
|
|
|
mMessageWidget->setCaptionWithReplacing(mMessage);
|
|
}
|
|
|
|
void MessageBox::update(int height)
|
|
{
|
|
MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
|
|
MyGUI::IntPoint pos;
|
|
pos.left = (gameWindowSize.width - mMainWidget->getWidth()) / 2;
|
|
pos.top = (gameWindowSize.height - mMainWidget->getHeight() - height - mBottomPadding);
|
|
|
|
mMainWidget->setPosition(pos);
|
|
}
|
|
|
|
int MessageBox::getHeight()
|
|
{
|
|
return mMainWidget->getHeight() + mNextBoxPadding;
|
|
}
|
|
|
|
void MessageBox::setVisible(bool value)
|
|
{
|
|
mMainWidget->setVisible(value);
|
|
}
|
|
|
|
InteractiveMessageBox::InteractiveMessageBox(MessageBoxManager& parMessageBoxManager, const std::string& message,
|
|
const std::vector<std::string>& buttons, bool immediate, int defaultFocus)
|
|
: WindowModal(MWBase::Environment::get().getWindowManager()->isGuiMode()
|
|
? "openmw_interactive_messagebox_notransp.layout"
|
|
: "openmw_interactive_messagebox.layout")
|
|
, mMessageBoxManager(parMessageBoxManager)
|
|
, mButtonPressed(-1)
|
|
, mDefaultFocus(defaultFocus)
|
|
, mImmediate(immediate)
|
|
{
|
|
int textPadding = 10; // padding between text-widget and main-widget
|
|
int textButtonPadding = 10; // padding between the text-widget und the button-widget
|
|
int buttonLeftPadding = 10; // padding between the buttons if horizontal
|
|
int buttonTopPadding = 10; // ^-- if vertical
|
|
int buttonLabelLeftPadding = 12; // padding between button label and button itself, from left
|
|
int buttonLabelTopPadding = 4; // padding between button label and button itself, from top
|
|
int buttonMainPadding = 10; // padding between buttons and bottom of the main widget
|
|
|
|
mMarkedToDelete = false;
|
|
|
|
getWidget(mMessageWidget, "message");
|
|
getWidget(mButtonsWidget, "buttons");
|
|
|
|
mMessageWidget->setSize(400, mMessageWidget->getHeight());
|
|
mMessageWidget->setCaptionWithReplacing(message);
|
|
|
|
MyGUI::IntSize textSize = mMessageWidget->getTextSize();
|
|
|
|
MyGUI::IntSize gameWindowSize = MyGUI::RenderManager::getInstance().getViewSize();
|
|
|
|
int biggestButtonWidth = 0;
|
|
int buttonsWidth = 0;
|
|
int buttonsHeight = 0;
|
|
int buttonHeight = 0;
|
|
MyGUI::IntCoord dummyCoord(0, 0, 0, 0);
|
|
|
|
for (const std::string& buttonId : buttons)
|
|
{
|
|
MyGUI::Button* button = mButtonsWidget->createWidget<MyGUI::Button>(
|
|
MyGUI::WidgetStyle::Child, std::string("MW_Button"), dummyCoord, MyGUI::Align::Default);
|
|
button->setCaptionWithReplacing(buttonId);
|
|
|
|
button->eventMouseButtonClick += MyGUI::newDelegate(this, &InteractiveMessageBox::mousePressed);
|
|
|
|
mButtons.push_back(button);
|
|
|
|
if (buttonsWidth != 0)
|
|
buttonsWidth += buttonLeftPadding;
|
|
|
|
int buttonWidth = button->getTextSize().width + 2 * buttonLabelLeftPadding;
|
|
buttonsWidth += buttonWidth;
|
|
|
|
buttonHeight = button->getTextSize().height + 2 * buttonLabelTopPadding;
|
|
|
|
if (buttonsHeight != 0)
|
|
buttonsHeight += buttonTopPadding;
|
|
buttonsHeight += buttonHeight;
|
|
|
|
if (buttonWidth > biggestButtonWidth)
|
|
{
|
|
biggestButtonWidth = buttonWidth;
|
|
}
|
|
}
|
|
|
|
MyGUI::IntSize mainWidgetSize;
|
|
if (buttonsWidth < textSize.width)
|
|
{
|
|
// on one line
|
|
mainWidgetSize.width = textSize.width + 3 * textPadding;
|
|
mainWidgetSize.height
|
|
= textPadding + textSize.height + textButtonPadding + buttonHeight + buttonMainPadding;
|
|
|
|
MyGUI::IntSize realSize = mainWidgetSize +
|
|
// To account for borders
|
|
(mMainWidget->getSize() - mMainWidget->getClientWidget()->getSize());
|
|
|
|
MyGUI::IntPoint absPos;
|
|
absPos.left = (gameWindowSize.width - realSize.width) / 2;
|
|
absPos.top = (gameWindowSize.height - realSize.height) / 2;
|
|
|
|
mMainWidget->setPosition(absPos);
|
|
mMainWidget->setSize(realSize);
|
|
|
|
MyGUI::IntCoord messageWidgetCoord;
|
|
messageWidgetCoord.left = (mainWidgetSize.width - textSize.width) / 2;
|
|
messageWidgetCoord.top = textPadding;
|
|
mMessageWidget->setCoord(messageWidgetCoord);
|
|
|
|
mMessageWidget->setSize(textSize);
|
|
|
|
MyGUI::IntCoord buttonCord;
|
|
MyGUI::IntSize buttonSize(0, buttonHeight);
|
|
int left = (mainWidgetSize.width - buttonsWidth) / 2;
|
|
|
|
for (MyGUI::Button* button : mButtons)
|
|
{
|
|
buttonCord.left = left;
|
|
buttonCord.top = messageWidgetCoord.top + textSize.height + textButtonPadding;
|
|
|
|
buttonSize.width = button->getTextSize().width + 2 * buttonLabelLeftPadding;
|
|
buttonSize.height = button->getTextSize().height + 2 * buttonLabelTopPadding;
|
|
|
|
button->setCoord(buttonCord);
|
|
button->setSize(buttonSize);
|
|
|
|
left += buttonSize.width + buttonLeftPadding;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// among each other
|
|
if (biggestButtonWidth > textSize.width)
|
|
{
|
|
mainWidgetSize.width = biggestButtonWidth + buttonTopPadding * 2;
|
|
}
|
|
else
|
|
{
|
|
mainWidgetSize.width = textSize.width + 3 * textPadding;
|
|
}
|
|
|
|
MyGUI::IntCoord buttonCord;
|
|
MyGUI::IntSize buttonSize(0, buttonHeight);
|
|
|
|
int top = textPadding + textSize.height + textButtonPadding;
|
|
|
|
for (MyGUI::Button* button : mButtons)
|
|
{
|
|
buttonSize.width = button->getTextSize().width + buttonLabelLeftPadding * 2;
|
|
buttonSize.height = button->getTextSize().height + buttonLabelTopPadding * 2;
|
|
|
|
buttonCord.top = top;
|
|
buttonCord.left = (mainWidgetSize.width - buttonSize.width) / 2;
|
|
|
|
button->setCoord(buttonCord);
|
|
button->setSize(buttonSize);
|
|
|
|
top += buttonSize.height + buttonTopPadding;
|
|
}
|
|
|
|
mainWidgetSize.height
|
|
= textPadding + textSize.height + textButtonPadding + buttonsHeight + buttonMainPadding;
|
|
mMainWidget->setSize(mainWidgetSize +
|
|
// To account for borders
|
|
(mMainWidget->getSize() - mMainWidget->getClientWidget()->getSize()));
|
|
|
|
MyGUI::IntPoint absPos;
|
|
absPos.left = (gameWindowSize.width - mainWidgetSize.width) / 2;
|
|
absPos.top = (gameWindowSize.height - mainWidgetSize.height) / 2;
|
|
|
|
mMainWidget->setPosition(absPos);
|
|
|
|
MyGUI::IntCoord messageWidgetCoord;
|
|
messageWidgetCoord.left = (mainWidgetSize.width - textSize.width) / 2;
|
|
messageWidgetCoord.top = textPadding;
|
|
messageWidgetCoord.width = textSize.width;
|
|
messageWidgetCoord.height = textSize.height;
|
|
mMessageWidget->setCoord(messageWidgetCoord);
|
|
}
|
|
|
|
setVisible(true);
|
|
}
|
|
|
|
MyGUI::Widget* InteractiveMessageBox::getDefaultKeyFocus()
|
|
{
|
|
if (mDefaultFocus >= 0 && mDefaultFocus < static_cast<int>(mButtons.size()))
|
|
return mButtons[mDefaultFocus];
|
|
auto& languageManager = MyGUI::LanguageManager::getInstance();
|
|
std::vector<MyGUI::UString> keywords{ languageManager.replaceTags("#{sOk}"),
|
|
languageManager.replaceTags("#{sYes}") };
|
|
|
|
for (MyGUI::Button* button : mButtons)
|
|
{
|
|
for (const MyGUI::UString& keyword : keywords)
|
|
{
|
|
if (Misc::StringUtils::ciEqual(keyword, button->getCaption()))
|
|
{
|
|
return button;
|
|
}
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
void InteractiveMessageBox::mousePressed(MyGUI::Widget* pressed)
|
|
{
|
|
buttonActivated(pressed);
|
|
}
|
|
|
|
void InteractiveMessageBox::buttonActivated(MyGUI::Widget* pressed)
|
|
{
|
|
mMarkedToDelete = true;
|
|
int index = 0;
|
|
for (const MyGUI::Button* button : mButtons)
|
|
{
|
|
if (button == pressed)
|
|
{
|
|
mButtonPressed = index;
|
|
mMessageBoxManager.onButtonPressed(mButtonPressed);
|
|
if (!mImmediate)
|
|
return;
|
|
|
|
mMessageBoxManager.setLastButtonPressed(mButtonPressed);
|
|
MWBase::Environment::get().getInputManager()->changeInputMode(
|
|
MWBase::Environment::get().getWindowManager()->isGuiMode());
|
|
return;
|
|
}
|
|
index++;
|
|
}
|
|
}
|
|
|
|
int InteractiveMessageBox::readPressedButton()
|
|
{
|
|
return mButtonPressed;
|
|
}
|
|
|
|
}
|