Share FontWithFace render code with getCluster for more functionality
This commit is contained in:
parent
4deeac7dc8
commit
8f41b721ed
@ -7,6 +7,7 @@
|
||||
|
||||
#include "irrTypes.h"
|
||||
#include "dimension2d.h"
|
||||
#include "rect.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
@ -275,6 +276,71 @@ inline void breakGlyphLayouts(std::vector<GlyphLayout>& gls, f32 max_line_width,
|
||||
}
|
||||
}
|
||||
|
||||
inline bool getDrawOffset(const core::rect<s32>& position, bool hcenter,
|
||||
bool vcenter, const std::vector<GlyphLayout>& gls,
|
||||
f32 inverse_shaping, s32 font_max_height,
|
||||
s32 glyph_max_height, f32 scale,
|
||||
const core::rect<s32>* clip,
|
||||
core::position2d<f32>* out_offset,
|
||||
f32* out_next_line_height,
|
||||
std::vector<f32>* out_width_per_line)
|
||||
{
|
||||
core::position2d<f32> offset(f32(position.UpperLeftCorner.X),
|
||||
f32(position.UpperLeftCorner.Y));
|
||||
core::dimension2d<s32> text_dimension;
|
||||
std::vector<f32> width_per_line = gui::getGlyphLayoutsWidthPerLine(gls,
|
||||
inverse_shaping, scale);
|
||||
if (width_per_line.empty())
|
||||
return false;
|
||||
|
||||
bool too_long_broken_text = false;
|
||||
f32 next_line_height = font_max_height * scale;
|
||||
if (width_per_line.size() > 1 &&
|
||||
width_per_line.size() * next_line_height > position.getHeight())
|
||||
{
|
||||
// Make too long broken text draw as fit as possible
|
||||
next_line_height = (f32)position.getHeight() / width_per_line.size();
|
||||
too_long_broken_text = true;
|
||||
}
|
||||
|
||||
// The offset must be round to integer when setting the offests
|
||||
// or * inverse_shaping, so the glyph is drawn without blurring effects
|
||||
if (hcenter || vcenter || clip)
|
||||
{
|
||||
text_dimension = gui::getGlyphLayoutsDimension(
|
||||
gls, next_line_height, inverse_shaping, scale);
|
||||
|
||||
if (hcenter)
|
||||
{
|
||||
offset.X += (s32)(
|
||||
(position.getWidth() - width_per_line[0]) / 2.0f);
|
||||
}
|
||||
if (vcenter)
|
||||
{
|
||||
if (too_long_broken_text)
|
||||
offset.Y -= (s32)
|
||||
((font_max_height - glyph_max_height) * scale);
|
||||
else
|
||||
{
|
||||
offset.Y += (s32)(
|
||||
(position.getHeight() - text_dimension.Height) / 2.0f);
|
||||
}
|
||||
}
|
||||
if (clip)
|
||||
{
|
||||
core::rect<s32> clippedRect(core::position2d<s32>
|
||||
(s32(offset.X), s32(offset.Y)), text_dimension);
|
||||
clippedRect.clipAgainst(*clip);
|
||||
if (!clippedRect.isValid())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*out_offset = offset;
|
||||
*out_next_line_height = next_line_height;
|
||||
*out_width_per_line = width_per_line;
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace Private
|
||||
{
|
||||
/** Used it only for single line (ie without line breaking mark). */
|
||||
|
@ -127,6 +127,9 @@ public:
|
||||
virtual f32 getInverseShaping() const = 0;
|
||||
virtual f32 getScale() const = 0;
|
||||
virtual void setScale(f32 scale) = 0;
|
||||
//! Return FontWithFace properties from stk-code, override later in scalable font. */
|
||||
virtual s32 getFaceFontMaxHeight() const { return getDimension(L"X").Height; }
|
||||
virtual s32 getFaceGlyphMaxHeight() const { return getDimension(L"X").Height; }
|
||||
};
|
||||
|
||||
} // end namespace gui
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace irr
|
||||
|
@ -90,28 +90,13 @@ void CGUIStaticText::draw()
|
||||
breakText();
|
||||
|
||||
core::rect<s32> r = frameRect;
|
||||
auto dim = getGlyphLayoutsDimension(m_glyph_layouts,
|
||||
font->getHeightPerLine(), font->getInverseShaping(), font->getScale());
|
||||
|
||||
s32 totalHeight = dim.Height;
|
||||
if (VAlign == EGUIA_CENTER)
|
||||
{
|
||||
r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
|
||||
}
|
||||
else if (VAlign == EGUIA_LOWERRIGHT)
|
||||
{
|
||||
r.UpperLeftCorner.Y = r.LowerRightCorner.Y - totalHeight;
|
||||
}
|
||||
|
||||
|
||||
if (HAlign == EGUIA_LOWERRIGHT)
|
||||
{
|
||||
r.UpperLeftCorner.X = frameRect.LowerRightCorner.X - dim.Width;
|
||||
}
|
||||
bool hcenter;
|
||||
const core::rect<s32>* clip;
|
||||
getDrawPosition(&r, &hcenter, &clip);
|
||||
|
||||
font->draw(m_glyph_layouts, r,
|
||||
OverrideColorEnabled ? OverrideColor : skin->getColor(isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT),
|
||||
HAlign == EGUIA_CENTER, false, (RestrainTextInside ? &AbsoluteClippingRect : NULL));
|
||||
hcenter, false, clip);
|
||||
}
|
||||
}
|
||||
|
||||
@ -405,40 +390,49 @@ s32 CGUIStaticText::getCluster(int x, int y, std::shared_ptr<std::u32string>* ou
|
||||
if (m_glyph_layouts.empty())
|
||||
return -1;
|
||||
|
||||
core::rect<s32> draw_pos = AbsoluteRect;
|
||||
IGUISkin* skin = Environment->getSkin();
|
||||
if (!skin)
|
||||
return -1;
|
||||
if (Border)
|
||||
draw_pos.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X);
|
||||
|
||||
IGUIFont* font = getActiveFont();
|
||||
std::vector<f32> width_per_line = gui::getGlyphLayoutsWidthPerLine(
|
||||
m_glyph_layouts, font->getInverseShaping(), font->getScale());
|
||||
if (width_per_line.empty())
|
||||
bool hcenter;
|
||||
const core::rect<s32>* clip;
|
||||
getDrawPosition(&draw_pos, &hcenter, &clip);
|
||||
|
||||
core::position2d<float> offset;
|
||||
f32 next_line_height = 0.0f;
|
||||
std::vector<f32> width_per_line;
|
||||
if (!gui::getDrawOffset(draw_pos, hcenter, false, m_glyph_layouts,
|
||||
font->getInverseShaping(), font->getFaceFontMaxHeight(),
|
||||
font->getFaceGlyphMaxHeight(), font->getScale(), clip, &offset,
|
||||
&next_line_height, &width_per_line))
|
||||
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]);
|
||||
if (!hcenter && rtl)
|
||||
offset.X += (s32)(draw_pos.getWidth() - width_per_line[0]);
|
||||
|
||||
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();
|
||||
}
|
||||
unsigned cur_line = 0;
|
||||
bool line_changed = false;
|
||||
|
||||
int idx = -1;
|
||||
core::recti r;
|
||||
r.UpperLeftCorner.X = r.LowerRightCorner.X = offset;
|
||||
r.LowerRightCorner.Y = (int)next_line_height;
|
||||
bool line_changed = false;
|
||||
core::recti test_rect;
|
||||
test_rect.UpperLeftCorner.X = test_rect.LowerRightCorner.X = (s32)offset.X;
|
||||
test_rect.UpperLeftCorner.Y = (s32)offset.Y;
|
||||
test_rect.LowerRightCorner.Y = (s32)offset.Y + (s32)next_line_height;
|
||||
|
||||
for (unsigned i = 0; i < m_glyph_layouts.size(); i++)
|
||||
{
|
||||
const GlyphLayout& glyph_layout = m_glyph_layouts[i];
|
||||
// Newline handling (from font with face render)
|
||||
if ((glyph_layout.flags & GLF_NEWLINE) != 0)
|
||||
{
|
||||
r.UpperLeftCorner.Y += (int)next_line_height;
|
||||
r.LowerRightCorner.Y += (int)next_line_height;
|
||||
test_rect.UpperLeftCorner.Y += (int)next_line_height;
|
||||
test_rect.LowerRightCorner.Y += (int)next_line_height;
|
||||
cur_line++;
|
||||
line_changed = true;
|
||||
continue;
|
||||
@ -447,18 +441,25 @@ s32 CGUIStaticText::getCluster(int x, int y, std::shared_ptr<std::u32string>* ou
|
||||
{
|
||||
line_changed = false;
|
||||
rtl = (glyph_layout.flags & gui::GLF_RTL_LINE) != 0;
|
||||
offset = 0;
|
||||
if (rtl)
|
||||
offset.X = float(draw_pos.UpperLeftCorner.X);
|
||||
if (hcenter)
|
||||
{
|
||||
offset = (s32)
|
||||
(position.getWidth() - width_per_line[cur_line]);
|
||||
offset.X += (s32)(
|
||||
(draw_pos.getWidth() - width_per_line.at(cur_line)) / 2.f);
|
||||
}
|
||||
r.UpperLeftCorner.X = r.LowerRightCorner.X = offset;
|
||||
else if (rtl)
|
||||
{
|
||||
offset.X +=
|
||||
(s32)(draw_pos.getWidth() - width_per_line.at(cur_line));
|
||||
}
|
||||
test_rect.UpperLeftCorner.X = test_rect.LowerRightCorner.X =
|
||||
(s32)offset.X;
|
||||
}
|
||||
r.LowerRightCorner.X += int(
|
||||
(float)glyph_layout.x_advance * font->getInverseShaping() *
|
||||
test_rect.LowerRightCorner.X += s32(
|
||||
(f32)glyph_layout.x_advance * font->getInverseShaping() *
|
||||
font->getScale());
|
||||
if (r.isPointInside(p))
|
||||
|
||||
if (test_rect.isPointInside(p))
|
||||
{
|
||||
idx = i;
|
||||
break;
|
||||
@ -476,6 +477,35 @@ s32 CGUIStaticText::getCluster(int x, int y, std::shared_ptr<std::u32string>* ou
|
||||
}
|
||||
|
||||
|
||||
void CGUIStaticText::getDrawPosition(core::rect<s32>* draw_pos, bool* hcenter, const core::rect<s32>** clip)
|
||||
{
|
||||
core::rect<s32> r = *draw_pos;
|
||||
IGUIFont* font = getActiveFont();
|
||||
auto dim = getGlyphLayoutsDimension(m_glyph_layouts,
|
||||
font->getHeightPerLine(), font->getInverseShaping(), font->getScale());
|
||||
|
||||
s32 totalHeight = dim.Height;
|
||||
if (VAlign == EGUIA_CENTER)
|
||||
{
|
||||
r.UpperLeftCorner.Y = r.getCenter().Y - (totalHeight / 2);
|
||||
}
|
||||
else if (VAlign == EGUIA_LOWERRIGHT)
|
||||
{
|
||||
r.UpperLeftCorner.Y = r.LowerRightCorner.Y - totalHeight;
|
||||
}
|
||||
|
||||
if (HAlign == EGUIA_LOWERRIGHT)
|
||||
{
|
||||
r.UpperLeftCorner.X = AbsoluteRect.LowerRightCorner.X - dim.Width;
|
||||
}
|
||||
|
||||
*draw_pos = r;
|
||||
*hcenter = (HAlign == EGUIA_CENTER);
|
||||
*clip = (RestrainTextInside ? &AbsoluteClippingRect : NULL);
|
||||
|
||||
}
|
||||
|
||||
|
||||
} // end namespace gui
|
||||
} // end namespace irr
|
||||
|
||||
|
@ -118,6 +118,7 @@ namespace gui
|
||||
|
||||
//! Breaks the single text line.
|
||||
void breakText();
|
||||
void getDrawPosition(core::rect<s32>* draw_pos, bool* hcenter, const core::rect<s32>** clip);
|
||||
|
||||
EGUI_ALIGNMENT HAlign, VAlign;
|
||||
bool Border;
|
||||
|
@ -591,56 +591,14 @@ void FontWithFace::render(const std::vector<gui::GlyphLayout>& gl,
|
||||
font_settings->setShadow(true);
|
||||
}
|
||||
|
||||
core::position2d<float> offset(float(position.UpperLeftCorner.X),
|
||||
float(position.UpperLeftCorner.Y));
|
||||
core::dimension2d<s32> text_dimension;
|
||||
auto width_per_line = gui::getGlyphLayoutsWidthPerLine(gl,
|
||||
m_inverse_shaping, scale);
|
||||
if (width_per_line.empty())
|
||||
core::position2d<float> offset;
|
||||
f32 next_line_height = 0.0f;
|
||||
std::vector<f32> width_per_line;
|
||||
if (!gui::getDrawOffset(position, hcenter, vcenter, gl, m_inverse_shaping,
|
||||
m_font_max_height, m_glyph_max_height, scale, clip, &offset,
|
||||
&next_line_height, &width_per_line))
|
||||
return;
|
||||
|
||||
bool too_long_broken_text = false;
|
||||
float next_line_height = m_font_max_height * scale;
|
||||
if (width_per_line.size() > 1 &&
|
||||
width_per_line.size() * next_line_height > position.getHeight())
|
||||
{
|
||||
// Make too long broken text draw as fit as possible
|
||||
next_line_height = (float)position.getHeight() / width_per_line.size();
|
||||
too_long_broken_text = true;
|
||||
}
|
||||
|
||||
// The offset must be round to integer when setting the offests
|
||||
// or * m_inverse_shaping, so the glyph is drawn without blurring effects
|
||||
if (hcenter || vcenter || clip)
|
||||
{
|
||||
text_dimension = gui::getGlyphLayoutsDimension(
|
||||
gl, next_line_height, m_inverse_shaping, scale);
|
||||
|
||||
if (hcenter)
|
||||
{
|
||||
offset.X += (s32)(
|
||||
(position.getWidth() - width_per_line[0]) / 2.0f);
|
||||
}
|
||||
if (vcenter)
|
||||
{
|
||||
if (too_long_broken_text)
|
||||
offset.Y -= (s32)
|
||||
((m_font_max_height - m_glyph_max_height) * scale);
|
||||
else
|
||||
{
|
||||
offset.Y += (s32)(
|
||||
(position.getHeight() - text_dimension.Height) / 2.0f);
|
||||
}
|
||||
}
|
||||
if (clip)
|
||||
{
|
||||
core::rect<s32> clippedRect(core::position2d<s32>
|
||||
(s32(offset.X), s32(offset.Y)), text_dimension);
|
||||
clippedRect.clipAgainst(*clip);
|
||||
if (!clippedRect.isValid()) return;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect character locations
|
||||
const unsigned int text_size = gl.size();
|
||||
std::vector<std::pair<s32, bool> > indices;
|
||||
|
@ -300,6 +300,8 @@ public:
|
||||
// ------------------------------------------------------------------------
|
||||
int getFontMaxHeight() const { return m_font_max_height; }
|
||||
// ------------------------------------------------------------------------
|
||||
int getGlyphMaxHeight() const { return m_glyph_max_height; }
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool disableTextShaping() const { return false; }
|
||||
// ------------------------------------------------------------------------
|
||||
float getInverseShaping() const { return m_inverse_shaping; }
|
||||
|
@ -176,5 +176,25 @@ f32 ScalableFont::getInverseShaping() const
|
||||
#endif
|
||||
} // getShapingScale
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
s32 ScalableFont::getFaceFontMaxHeight() const
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
return m_face->getFontMaxHeight();
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
} // getFaceFontMaxHeight
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
s32 ScalableFont::getFaceGlyphMaxHeight() const
|
||||
{
|
||||
#ifndef SERVER_ONLY
|
||||
return m_face->getGlyphMaxHeight();
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
} // getFaceGlyphMaxHeight
|
||||
|
||||
} // end namespace gui
|
||||
} // end namespace irr
|
||||
|
@ -125,7 +125,10 @@ public:
|
||||
virtual void setInvisibleCharacters( const wchar_t *s ) {}
|
||||
// ------------------------------------------------------------------------
|
||||
virtual f32 getInverseShaping() const;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
virtual s32 getFaceFontMaxHeight() const;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual s32 getFaceGlyphMaxHeight() const;
|
||||
};
|
||||
|
||||
} // end namespace gui
|
||||
|
@ -265,9 +265,7 @@ void NetworkingLobby::init()
|
||||
if (mouse.Event == EMIE_LMOUSE_PRESSED_DOWN)
|
||||
{
|
||||
std::shared_ptr<std::u32string> s;
|
||||
int cluster = text->getCluster(
|
||||
mouse.X - text->getAbsolutePosition().UpperLeftCorner.X,
|
||||
mouse.Y - text->getAbsolutePosition().UpperLeftCorner.Y, &s);
|
||||
int cluster = text->getCluster(mouse.X, mouse.Y, &s);
|
||||
if (cluster == -1 || (unsigned)cluster > s->size())
|
||||
return false;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user