summaryrefslogtreecommitdiff
path: root/src/gui/guiEditBox.cpp
diff options
context:
space:
mode:
authorLoïc Blot <nerzhul@users.noreply.github.com>2021-01-07 13:21:12 +0100
committerGitHub <noreply@github.com>2021-01-07 13:21:12 +0100
commit5fcc78a1feeffbc1a4fdd1cfffb49451694786d3 (patch)
treecd42adacba88ea4d99816a2f13f4c44593d89d7c /src/gui/guiEditBox.cpp
parent58a709096ef8ff17644cf201f25b1831d9506514 (diff)
downloadminetest-5fcc78a1feeffbc1a4fdd1cfffb49451694786d3.tar.gz
minetest-5fcc78a1feeffbc1a4fdd1cfffb49451694786d3.tar.bz2
minetest-5fcc78a1feeffbc1a4fdd1cfffb49451694786d3.zip
Refactor/gui editbox (#10787)
Diffstat (limited to 'src/gui/guiEditBox.cpp')
-rw-r--r--src/gui/guiEditBox.cpp724
1 files changed, 724 insertions, 0 deletions
diff --git a/src/gui/guiEditBox.cpp b/src/gui/guiEditBox.cpp
index 159bd38ac..11d080be9 100644
--- a/src/gui/guiEditBox.cpp
+++ b/src/gui/guiEditBox.cpp
@@ -23,10 +23,18 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "IGUIEnvironment.h"
#include "IGUIFont.h"
+#include "porting.h"
+
GUIEditBox::~GUIEditBox()
{
if (m_override_font)
m_override_font->drop();
+
+ if (m_operator)
+ m_operator->drop();
+
+ if (m_vscrollbar)
+ m_vscrollbar->drop();
}
void GUIEditBox::setOverrideFont(IGUIFont *font)
@@ -93,3 +101,719 @@ void GUIEditBox::setAutoScroll(bool enable)
{
m_autoscroll = enable;
}
+
+void GUIEditBox::setPasswordBox(bool password_box, wchar_t password_char)
+{
+ m_passwordbox = password_box;
+ if (m_passwordbox) {
+ m_passwordchar = password_char;
+ setMultiLine(false);
+ setWordWrap(false);
+ m_broken_text.clear();
+ }
+}
+
+//! Sets text justification
+void GUIEditBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical)
+{
+ m_halign = horizontal;
+ m_valign = vertical;
+}
+
+//! Sets the new caption of this element.
+void GUIEditBox::setText(const wchar_t *text)
+{
+ Text = text;
+ if (u32(m_cursor_pos) > Text.size())
+ m_cursor_pos = Text.size();
+ m_hscroll_pos = 0;
+ breakText();
+}
+
+//! Sets the maximum amount of characters which may be entered in the box.
+//! \param max: Maximum amount of characters. If 0, the character amount is
+//! infinity.
+void GUIEditBox::setMax(u32 max)
+{
+ m_max = max;
+
+ if (Text.size() > m_max && m_max != 0)
+ Text = Text.subString(0, m_max);
+}
+
+//! Gets the area of the text in the edit box
+//! \return Returns the size in pixels of the text
+core::dimension2du GUIEditBox::getTextDimension()
+{
+ core::rect<s32> ret;
+
+ setTextRect(0);
+ ret = m_current_text_rect;
+
+ for (u32 i = 1; i < m_broken_text.size(); ++i) {
+ setTextRect(i);
+ ret.addInternalPoint(m_current_text_rect.UpperLeftCorner);
+ ret.addInternalPoint(m_current_text_rect.LowerRightCorner);
+ }
+
+ return core::dimension2du(ret.getSize());
+}
+
+//! Turns the border on or off
+void GUIEditBox::setDrawBorder(bool border)
+{
+ m_border = border;
+}
+
+void GUIEditBox::setWritable(bool can_write_text)
+{
+ m_writable = can_write_text;
+}
+
+//! set text markers
+void GUIEditBox::setTextMarkers(s32 begin, s32 end)
+{
+ if (begin != m_mark_begin || end != m_mark_end) {
+ m_mark_begin = begin;
+ m_mark_end = end;
+ sendGuiEvent(EGET_EDITBOX_MARKING_CHANGED);
+ }
+}
+
+//! send some gui event to parent
+void GUIEditBox::sendGuiEvent(EGUI_EVENT_TYPE type)
+{
+ if (Parent) {
+ SEvent e;
+ e.EventType = EET_GUI_EVENT;
+ e.GUIEvent.Caller = this;
+ e.GUIEvent.Element = 0;
+ e.GUIEvent.EventType = type;
+
+ Parent->OnEvent(e);
+ }
+}
+
+//! called if an event happened.
+bool GUIEditBox::OnEvent(const SEvent &event)
+{
+ if (isEnabled()) {
+
+ switch (event.EventType) {
+ case EET_GUI_EVENT:
+ if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST) {
+ if (event.GUIEvent.Caller == this) {
+ m_mouse_marking = false;
+ setTextMarkers(0, 0);
+ }
+ }
+ break;
+ case EET_KEY_INPUT_EVENT: {
+#if (defined(__linux__) || defined(__FreeBSD__)) || defined(__DragonFly__)
+ // ################################################################
+ // ValkaTR:
+ // This part is the difference from the original intlGUIEditBox
+ // It converts UTF-8 character into a UCS-2 (wchar_t)
+ wchar_t wc = L'_';
+ mbtowc(&wc, (char *)&event.KeyInput.Char,
+ sizeof(event.KeyInput.Char));
+
+ // printf( "char: %lc (%u) \r\n", wc, wc );
+
+ SEvent irrevent(event);
+ irrevent.KeyInput.Char = wc;
+ // ################################################################
+
+ if (processKey(irrevent))
+ return true;
+#else
+ if (processKey(event))
+ return true;
+#endif // defined(linux)
+
+ break;
+ }
+ case EET_MOUSE_INPUT_EVENT:
+ if (processMouse(event))
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return IGUIElement::OnEvent(event);
+}
+
+bool GUIEditBox::processKey(const SEvent &event)
+{
+ if (!m_writable) {
+ return false;
+ }
+
+ if (!event.KeyInput.PressedDown)
+ return false;
+
+ bool text_changed = false;
+ s32 new_mark_begin = m_mark_begin;
+ s32 new_mark_end = m_mark_end;
+
+ // control shortcut handling
+ if (event.KeyInput.Control) {
+
+ // german backlash '\' entered with control + '?'
+ if (event.KeyInput.Char == '\\') {
+ inputChar(event.KeyInput.Char);
+ return true;
+ }
+
+ switch (event.KeyInput.Key) {
+ case KEY_KEY_A:
+ // select all
+ new_mark_begin = 0;
+ new_mark_end = Text.size();
+ break;
+ case KEY_KEY_C:
+ onKeyControlC(event);
+ break;
+ case KEY_KEY_X:
+ text_changed = onKeyControlX(event, new_mark_begin, new_mark_end);
+ break;
+ case KEY_KEY_V:
+ text_changed = onKeyControlV(event, new_mark_begin, new_mark_end);
+ break;
+ case KEY_HOME:
+ // move/highlight to start of text
+ if (event.KeyInput.Shift) {
+ new_mark_end = m_cursor_pos;
+ new_mark_begin = 0;
+ m_cursor_pos = 0;
+ } else {
+ m_cursor_pos = 0;
+ new_mark_begin = 0;
+ new_mark_end = 0;
+ }
+ break;
+ case KEY_END:
+ // move/highlight to end of text
+ if (event.KeyInput.Shift) {
+ new_mark_begin = m_cursor_pos;
+ new_mark_end = Text.size();
+ m_cursor_pos = 0;
+ } else {
+ m_cursor_pos = Text.size();
+ new_mark_begin = 0;
+ new_mark_end = 0;
+ }
+ break;
+ default:
+ return false;
+ }
+ } else {
+ switch (event.KeyInput.Key) {
+ case KEY_END: {
+ s32 p = Text.size();
+ if (m_word_wrap || m_multiline) {
+ p = getLineFromPos(m_cursor_pos);
+ p = m_broken_text_positions[p] +
+ (s32)m_broken_text[p].size();
+ if (p > 0 && (Text[p - 1] == L'\r' ||
+ Text[p - 1] == L'\n'))
+ p -= 1;
+ }
+
+ if (event.KeyInput.Shift) {
+ if (m_mark_begin == m_mark_end)
+ new_mark_begin = m_cursor_pos;
+
+ new_mark_end = p;
+ } else {
+ new_mark_begin = 0;
+ new_mark_end = 0;
+ }
+ m_cursor_pos = p;
+ m_blink_start_time = porting::getTimeMs();
+ } break;
+ case KEY_HOME: {
+
+ s32 p = 0;
+ if (m_word_wrap || m_multiline) {
+ p = getLineFromPos(m_cursor_pos);
+ p = m_broken_text_positions[p];
+ }
+
+ if (event.KeyInput.Shift) {
+ if (m_mark_begin == m_mark_end)
+ new_mark_begin = m_cursor_pos;
+ new_mark_end = p;
+ } else {
+ new_mark_begin = 0;
+ new_mark_end = 0;
+ }
+ m_cursor_pos = p;
+ m_blink_start_time = porting::getTimeMs();
+ } break;
+ case KEY_RETURN:
+ if (m_multiline) {
+ inputChar(L'\n');
+ } else {
+ calculateScrollPos();
+ sendGuiEvent(EGET_EDITBOX_ENTER);
+ }
+ return true;
+ case KEY_LEFT:
+ if (event.KeyInput.Shift) {
+ if (m_cursor_pos > 0) {
+ if (m_mark_begin == m_mark_end)
+ new_mark_begin = m_cursor_pos;
+
+ new_mark_end = m_cursor_pos - 1;
+ }
+ } else {
+ new_mark_begin = 0;
+ new_mark_end = 0;
+ }
+
+ if (m_cursor_pos > 0)
+ m_cursor_pos--;
+ m_blink_start_time = porting::getTimeMs();
+ break;
+ case KEY_RIGHT:
+ if (event.KeyInput.Shift) {
+ if (Text.size() > (u32)m_cursor_pos) {
+ if (m_mark_begin == m_mark_end)
+ new_mark_begin = m_cursor_pos;
+
+ new_mark_end = m_cursor_pos + 1;
+ }
+ } else {
+ new_mark_begin = 0;
+ new_mark_end = 0;
+ }
+
+ if (Text.size() > (u32)m_cursor_pos)
+ m_cursor_pos++;
+ m_blink_start_time = porting::getTimeMs();
+ break;
+ case KEY_UP:
+ if (!onKeyUp(event, new_mark_begin, new_mark_end)) {
+ return false;
+ }
+ break;
+ case KEY_DOWN:
+ if (!onKeyDown(event, new_mark_begin, new_mark_end)) {
+ return false;
+ }
+ break;
+ case KEY_BACK:
+ text_changed = onKeyBack(event, new_mark_begin, new_mark_end);
+ break;
+
+ case KEY_DELETE:
+ text_changed = onKeyDelete(event, new_mark_begin, new_mark_end);
+ break;
+
+ case KEY_ESCAPE:
+ case KEY_TAB:
+ case KEY_SHIFT:
+ case KEY_F1:
+ case KEY_F2:
+ case KEY_F3:
+ case KEY_F4:
+ case KEY_F5:
+ case KEY_F6:
+ case KEY_F7:
+ case KEY_F8:
+ case KEY_F9:
+ case KEY_F10:
+ case KEY_F11:
+ case KEY_F12:
+ case KEY_F13:
+ case KEY_F14:
+ case KEY_F15:
+ case KEY_F16:
+ case KEY_F17:
+ case KEY_F18:
+ case KEY_F19:
+ case KEY_F20:
+ case KEY_F21:
+ case KEY_F22:
+ case KEY_F23:
+ case KEY_F24:
+ // ignore these keys
+ return false;
+
+ default:
+ inputChar(event.KeyInput.Char);
+ return true;
+ }
+ }
+
+ // Set new text markers
+ setTextMarkers(new_mark_begin, new_mark_end);
+
+ // break the text if it has changed
+ if (text_changed) {
+ breakText();
+ sendGuiEvent(EGET_EDITBOX_CHANGED);
+ }
+
+ calculateScrollPos();
+
+ return true;
+}
+
+bool GUIEditBox::onKeyUp(const SEvent &event, s32 &mark_begin, s32 &mark_end)
+{
+ // clang-format off
+ if (m_multiline || (m_word_wrap && m_broken_text.size() > 1)) {
+ s32 lineNo = getLineFromPos(m_cursor_pos);
+ s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos :
+ (m_mark_begin > m_mark_end ? m_mark_begin : m_mark_end);
+ if (lineNo > 0) {
+ s32 cp = m_cursor_pos - m_broken_text_positions[lineNo];
+ if ((s32)m_broken_text[lineNo - 1].size() < cp) {
+ m_cursor_pos = m_broken_text_positions[lineNo - 1] +
+ core::max_((u32)1, m_broken_text[lineNo - 1].size()) - 1;
+ }
+ else
+ m_cursor_pos = m_broken_text_positions[lineNo - 1] + cp;
+ }
+
+ if (event.KeyInput.Shift) {
+ mark_begin = mb;
+ mark_end = m_cursor_pos;
+ } else {
+ mark_begin = 0;
+ mark_end = 0;
+ }
+
+ return true;
+ }
+
+ // clang-format on
+ return false;
+}
+
+bool GUIEditBox::onKeyDown(const SEvent &event, s32 &mark_begin, s32 &mark_end)
+{
+ // clang-format off
+ if (m_multiline || (m_word_wrap && m_broken_text.size() > 1)) {
+ s32 lineNo = getLineFromPos(m_cursor_pos);
+ s32 mb = (m_mark_begin == m_mark_end) ? m_cursor_pos :
+ (m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end);
+ if (lineNo < (s32)m_broken_text.size() - 1) {
+ s32 cp = m_cursor_pos - m_broken_text_positions[lineNo];
+ if ((s32)m_broken_text[lineNo + 1].size() < cp) {
+ m_cursor_pos = m_broken_text_positions[lineNo + 1] +
+ core::max_((u32)1, m_broken_text[lineNo + 1].size()) - 1;
+ }
+ else
+ m_cursor_pos = m_broken_text_positions[lineNo + 1] + cp;
+ }
+
+ if (event.KeyInput.Shift) {
+ mark_begin = mb;
+ mark_end = m_cursor_pos;
+ } else {
+ mark_begin = 0;
+ mark_end = 0;
+ }
+
+ return true;
+ }
+
+ // clang-format on
+ return false;
+}
+
+void GUIEditBox::onKeyControlC(const SEvent &event)
+{
+ // copy to clipboard
+ if (m_passwordbox || !m_operator || m_mark_begin == m_mark_end)
+ return;
+
+ const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+ const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+ core::stringc s;
+ s = Text.subString(realmbgn, realmend - realmbgn).c_str();
+ m_operator->copyToClipboard(s.c_str());
+}
+
+bool GUIEditBox::onKeyControlX(const SEvent &event, s32 &mark_begin, s32 &mark_end)
+{
+ // First copy to clipboard
+ onKeyControlC(event);
+
+ if (m_passwordbox || !m_operator || m_mark_begin == m_mark_end)
+ return false;
+
+ const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+ const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+ // Now remove from box if enabled
+ if (isEnabled()) {
+ // delete
+ core::stringw s;
+ s = Text.subString(0, realmbgn);
+ s.append(Text.subString(realmend, Text.size() - realmend));
+ Text = s;
+
+ m_cursor_pos = realmbgn;
+ mark_begin = 0;
+ mark_end = 0;
+ return true;
+ }
+
+ return false;
+}
+
+bool GUIEditBox::onKeyControlV(const SEvent &event, s32 &mark_begin, s32 &mark_end)
+{
+ if (!isEnabled())
+ return false;
+
+ // paste from the clipboard
+ if (!m_operator)
+ return false;
+
+ const s32 realmbgn = m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+ const s32 realmend = m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+ // add new character
+ if (const c8 *p = m_operator->getTextFromClipboard()) {
+ if (m_mark_begin == m_mark_end) {
+ // insert text
+ core::stringw s = Text.subString(0, m_cursor_pos);
+ s.append(p);
+ s.append(Text.subString(
+ m_cursor_pos, Text.size() - m_cursor_pos));
+
+ if (!m_max || s.size() <= m_max) {
+ Text = s;
+ s = p;
+ m_cursor_pos += s.size();
+ }
+ } else {
+ // replace text
+
+ core::stringw s = Text.subString(0, realmbgn);
+ s.append(p);
+ s.append(Text.subString(realmend, Text.size() - realmend));
+
+ if (!m_max || s.size() <= m_max) {
+ Text = s;
+ s = p;
+ m_cursor_pos = realmbgn + s.size();
+ }
+ }
+ }
+
+ mark_begin = 0;
+ mark_end = 0;
+ return true;
+}
+
+bool GUIEditBox::onKeyBack(const SEvent &event, s32 &mark_begin, s32 &mark_end)
+{
+ if (!isEnabled() || Text.empty())
+ return false;
+
+ core::stringw s;
+
+ if (m_mark_begin != m_mark_end) {
+ // delete marked text
+ const s32 realmbgn =
+ m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+ const s32 realmend =
+ m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+ s = Text.subString(0, realmbgn);
+ s.append(Text.subString(realmend, Text.size() - realmend));
+ Text = s;
+
+ m_cursor_pos = realmbgn;
+ } else {
+ // delete text behind cursor
+ if (m_cursor_pos > 0)
+ s = Text.subString(0, m_cursor_pos - 1);
+ else
+ s = L"";
+ s.append(Text.subString(m_cursor_pos, Text.size() - m_cursor_pos));
+ Text = s;
+ --m_cursor_pos;
+ }
+
+ if (m_cursor_pos < 0)
+ m_cursor_pos = 0;
+ m_blink_start_time = porting::getTimeMs(); // os::Timer::getTime();
+ mark_begin = 0;
+ mark_end = 0;
+ return true;
+}
+
+bool GUIEditBox::onKeyDelete(const SEvent &event, s32 &mark_begin, s32 &mark_end)
+{
+ if (!isEnabled() || Text.empty())
+ return false;
+
+ core::stringw s;
+
+ if (m_mark_begin != m_mark_end) {
+ // delete marked text
+ const s32 realmbgn =
+ m_mark_begin < m_mark_end ? m_mark_begin : m_mark_end;
+ const s32 realmend =
+ m_mark_begin < m_mark_end ? m_mark_end : m_mark_begin;
+
+ s = Text.subString(0, realmbgn);
+ s.append(Text.subString(realmend, Text.size() - realmend));
+ Text = s;
+
+ m_cursor_pos = realmbgn;
+ } else {
+ // delete text before cursor
+ s = Text.subString(0, m_cursor_pos);
+ s.append(Text.subString(
+ m_cursor_pos + 1, Text.size() - m_cursor_pos - 1));
+ Text = s;
+ }
+
+ if (m_cursor_pos > (s32)Text.size())
+ m_cursor_pos = (s32)Text.size();
+
+ m_blink_start_time = porting::getTimeMs(); // os::Timer::getTime();
+ mark_begin = 0;
+ mark_end = 0;
+ return true;
+}
+
+bool GUIEditBox::processMouse(const SEvent &event)
+{
+ switch (event.MouseInput.Event) {
+ case irr::EMIE_LMOUSE_LEFT_UP:
+ if (Environment->hasFocus(this)) {
+ m_cursor_pos = getCursorPos(
+ event.MouseInput.X, event.MouseInput.Y);
+ if (m_mouse_marking) {
+ setTextMarkers(m_mark_begin, m_cursor_pos);
+ }
+ m_mouse_marking = false;
+ calculateScrollPos();
+ return true;
+ }
+ break;
+ case irr::EMIE_MOUSE_MOVED: {
+ if (m_mouse_marking) {
+ m_cursor_pos = getCursorPos(
+ event.MouseInput.X, event.MouseInput.Y);
+ setTextMarkers(m_mark_begin, m_cursor_pos);
+ calculateScrollPos();
+ return true;
+ }
+ } break;
+ case EMIE_LMOUSE_PRESSED_DOWN:
+
+ if (!Environment->hasFocus(this)) {
+ m_blink_start_time = porting::getTimeMs();
+ m_mouse_marking = true;
+ m_cursor_pos = getCursorPos(
+ event.MouseInput.X, event.MouseInput.Y);
+ setTextMarkers(m_cursor_pos, m_cursor_pos);
+ calculateScrollPos();
+ return true;
+ } else {
+ if (!AbsoluteClippingRect.isPointInside(core::position2d<s32>(
+ event.MouseInput.X, event.MouseInput.Y))) {
+ return false;
+ } else {
+ // move cursor
+ m_cursor_pos = getCursorPos(
+ event.MouseInput.X, event.MouseInput.Y);
+
+ s32 newMarkBegin = m_mark_begin;
+ if (!m_mouse_marking)
+ newMarkBegin = m_cursor_pos;
+
+ m_mouse_marking = true;
+ setTextMarkers(newMarkBegin, m_cursor_pos);
+ calculateScrollPos();
+ return true;
+ }
+ }
+ case EMIE_MOUSE_WHEEL:
+ if (m_vscrollbar && m_vscrollbar->isVisible()) {
+ s32 pos = m_vscrollbar->getPos();
+ s32 step = m_vscrollbar->getSmallStep();
+ m_vscrollbar->setPos(pos - event.MouseInput.Wheel * step);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+s32 GUIEditBox::getLineFromPos(s32 pos)
+{
+ if (!m_word_wrap && !m_multiline)
+ return 0;
+
+ s32 i = 0;
+ while (i < (s32)m_broken_text_positions.size()) {
+ if (m_broken_text_positions[i] > pos)
+ return i - 1;
+ ++i;
+ }
+ return (s32)m_broken_text_positions.size() - 1;
+}
+
+void GUIEditBox::updateVScrollBar()
+{
+ if (!m_vscrollbar) {
+ return;
+ }
+
+ // OnScrollBarChanged(...)
+ if (m_vscrollbar->getPos() != m_vscroll_pos) {
+ s32 deltaScrollY = m_vscrollbar->getPos() - m_vscroll_pos;
+ m_current_text_rect.UpperLeftCorner.Y -= deltaScrollY;
+ m_current_text_rect.LowerRightCorner.Y -= deltaScrollY;
+
+ s32 scrollymax = getTextDimension().Height - m_frame_rect.getHeight();
+ if (scrollymax != m_vscrollbar->getMax()) {
+ // manage a newline or a deleted line
+ m_vscrollbar->setMax(scrollymax);
+ m_vscrollbar->setPageSize(s32(getTextDimension().Height));
+ calculateScrollPos();
+ } else {
+ // manage a newline or a deleted line
+ m_vscroll_pos = m_vscrollbar->getPos();
+ }
+ }
+
+ // check if a vertical scrollbar is needed ?
+ if (getTextDimension().Height > (u32)m_frame_rect.getHeight()) {
+ m_frame_rect.LowerRightCorner.X -= m_scrollbar_width;
+
+ s32 scrollymax = getTextDimension().Height - m_frame_rect.getHeight();
+ if (scrollymax != m_vscrollbar->getMax()) {
+ m_vscrollbar->setMax(scrollymax);
+ m_vscrollbar->setPageSize(s32(getTextDimension().Height));
+ }
+
+ if (!m_vscrollbar->isVisible()) {
+ m_vscrollbar->setVisible(true);
+ }
+ } else {
+ if (m_vscrollbar->isVisible()) {
+ m_vscrollbar->setVisible(false);
+ m_vscroll_pos = 0;
+ m_vscrollbar->setPos(0);
+ m_vscrollbar->setMax(1);
+ m_vscrollbar->setPageSize(s32(getTextDimension().Height));
+ }
+ }
+}