[Scummvm-git-logs] scummvm master -> b67b88e6d99072d23dd978bf22b066d56496b33c

sev- noreply at scummvm.org
Tue Aug 2 20:04:57 UTC 2022


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
b67b88e6d9 GUI: Support unicode and BiDi in editable widget


Commit: b67b88e6d99072d23dd978bf22b066d56496b33c
    https://github.com/scummvm/scummvm/commit/b67b88e6d99072d23dd978bf22b066d56496b33c
Author: BLooperZ (blooperz at users.noreply.github.com)
Date: 2022-08-02T22:04:54+02:00

Commit Message:
GUI: Support unicode and BiDi in editable widget

Changed paths:
    gui/ThemeEngine.cpp
    gui/ThemeEngine.h
    gui/editgamedialog.cpp
    gui/gui-manager.h
    gui/widgets/editable.cpp
    gui/widgets/editable.h


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




More information about the Scummvm-git-logs mailing list