Move getCluster code to a dedicated function for later usage

This commit is contained in:
Benau 2021-09-05 00:54:52 +08:00
parent fe5b49e63a
commit 4deeac7dc8
4 changed files with 93 additions and 78 deletions

View File

@ -9,6 +9,7 @@
#include "SColor.h"
#include <functional>
#include <memory>
#include <vector>
namespace irr
@ -125,6 +126,7 @@ namespace gui
virtual void setUseGlyphLayoutsOnly(bool gls_only) = 0;
virtual bool useGlyphLayoutsOnly() const = 0;
virtual void setMouseCallback(std::function<bool(IGUIStaticText* text, SEvent::SMouseInput)> cb) {}
virtual s32 getCluster(int x, int y, std::shared_ptr<std::u32string>* out_orig_str) { return -1; }
};

View File

@ -393,6 +393,89 @@ bool CGUIStaticText::OnEvent(const SEvent& event)
return IGUIElement::OnEvent(event);
}
s32 CGUIStaticText::getCluster(int x, int y, std::shared_ptr<std::u32string>* out_orig_str)
{
core::position2di p;
p.X = x;
p.Y = y;
if (p.X < 0 || p.Y < 0)
return -1;
if (m_glyph_layouts.empty())
return -1;
IGUIFont* font = getActiveFont();
std::vector<f32> width_per_line = gui::getGlyphLayoutsWidthPerLine(
m_glyph_layouts, font->getInverseShaping(), font->getScale());
if (width_per_line.empty())
return -1;
// Check if the line is RTL
core::rect<s32> position = getAbsolutePosition();
bool rtl = (m_glyph_layouts[0].flags & gui::GLF_RTL_LINE) != 0;
int offset = 0;
int cur_line = 0;
if (rtl)
offset = (s32)(position.getWidth() - width_per_line[cur_line]);
float next_line_height = font->getHeightPerLine();
if (width_per_line.size() > 1 &&
width_per_line.size() * next_line_height > position.getHeight())
{
next_line_height = (float)position.getHeight() /
(float)width_per_line.size();
}
int idx = -1;
core::recti r;
r.UpperLeftCorner.X = r.LowerRightCorner.X = offset;
r.LowerRightCorner.Y = (int)next_line_height;
bool line_changed = false;
for (unsigned i = 0; i < m_glyph_layouts.size(); i++)
{
const GlyphLayout& glyph_layout = m_glyph_layouts[i];
if ((glyph_layout.flags & GLF_NEWLINE) != 0)
{
r.UpperLeftCorner.Y += (int)next_line_height;
r.LowerRightCorner.Y += (int)next_line_height;
cur_line++;
line_changed = true;
continue;
}
if (line_changed)
{
line_changed = false;
rtl = (glyph_layout.flags & gui::GLF_RTL_LINE) != 0;
offset = 0;
if (rtl)
{
offset = (s32)
(position.getWidth() - width_per_line[cur_line]);
}
r.UpperLeftCorner.X = r.LowerRightCorner.X = offset;
}
r.LowerRightCorner.X += int(
(float)glyph_layout.x_advance * font->getInverseShaping() *
font->getScale());
if (r.isPointInside(p))
{
idx = i;
break;
}
}
if (idx == -1)
return -1;
std::shared_ptr<std::u32string> s = m_glyph_layouts[idx].orig_string;
unsigned cluster = m_glyph_layouts[idx].cluster.front();
if (cluster > s->size())
return -1;
*out_orig_str = s;
return cluster;
}
} // end namespace gui
} // end namespace irr

View File

@ -113,6 +113,7 @@ namespace gui
//! called if an event happened.
virtual bool OnEvent(const SEvent& event);
virtual void setMouseCallback(std::function<bool(IGUIStaticText* text, SEvent::SMouseInput)> cb) { m_callback = cb; }
virtual s32 getCluster(int x, int y, std::shared_ptr<std::u32string>* out_orig_str);
private:
//! Breaks the single text line.

View File

@ -264,81 +264,11 @@ void NetworkingLobby::init()
{
if (mouse.Event == EMIE_LMOUSE_PRESSED_DOWN)
{
core::position2di p;
p.X = mouse.X - text->getAbsolutePosition().UpperLeftCorner.X;
p.Y = mouse.Y - text->getAbsolutePosition().UpperLeftCorner.Y;
if (p.X < 0 || p.Y < 0)
return false;
const std::vector<GlyphLayout>& gls = text->getGlyphLayouts();
if (gls.empty())
return false;
gui::IGUIFont* font = GUIEngine::getFont();
auto width_per_line = gui::getGlyphLayoutsWidthPerLine(gls,
font->getInverseShaping(), font->getScale());
if (width_per_line.empty())
return false;
// Check if the line is RTL
auto position = text->getAbsolutePosition();
bool rtl = (gls[0].flags & gui::GLF_RTL_LINE) != 0;
int offset = 0;
int cur_line = 0;
if (rtl)
offset = (s32)(position.getWidth() - width_per_line[cur_line]);
float next_line_height = font->getHeightPerLine();
if (width_per_line.size() > 1 &&
width_per_line.size() * next_line_height > position.getHeight())
{
next_line_height = (float)position.getHeight() /
(float)width_per_line.size();
}
int idx = -1;
core::recti r;
r.UpperLeftCorner.X = r.LowerRightCorner.X = offset;
r.LowerRightCorner.Y = (int)next_line_height;
bool line_changed = false;
for (unsigned i = 0; i < gls.size(); i++)
{
const GlyphLayout& glyph_layout = gls[i];
if ((glyph_layout.flags & GLF_NEWLINE) != 0)
{
r.UpperLeftCorner.Y += (int)next_line_height;
r.LowerRightCorner.Y += (int)next_line_height;
cur_line++;
line_changed = true;
continue;
}
if (line_changed)
{
line_changed = false;
rtl = (glyph_layout.flags & gui::GLF_RTL_LINE) != 0;
offset = 0;
if (rtl)
{
offset = (s32)
(position.getWidth() - width_per_line[cur_line]);
}
r.UpperLeftCorner.X = r.LowerRightCorner.X = offset;
}
r.LowerRightCorner.X += int(
(float)glyph_layout.x_advance * font->getInverseShaping() *
font->getScale());
if (r.isPointInside(p))
{
idx = i;
break;
}
}
if (idx == -1)
return false;
auto s = gls[idx].orig_string;
unsigned cluster = gls[idx].cluster.front();
if (cluster > s->size())
std::shared_ptr<std::u32string> s;
int cluster = text->getCluster(
mouse.X - text->getAbsolutePosition().UpperLeftCorner.X,
mouse.Y - text->getAbsolutePosition().UpperLeftCorner.Y, &s);
if (cluster == -1 || (unsigned)cluster > s->size())
return false;
size_t start = s->substr(0, cluster).rfind(U'\n');
@ -351,10 +281,9 @@ void NetworkingLobby::init()
end = s->size();
else
end += cluster - start;
if (idx == -1)
return false;
std::u32string substr = s->substr(start, end);
int local_pos = (int)cluster - (int)start;
int local_pos = cluster - (int)start;
if ((size_t)local_pos > substr.size())
return false;