diff --git a/lib/irrlicht/include/GlyphLayout.h b/lib/irrlicht/include/GlyphLayout.h index d7d37028e..2aeb20010 100644 --- a/lib/irrlicht/include/GlyphLayout.h +++ b/lib/irrlicht/include/GlyphLayout.h @@ -7,6 +7,7 @@ #include "irrTypes.h" #include "dimension2d.h" +#include "rect.h" #include #include @@ -275,6 +276,71 @@ inline void breakGlyphLayouts(std::vector& gls, f32 max_line_width, } } +inline bool getDrawOffset(const core::rect& position, bool hcenter, + bool vcenter, const std::vector& gls, + f32 inverse_shaping, s32 font_max_height, + s32 glyph_max_height, f32 scale, + const core::rect* clip, + core::position2d* out_offset, + f32* out_next_line_height, + std::vector* out_width_per_line) +{ + core::position2d offset(f32(position.UpperLeftCorner.X), + f32(position.UpperLeftCorner.Y)); + core::dimension2d text_dimension; + std::vector 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 clippedRect(core::position2d + (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). */ diff --git a/lib/irrlicht/include/IGUIFont.h b/lib/irrlicht/include/IGUIFont.h index 21b152a36..e3ae503be 100644 --- a/lib/irrlicht/include/IGUIFont.h +++ b/lib/irrlicht/include/IGUIFont.h @@ -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 diff --git a/lib/irrlicht/include/IGUIStaticText.h b/lib/irrlicht/include/IGUIStaticText.h index f69441fea..bfce93e53 100644 --- a/lib/irrlicht/include/IGUIStaticText.h +++ b/lib/irrlicht/include/IGUIStaticText.h @@ -10,6 +10,7 @@ #include #include +#include #include namespace irr diff --git a/lib/irrlicht/source/Irrlicht/CGUIStaticText.cpp b/lib/irrlicht/source/Irrlicht/CGUIStaticText.cpp index be34b4f25..f94a05396 100644 --- a/lib/irrlicht/source/Irrlicht/CGUIStaticText.cpp +++ b/lib/irrlicht/source/Irrlicht/CGUIStaticText.cpp @@ -90,28 +90,13 @@ void CGUIStaticText::draw() breakText(); core::rect 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* 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* ou if (m_glyph_layouts.empty()) return -1; + core::rect 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 width_per_line = gui::getGlyphLayoutsWidthPerLine( - m_glyph_layouts, font->getInverseShaping(), font->getScale()); - if (width_per_line.empty()) + bool hcenter; + const core::rect* clip; + getDrawPosition(&draw_pos, &hcenter, &clip); + + core::position2d offset; + f32 next_line_height = 0.0f; + std::vector 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 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* 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* ou } +void CGUIStaticText::getDrawPosition(core::rect* draw_pos, bool* hcenter, const core::rect** clip) +{ + core::rect 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 diff --git a/lib/irrlicht/source/Irrlicht/CGUIStaticText.h b/lib/irrlicht/source/Irrlicht/CGUIStaticText.h index 9b7facc98..a569b2cac 100644 --- a/lib/irrlicht/source/Irrlicht/CGUIStaticText.h +++ b/lib/irrlicht/source/Irrlicht/CGUIStaticText.h @@ -118,6 +118,7 @@ namespace gui //! Breaks the single text line. void breakText(); + void getDrawPosition(core::rect* draw_pos, bool* hcenter, const core::rect** clip); EGUI_ALIGNMENT HAlign, VAlign; bool Border; diff --git a/src/font/font_with_face.cpp b/src/font/font_with_face.cpp index d3cf976a4..d0dcb9b6c 100644 --- a/src/font/font_with_face.cpp +++ b/src/font/font_with_face.cpp @@ -591,56 +591,14 @@ void FontWithFace::render(const std::vector& gl, font_settings->setShadow(true); } - core::position2d offset(float(position.UpperLeftCorner.X), - float(position.UpperLeftCorner.Y)); - core::dimension2d text_dimension; - auto width_per_line = gui::getGlyphLayoutsWidthPerLine(gl, - m_inverse_shaping, scale); - if (width_per_line.empty()) + core::position2d offset; + f32 next_line_height = 0.0f; + std::vector 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 clippedRect(core::position2d - (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 > indices; diff --git a/src/font/font_with_face.hpp b/src/font/font_with_face.hpp index c05fbe07e..d749101ed 100644 --- a/src/font/font_with_face.hpp +++ b/src/font/font_with_face.hpp @@ -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; } diff --git a/src/guiengine/scalable_font.cpp b/src/guiengine/scalable_font.cpp index 202268cdc..43294f28c 100644 --- a/src/guiengine/scalable_font.cpp +++ b/src/guiengine/scalable_font.cpp @@ -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 diff --git a/src/guiengine/scalable_font.hpp b/src/guiengine/scalable_font.hpp index 498f5fd89..6b40135b8 100644 --- a/src/guiengine/scalable_font.hpp +++ b/src/guiengine/scalable_font.hpp @@ -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 diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index eb0d9706e..acb5f55e1 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -265,9 +265,7 @@ void NetworkingLobby::init() if (mouse.Event == EMIE_LMOUSE_PRESSED_DOWN) { std::shared_ptr 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;