Add Arabic text shaping support for chat functionality

This commit introduces Arabic text shaping in the chat application by adding `ArabicShaping.cpp` and `ArabicShaping.h` for handling contextual forms and visual reordering.

The rendering logic in `ChatScreen.cpp` is updated to utilize this new functionality, adjusting cursor positions accordingly. Other UI components, including `UIControl_Base.cpp`, `UIControl_Label.cpp`, and `UIControl_SaveList.cpp`, are modified to ensure proper display of Arabic text.

Additionally, `Font.cpp` is enhanced with methods for efficient rendering of pre-shaped text.
This commit is contained in:
Revela committed 2026-03-17 17:08:58 -05:00
1 parent d473ef0dc5
commit e786604228
17 files changed
+717 -28

No files matched your search

+11 -4
View File
@@ -3,6 +3,7 @@
#include "UIControl.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include "..\..\..\Minecraft.World\JavaMath.h"
#include "..\..\..\Minecraft.World\ArabicShaping.h"
UIControl_Base::UIControl_Base()
{
@@ -32,13 +33,16 @@ void UIControl_Base::tick()
//app.DebugPrintf("Calling SetLabel - '%ls'\n", m_label.c_str());
m_bLabelChanged = false;
// Shape the text before sending to Iggy; m_label stays unshaped for future updates
wstring shaped = shapeArabicText(m_label.getString());
IggyDataValue result;
IggyDataValue value[1];
value[0].type = IGGY_DATATYPE_string_UTF16;
IggyStringUTF16 stringVal;
stringVal.string = (IggyUTF16*) m_label.c_str();
stringVal.length = m_label.length();
stringVal.string = (IggyUTF16*) shaped.c_str();
stringVal.length = (int)shaped.length();
value[0].string16 = stringVal;
IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath() , m_setLabelFunc , 1 , value );
@@ -56,13 +60,16 @@ void UIControl_Base::setLabel(UIString label, bool instant, bool force)
{
m_bLabelChanged = false;
// Shape the text before sending to Iggy; m_label stays unshaped for future updates
wstring shaped = shapeArabicText(m_label.getString());
IggyDataValue result;
IggyDataValue value[1];
value[0].type = IGGY_DATATYPE_string_UTF16;
IggyStringUTF16 stringVal;
stringVal.string = (IggyUTF16*)m_label.c_str();
stringVal.length = m_label.length();
stringVal.string = (IggyUTF16*) shaped.c_str();
stringVal.length = (int)shaped.length();
value[0].string16 = stringVal;
IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath() , m_setLabelFunc , 1 , value );
@@ -2,6 +2,7 @@
#include "UI.h"
#include "UIControl_Label.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include "..\..\..\Minecraft.World\ArabicShaping.h"
UIControl_Label::UIControl_Label()
{
@@ -22,13 +23,15 @@ void UIControl_Label::init(UIString label)
{
m_label = label;
wstring shaped = shapeArabicText(m_label.getString());
IggyDataValue result;
IggyDataValue value[1];
value[0].type = IGGY_DATATYPE_string_UTF16;
IggyStringUTF16 stringVal;
stringVal.string = (IggyUTF16*)label.c_str();
stringVal.length = label.length();
stringVal.string = (IggyUTF16*)shaped.c_str();
stringVal.length = (int)shaped.length();
value[0].string16 = stringVal;
IggyResult out = IggyPlayerCallMethodRS ( m_parentScene->getMovie() , &result, getIggyValuePath() , m_initFunc , 1 , value );
}
@@ -1,6 +1,7 @@
#include "stdafx.h"
#include "UI.h"
#include "UIControl_SaveList.h"
#include "..\..\..\Minecraft.World\ArabicShaping.h"
bool UIControl_SaveList::setupControl(UIScene *scene, IggyValuePath *parent, const string &controlName)
{
@@ -69,12 +70,14 @@ void UIControl_SaveList::addItem(const string &label, const wstring &iconName, i
void UIControl_SaveList::addItem(const wstring &label, const wstring &iconName, int data)
{
wstring shaped = shapeArabicText(label);
IggyDataValue result;
IggyDataValue value[3];
IggyStringUTF16 stringVal;
stringVal.string = (IggyUTF16*)label.c_str();
stringVal.length = static_cast<S32>(label.length());
stringVal.string = (IggyUTF16*)shaped.c_str();
stringVal.length = static_cast<S32>(shaped.length());
value[0].type = IGGY_DATATYPE_string_UTF16;
value[0].string16 = stringVal;
@@ -255,7 +255,7 @@ UIScene_LoadMenu::UIScene_LoadMenu(int iPad, void *initData, UILayer *parentLaye
{
wchar_t wSaveName[128];
ZeroMemory(wSaveName, sizeof(wSaveName));
mbstowcs(wSaveName, params->saveDetails->UTF8SaveName, 127);
MultiByteToWideChar(CP_UTF8, 0, params->saveDetails->UTF8SaveName, -1, wSaveName, 127);
m_levelName = wstring(wSaveName);
m_labelGameName.init(m_levelName);
}
@@ -49,7 +49,7 @@ static wstring ReadLevelNameFromSaveFile(const wstring& filePath, bool *outHardc
if (len > 0)
{
wchar_t wbuf[128] = {};
mbstowcs(wbuf, buf, 127);
MultiByteToWideChar(CP_UTF8, 0, buf, -1, wbuf, 127);
return wstring(wbuf);
}
}
@@ -785,8 +785,11 @@ void UIScene_LoadOrJoinMenu::tick()
if (!levelName.empty())
{
m_buttonListSaves.addItem(levelName, wstring(L""));
wcstombs(m_saveDetails[i].UTF8SaveName, levelName.c_str(), 127);
m_saveDetails[i].UTF8SaveName[127] = '\0';
{
int n = WideCharToMultiByte(CP_UTF8, 0, levelName.c_str(), -1, m_saveDetails[i].UTF8SaveName, 127, nullptr, nullptr);
if (n <= 0) m_saveDetails[i].UTF8SaveName[0] = '\0';
m_saveDetails[i].UTF8SaveName[127] = '\0';
}
}
else
{
@@ -1431,9 +1434,9 @@ int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,boo
for (int k = 0; k < 127 && ui16Text[k]; k++)
wNewName[k] = static_cast<wchar_t>(ui16Text[k]);
// Convert to narrow for storage and in-memory update
char narrowName[128] = {};
wcstombs(narrowName, wNewName, 127);
// Convert to narrow for storage and in-memory update (UTF-8 to preserve Unicode)
char narrowName[256] = {};
WideCharToMultiByte(CP_UTF8, 0, wNewName, -1, narrowName, 255, nullptr, nullptr);
// Build the sidecar path: Windows64\GameHDD\{folder}\worldname.txt
wchar_t wFilename[MAX_SAVEFILENAME_LENGTH] = {};
@@ -1449,7 +1452,7 @@ int UIScene_LoadOrJoinMenu::KeyboardCompleteWorldNameCallback(LPVOID lpParam,boo
// Update the in-memory display name so the list reflects it immediately
strncpy_s(pClass->m_saveDetails[listPos].UTF8SaveName, narrowName, 127);
pClass->m_saveDetails[listPos].UTF8SaveName[127] = '\0';
pClass->m_saveDetails[listPos].UTF8SaveName[127] = '\0'; // UTF8SaveName is still 128 bytes; narrowName fits as Arabic is <=2 bytes/char in UTF-8
// Reuse the existing callback to trigger the list repopulate
UIScene_LoadOrJoinMenu::RenameSaveDataReturned(pClass, true);
@@ -2517,7 +2520,7 @@ int UIScene_LoadOrJoinMenu::SaveOptionsDialogReturned(void *pParam,int iPad,C4JS
{
wchar_t wSaveName[128];
ZeroMemory(wSaveName, 128 * sizeof(wchar_t));
mbstowcs_s(nullptr, wSaveName, 128, pClass->m_saveDetails[pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC].UTF8SaveName, _TRUNCATE);
MultiByteToWideChar(CP_UTF8, 0, pClass->m_saveDetails[pClass->m_iSaveListIndex - pClass->m_iDefaultButtonsC].UTF8SaveName, -1, wSaveName, 127);
UIKeyboardInitData kbData;
kbData.title = app.GetString(IDS_RENAME_WORLD_TITLE);
kbData.defaultText = wSaveName;