Rewrite message queue with GlyphLayout and fix #3922

This commit is contained in:
Benau 2019-06-17 15:48:15 +08:00
parent 2ff899e23e
commit d666a350f6

View File

@ -27,10 +27,7 @@
#include "modes/profile_world.hpp" #include "modes/profile_world.hpp"
#include "utils/synchronised.hpp" #include "utils/synchronised.hpp"
#include "IGUIElement.h" #include "GlyphLayout.h"
#include "IGUIEnvironment.h"
#include "IGUIStaticText.h"
#include <atomic> #include <atomic>
using namespace GUIEngine; using namespace GUIEngine;
@ -96,16 +93,17 @@ private:
* or friend-message::neutral. */ * or friend-message::neutral. */
std::string m_render_type; std::string m_render_type;
/** The text label, can do linebreak if needed. */ /** The text layout, can do linebreak if needed. */
gui::IGUIStaticText* m_text; std::vector<gui::GlyphLayout> m_gls;
/** Drawing rectangle of text layout. */
core::recti m_text_rect;
public: public:
TextMessage(MessageQueue::MessageType mt, const core::stringw &message) : TextMessage(MessageQueue::MessageType mt, const core::stringw &message) :
Message(5.0f) Message(5.0f)
{ {
m_message_type = mt; m_message_type = mt;
m_message = message; m_message = message;
m_text = NULL;
assert(mt != MessageQueue::MT_PROGRESS); assert(mt != MessageQueue::MT_PROGRESS);
if (mt == MessageQueue::MT_ACHIEVEMENT) if (mt == MessageQueue::MT_ACHIEVEMENT)
m_render_type = "achievement-message::neutral"; m_render_type = "achievement-message::neutral";
@ -119,8 +117,6 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
~TextMessage() ~TextMessage()
{ {
assert(m_text != NULL);
m_text->drop();
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Returns the type of the message.*/ /** Returns the type of the message.*/
@ -130,39 +126,75 @@ public:
/** Init the message text, do linebreak as required. */ /** Init the message text, do linebreak as required. */
virtual void init() virtual void init()
{ {
if (m_text)
m_text->drop();
const GUIEngine::BoxRenderParams &brp = const GUIEngine::BoxRenderParams &brp =
GUIEngine::getSkin()->getBoxRenderParams(m_render_type); GUIEngine::getSkin()->getBoxRenderParams(m_render_type);
const unsigned width = irr_driver->getActualScreenSize().Width; const unsigned width = irr_driver->getActualScreenSize().Width;
const unsigned height = irr_driver->getActualScreenSize().Height; const unsigned height = irr_driver->getActualScreenSize().Height;
const unsigned max_width = width - (brp.m_left_border + gui::IGUIFont* font = GUIEngine::getFont();
brp.m_right_border); font->initGlyphLayouts(m_message, m_gls);
m_text = // Reserve space for 5 lines of text, it will occupy the circle
GUIEngine::getGUIEnv()->addStaticText(m_message.c_str(), const int max_width = width - (brp.m_left_border +
core::recti(0, 0, max_width, height)); brp.m_right_border) - (font->getHeightPerLine() * 5);
core::dimension2du dim(m_text->getTextWidth(), if (max_width < 0)
m_text->getTextHeight()); {
dim.Width += brp.m_left_border + brp.m_right_border; m_display_timer = -1;
return;
}
int leftIconSize = dim.Height + 10; gui::breakGlyphLayouts(m_gls, max_width, font->getInverseShaping(),
int x = (width - dim.Width) / 2; font->getScale());
int y = height - int(1.5f * dim.Height); core::dimension2du dim = gui::getGlyphLayoutsDimension(m_gls,
m_area = irr::core::recti(x, y, x + dim.Width, y + dim.Height); font->getHeightPerLine(), font->getInverseShaping(),
m_text->setRelativePosition(irr::core::recti(x + leftIconSize, y, font->getScale());
x + dim.Width - 10, y + dim.Height));
m_text->setTextAlignment(gui::EGUIA_CENTER, gui::EGUIA_CENTER); if ((int)dim.Height > font->getHeightPerLine() * 5)
m_text->grab(); {
m_text->remove(); // Max 5 lines to prevent too long message from network chat
int newline_count = 0;
for (unsigned i = 0; i < m_gls.size(); i++)
{
if (m_gls[i].flags & gui::GLF_NEWLINE)
{
if (++newline_count >= 5)
{
m_gls.erase(m_gls.begin() + i, m_gls.end());
dim.Height = font->getHeightPerLine() * 5;
break;
}
}
}
}
int left_icon_size = dim.Height;
int total_width = dim.Width + brp.m_left_border + brp.m_right_border +
left_icon_size;
int x = (width - total_width) / 2;
int y = height - int(dim.Height) - font->getHeightPerLine() / 2;
if (x < 0 || y < 0)
{
m_gls.clear();
m_display_timer = -1;
return;
}
m_area = irr::core::recti(x, y, x + total_width, y + dim.Height);
m_text_rect = core::recti(x, y, x + left_icon_size + total_width,
y + dim.Height);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** Draw the message. */ /** Draw the message. */
virtual void draw(float dt) virtual void draw(float dt)
{ {
if (m_gls.empty())
{
Message::draw(dt);
return;
}
Message::draw(dt); Message::draw(dt);
GUIEngine::getSkin()->drawMessage(g_container, m_area, m_render_type); GUIEngine::getSkin()->drawMessage(g_container, m_area, m_render_type);
assert(m_text != NULL); GUIEngine::getFont()->draw(m_gls, m_text_rect,
m_text->draw(); GUIEngine::getSkin()->getColor("text::neutral"), true/*hcenter*/);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual void remove() { delete this; } virtual void remove() { delete this; }