GUI: Support unicode and BiDi in editable widget
This commit is contained in:
parent
14e61b0590
commit
b67b88e6d9
6 changed files with 46 additions and 25 deletions
|
@ -1665,11 +1665,11 @@ int ThemeEngine::getStringWidth(const Common::U32String &str, FontStyle font) co
|
||||||
return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getStringWidth(str) : 0;
|
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;
|
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;
|
return ready() ? _texts[fontStyleToData(font)]->_fontPtr->getKerningOffset(left, right) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -432,9 +432,9 @@ public:
|
||||||
|
|
||||||
int getStringWidth(const Common::U32String &str, FontStyle font = kFontStyleBold) const;
|
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;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ public:
|
||||||
: EditTextWidget(boss, name, text, tooltip) {}
|
: EditTextWidget(boss, name, text, tooltip) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool tryInsertChar(byte c, int pos) override {
|
bool tryInsertChar(Common::u32char_type_t c, int pos) override {
|
||||||
if (Common::isAlnum(c) || c == '-' || c == '_') {
|
if (Common::isAlnum(c) || c == '-' || c == '_') {
|
||||||
_editString.insertChar(c, pos);
|
_editString.insertChar(c, pos);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -115,8 +115,8 @@ public:
|
||||||
int getFontHeight(ThemeEngine::FontStyle style = ThemeEngine::kFontStyleBold) const { return _theme->getFontHeight(style); }
|
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::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 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 getCharWidth(uint32 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 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.
|
* Tell the GuiManager to check whether the screen resolution has changed.
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "common/rect.h"
|
#include "common/rect.h"
|
||||||
#include "common/system.h"
|
#include "common/system.h"
|
||||||
|
#include "common/unicode-bidi.h"
|
||||||
#include "gui/widgets/editable.h"
|
#include "gui/widgets/editable.h"
|
||||||
#include "gui/gui-manager.h"
|
#include "gui/gui-manager.h"
|
||||||
#include "graphics/font.h"
|
#include "graphics/font.h"
|
||||||
|
@ -75,7 +76,7 @@ void EditableWidget::setEditString(const Common::U32String &str) {
|
||||||
_caretPos = 0;
|
_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) {
|
if ((c >= 32 && c <= 127) || c >= 160) {
|
||||||
_editString.insertChar(c, pos);
|
_editString.insertChar(c, pos);
|
||||||
return true;
|
return true;
|
||||||
|
@ -83,6 +84,14 @@ bool EditableWidget::tryInsertChar(byte c, int pos) {
|
||||||
return false;
|
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() {
|
void EditableWidget::handleTickle() {
|
||||||
uint32 time = g_system->getMillis();
|
uint32 time = g_system->getMillis();
|
||||||
if (_caretTime < time && isEnabled()) {
|
if (_caretTime < time && isEnabled()) {
|
||||||
|
@ -95,6 +104,7 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
|
||||||
bool handled = true;
|
bool handled = true;
|
||||||
bool dirty = false;
|
bool dirty = false;
|
||||||
bool forcecaret = false;
|
bool forcecaret = false;
|
||||||
|
int deleteIndex;
|
||||||
|
|
||||||
if (!isEnabled())
|
if (!isEnabled())
|
||||||
return false;
|
return false;
|
||||||
|
@ -139,9 +149,11 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Common::KEYCODE_BACKSPACE:
|
case Common::KEYCODE_BACKSPACE:
|
||||||
if (_caretPos > 0) {
|
deleteIndex = caretLogicalPos();
|
||||||
_caretPos--;
|
if (deleteIndex > 0) {
|
||||||
_editString.deleteChar(_caretPos);
|
deleteIndex--;
|
||||||
|
_editString.deleteChar(deleteIndex);
|
||||||
|
setCaretPos(caretVisualPos(deleteIndex));
|
||||||
dirty = true;
|
dirty = true;
|
||||||
|
|
||||||
sendCommand(_cmd, 0);
|
sendCommand(_cmd, 0);
|
||||||
|
@ -150,8 +162,10 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Common::KEYCODE_DELETE:
|
case Common::KEYCODE_DELETE:
|
||||||
if (_caretPos < (int)_editString.size()) {
|
deleteIndex = caretLogicalPos();
|
||||||
_editString.deleteChar(_caretPos);
|
if (deleteIndex < (int)_editString.size()) {
|
||||||
|
_editString.deleteChar(deleteIndex);
|
||||||
|
setCaretPos(caretVisualPos(deleteIndex));
|
||||||
dirty = true;
|
dirty = true;
|
||||||
|
|
||||||
sendCommand(_cmd, 0);
|
sendCommand(_cmd, 0);
|
||||||
|
@ -162,7 +176,7 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
|
||||||
case Common::KEYCODE_DOWN:
|
case Common::KEYCODE_DOWN:
|
||||||
case Common::KEYCODE_END:
|
case Common::KEYCODE_END:
|
||||||
// Move caret to end
|
// Move caret to end
|
||||||
setCaretPos(_editString.size());
|
setCaretPos(caretVisualPos(_editString.size()));
|
||||||
forcecaret = true;
|
forcecaret = true;
|
||||||
dirty = true;
|
dirty = true;
|
||||||
break;
|
break;
|
||||||
|
@ -188,7 +202,7 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
|
||||||
case Common::KEYCODE_UP:
|
case Common::KEYCODE_UP:
|
||||||
case Common::KEYCODE_HOME:
|
case Common::KEYCODE_HOME:
|
||||||
// Move caret to start
|
// Move caret to start
|
||||||
setCaretPos(0);
|
setCaretPos(caretVisualPos(0));
|
||||||
forcecaret = true;
|
forcecaret = true;
|
||||||
dirty = true;
|
dirty = true;
|
||||||
break;
|
break;
|
||||||
|
@ -198,8 +212,9 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
|
||||||
if (g_system->hasTextInClipboard()) {
|
if (g_system->hasTextInClipboard()) {
|
||||||
Common::U32String text = g_system->getTextFromClipboard();
|
Common::U32String text = g_system->getTextFromClipboard();
|
||||||
for (uint32 i = 0; i < text.size(); ++i) {
|
for (uint32 i = 0; i < text.size(); ++i) {
|
||||||
if (tryInsertChar(text[i], _caretPos))
|
const int logicalPosition = caretLogicalPos();
|
||||||
++_caretPos;
|
if (tryInsertChar(text[i], logicalPosition))
|
||||||
|
setCaretPos(caretVisualPos(logicalPosition + 1));
|
||||||
}
|
}
|
||||||
dirty = true;
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
@ -261,8 +276,9 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditableWidget::defaultKeyDownHandler(Common::KeyState &state, bool &dirty, bool &forcecaret, bool &handled) {
|
void EditableWidget::defaultKeyDownHandler(Common::KeyState &state, bool &dirty, bool &forcecaret, bool &handled) {
|
||||||
if (state.ascii < 256 && tryInsertChar((byte)state.ascii, _caretPos)) {
|
const int logicalPosition = caretLogicalPos();
|
||||||
_caretPos++;
|
if (tryInsertChar(state.ascii, logicalPosition)) {
|
||||||
|
setCaretPos(caretVisualPos(logicalPosition + 1));
|
||||||
dirty = true;
|
dirty = true;
|
||||||
forcecaret = true;
|
forcecaret = true;
|
||||||
|
|
||||||
|
@ -273,7 +289,8 @@ void EditableWidget::defaultKeyDownHandler(Common::KeyState &state, bool &dirty,
|
||||||
}
|
}
|
||||||
|
|
||||||
int EditableWidget::getCaretOffset() const {
|
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;
|
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);
|
g_gui.theme()->drawCaret(Common::Rect(x, y, x + 1, y + editRect.height()), erase);
|
||||||
|
|
||||||
if (erase) {
|
if (erase) {
|
||||||
Common::String character;
|
Common::U32String character;
|
||||||
int width;
|
int width;
|
||||||
|
|
||||||
if ((uint)_caretPos < _editString.size()) {
|
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);
|
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);
|
x += g_gui.getKerningOffset(last, chr, _font);
|
||||||
} else {
|
} else {
|
||||||
// We draw a fake space here to assure that removing the caret
|
// We draw a fake space here to assure that removing the caret
|
||||||
|
|
|
@ -94,7 +94,10 @@ protected:
|
||||||
|
|
||||||
void setFontStyle(ThemeEngine::FontStyle font) { _font = font; }
|
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
|
} // End of namespace GUI
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue