diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp index 9eda4286ff3..6a926d19080 100644 --- a/gui/ThemeEngine.cpp +++ b/gui/ThemeEngine.cpp @@ -1665,11 +1665,11 @@ int ThemeEngine::getStringWidth(const Common::U32String &str, FontStyle font) co return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getStringWidth(str) : 0; } -int ThemeEngine::getCharWidth(byte c, FontStyle font) const { +int ThemeEngine::getCharWidth(uint32 c, FontStyle font) const { return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getCharWidth(c) : 0; } -int ThemeEngine::getKerningOffset(byte left, byte right, FontStyle font) const { +int ThemeEngine::getKerningOffset(uint32 left, uint32 right, FontStyle font) const { return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getKerningOffset(left, right) : 0; } diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h index 0c0b5fdaa95..2e21abd0e17 100644 --- a/gui/ThemeEngine.h +++ b/gui/ThemeEngine.h @@ -432,9 +432,9 @@ public: int getStringWidth(const Common::U32String &str, FontStyle font = kFontStyleBold) const; - int getCharWidth(byte c, FontStyle font = kFontStyleBold) const; + int getCharWidth(uint32 c, FontStyle font = kFontStyleBold) const; - int getKerningOffset(byte left, byte right, FontStyle font = kFontStyleBold) const; + int getKerningOffset(uint32 left, uint32 right, FontStyle font = kFontStyleBold) const; //@} diff --git a/gui/editgamedialog.cpp b/gui/editgamedialog.cpp index 259f7b2e7c1..7b3bdf5d147 100644 --- a/gui/editgamedialog.cpp +++ b/gui/editgamedialog.cpp @@ -92,7 +92,7 @@ public: : EditTextWidget(boss, name, text, tooltip) {} protected: - bool tryInsertChar(byte c, int pos) override { + bool tryInsertChar(Common::u32char_type_t c, int pos) override { if (Common::isAlnum(c) || c == '-' || c == '_') { _editString.insertChar(c, pos); return true; diff --git a/gui/gui-manager.h b/gui/gui-manager.h index 3127788b3e0..66df2f6acdb 100644 --- a/gui/gui-manager.h +++ b/gui/gui-manager.h @@ -115,8 +115,8 @@ public: int getFontHeight(ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return _theme->getFontHeight(style); } int getStringWidth(const Common::String &str, ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return _theme->getStringWidth(str, style); } int getStringWidth(const Common::U32String &str, ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return _theme->getStringWidth(str, style); } - int getCharWidth(byte c, ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return _theme->getCharWidth(c, style); } - int getKerningOffset(byte left, byte right, ThemeEngine::FontStyle font = ThemeEngine::kFontStyleBold) const { return _theme->getKerningOffset(left, right, font); } + int getCharWidth(uint32 c, ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return _theme->getCharWidth(c, style); } + int getKerningOffset(uint32 left, uint32 right, ThemeEngine::FontStyle font = ThemeEngine::kFontStyleBold) const { return _theme->getKerningOffset(left, right, font); } /** * Tell the GuiManager to check whether the screen resolution has changed. diff --git a/gui/widgets/editable.cpp b/gui/widgets/editable.cpp index 8591911c9cf..7c0f384a505 100644 --- a/gui/widgets/editable.cpp +++ b/gui/widgets/editable.cpp @@ -21,6 +21,7 @@ #include "common/rect.h" #include "common/system.h" +#include "common/unicode-bidi.h" #include "gui/widgets/editable.h" #include "gui/gui-manager.h" #include "graphics/font.h" @@ -75,7 +76,7 @@ void EditableWidget::setEditString(const Common::U32String &str) { _caretPos = 0; } -bool EditableWidget::tryInsertChar(byte c, int pos) { +bool EditableWidget::tryInsertChar(Common::u32char_type_t c, int pos) { if ((c >= 32 && c <= 127) || c >= 160) { _editString.insertChar(c, pos); return true; @@ -83,6 +84,14 @@ bool EditableWidget::tryInsertChar(byte c, int pos) { return false; } +int EditableWidget::caretVisualPos(int logicalPos) { + return Common::convertBiDiU32String(_editString + " ").getVisualPosition(logicalPos); +} + +int EditableWidget::caretLogicalPos() const { + return Common::convertBiDiU32String(_editString + " ").getLogicalPosition(_caretPos); +} + void EditableWidget::handleTickle() { uint32 time = g_system->getMillis(); if (_caretTime < time && isEnabled()) { @@ -95,6 +104,7 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) { bool handled = true; bool dirty = false; bool forcecaret = false; + int deleteIndex; if (!isEnabled()) return false; @@ -139,9 +149,11 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) { break; case Common::KEYCODE_BACKSPACE: - if (_caretPos > 0) { - _caretPos--; - _editString.deleteChar(_caretPos); + deleteIndex = caretLogicalPos(); + if (deleteIndex > 0) { + deleteIndex--; + _editString.deleteChar(deleteIndex); + setCaretPos(caretVisualPos(deleteIndex)); dirty = true; sendCommand(_cmd, 0); @@ -150,8 +162,10 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) { break; case Common::KEYCODE_DELETE: - if (_caretPos < (int)_editString.size()) { - _editString.deleteChar(_caretPos); + deleteIndex = caretLogicalPos(); + if (deleteIndex < (int)_editString.size()) { + _editString.deleteChar(deleteIndex); + setCaretPos(caretVisualPos(deleteIndex)); dirty = true; sendCommand(_cmd, 0); @@ -162,7 +176,7 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) { case Common::KEYCODE_DOWN: case Common::KEYCODE_END: // Move caret to end - setCaretPos(_editString.size()); + setCaretPos(caretVisualPos(_editString.size())); forcecaret = true; dirty = true; break; @@ -188,7 +202,7 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) { case Common::KEYCODE_UP: case Common::KEYCODE_HOME: // Move caret to start - setCaretPos(0); + setCaretPos(caretVisualPos(0)); forcecaret = true; dirty = true; break; @@ -198,8 +212,9 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) { if (g_system->hasTextInClipboard()) { Common::U32String text = g_system->getTextFromClipboard(); for (uint32 i = 0; i < text.size(); ++i) { - if (tryInsertChar(text[i], _caretPos)) - ++_caretPos; + const int logicalPosition = caretLogicalPos(); + if (tryInsertChar(text[i], logicalPosition)) + setCaretPos(caretVisualPos(logicalPosition + 1)); } dirty = true; } @@ -261,8 +276,9 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) { } void EditableWidget::defaultKeyDownHandler(Common::KeyState &state, bool &dirty, bool &forcecaret, bool &handled) { - if (state.ascii < 256 && tryInsertChar((byte)state.ascii, _caretPos)) { - _caretPos++; + const int logicalPosition = caretLogicalPos(); + if (tryInsertChar(state.ascii, logicalPosition)) { + setCaretPos(caretVisualPos(logicalPosition + 1)); dirty = true; forcecaret = true; @@ -273,7 +289,8 @@ void EditableWidget::defaultKeyDownHandler(Common::KeyState &state, bool &dirty, } int EditableWidget::getCaretOffset() const { - Common::U32String substr(_editString.begin(), _editString.begin() + _caretPos); + Common::UnicodeBiDiText utxt(_editString); + Common::U32String substr(utxt.visual.begin(), utxt.visual.begin() + _caretPos); return g_gui.getStringWidth(substr, _font) - _editScrollOffset; } @@ -313,15 +330,16 @@ void EditableWidget::drawCaret(bool erase) { g_gui.theme()->drawCaret(Common::Rect(x, y, x + 1, y + editRect.height()), erase); if (erase) { - Common::String character; + Common::U32String character; int width; if ((uint)_caretPos < _editString.size()) { - const byte chr = _editString[_caretPos]; + Common::UnicodeBiDiText utxt(_editString); + const Common::u32char_type_t chr = utxt.visual[_caretPos]; width = g_gui.getCharWidth(chr, _font); - character = chr; + character = Common::U32String(chr); - const uint last = (_caretPos > 0) ? _editString[_caretPos - 1] : 0; + const uint32 last = (_caretPos > 0) ? utxt.visual[_caretPos - 1] : 0; x += g_gui.getKerningOffset(last, chr, _font); } else { // We draw a fake space here to assure that removing the caret diff --git a/gui/widgets/editable.h b/gui/widgets/editable.h index 551c0175a68..d64eb317214 100644 --- a/gui/widgets/editable.h +++ b/gui/widgets/editable.h @@ -94,7 +94,10 @@ protected: void setFontStyle(ThemeEngine::FontStyle font) { _font = font; } - virtual bool tryInsertChar(byte c, int pos); + virtual bool tryInsertChar(Common::u32char_type_t c, int pos); + + int caretVisualPos(int logicalPos); + int caretLogicalPos() const; }; } // End of namespace GUI