Full Unicode patch with RTL Support & BiDi logic.
This commit is well documented, so no need to tell you my life story. Full Unicode patch with RTL Support & BiDi logic. Removed the legacy codePage, normalised to UTF8 (65001). It also comes with: CTRL + A : select text (highlighted) CTRL + C : copy CTRL + V : paste CTRL + X : cut CTRL + Y : redo CTRL + Z : undo
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
#include "EterLib/StateManager.h"
|
||||
#include "EterLib/JpegFile.h"
|
||||
#include "PythonGraphic.h"
|
||||
#include <utf8.h>
|
||||
|
||||
bool g_isScreenShotKey = false;
|
||||
|
||||
@@ -307,7 +308,9 @@ bool CPythonGraphic::SaveScreenShot(const char * c_pszFileName)
|
||||
|
||||
if (g_isScreenShotKey)
|
||||
{
|
||||
FILE* srcFilePtr = fopen(c_pszFileName, "rb");
|
||||
// UTF-8 → UTF-16 conversion for Unicode path support
|
||||
std::wstring wFileName = Utf8ToWide(c_pszFileName);
|
||||
FILE* srcFilePtr = _wfopen(wFileName.c_str(), L"rb");
|
||||
if (srcFilePtr)
|
||||
{
|
||||
fseek(srcFilePtr, 0, SEEK_END);
|
||||
@@ -367,8 +370,7 @@ bool CPythonGraphic::SaveScreenShot(const char * c_pszFileName)
|
||||
|
||||
exifHeader[2] = sizeof(exifHeader) + imgDescLen;
|
||||
|
||||
FILE* dstFilePtr = fopen(c_pszFileName, "wb");
|
||||
//FILE* dstFilePtr = fopen("temp.jpg", "wb");
|
||||
FILE* dstFilePtr = _wfopen(wFileName.c_str(), L"wb");
|
||||
if (dstFilePtr)
|
||||
{
|
||||
fwrite(head, sizeof(head), 1, dstFilePtr);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#include "EterLib/Camera.h"
|
||||
#include "EterLib/TextBar.h"
|
||||
|
||||
#include <string>
|
||||
#include <utf8.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
PyObject* grpCreateTextBar(PyObject* poSelf, PyObject* poArgs)
|
||||
@@ -830,35 +832,50 @@ PyObject * grpSaveScreenShotToPath(PyObject * poSelf, PyObject * poArgs)
|
||||
}
|
||||
// END_OF_SCREENSHOT_CWDSAVE
|
||||
|
||||
PyObject * grpSaveScreenShot(PyObject * poSelf, PyObject * poArgs)
|
||||
PyObject* grpSaveScreenShot(PyObject* poSelf, PyObject* poArgs)
|
||||
{
|
||||
struct tm * tmNow;
|
||||
time_t ct;
|
||||
time_t ct = time(nullptr);
|
||||
tm tmNow{};
|
||||
localtime_s(&tmNow, &ct);
|
||||
|
||||
ct = time(0);
|
||||
tmNow = localtime(&ct);
|
||||
wchar_t wPath[MAX_PATH + 256]{};
|
||||
|
||||
char szPath[MAX_PATH + 256];
|
||||
SHGetSpecialFolderPath(NULL, szPath, CSIDL_PERSONAL, TRUE);
|
||||
//GetTempPath();
|
||||
strcat(szPath, "\\METIN2\\");
|
||||
if (!SHGetSpecialFolderPathW(nullptr, wPath, CSIDL_PERSONAL, TRUE))
|
||||
{
|
||||
TraceError("SHGetSpecialFolderPathW failed");
|
||||
return Py_BuildValue("(is)", FALSE, "");
|
||||
}
|
||||
|
||||
if (-1 == _access(szPath, 0))
|
||||
if (!CreateDirectory(szPath, NULL))
|
||||
wcscat_s(wPath, L"\\METIN2\\");
|
||||
|
||||
if (_waccess(wPath, 0) == -1)
|
||||
{
|
||||
if (!CreateDirectoryW(wPath, nullptr) && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||
{
|
||||
TraceError("Failed to create directory [%s]\n", szPath);
|
||||
TraceError("Failed to create directory [%s]", WideToUtf8(wPath).c_str());
|
||||
return Py_BuildValue("(is)", FALSE, "");
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(szPath + strlen(szPath), "%02d%02d_%02d%02d%02d.jpg",
|
||||
tmNow->tm_mon + 1,
|
||||
tmNow->tm_mday,
|
||||
tmNow->tm_hour,
|
||||
tmNow->tm_min,
|
||||
tmNow->tm_sec);
|
||||
wchar_t wFile[64]{};
|
||||
swprintf_s(
|
||||
wFile,
|
||||
L"%02d%02d_%02d%02d%02d.jpg",
|
||||
tmNow.tm_mon + 1,
|
||||
tmNow.tm_mday,
|
||||
tmNow.tm_hour,
|
||||
tmNow.tm_min,
|
||||
tmNow.tm_sec
|
||||
);
|
||||
|
||||
BOOL bResult = CPythonGraphic::Instance().SaveScreenShot(szPath);
|
||||
return Py_BuildValue("(is)", bResult, szPath);
|
||||
wcscat_s(wPath, wFile);
|
||||
|
||||
// If SaveScreenShot accepts wide paths:
|
||||
BOOL bResult = CPythonGraphic::Instance().SaveScreenShot(WideToUtf8(wPath).c_str());
|
||||
|
||||
// Python expects bytes -> return UTF-8
|
||||
std::string pathUtf8 = WideToUtf8(wPath);
|
||||
return Py_BuildValue("(is)", bResult, pathUtf8.c_str());
|
||||
}
|
||||
|
||||
PyObject * grpSetGamma(PyObject * poSelf, PyObject * poArgs)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "PythonWindowManager.h"
|
||||
|
||||
#include "EterLib/StateManager.h"
|
||||
#include "UserInterface/Locale.h"
|
||||
|
||||
BOOL g_bOutlineBoxEnable = FALSE;
|
||||
|
||||
@@ -781,16 +782,6 @@ namespace UI
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CWindow::OnIMEChangeCodePage()
|
||||
{
|
||||
long lValue;
|
||||
if (PyCallClassMemberFunc(m_poHandler, "OnIMEChangeCodePage", BuildEmptyTuple(), &lValue))
|
||||
if (0 != lValue)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL CWindow::OnIMEOpenCandidateListEvent()
|
||||
{
|
||||
long lValue;
|
||||
@@ -1053,6 +1044,9 @@ namespace UI
|
||||
m_TextInstance.SetColor(0.78f, 0.78f, 0.78f);
|
||||
m_TextInstance.SetHorizonalAlign(CGraphicTextInstance::HORIZONTAL_ALIGN_LEFT);
|
||||
m_TextInstance.SetVerticalAlign(CGraphicTextInstance::VERTICAL_ALIGN_TOP);
|
||||
|
||||
m_baseDirection = ::IsRTL() ? CGraphicTextInstance::ETextDirection::RTL : CGraphicTextInstance::ETextDirection::LTR;
|
||||
m_TextInstance.SetTextDirection(m_baseDirection);
|
||||
}
|
||||
CTextLine::~CTextLine()
|
||||
{
|
||||
@@ -1132,10 +1126,41 @@ namespace UI
|
||||
return m_TextInstance.PixelPositionToCharacterPosition(lx);
|
||||
}
|
||||
|
||||
void CTextLine::SetBaseDirection(int iDir)
|
||||
{
|
||||
if (iDir == 2)
|
||||
m_baseDirection = CGraphicTextInstance::ETextDirection::RTL;
|
||||
else if (iDir == 1)
|
||||
m_baseDirection = CGraphicTextInstance::ETextDirection::LTR;
|
||||
else
|
||||
m_baseDirection = CGraphicTextInstance::ETextDirection::Auto;
|
||||
|
||||
// Apply paragraph direction to the text instance
|
||||
m_TextInstance.SetTextDirection(m_baseDirection);
|
||||
|
||||
// Re-anchor immediately
|
||||
OnChangePosition();
|
||||
}
|
||||
|
||||
int CTextLine::GetBaseDirection() const
|
||||
{
|
||||
if (m_baseDirection == CGraphicTextInstance::ETextDirection::RTL)
|
||||
return 2;
|
||||
if (m_baseDirection == CGraphicTextInstance::ETextDirection::LTR)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CTextLine::OnSetText(const char * c_szText)
|
||||
{
|
||||
m_TextInstance.SetValue(c_szText);
|
||||
|
||||
// Use the control's base direction (AUTO/LTR/RTL)
|
||||
m_TextInstance.SetTextDirection(m_baseDirection);
|
||||
m_TextInstance.Update();
|
||||
|
||||
// RTL anchor
|
||||
OnChangePosition();
|
||||
}
|
||||
|
||||
void CTextLine::OnUpdate()
|
||||
@@ -1151,16 +1176,16 @@ namespace UI
|
||||
|
||||
void CTextLine::OnChangePosition()
|
||||
{
|
||||
// FOR_ARABIC_ALIGN
|
||||
//if (m_TextInstance.GetHorizontalAlign() == CGraphicTextInstance::HORIZONTAL_ALIGN_ARABIC)
|
||||
if( GetDefaultCodePage() == CP_ARABIC )
|
||||
{
|
||||
m_TextInstance.SetPosition(m_rect.right, m_rect.top);
|
||||
}
|
||||
bool bAnchorRTL = false;
|
||||
|
||||
if (m_baseDirection == CGraphicTextInstance::ETextDirection::RTL)
|
||||
bAnchorRTL = true;
|
||||
else if (m_baseDirection == CGraphicTextInstance::ETextDirection::LTR)
|
||||
bAnchorRTL = false;
|
||||
else
|
||||
{
|
||||
m_TextInstance.SetPosition(m_rect.left, m_rect.top);
|
||||
}
|
||||
bAnchorRTL = m_TextInstance.IsRTL(); // AUTO fallback
|
||||
|
||||
m_TextInstance.SetPosition(bAnchorRTL ? m_rect.right : m_rect.left, m_rect.top);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -2096,10 +2121,10 @@ namespace UI
|
||||
|
||||
void CDragButton::OnChangePosition()
|
||||
{
|
||||
m_x = std::max(m_x, m_restrictArea.left);
|
||||
m_y = std::max(m_y, m_restrictArea.top);
|
||||
m_x = std::min(m_x, std::max(0l, m_restrictArea.right - m_lWidth));
|
||||
m_y = std::min(m_y, std::max(0l, m_restrictArea.bottom - m_lHeight));
|
||||
m_x = (std::max)(m_x, m_restrictArea.left);
|
||||
m_y = (std::max)(m_y, m_restrictArea.top);
|
||||
m_x = (std::min)(m_x, (std::max)(0l, m_restrictArea.right - m_lWidth));
|
||||
m_y = (std::min)(m_y, (std::max)(0l, m_restrictArea.bottom - m_lHeight));
|
||||
|
||||
m_rect.left = m_x;
|
||||
m_rect.top = m_y;
|
||||
|
||||
@@ -139,7 +139,6 @@ namespace UI
|
||||
virtual BOOL OnIMEReturnEvent();
|
||||
virtual BOOL OnIMEKeyDownEvent(int ikey);
|
||||
|
||||
virtual BOOL OnIMEChangeCodePage();
|
||||
virtual BOOL OnIMEOpenCandidateListEvent();
|
||||
virtual BOOL OnIMECloseCandidateListEvent();
|
||||
virtual BOOL OnIMEOpenReadingWndEvent();
|
||||
@@ -298,6 +297,9 @@ namespace UI
|
||||
|
||||
void GetTextSize(int* pnWidth, int* pnHeight);
|
||||
|
||||
void SetBaseDirection(int iDir);
|
||||
int GetBaseDirection() const;
|
||||
|
||||
protected:
|
||||
void OnUpdate();
|
||||
void OnRender();
|
||||
@@ -307,6 +309,7 @@ namespace UI
|
||||
|
||||
protected:
|
||||
CGraphicTextInstance m_TextInstance;
|
||||
CGraphicTextInstance::ETextDirection m_baseDirection;
|
||||
};
|
||||
|
||||
class CNumberLine : public CWindow
|
||||
|
||||
@@ -1133,15 +1133,6 @@ namespace UI
|
||||
// NOTE : 전체로 돌리지 않고 Activate되어있는 EditLine에만 보내는 이벤트
|
||||
}
|
||||
|
||||
void CWindowManager::RunChangeCodePage()
|
||||
{
|
||||
if (m_pActiveWindow)
|
||||
if (m_pActiveWindow->IsRendering())
|
||||
{
|
||||
if (m_pActiveWindow->OnIMEChangeCodePage())
|
||||
return;
|
||||
}
|
||||
}
|
||||
void CWindowManager::RunOpenCandidate()
|
||||
{
|
||||
if (m_pLockWindow)
|
||||
|
||||
@@ -126,7 +126,6 @@ namespace UI
|
||||
void RunIMETabEvent();
|
||||
void RunIMEReturnEvent();
|
||||
void RunIMEKeyDown(int vkey);
|
||||
void RunChangeCodePage();
|
||||
void RunOpenCandidate();
|
||||
void RunCloseCandidate();
|
||||
void RunOpenReading();
|
||||
|
||||
@@ -1822,6 +1822,19 @@ PyObject * wndTextSetLimitWidth(PyObject * poSelf, PyObject * poArgs)
|
||||
((UI::CTextLine*)pWindow)->SetLimitWidth(fWidth);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
PyObject * wndTextSetBaseDirection(PyObject * poSelf, PyObject * poArgs)
|
||||
{
|
||||
UI::CWindow * pWindow;
|
||||
if (!PyTuple_GetWindow(poArgs, 0, &pWindow))
|
||||
return Py_BuildException();
|
||||
|
||||
int iDir;
|
||||
if (!PyTuple_GetInteger(poArgs, 1, &iDir))
|
||||
return Py_BuildException();
|
||||
|
||||
((UI::CTextLine*)pWindow)->SetBaseDirection(iDir);
|
||||
return Py_BuildNone();
|
||||
}
|
||||
PyObject * wndTextSetText(PyObject * poSelf, PyObject * poArgs)
|
||||
{
|
||||
UI::CWindow * pWindow;
|
||||
@@ -2549,6 +2562,7 @@ void initwndMgr()
|
||||
{ "SetFontName", wndTextSetFontName, METH_VARARGS },
|
||||
{ "SetFontColor", wndTextSetFontColor, METH_VARARGS },
|
||||
{ "SetLimitWidth", wndTextSetLimitWidth, METH_VARARGS },
|
||||
{ "SetBaseDirection", wndTextSetBaseDirection, METH_VARARGS },
|
||||
{ "GetText", wndTextGetText, METH_VARARGS },
|
||||
{ "GetTextSize", wndTextGetTextSize, METH_VARARGS },
|
||||
{ "ShowCursor", wndTextShowCursor, METH_VARARGS },
|
||||
@@ -2631,6 +2645,10 @@ void initwndMgr()
|
||||
PyModule_AddIntConstant(poModule, "TEXT_VERTICAL_ALIGN_BOTTOM", CGraphicTextInstance::VERTICAL_ALIGN_BOTTOM);
|
||||
PyModule_AddIntConstant(poModule, "TEXT_VERTICAL_ALIGN_CENTER", CGraphicTextInstance::VERTICAL_ALIGN_CENTER);
|
||||
|
||||
PyModule_AddIntConstant(poModule, "TEXT_BASEDIR_AUTO", 0);
|
||||
PyModule_AddIntConstant(poModule, "TEXT_BASEDIR_LTR", 1);
|
||||
PyModule_AddIntConstant(poModule, "TEXT_BASEDIR_RTL", 2);
|
||||
|
||||
PyModule_AddIntConstant(poModule, "HORIZONTAL_ALIGN_LEFT", UI::CWindow::HORIZONTAL_ALIGN_LEFT);
|
||||
PyModule_AddIntConstant(poModule, "HORIZONTAL_ALIGN_CENTER", UI::CWindow::HORIZONTAL_ALIGN_CENTER);
|
||||
PyModule_AddIntConstant(poModule, "HORIZONTAL_ALIGN_RIGHT", UI::CWindow::HORIZONTAL_ALIGN_RIGHT);
|
||||
|
||||
Reference in New Issue
Block a user