diff --git a/extension/src/platform/EterLib/Util.cpp b/extension/src/platform/EterLib/Util.cpp new file mode 100644 index 00000000..a566afe8 --- /dev/null +++ b/extension/src/platform/EterLib/Util.cpp @@ -0,0 +1,18 @@ +// 40250 EterLib/Util.cpp 的“默认代码页”那一小块。 +// +// Util.cpp 本身是逻辑单元(LoadTextData / base64 / TokenTo*),但代码页这几个函数和它们旁边的 +// GetFontFaceFromCodePage 是连在一起的,后者靠 GDI 的 EnumFontFamiliesEx 枚举字体,win32 shim 里没有, +// 真正的实现要等 2V0-f 的文字渲染。所以整份 Util.cpp 的移植留到那时,这里只放现在真正被调用到的 +// GetDefaultCodePage:EterPythonLib/PythonWindow.cpp 的 CTextLine::OnChangePosition 用它判断 CP_ARABIC。 +// +// 默认值和 40250 一致:gs_codePage = 0,也就是“还没有 SetDefaultCodePage”。40250 在 +// PythonApplication 里根据 locale 调 SetDefaultCodePage(),那条路径同样等 2V0-d。 +#include "EterLib/StdAfx.h" +#include "EterLib/Util.h" + +static DWORD gs_codePage = 0; + +DWORD GetDefaultCodePage() +{ + return gs_codePage; +} diff --git a/extension/src/platform/EterPythonLib/PythonGraphic.cpp b/extension/src/platform/EterPythonLib/PythonGraphic.cpp new file mode 100644 index 00000000..b3003f02 --- /dev/null +++ b/extension/src/platform/EterPythonLib/PythonGraphic.cpp @@ -0,0 +1,17 @@ +// CPythonGraphic(40250 EterPythonLib/PythonGraphic.cpp)的平台骨架 —— 目前只有窗口树链接时真正需要 +// 的那一个函数。 +// +// CPythonGraphic 是 UI 的 2D 绘制层(D3D8 的正交投影、按钮的立体边框、冷却圈、截图),整份实现属于 +// 2V0-f;platform_stub.py 不认 EterPythonLib(port_map 把它划成 python 层),所以这里按手写平台桩的 +// 惯例来:先只放被引用到的符号,链接器会告诉我们下一个是谁。 +// +// RenderCoolTimeBox:CSlotWindow::OnRender 画技能冷却扇形用的,没有渲染设备时什么都不做。 +#include "EterPythonLib/StdAfx.h" +#include "EterPythonLib/PythonGraphic.h" + +#include "../PlatformStub.h" + +void CPythonGraphic::RenderCoolTimeBox(float fxCenter, float fyCenter, float fRadius, float fTime) +{ + MT_PLATFORM_STUB(); +} diff --git a/extension/src/port/CMakeLists.txt b/extension/src/port/CMakeLists.txt index ff7ab48e..67ec68b8 100644 --- a/extension/src/port/CMakeLists.txt +++ b/extension/src/port/CMakeLists.txt @@ -171,5 +171,14 @@ if(BUILD_TESTING AND CMAKE_SYSTEM_NAME STREQUAL CMAKE_HOST_SYSTEM_NAME) add_test(NAME port.python_launcher COMMAND $ ${MT_40250_CLIENT} ${MT_PYTHON_STDLIB_ZIP}) set_tests_properties(port.python_launcher PROPERTIES SKIP_RETURN_CODE 77) + + # EterPythonLib 的窗口树(批次 2V0-b)。需要解释器(CWindowManager 的构造函数就调 Python), + # 但不需要 40250 的 Client/pack —— 布局/命中/事件都不读资源。 + add_executable(port_window_tree_test ${CMAKE_CURRENT_SOURCE_DIR}/../../tests/port_window_tree_test.cpp) + target_link_libraries(port_window_tree_test PRIVATE port_platform) + add_dependencies(port_window_tree_test mtpython_stdlib) + add_test(NAME port.window_tree + COMMAND $ ${MT_PYTHON_STDLIB_ZIP}) + set_tests_properties(port.window_tree PROPERTIES SKIP_RETURN_CODE 77) endif() endif() diff --git a/extension/src/port/EterLib/ReferenceObject.cpp b/extension/src/port/EterLib/ReferenceObject.cpp new file mode 100644 index 00000000..356819a1 --- /dev/null +++ b/extension/src/port/EterLib/ReferenceObject.cpp @@ -0,0 +1,61 @@ +#include "StdAfx.h" +#include "ReferenceObject.h" + +CReferenceObject::CReferenceObject() : m_refCount(0), m_destructed(false) +{ +} + +CReferenceObject::~CReferenceObject() +{ +} + +void CReferenceObject::AddReference() +{ + if (m_refCount == 0) + OnConstruct(); + + ++m_refCount; +} + +int CReferenceObject::GetReferenceCount() +{ + return m_refCount; +} + +void CReferenceObject::AddReferenceOnly() +{ + ++m_refCount; +} + +void CReferenceObject::Release() +{ + if (m_refCount > 1) + { + --m_refCount; + return; + } + + assert(m_destructed == false); + assert(m_refCount >= 0); + m_refCount = 0; + OnSelfDestruct(); +} + +void CReferenceObject::OnConstruct() +{ + m_destructed = false; +} + +void CReferenceObject::OnSelfDestruct() +{ + m_destructed = true; + delete this; +} + +bool CReferenceObject::canDestroy() +{ + if (m_refCount > 0) + return false; + + return true; +} diff --git a/extension/src/port/EterLib/Resource.cpp b/extension/src/port/EterLib/Resource.cpp new file mode 100644 index 00000000..564d62b4 --- /dev/null +++ b/extension/src/port/EterLib/Resource.cpp @@ -0,0 +1,181 @@ +#include "StdAfx.h" +#include "../EterPack/EterPackManager.h" +#include "../EterBase/CRC32.h" +#include "../EterBase/Timer.h" + +#include "Resource.h" +#include "ResourceManager.h" + +bool CResource::ms_bDeleteImmediately = false; + +CResource::CResource(const char* c_szFileName) : me_state(STATE_EMPTY) +{ + SetFileName(c_szFileName); +} + +CResource::~CResource() +{ +} + +void CResource::SetDeleteImmediately(bool isSet) +{ + ms_bDeleteImmediately = isSet; +} + +void CResource::OnConstruct() +{ + Load(); +} + +void CResource::OnSelfDestruct() +{ + if (ms_bDeleteImmediately) + Clear(); + else + CResourceManager::Instance().ReserveDeletingResource(this); +} + +void CResource::Load() +{ + if (me_state != STATE_EMPTY) + return; + + const char * c_szFileName = GetFileName(); + + DWORD dwStart = ELTimer_GetMSec(); + CMappedFile file; + LPCVOID fileData; + + //Tracenf("Load %s", c_szFileName); + + if (CEterPackManager::Instance().Get(file, c_szFileName, &fileData)) + { + m_dwLoadCostMiliiSecond = ELTimer_GetMSec() - dwStart; + //Tracef("CResource::Load %s (%d bytes) in %d ms\n", c_szFileName, file.Size(), m_dwLoadCostMiliiSecond); + + if (OnLoad(file.Size(), fileData)) + { + me_state = STATE_EXIST; + } + else + { + Tracef("CResource::Load Error %s\n", c_szFileName); + me_state = STATE_ERROR; + return; + } + } + else + { + if (OnLoad(0, NULL)) + me_state = STATE_EXIST; + else + { + Tracef("CResource::Load file not exist %s\n", c_szFileName); + me_state = STATE_ERROR; + } + } +} + +void CResource::Reload() +{ + Clear(); + Tracef("CResource::Reload %s\n", GetFileName()); + + CMappedFile file; + LPCVOID fileData; + + if (CEterPackManager::Instance().Get(file, GetFileName(), &fileData)) + { + if (OnLoad(file.Size(), fileData)) + { + me_state = STATE_EXIST; + } + else + { + me_state = STATE_ERROR; + return; + } + } + else + { + if (OnLoad(0, NULL)) + me_state = STATE_EXIST; + else + { + me_state = STATE_ERROR; + } + } +} + +CResource::TType CResource::StringToType(const char* c_szType) +{ + return GetCRC32(c_szType, strlen(c_szType)); +} + +int CResource::ConvertPathName(const char * c_szPathName, char * pszRetPathName, int retLen) +{ + const char * pc; + int len = 0; + + for (pc = c_szPathName; *pc && len < retLen; ++pc, ++len) + { + if (*pc == '/') + *(pszRetPathName++) = '\\'; + else + *(pszRetPathName++) = (char) korean_tolower(*pc); + } + + *pszRetPathName = '\0'; + return len; +} + +void CResource::SetFileName(const char* c_szFileName) +{ + // 2004. 2. 1. myevan. 쓰레드가 사용되는 상황에서 static 변수는 사용하지 않는것이 좋다. + // 2004. 2. 1. myevan. 파일 이름 처리를 std::string 사용 + m_stFileName=c_szFileName; +} + +void CResource::Clear() +{ + OnClear(); + me_state = STATE_EMPTY; +} + +bool CResource::IsType(TType type) +{ + return OnIsType(type); +} + +CResource::TType CResource::Type() +{ + static TType s_type = StringToType("CResource"); + return s_type; +} + +bool CResource::OnIsType(TType type) +{ + if (CResource::Type() == type) + return true; + + return false; +} + +bool CResource::IsData() const +{ + return me_state != STATE_EMPTY; +} + +bool CResource::IsEmpty() const +{ + return OnIsEmpty(); +} + +bool CResource::CreateDeviceObjects() +{ + return true; +} + +void CResource::DestroyDeviceObjects() +{ +} diff --git a/extension/src/port/EterLib/ResourceManager.cpp b/extension/src/port/EterLib/ResourceManager.cpp new file mode 100644 index 00000000..3312220a --- /dev/null +++ b/extension/src/port/EterLib/ResourceManager.cpp @@ -0,0 +1,525 @@ +#include "StdAfx.h" +#include +#include "../EterBase/CRC32.h" +#include "../EterBase/Timer.h" +#include "../EterBase/Stl.h" +#include "../EterPack/EterPackManager.h" + +#include "ResourceManager.h" +#include "GrpImage.h" + +int g_iLoadingDelayTime = 20; + +const long c_Deleting_Wait_Time = 30000; // 삭제 대기 시간 (30초) +const long c_DeletingCountPerFrame = 30; // 프레임당 체크 리소스 갯수 +const long c_Reference_Decrease_Wait_Time = 30000; // 선로딩 리소스의 해제 대기 시간 (30초) + +CFileLoaderThread CResourceManager::ms_loadingThread; + +void CResourceManager::LoadStaticCache(const char* c_szFileName) +{ + CResource* pkRes=GetResourcePointer(c_szFileName); + if (!pkRes) + { + Lognf(1, "CResourceManager::LoadStaticCache %s - FAILED", c_szFileName); + return; + } + + DWORD dwCacheKey=GetCRC32(c_szFileName, strlen(c_szFileName)); + TResourcePointerMap::iterator f=m_pCacheMap.find(dwCacheKey); + if (m_pCacheMap.end()!=f) + return; + + pkRes->AddReference(); + m_pCacheMap.insert(TResourcePointerMap::value_type(dwCacheKey, pkRes)); + +} + +void CResourceManager::ProcessBackgroundLoading() +{ + TResourceRequestMap::iterator itor = m_RequestMap.begin(); + + while (itor != m_RequestMap.end()) + { + DWORD dwFileCRC = itor->first; + std::string & stFileName = itor->second; + + if (isResourcePointerData(dwFileCRC) || + (m_WaitingMap.end() != m_WaitingMap.find(dwFileCRC))) + { + //printf("SKP %s\n", stFileName.c_str()); + itor = m_RequestMap.erase(itor); + continue; + } + + //printf("REQ %s\n", stFileName.c_str()); + ms_loadingThread.Request(stFileName); + m_WaitingMap.insert(TResourceRequestMap::value_type(dwFileCRC, stFileName)); + itor = m_RequestMap.erase(itor); + //break; // NOTE: 여기서 break 하면 천천히 로딩 된다. + } + + DWORD dwCurrentTime = ELTimer_GetMSec(); + + CFileLoaderThread::TData * pData; + while (ms_loadingThread.Fetch(&pData)) + { + //printf("LOD %s\n", pData->stFileName.c_str()); + CResource * pResource = GetResourcePointer(pData->stFileName.c_str()); + + if (pResource) + { + if (pResource->IsEmpty()) + { + pResource->OnLoad(pData->dwSize, pData->pvBuf); + pResource->AddReferenceOnly(); + + // 여기서 올라간 레퍼런스 카운트를 일정 시간이 지난 뒤에 풀어주기 위하여 + m_pResRefDecreaseWaitingMap.insert(TResourceRefDecreaseWaitingMap::value_type(dwCurrentTime, pResource)); + } + } + + m_WaitingMap.erase(GetCRC32(pData->stFileName.c_str(), pData->stFileName.size())); + + delete [] ((char *) pData->pvBuf); + delete pData; + } + + // DO : 일정 시간이 지나고 난뒤 미리 로딩해 두었던 리소스의 레퍼런스 카운트를 감소 시킨다 - [levites] + long lCurrentTime = ELTimer_GetMSec(); + + TResourceRefDecreaseWaitingMap::iterator itorRef = m_pResRefDecreaseWaitingMap.begin(); + + while (itorRef != m_pResRefDecreaseWaitingMap.end()) + { + const long & rCreatingTime = itorRef->first; + + if (lCurrentTime - rCreatingTime > c_Reference_Decrease_Wait_Time) + { + CResource * pResource = itorRef->second; + + // Decrease Reference Count + pResource->Release(); + itorRef = m_pResRefDecreaseWaitingMap.erase(itorRef); + //Tracef("Decrease Pre Loading Resource\n", rCreatingTime); + } + else + ++itorRef; + } +} + +void CResourceManager::PushBackgroundLoadingSet(std::set & LoadingSet) +{ + std::set::iterator itor = LoadingSet.begin(); + + while (itor != LoadingSet.end()) + { + DWORD dwFileCRC = __GetFileCRC(itor->c_str()); + + if (NULL != isResourcePointerData(dwFileCRC)) + { + ++itor; + continue; + } + + m_RequestMap.insert(TResourceRequestMap::value_type(dwFileCRC, itor->c_str())); + ++itor; + } +} + +void CResourceManager::__DestroyCacheMap() +{ + TResourcePointerMap::iterator i; + for (i = m_pCacheMap.begin(); i != m_pCacheMap.end(); ++i) + { + CResource* pResource = i->second; + pResource->Release(); + } + + m_pCacheMap.clear(); +} + +void CResourceManager::__DestroyDeletingResourceMap() +{ + Tracenf("CResourceManager::__DestroyDeletingResourceMap %d", m_ResourceDeletingMap.size()); + for (TResourceDeletingMap::iterator i = m_ResourceDeletingMap.begin(); i != m_ResourceDeletingMap.end(); ++i) + (i->first)->Clear(); + + m_ResourceDeletingMap.clear(); +} + +void CResourceManager::__DestroyResourceMap() +{ + Tracenf("CResourceManager::__DestroyResourceMap %d", m_pResMap.size()); + + TResourcePointerMap::iterator i; + for (i = m_pResMap.begin(); i != m_pResMap.end(); ++i) + { + CResource* pResource = i->second; + pResource->Clear(); + } + + stl_wipe_second(m_pResMap); +} + +void CResourceManager::DestroyDeletingList() +{ + CResource::SetDeleteImmediately(true); + + __DestroyCacheMap(); + __DestroyDeletingResourceMap(); +} + +void CResourceManager::Destroy() +{ + assert(m_ResourceDeletingMap.empty() && "CResourceManager::Destroy - YOU MUST CALL DestroyDeletingList"); + __DestroyResourceMap(); +} + +void CResourceManager::RegisterResourceNewFunctionPointer(const char* c_szFileExt, CResource* (*pNewFunc)(const char* c_szFileName)) +{ + m_pResNewFuncMap[c_szFileExt] = pNewFunc; +} + +void CResourceManager::RegisterResourceNewFunctionByTypePointer(int iType, CResource* (*pNewFunc) (const char* c_szFileName)) +{ + assert(iType >= 0); + m_pResNewFuncByTypeMap[iType] = pNewFunc; +} + +CResource * CResourceManager::InsertResourcePointer(DWORD dwFileCRC, CResource* pResource) +{ + TResourcePointerMap::iterator itor = m_pResMap.find(dwFileCRC); + + if (m_pResMap.end() != itor) + { + TraceError("CResource::InsertResourcePointer: %s is already registered\n", pResource->GetFileName()); + assert(!"CResource::InsertResourcePointer: Resource already resistered"); + delete pResource; + return itor->second; + } + + m_pResMap.insert(TResourcePointerMap::value_type(dwFileCRC, pResource)); + return pResource; +} + + +int __ConvertPathName(const char * c_szPathName, char * pszRetPathName, int retLen) +{ + const char * pc; + int len = 0; + + for (pc = c_szPathName; *pc && len < retLen; ++pc, ++len) + { + if (*pc == '/') + *(pszRetPathName++) = '\\'; + else + *(pszRetPathName++) = (char) korean_tolower(*pc); + } + + *pszRetPathName = '\0'; + return len; +} + +CResource * CResourceManager::GetTypeResourcePointer(const char * c_szFileName, int iType) +{ + if (!c_szFileName || !*c_szFileName) + { + assert(c_szFileName != NULL && *c_szFileName != '\0'); + return NULL; + } + + const char * c_pszFile; + DWORD dwFileCRC = __GetFileCRC(c_szFileName, &c_pszFile); + CResource * pResource = FindResourcePointer(dwFileCRC); + + if (pResource) // 이미 리소스가 있으면 리턴 한다. + return pResource; + + CResource * (*newFunc) (const char *) = NULL; + + if (iType != -1) + { + TResourceNewFunctionByTypePointerMap::iterator f = m_pResNewFuncByTypeMap.find(iType); + + if (m_pResNewFuncByTypeMap.end() != f) + newFunc = f->second; + } + else + { + const char * pcFileExt = strrchr(c_pszFile, '.'); + + if (pcFileExt) + { + static char s_szFileExt[8 + 1]; + strncpy(s_szFileExt, pcFileExt + 1, 8); + + TResourceNewFunctionPointerMap::iterator f = m_pResNewFuncMap.find(s_szFileExt); + + if (m_pResNewFuncMap.end() != f) + newFunc = f->second; + } + } + + if (!newFunc) + { + TraceError("ResourceManager::GetResourcePointer: NOT SUPPORT FILE %s", c_pszFile); + return NULL; + } + + pResource = InsertResourcePointer(dwFileCRC, newFunc(c_pszFile)); + return pResource; +} + +CResource * CResourceManager::GetResourcePointer(const char * c_szFileName) +{ + if (!c_szFileName || !*c_szFileName) + { + TraceError("CResourceManager::GetResourcePointer: filename error!"); + return NULL; + } + + const char * c_pszFile; + DWORD dwFileCRC = __GetFileCRC(c_szFileName, &c_pszFile); + CResource * pResource = FindResourcePointer(dwFileCRC); + + if (pResource) // 이미 리소스가 있으면 리턴 한다. + return pResource; + + const char * pcFileExt = strrchr(c_pszFile, '.'); + +#ifdef _DEBUG + if (!IsFileExist(c_szFileName) ) + { + if( pcFileExt == NULL || (stricmp( pcFileExt, ".fnt" ) != 0) ) { + TraceError("CResourceManager::GetResourcePointer: File not exist %s", c_szFileName); + } + } +#endif + + CResource * (*newFunc) (const char *) = NULL; + + if (pcFileExt) + { + static char s_szFileExt[8 + 1]; + strncpy(s_szFileExt, pcFileExt + 1, 8); + + TResourceNewFunctionPointerMap::iterator f = m_pResNewFuncMap.find(s_szFileExt); + + if (m_pResNewFuncMap.end() != f) + newFunc = f->second; + } + + if (!newFunc) + { + TraceError("ResourceManager::GetResourcePointer: NOT SUPPORT FILE %s", c_pszFile); + return NULL; + } + + pResource = InsertResourcePointer(dwFileCRC, newFunc(c_pszFile)); + return pResource; +} + +CResource * CResourceManager::FindResourcePointer(DWORD dwFileCRC) +{ + TResourcePointerMap::iterator itor = m_pResMap.find(dwFileCRC); + + if (m_pResMap.end() == itor) + return NULL; + + return itor->second; +} + +bool CResourceManager::isResourcePointerData(DWORD dwFileCRC) +{ + TResourcePointerMap::iterator itor = m_pResMap.find(dwFileCRC); + + if (m_pResMap.end() == itor) + return NULL; + + return (itor->second)->IsData(); +} + +DWORD CResourceManager::__GetFileCRC(const char * c_szFileName, const char ** c_ppszLowerFileName) +{ + static char s_szFullPathFileName[MAX_PATH]; + const char * src = c_szFileName; + char * dst = s_szFullPathFileName; + int len = 0; + + while (src[len]) + { + if (src[len]=='/') + dst[len] = '\\'; + else + dst[len] = (char) korean_tolower(src[len]); + + ++len; + } + + dst[len] = '\0'; + + if (c_ppszLowerFileName) + *c_ppszLowerFileName = &s_szFullPathFileName[0]; + + return (GetCRC32(s_szFullPathFileName, len)); +} + +typedef struct SDumpData +{ + const char * filename; + float KB; + DWORD cost; +} TDumpData; + +bool DumpKBCompare(const TDumpData& lhs, const TDumpData& rhs) +{ + return (lhs.KB > rhs.KB) ? true : false; +} + +bool DumpCostCompare(const TDumpData& lhs, const TDumpData& rhs) +{ + return (lhs.cost > rhs.cost) ? true : false; +} + +struct FDumpPrint +{ + FILE * m_fp; + static float m_totalKB; + + void operator () (TDumpData & data) + { + m_totalKB += data.KB; + fprintf(m_fp, "%6.1f %s\n", data.KB, data.filename); + } +}; + +float FDumpPrint::m_totalKB; + +struct FDumpCostPrint +{ + FILE * m_fp; + + void operator() (TDumpData & data) + { + fprintf(m_fp, "%-4d %s\n", data.cost, data.filename); + } +}; + +void CResourceManager::DumpFileListToTextFile(const char* c_szFileName) +{ + std::vector dumpVector; + + for (TResourcePointerMap::iterator i = m_pResMap.begin(); i != m_pResMap.end(); ++i) + { + CResource* pResource = i->second; + TDumpData data; + + if (pResource->IsEmpty()) + continue; + + data.filename = pResource->GetFileName(); + + int filesize; + + const char * ext = strrchr(data.filename, '.'); + + if (pResource->IsType(CGraphicImage::Type()) && strnicmp(ext, ".sub", 4)) + filesize = ((CGraphicImage*) pResource)->GetWidth() * ((CGraphicImage*) pResource)->GetHeight() * 4; + else + { + FILE * fp2 = fopen(data.filename, "rb"); + + if (fp2) + { + fseek(fp2, 0L, SEEK_END); + filesize = ftell(fp2); + fclose(fp2); + } + else + filesize = 0; + } + + data.KB = (float) filesize / (float) 1024; + data.cost = pResource->GetLoadCostMilliSecond(); + + dumpVector.push_back(data); + } + + FILE * fp = fopen(c_szFileName, "w"); + + if (fp) + { + std::sort(dumpVector.begin(), dumpVector.end(), DumpKBCompare); + + FDumpPrint DumpPrint; + DumpPrint.m_fp = fp; + DumpPrint.m_totalKB = 0; + + std::for_each(dumpVector.begin(), dumpVector.end(), DumpPrint); + fprintf(fp, "total: %.2fmb", DumpPrint.m_totalKB / 1024.0f); + + FDumpCostPrint DumpCostPrint; + DumpCostPrint.m_fp = fp; + + std::sort(dumpVector.begin(), dumpVector.end(), DumpCostCompare); + std::for_each(dumpVector.begin(), dumpVector.end(), DumpCostPrint); + fprintf(fp, "total: %.2fmb", DumpPrint.m_totalKB / 1024.0f); + + fclose(fp); + } +} + +bool CResourceManager::IsFileExist(const char * c_szFileName) +{ + return CEterPackManager::Instance().isExist(c_szFileName); +} + +void CResourceManager::Update() +{ + DWORD CurrentTime = ELTimer_GetMSec(); + CResource * pResource; + int Count = 0; + + TResourceDeletingMap::iterator itor = m_ResourceDeletingMap.begin(); + + while (itor != m_ResourceDeletingMap.end()) + { + pResource = itor->first; + + if (CurrentTime >= itor->second) + { + if (pResource->canDestroy()) + { + //Tracef("Resource Clear %s\n", pResource->GetFileName()); + pResource->Clear(); + } + + itor = m_ResourceDeletingMap.erase(itor); + + if (++Count >= c_DeletingCountPerFrame) + break; + } + else + ++itor; + } + + ProcessBackgroundLoading(); +} + +void CResourceManager::ReserveDeletingResource(CResource * pResource) +{ + DWORD dwCurrentTime = ELTimer_GetMSec(); + m_ResourceDeletingMap.insert(TResourceDeletingMap::value_type(pResource, dwCurrentTime + c_Deleting_Wait_Time)); +} + +CResourceManager::CResourceManager() +{ + //ms_loadingThread.Create(0); +} + +CResourceManager::~CResourceManager() +{ + Destroy(); + //ms_loadingThread.Shutdown(); +} diff --git a/extension/src/port/EterPythonLib/PythonGridSlotWindow.cpp b/extension/src/port/EterPythonLib/PythonGridSlotWindow.cpp new file mode 100644 index 00000000..b98f869b --- /dev/null +++ b/extension/src/port/EterPythonLib/PythonGridSlotWindow.cpp @@ -0,0 +1,400 @@ +#include "StdAfx.h" +#include "../EterBase/CRC32.h" +#include "PythonGridSlotWindow.h" + +using namespace UI; + +void CGridSlotWindow::OnRenderPickingSlot() +{ + if (!UI::CWindowManager::Instance().IsAttaching()) + return; + + BYTE byWidth, byHeight; + UI::CWindowManager::Instance().GetAttachingIconSize(&byWidth, &byHeight); + + std::list SlotList; + if (GetPickedSlotList(byWidth, byHeight, &SlotList)) + { + DWORD dwSlotNumber = UI::CWindowManager::Instance().GetAttachingSlotNumber(); + DWORD dwItemIndex = UI::CWindowManager::Instance().GetAttachingIndex(); + + // UseMode 이고.. + if (m_isUseMode) + { + // Pick 된 아이템이 있으면.. + TSlot * pSlot = *SlotList.begin(); + TSlot * pCenterSlot; + if (GetSlotPointer(pSlot->dwCenterSlotNumber, &pCenterSlot)) + if (pCenterSlot->isItem) + { + if (m_isUsableItem) + CPythonGraphic::Instance().SetDiffuseColor(1.0f, 1.0f, 0.0f, 0.5f); + else + CPythonGraphic::Instance().SetDiffuseColor(1.0f, 0.0f, 0.0f, 0.5f); + + CPythonGraphic::Instance().RenderBar2d( m_rect.left + pCenterSlot->ixPosition, + m_rect.top + pCenterSlot->iyPosition, + m_rect.left + pCenterSlot->ixPosition + pCenterSlot->byxPlacedItemSize * ITEM_WIDTH, + m_rect.top + pCenterSlot->iyPosition + pCenterSlot->byyPlacedItemSize * ITEM_HEIGHT); + return; + } + } + + // 아니면 그냥 옮기기 + if (CheckMoving(dwSlotNumber, dwItemIndex, SlotList)) + CPythonGraphic::Instance().SetDiffuseColor(1.0f, 1.0f, 1.0f, 0.5f); + else + CPythonGraphic::Instance().SetDiffuseColor(1.0f, 0.0f, 0.0f, 0.5f); + + RECT Rect; + Rect.left = m_rect.right; + Rect.top = m_rect.bottom; + Rect.right = 0; + Rect.bottom = 0; + + for (std::list::iterator itor = SlotList.begin(); itor != SlotList.end(); ++itor) + { + TSlot * pSlot = *itor; + Rect.left = min(Rect.left, m_rect.left + pSlot->ixPosition); + Rect.top = min(Rect.top, m_rect.top + pSlot->iyPosition); + Rect.right = max(Rect.right, m_rect.left + pSlot->ixPosition + pSlot->byxPlacedItemSize*ITEM_WIDTH); + Rect.bottom = max(Rect.bottom, m_rect.top + pSlot->iyPosition + pSlot->byxPlacedItemSize*ITEM_HEIGHT); + } + + CPythonGraphic::Instance().RenderBar2d(Rect.left, Rect.top, Rect.right, Rect.bottom); + } +} + +BOOL CGridSlotWindow::GetPickedSlotPointer(TSlot ** ppSlot) +{ + if (!UI::CWindowManager::Instance().IsAttaching()) + return CSlotWindow::GetPickedSlotPointer(ppSlot); + + BYTE byWidth, byHeight; + UI::CWindowManager::Instance().GetAttachingIconSize(&byWidth, &byHeight); + + std::list SlotList; + if (!GetPickedSlotList(byWidth, byHeight, &SlotList)) + return FALSE; + + TSlot * pMinSlot = NULL; + //DWORD dwSlotNumber = UI::CWindowManager::Instance().GetAttachingSlotNumber(); + //DWORD dwAttachingItemIndex = UI::CWindowManager::Instance().GetAttachingIndex(); + + for (std::list::iterator itor = SlotList.begin(); itor != SlotList.end(); ++itor) + { + TSlot * pSlot = *itor; + + // NOTE : 한 슬롯 이상 사이즈의 아이템의 경우 가장 왼쪽 위의 슬롯 포인터를 리턴한다. + // 명시적이지 못한 코드.. 더 좋은 방법은 없는가? - [levites] + if (!pMinSlot) + { + pMinSlot = pSlot; + } + else + { + if (pSlot->dwSlotNumber < pMinSlot->dwSlotNumber) + { + pMinSlot = pSlot; + } + else + { + if (!pMinSlot->isItem && pSlot->isItem) + { + pMinSlot = pSlot; + } + } + } + } + + if (!pMinSlot) + { + return FALSE; + } + else + { + TSlot * pCenterSlot; + if (!GetSlotPointer(pMinSlot->dwCenterSlotNumber, &pCenterSlot)) + return FALSE; + + *ppSlot = pCenterSlot; + + // 현재 아이템을 들고 있는 중이고.. + if (UI::CWindowManager::Instance().IsAttaching()) + { + DWORD dwSlotNumber = UI::CWindowManager::Instance().GetAttachingSlotNumber(); + + if (dwSlotNumber == pCenterSlot->dwSlotNumber) + { + *ppSlot = pMinSlot; + } + } + } + + return TRUE; +} + +BOOL CGridSlotWindow::GetPickedSlotList(int iWidth, int iHeight, std::list * pSlotPointerList) +{ + long lx, ly; + GetMouseLocalPosition(lx, ly); + + if (lx < 0) + return FALSE; + if (ly < 0) + return FALSE; + if (lx >= GetWidth()) + return FALSE; + if (ly >= GetHeight()) + return FALSE; + + pSlotPointerList->clear(); + + int ix, iy; + if (GetPickedGridSlotPosition(lx, ly, &ix, &iy)) + { + int ixHalfStep = (iWidth / 2); + //int iyHalfStep = (iHeight / 2); + + int ixStart = int(ix) - int(ixHalfStep - (ixHalfStep % 2)); + int ixEnd = int(ix) + int(ixHalfStep); + + // FIXME : 제대로 된 계산 공식을 찾자 - [levites] + int iyStart = 0, iyEnd = 0; + + if (1 == iHeight) + { + iyStart = iy; + iyEnd = iy; + } + else if (2 == iHeight) + { + iyStart = iy; + iyEnd = iy + 1; + } + else if (3 == iHeight) + { + iyStart = iy - 1; + iyEnd = iy + 1; + } + + if (ixStart < 0) + { + ixEnd += -ixStart; + ixStart = 0; + } + + if (iyStart < 0) + { + iyEnd += -iyStart; + iyStart = 0; + } + + if (DWORD(ixEnd) >= m_dwxCount) + { + int ixTemporary = DWORD(ixEnd) - m_dwxCount + 1; + ixStart -= ixTemporary; + ixEnd -= ixTemporary; + } + + if (DWORD(iyEnd) >= m_dwyCount) + { + int iyTemporary = DWORD(iyEnd) - m_dwyCount + 1; + iyStart -= iyTemporary; + iyEnd -= iyTemporary; + } + + for (int i = ixStart; i <= ixEnd; ++i) + for (int j = iyStart; j <= iyEnd; ++j) + { + TSlot * pSlot; + if (GetGridSlotPointer(DWORD(i), DWORD(j), &pSlot)) + { + pSlotPointerList->push_back(pSlot); + } + } + + // Refine Scroll 등을 위한 예외 처리 + if (m_isUseMode && 1 == pSlotPointerList->size()) + { + TSlot * pMainSlot = *pSlotPointerList->begin(); + + std::vector::iterator itor = m_SlotVector.begin(); + for (; itor != m_SlotVector.end(); ++itor) + { + TSlot * pSlot = *itor; + if (pSlot->dwCenterSlotNumber == pMainSlot->dwCenterSlotNumber) + if (pSlotPointerList->end() == std::find(pSlotPointerList->begin(), pSlotPointerList->end(), pSlot)) + { + pSlotPointerList->push_back(pSlot); + } + } + } + + if (!pSlotPointerList->empty()) + return TRUE; + } + + return FALSE; +} + +BOOL CGridSlotWindow::GetGridSlotPointer(int ix, int iy, TSlot ** ppSlot) +{ + DWORD dwSlotIndex = ix + iy*m_dwxCount; + if (dwSlotIndex >= m_SlotVector.size()) + return FALSE; + + *ppSlot = m_SlotVector[dwSlotIndex]; + + return TRUE; +} + +BOOL CGridSlotWindow::GetPickedGridSlotPosition(int ixLocal, int iyLocal, int * pix, int * piy) +{ + for (DWORD x = 0; x < m_dwxCount; ++x) + for (DWORD y = 0; y < m_dwyCount; ++y) + { + TSlot * pSlot; + if (!GetGridSlotPointer(x, y, &pSlot)) + continue; + + if (ixLocal >= pSlot->ixPosition) + if (iyLocal >= pSlot->iyPosition) + if (ixLocal <= pSlot->ixPosition + pSlot->ixCellSize) + if (iyLocal <= pSlot->iyPosition + pSlot->iyCellSize) + { + *pix = x; + *piy = y; + return TRUE; + } + } + + return FALSE; +} + +void CGridSlotWindow::ArrangeGridSlot(DWORD dwStartIndex, DWORD dwxCount, DWORD dwyCount, int ixSlotSize, int iySlotSize, int ixTemporarySize, int iyTemporarySize) +{ + Destroy(); + + m_dwxCount = dwxCount; + m_dwyCount = dwyCount; + + m_SlotVector.clear(); + m_SlotVector.resize(dwxCount*dwyCount); + + for (DWORD x = 0; x < dwxCount; ++x) + for (DWORD y = 0; y < dwyCount; ++y) + { + DWORD dwIndex = dwStartIndex + x + y * dwxCount; + int ixPosition = x * (ixSlotSize + ixTemporarySize); + int iyPosition = y * (iySlotSize + iyTemporarySize); + + AppendSlot(dwIndex, ixPosition, iyPosition, ixSlotSize, iySlotSize); + + m_SlotVector[x+y*dwxCount] = &(*m_SlotList.rbegin()); + } + + int iWidth = dwxCount * (ixSlotSize + ixTemporarySize); + int iHeight = dwyCount * (iySlotSize + iyTemporarySize); + SetSize(iWidth, iHeight); +} + +void CGridSlotWindow::OnRefreshSlot() +{ + DWORD x, y; + + for (x = 0; x < m_dwxCount; ++x) + for (y = 0; y < m_dwyCount; ++y) + { + TSlot * pSlot; + if (!GetGridSlotPointer(x, y, &pSlot)) + continue; + + pSlot->dwCenterSlotNumber = pSlot->dwSlotNumber; + } + + for (x = 0; x < m_dwxCount; ++x) + for (y = 0; y < m_dwyCount; ++y) + { + TSlot * pSlot; + if (!GetGridSlotPointer(x, y, &pSlot)) + continue; + + if (pSlot->isItem) + { + for (DWORD xSub = 0; xSub < pSlot->byxPlacedItemSize; ++xSub) + for (DWORD ySub = 0; ySub < pSlot->byyPlacedItemSize; ++ySub) + { + TSlot * pSubSlot; + if (!GetGridSlotPointer(x+xSub, y+ySub, &pSubSlot)) + continue; + + pSubSlot->dwCenterSlotNumber = pSlot->dwSlotNumber; + pSubSlot->dwItemIndex = pSlot->dwItemIndex; + } + } + else + { + pSlot->dwItemIndex = 0; + } + } +} + +BOOL CGridSlotWindow::CheckMoving(DWORD dwSlotNumber, DWORD dwItemIndex, const std::list & c_rSlotList) +{ + if (m_dwSlotStyle != SLOT_STYLE_PICK_UP) + return TRUE; + + for (std::list::const_iterator itor = c_rSlotList.begin(); itor != c_rSlotList.end(); ++itor) + { + TSlot * pSlot = *itor; + + if (dwSlotNumber != pSlot->dwCenterSlotNumber) // 들었던 자리가 아닐 경우에 + { + if (0 != pSlot->dwItemIndex || pSlot->dwCenterSlotNumber != pSlot->dwSlotNumber) // 아이템이 있고 + { + if (dwItemIndex != pSlot->dwItemIndex) // 다른 아이템이면 못 옮김 + return false; + } + } + } + + return true; +} + +void CGridSlotWindow::Destroy() +{ + CSlotWindow::Destroy(); + + m_SlotVector.clear(); + + __Initialize(); +} + +void CGridSlotWindow::__Initialize() +{ + m_dwxCount = 0; + m_dwyCount = 0; +} + +DWORD CGridSlotWindow::Type() +{ + static int s_Type = GetCRC32("CGridSlotWindow", strlen("CGridSlotWindow")); + return s_Type; +} + +BOOL CGridSlotWindow::OnIsType(DWORD dwType) +{ + if (CGridSlotWindow::Type() == dwType) + return TRUE; + + return CSlotWindow::OnIsType(dwType); +} + +CGridSlotWindow::CGridSlotWindow(PyObject * ppyObject) : CSlotWindow(ppyObject) +{ +} + +CGridSlotWindow::~CGridSlotWindow() +{ +} diff --git a/extension/src/port/EterPythonLib/PythonSlotWindow.cpp b/extension/src/port/EterPythonLib/PythonSlotWindow.cpp new file mode 100644 index 00000000..cdd3b077 --- /dev/null +++ b/extension/src/port/EterPythonLib/PythonSlotWindow.cpp @@ -0,0 +1,1442 @@ +#include "StdAfx.h" +#include "../EterBase/CRC32.h" +#include "../EterBase/Filename.h" +#include "PythonWindow.h" +#include "PythonSlotWindow.h" + +//#define __RENDER_SLOT_AREA__ + +using namespace UI; + +class UI::CSlotWindow::CSlotButton : public CButton +{ + public: + enum ESlotButtonType + { + SLOT_BUTTON_TYPE_PLUS, + SLOT_BUTTON_TYPE_COVER, + }; + + public: + CSlotButton(ESlotButtonType dwType, DWORD dwSlotNumber, CSlotWindow * pParent) : CButton(NULL) + { + m_dwSlotButtonType = dwType; + m_dwSlotNumber = dwSlotNumber; + m_pParent = pParent; + } + virtual ~CSlotButton() + { + } + + BOOL OnMouseLeftButtonDown() + { + if (!IsEnable()) + return TRUE; + if (UI::CWindowManager::Instance().IsAttaching()) + return TRUE; + + m_isPressed = TRUE; + Down(); + + return TRUE; + } + BOOL OnMouseLeftButtonUp() + { + if (!IsEnable()) + return TRUE; + if (!IsPressed()) + return TRUE; + + if (IsIn()) + SetCurrentVisual(&m_overVisual); + else + SetCurrentVisual(&m_upVisual); + + m_pParent->OnPressedSlotButton(m_dwSlotButtonType, m_dwSlotNumber); + + return TRUE; + } + + void OnMouseOverIn() + { + if (IsEnable()) + { + SetCurrentVisual(&m_overVisual); + } + m_pParent->OnOverInItem(m_dwSlotNumber); + } + void OnMouseOverOut() + { + if (IsEnable()) + { + SetUp(); + SetCurrentVisual(&m_upVisual); + } + m_pParent->OnOverOutItem(); + } + + protected: + ESlotButtonType m_dwSlotButtonType; + DWORD m_dwSlotNumber; + CSlotWindow * m_pParent; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class UI::CSlotWindow::CCoverButton : public CSlotButton +{ + public: + CCoverButton(ESlotButtonType dwType, DWORD dwSlotNumber, CSlotWindow * pParent) : CSlotButton(dwType, dwSlotNumber, pParent) + { + m_bLeftButtonEnable = TRUE; + m_bRightButtonEnable = TRUE; + } + virtual ~CCoverButton() + { + } + + void SetLeftButtonEnable(BOOL bEnable) + { + m_bLeftButtonEnable = bEnable; + } + void SetRightButtonEnable(BOOL bEnable) + { + m_bRightButtonEnable = bEnable; + } + + void OnRender() + { + } + + void RenderButton() + { + CButton::OnRender(); + } + + BOOL OnMouseLeftButtonDown() + { + if (!IsEnable()) + return TRUE; + if (m_bLeftButtonEnable) + { + CButton::OnMouseLeftButtonDown(); + } + else + { + m_pParent->OnMouseLeftButtonDown(); + } + return TRUE; + } + BOOL OnMouseLeftButtonUp() + { + if (!IsEnable()) + return TRUE; + if (m_bLeftButtonEnable) + { + CButton::OnMouseLeftButtonUp(); + m_pParent->OnMouseLeftButtonDown(); + } + else + { + m_pParent->OnMouseLeftButtonUp(); + } + return TRUE; + } + + BOOL OnMouseRightButtonDown() + { + if (!IsEnable()) + return TRUE; + if (m_bRightButtonEnable) + CButton::OnMouseLeftButtonDown(); + return TRUE; + } + BOOL OnMouseRightButtonUp() + { + if (!IsEnable()) + return TRUE; + m_pParent->OnMouseRightButtonDown(); + if (m_bRightButtonEnable) + CButton::OnMouseLeftButtonUp(); + return TRUE; + } + + protected: + BOOL m_bLeftButtonEnable; + BOOL m_bRightButtonEnable; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +class UI::CSlotWindow::CCoolTimeFinishEffect : public CAniImageBox +{ + public: + CCoolTimeFinishEffect(CSlotWindow * pParent, DWORD dwSlotIndex) : CAniImageBox(NULL) + { + m_pParent = pParent; + m_dwSlotIndex = dwSlotIndex; + } + virtual ~CCoolTimeFinishEffect() + { + } + + void OnEndFrame() + { + ((CSlotWindow *)m_pParent)->ReserveDestroyCoolTimeFinishEffect(m_dwSlotIndex); + } + + protected: + DWORD m_dwSlotIndex; +}; + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// + +// Set & Append + +void CSlotWindow::SetSlotType(DWORD dwType) +{ + m_dwSlotType = dwType; +} + +void CSlotWindow::SetSlotStyle(DWORD dwStyle) +{ + m_dwSlotStyle = dwStyle; +} + +void CSlotWindow::AppendSlot(DWORD dwIndex, int ixPosition, int iyPosition, int ixCellSize, int iyCellSize) +{ + TSlot Slot; + Slot.pInstance = NULL; + Slot.pNumberLine = NULL; + Slot.pCoverButton = NULL; + Slot.pSlotButton = NULL; + Slot.pSignImage = NULL; + Slot.pFinishCoolTimeEffect = NULL; + + ClearSlot(&Slot); + Slot.dwSlotNumber = dwIndex; + Slot.dwCenterSlotNumber = dwIndex; + Slot.ixPosition = ixPosition; + Slot.iyPosition = iyPosition; + Slot.ixCellSize = ixCellSize; + Slot.iyCellSize = iyCellSize; + m_SlotList.push_back(Slot); +} + +void CSlotWindow::SetCoverButton(DWORD dwIndex, const char * c_szUpImageName, const char * c_szOverImageName, const char * c_szDownImageName, const char * c_szDisableImageName, BOOL bLeftButtonEnable, BOOL bRightButtonEnable) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + CCoverButton *& rpCoverButton = pSlot->pCoverButton; + + if (!rpCoverButton) + { + rpCoverButton = new CCoverButton(CSlotButton::SLOT_BUTTON_TYPE_COVER, pSlot->dwSlotNumber, this); + CWindowManager::Instance().SetParent(rpCoverButton, this); + } + + rpCoverButton->SetLeftButtonEnable(bLeftButtonEnable); + rpCoverButton->SetRightButtonEnable(bRightButtonEnable); + rpCoverButton->SetUpVisual(c_szUpImageName); + rpCoverButton->SetOverVisual(c_szOverImageName); + rpCoverButton->SetDownVisual(c_szDownImageName); + rpCoverButton->SetDisableVisual(c_szDisableImageName); + rpCoverButton->Enable(); + rpCoverButton->Show(); + + // NOTE : Cover 버튼이 Plus 버튼을 가려버려서 임시 코드를.. + if (pSlot->pSlotButton) + { + SetTop(pSlot->pSlotButton); + } +} + +void CSlotWindow::EnableCoverButton(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + if (!pSlot->pCoverButton) + return; + + pSlot->pCoverButton->Enable(); +} + +void CSlotWindow::DisableCoverButton(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + if (!pSlot->pCoverButton) + return; + + pSlot->pCoverButton->Disable(); +} + +void CSlotWindow::SetAlwaysRenderCoverButton(DWORD dwIndex, bool bAlwaysRender) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + if (bAlwaysRender) + SET_BIT(pSlot->dwState, SLOT_STATE_ALWAYS_RENDER_COVER); + else + REMOVE_BIT(pSlot->dwState, SLOT_STATE_ALWAYS_RENDER_COVER); +} + +void CSlotWindow::ShowSlotBaseImage(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + pSlot->bRenderBaseSlotImage = true; +} + +void CSlotWindow::HideSlotBaseImage(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + pSlot->bRenderBaseSlotImage = false; +} + +BOOL CSlotWindow::IsDisableCoverButton(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return FALSE; + + if (!pSlot->pCoverButton) + return FALSE; + + return pSlot->pCoverButton->IsDisable(); +} + +void CSlotWindow::SetSlotBaseImage(const char * c_szFileName, float fr, float fg, float fb, float fa) +{ + __CreateBaseImage(c_szFileName, fr, fg, fb, fa); +} + +void CSlotWindow::AppendSlotButton(const char * c_szUpImageName, const char * c_szOverImageName, const char * c_szDownImageName) +{ + for (TSlotListIterator itor = m_SlotList.begin(); itor != m_SlotList.end(); ++itor) + { + TSlot & rSlot = *itor; + CSlotButton *& rpSlotButton = rSlot.pSlotButton; + + if (!rpSlotButton) + { + rpSlotButton = new CSlotButton(CSlotButton::SLOT_BUTTON_TYPE_PLUS, rSlot.dwSlotNumber, this); + rpSlotButton->AddFlag(FLAG_FLOAT); + CWindowManager::Instance().SetParent(rpSlotButton, this); + } + + rpSlotButton->SetUpVisual(c_szUpImageName); + rpSlotButton->SetOverVisual(c_szOverImageName); + rpSlotButton->SetDownVisual(c_szDownImageName); + rpSlotButton->SetPosition(rSlot.ixPosition + 1, rSlot.iyPosition + 19); + rpSlotButton->Hide(); + } +} + +void CSlotWindow::AppendRequirementSignImage(const char * c_szImageName) +{ + for (TSlotListIterator itor = m_SlotList.begin(); itor != m_SlotList.end(); ++itor) + { + TSlot & rSlot = *itor; + CImageBox *& rpSignImage = rSlot.pSignImage; + + if (!rpSignImage) + { + rpSignImage = new CImageBox(NULL); + CWindowManager::Instance().SetParent(rpSignImage, this); + } + + rpSignImage->LoadImage(c_szImageName); + rpSignImage->Hide(); + } +} + +BOOL CSlotWindow::HasSlot(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return FALSE; + + return TRUE; +} + +void CSlotWindow::SetSlot(DWORD dwIndex, DWORD dwVirtualNumber, BYTE byWidth, BYTE byHeight, CGraphicImage * pImage, D3DXCOLOR& diffuseColor) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + if (pSlot->isItem) + if (pSlot->dwItemIndex == dwVirtualNumber) + { + pSlot->dwState = 0; + pSlot->isItem = TRUE; + if (pImage && pSlot->pInstance) + { + pSlot->pInstance->SetImagePointer(pImage); + } + return; + } + + ClearSlot(pSlot); + pSlot->dwState = 0; + pSlot->isItem = TRUE; + pSlot->dwItemIndex = dwVirtualNumber; + + if (pImage) + { + assert(NULL == pSlot->pInstance); + pSlot->pInstance = CGraphicImageInstance::New(); + pSlot->pInstance->SetDiffuseColor(diffuseColor.r, diffuseColor.g, diffuseColor.b, diffuseColor.a); + pSlot->pInstance->SetImagePointer(pImage); + } + + pSlot->byxPlacedItemSize = byWidth; + pSlot->byyPlacedItemSize = byHeight; + + if (pSlot->pCoverButton) + { + pSlot->pCoverButton->Show(); + } +} + +void CSlotWindow::SetSlotCount(DWORD dwIndex, DWORD dwCount) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + if (dwCount <= 0) + { + if (pSlot->pNumberLine) + { + delete pSlot->pNumberLine; + pSlot->pNumberLine = NULL; + } + } + else + { + char szCount[16+1]; + _snprintf(szCount, sizeof(szCount), "%d", dwCount); + + if (!pSlot->pNumberLine) + { + CNumberLine * pNumberLine = new UI::CNumberLine(this); + pNumberLine->SetHorizontalAlign(CNumberLine::HORIZONTAL_ALIGN_RIGHT); + pNumberLine->Show(); + pSlot->pNumberLine = pNumberLine; + } + + pSlot->pNumberLine->SetNumber(szCount); + } +} + +void CSlotWindow::SetSlotCountNew(DWORD dwIndex, DWORD dwGrade, DWORD dwCount) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + if (dwCount <= 0) + { + if (pSlot->pNumberLine) + { + delete pSlot->pNumberLine; + pSlot->pNumberLine = NULL; + } + } + else + { + char szCount[16+1]; + + switch (dwGrade) + { + case 0: + _snprintf(szCount, sizeof(szCount), "%d", dwCount); + break; + case 1: + _snprintf(szCount, sizeof(szCount), "m%d", dwCount); + break; + case 2: + _snprintf(szCount, sizeof(szCount), "g%d", dwCount); + break; + case 3: + _snprintf(szCount, sizeof(szCount), "p"); + break; + } + + if (!pSlot->pNumberLine) + { + CNumberLine * pNumberLine = new UI::CNumberLine(this); + pNumberLine->SetHorizontalAlign(CNumberLine::HORIZONTAL_ALIGN_RIGHT); + pNumberLine->Show(); + pSlot->pNumberLine = pNumberLine; + } + + pSlot->pNumberLine->SetNumber(szCount); + } +} + +void CSlotWindow::SetSlotCoolTime(DWORD dwIndex, float fCoolTime, float fElapsedTime) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + pSlot->fCoolTime = fCoolTime; + pSlot->fStartCoolTime = CTimer::Instance().GetCurrentSecond() - fElapsedTime; +} + +void CSlotWindow::ActivateSlot(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + pSlot->bActive = TRUE; + + if (!m_pSlotActiveEffect) + { + __CreateSlotEnableEffect(); + } +} + +void CSlotWindow::DeactivateSlot(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + pSlot->bActive = FALSE; +} + +void CSlotWindow::ClearSlot(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + ClearSlot(pSlot); +} + +void CSlotWindow::ClearSlot(TSlot * pSlot) +{ + pSlot->bActive = FALSE; + pSlot->byxPlacedItemSize = 1; + pSlot->byyPlacedItemSize = 1; + + pSlot->isItem = FALSE; + pSlot->dwState = 0; + pSlot->fCoolTime = 0.0f; + pSlot->fStartCoolTime = 0.0f; + pSlot->dwCenterSlotNumber = 0xffffffff; + + pSlot->dwItemIndex = 0; + pSlot->bRenderBaseSlotImage = true; + + if (pSlot->pInstance) + { + CGraphicImageInstance::Delete(pSlot->pInstance); + pSlot->pInstance = NULL; + } + if (pSlot->pCoverButton) + { + pSlot->pCoverButton->Hide(); + } + if (pSlot->pSlotButton) + { + pSlot->pSlotButton->Hide(); + } + if (pSlot->pSignImage) + { + pSlot->pSignImage->Hide(); + } + if (pSlot->pFinishCoolTimeEffect) + { + pSlot->pFinishCoolTimeEffect->Hide(); + } +} + +void CSlotWindow::ClearAllSlot() +{ + Destroy(); +} + +void CSlotWindow::RefreshSlot() +{ + OnRefreshSlot(); + + // NOTE : Refresh 될때 ToolTip 도 갱신 합니다 - [levites] + if (IsRendering()) + { + TSlot * pSlot; + if (GetPickedSlotPointer(&pSlot)) + { + OnOverOutItem(); + OnOverInItem(pSlot->dwSlotNumber); + } + } +} + +void CSlotWindow::OnRefreshSlot() +{ +} + +DWORD CSlotWindow::GetSlotCount() +{ + return m_SlotList.size(); +} + +void CSlotWindow::LockSlot(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + pSlot->dwState |= SLOT_STATE_LOCK; +} +void CSlotWindow::UnlockSlot(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + pSlot->dwState ^= SLOT_STATE_LOCK; +} +void CSlotWindow::SetCantUseSlot(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + pSlot->dwState |= SLOT_STATE_CANT_USE; +} +void CSlotWindow::SetUseSlot(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + pSlot->dwState ^= SLOT_STATE_CANT_USE; +} +void CSlotWindow::EnableSlot(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + + REMOVE_BIT(pSlot->dwState, SLOT_STATE_DISABLE); + //pSlot->dwState |= SLOT_STATE_DISABLE; +} +void CSlotWindow::DisableSlot(DWORD dwIndex) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwIndex, &pSlot)) + return; + SET_BIT(pSlot->dwState, SLOT_STATE_DISABLE); + //pSlot->dwState ^= SLOT_STATE_DISABLE; +} + +// Select + +void CSlotWindow::SelectSlot(DWORD dwSelectingIndex) +{ + std::list::iterator itor = m_dwSelectedSlotIndexList.begin(); + for (; itor != m_dwSelectedSlotIndexList.end();) + { + if (dwSelectingIndex == *itor) + { + itor = m_dwSelectedSlotIndexList.erase(itor); + return; + } + else + { + ++itor; + } + } + + TSlot * pSlot; + if (GetSlotPointer(dwSelectingIndex, &pSlot)) + { + if (!pSlot->isItem) + return; + + m_dwSelectedSlotIndexList.push_back(dwSelectingIndex); + } +} + +BOOL CSlotWindow::isSelectedSlot(DWORD dwIndex) +{ + std::list::iterator itor = m_dwSelectedSlotIndexList.begin(); + for (; itor != m_dwSelectedSlotIndexList.end(); ++itor) + { + if (dwIndex == *itor) + return TRUE; + } + + return FALSE; +} + +void CSlotWindow::ClearSelected() +{ + m_dwSelectedSlotIndexList.clear(); +} + +DWORD CSlotWindow::GetSelectedSlotCount() +{ + return m_dwSelectedSlotIndexList.size(); +} + +DWORD CSlotWindow::GetSelectedSlotNumber(DWORD dwIndex) +{ + if (dwIndex >= m_dwSelectedSlotIndexList.size()) + return DWORD(-1); + + DWORD dwCount = 0; + std::list::iterator itor = m_dwSelectedSlotIndexList.begin(); + for (; itor != m_dwSelectedSlotIndexList.end(); ++itor) + { + if (dwIndex == dwCount) + break; + + ++dwCount; + } + + return *itor; +} + +void CSlotWindow::ShowSlotButton(DWORD dwSlotNumber) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwSlotNumber, &pSlot)) + return; + + if (pSlot->pSlotButton) + { + pSlot->pSlotButton->Show(); + } +} + +void CSlotWindow::HideAllSlotButton() +{ + for (TSlotListIterator itor = m_SlotList.begin(); itor != m_SlotList.end(); ++itor) + { + TSlot & rSlot = *itor; + + if (rSlot.pSlotButton) + { + rSlot.pSlotButton->Hide(); + } + } +} + +void CSlotWindow::ShowRequirementSign(DWORD dwSlotNumber) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwSlotNumber, &pSlot)) + return; + + if (!pSlot->pSignImage) + return; + + pSlot->pSignImage->Show(); +} + +void CSlotWindow::HideRequirementSign(DWORD dwSlotNumber) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwSlotNumber, &pSlot)) + return; + + if (!pSlot->pSignImage) + return; + + pSlot->pSignImage->Hide(); +} + +// Event + +BOOL CSlotWindow::OnMouseLeftButtonDown() +{ + TSlot * pSlot; + if (!GetPickedSlotPointer(&pSlot)) + { + UI::CWindowManager::Instance().DeattachIcon(); + return TRUE; + } + + if (pSlot->isItem && !(pSlot->dwState & SLOT_STATE_LOCK)) + { + OnSelectItemSlot(pSlot->dwSlotNumber); + } + else + { + OnSelectEmptySlot(pSlot->dwSlotNumber); + } + + return TRUE; +} + +BOOL CSlotWindow::OnMouseLeftButtonUp() +{ + if (UI::CWindowManager::Instance().IsAttaching()) + if (UI::CWindowManager::Instance().IsDragging()) + if (IsIn()) + { + UI::CWindow * pWin = UI::CWindowManager::Instance().GetPointWindow(); + + if (pWin) + if (pWin->IsType(UI::CSlotWindow::Type())) + { + UI::CSlotWindow * pSlotWin = (UI::CSlotWindow *)pWin; + + TSlot * pSlot; + if (!pSlotWin->GetPickedSlotPointer(&pSlot)) + { + UI::CWindowManager::Instance().DeattachIcon(); + return TRUE; + } + + if (pSlot->isItem) + pSlotWin->OnSelectItemSlot(pSlot->dwSlotNumber); + else + pSlotWin->OnSelectEmptySlot(pSlot->dwSlotNumber); + + return TRUE; + } + + return FALSE; + } + + return FALSE; +} + +BOOL CSlotWindow::OnMouseRightButtonDown() +{ + TSlot * pSlot; + if (!GetPickedSlotPointer(&pSlot)) + return TRUE; + + if (pSlot->isItem) + { + OnUnselectItemSlot(pSlot->dwSlotNumber); + } + else + { + OnUnselectEmptySlot(pSlot->dwSlotNumber); + } + + return TRUE; +} + +BOOL CSlotWindow::OnMouseLeftButtonDoubleClick() +{ + OnUseSlot(); + + return TRUE; +} + +void CSlotWindow::OnMouseOverOut() +{ + OnOverOutItem(); +} + +void CSlotWindow::OnMouseOver() +{ + // FIXME : 윈도우를 드래깅 하는 도중에 SetTop이 되어버리면 Capture가 풀어져 버린다. 그것의 방지 코드. + // 좀 더 근본적인 해결책을 찾아야 할 듯 - [levites] +// if (UI::CWindowManager::Instance().IsCapture()) +// if (!UI::CWindowManager::Instance().IsAttaching()) +// return; + + CWindow * pPointWindow = UI::CWindowManager::Instance().GetPointWindow(); + if (this == pPointWindow) + { + TSlot * pSlot; + if (GetPickedSlotPointer(&pSlot)) + { + if (OnOverInItem(pSlot->dwSlotNumber)) + return; + } + } + + OnOverOutItem(); +} + +void CSlotWindow::OnSelectEmptySlot(int iSlotNumber) +{ + PyCallClassMemberFunc(m_poHandler, "OnSelectEmptySlot", Py_BuildValue("(i)", iSlotNumber)); +} +void CSlotWindow::OnSelectItemSlot(int iSlotNumber) +{ +// OnOverOutItem(); + PyCallClassMemberFunc(m_poHandler, "OnSelectItemSlot", Py_BuildValue("(i)", iSlotNumber)); + + if (UI::CWindowManager::Instance().IsAttaching()) + OnOverOutItem(); +} +void CSlotWindow::OnUnselectEmptySlot(int iSlotNumber) +{ + PyCallClassMemberFunc(m_poHandler, "OnUnselectEmptySlot", Py_BuildValue("(i)", iSlotNumber)); +} +void CSlotWindow::OnUnselectItemSlot(int iSlotNumber) +{ + PyCallClassMemberFunc(m_poHandler, "OnUnselectItemSlot", Py_BuildValue("(i)", iSlotNumber)); +} +void CSlotWindow::OnUseSlot() +{ + TSlot * pSlot; + if (GetPickedSlotPointer(&pSlot)) + if (pSlot->isItem) + { + PyCallClassMemberFunc(m_poHandler, "OnUseSlot", Py_BuildValue("(i)", pSlot->dwSlotNumber)); + } +} + +BOOL CSlotWindow::OnOverInItem(DWORD dwSlotNumber) +{ + TSlot * pSlot; + if (!GetSlotPointer(dwSlotNumber, &pSlot)) + return FALSE; + + if (!pSlot->isItem) + return FALSE; + + if (pSlot->dwSlotNumber == m_dwToolTipSlotNumber) + return TRUE; + + m_dwToolTipSlotNumber = dwSlotNumber; + PyCallClassMemberFunc(m_poHandler, "OnOverInItem", Py_BuildValue("(i)", dwSlotNumber)); + + return TRUE; +} + +void CSlotWindow::OnOverOutItem() +{ + if (SLOT_NUMBER_NONE == m_dwToolTipSlotNumber) + return; + + m_dwToolTipSlotNumber = SLOT_NUMBER_NONE; + PyCallClassMemberFunc(m_poHandler, "OnOverOutItem", Py_BuildValue("()")); +} + +void CSlotWindow::OnPressedSlotButton(DWORD dwType, DWORD dwSlotNumber, BOOL isLeft) +{ + if (CSlotButton::SLOT_BUTTON_TYPE_PLUS == dwType) + { + PyCallClassMemberFunc(m_poHandler, "OnPressedSlotButton", Py_BuildValue("(i)", dwSlotNumber)); + } + else if (CSlotButton::SLOT_BUTTON_TYPE_COVER == dwType) + { + if (isLeft) + { + OnMouseLeftButtonDown(); + } + } +} + +void CSlotWindow::OnUpdate() +{ + for (std::deque::iterator itor = m_ReserveDestroyEffectDeque.begin(); itor != m_ReserveDestroyEffectDeque.end(); ++itor) + { + DWORD dwSlotIndex = *itor; + + TSlot * pSlot; + if (!GetSlotPointer(dwSlotIndex, &pSlot)) + continue; + + __DestroyFinishCoolTimeEffect(pSlot); + } + m_ReserveDestroyEffectDeque.clear(); + + if (m_pSlotActiveEffect) + m_pSlotActiveEffect->Update(); +} + +void CSlotWindow::OnRender() +{ + RenderSlotBaseImage(); + + switch (m_dwSlotStyle) + { + case SLOT_STYLE_PICK_UP: + OnRenderPickingSlot(); + break; + case SLOT_STYLE_SELECT: + OnRenderSelectedSlot(); + break; + } + + std::for_each(m_pChildList.begin(), m_pChildList.end(), std::mem_fn(&CWindow::OnRender)); + + TSlotListIterator itor; + + // + // 모든 슬롯 상자 그리기 + ////////////////////////////////////////////////////////////////////////// +#ifdef __RENDER_SLOT_AREA__ + CPythonGraphic::Instance().SetDiffuseColor(0.5f, 0.5f, 0.5f); + for (itor = m_SlotList.begin(); itor != m_SlotList.end(); ++itor) + { + TSlot & rSlot = *itor; + CPythonGraphic::Instance().RenderBox2d(m_rect.left + rSlot.ixPosition, + m_rect.top + rSlot.iyPosition, + m_rect.left + rSlot.ixPosition + rSlot.ixCellSize, + m_rect.top + rSlot.iyPosition + rSlot.iyCellSize); + } + CPythonGraphic::Instance().SetDiffuseColor(1.0f, 0.0f, 0.0f, 1.0f); + CPythonGraphic::Instance().RenderBox2d(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom); +#endif + ////////////////////////////////////////////////////////////////////////// + + for (itor = m_SlotList.begin(); itor != m_SlotList.end(); ++itor) + { + TSlot & rSlot = *itor; + + if (rSlot.pSlotButton) + { + rSlot.pSlotButton->SetPosition(rSlot.ixPosition + 1, rSlot.iyPosition + 19); + } + if (rSlot.pSignImage) + { + rSlot.pSignImage->SetPosition(rSlot.ixPosition - 7, rSlot.iyPosition + 10); + } + + if (rSlot.pInstance) + { + rSlot.pInstance->SetPosition(m_rect.left + rSlot.ixPosition, m_rect.top + rSlot.iyPosition); + rSlot.pInstance->Render(); + } + + if (!rSlot.isItem) + { + if (IS_SET(rSlot.dwState, SLOT_STATE_ALWAYS_RENDER_COVER)) + { + rSlot.pCoverButton->Show(); + rSlot.pCoverButton->SetPosition(rSlot.ixPosition, rSlot.iyPosition); + rSlot.pCoverButton->RenderButton(); + } + + continue; + } + + if (IS_SET(rSlot.dwState, SLOT_STATE_DISABLE)) + { + CPythonGraphic::Instance().SetDiffuseColor(1.0f, 0.0f, 0.0f, 0.3f); + CPythonGraphic::Instance().RenderBar2d(m_rect.left + rSlot.ixPosition, + m_rect.top + rSlot.iyPosition, + m_rect.left + rSlot.ixPosition + rSlot.ixCellSize, + m_rect.top + rSlot.iyPosition + rSlot.iyCellSize); + } + + if (rSlot.fCoolTime != 0.0f) + { + float fcurTime = CTimer::Instance().GetCurrentSecond(); + float fPercentage = (fcurTime - rSlot.fStartCoolTime) / rSlot.fCoolTime; + CPythonGraphic::Instance().RenderCoolTimeBox(m_rect.left + rSlot.ixPosition + 16.0f, m_rect.top + rSlot.iyPosition + 16.0f, 16.0f, fPercentage); + + if (fcurTime - rSlot.fStartCoolTime >= rSlot.fCoolTime) + { + // 쿨타임이 끝난지 1초 이내라면.. + if ((fcurTime - rSlot.fStartCoolTime) - rSlot.fCoolTime < 1.0f) + __CreateFinishCoolTimeEffect(&rSlot); + + rSlot.fCoolTime = 0.0f; + rSlot.fStartCoolTime = 0.0f; + } + } + + if (rSlot.pCoverButton) + { + rSlot.pCoverButton->SetPosition(rSlot.ixPosition, rSlot.iyPosition); + rSlot.pCoverButton->RenderButton(); + } + + if (rSlot.pNumberLine) + { + int ix = rSlot.byxPlacedItemSize*ITEM_WIDTH + rSlot.ixPosition - 4; + int iy = rSlot.iyPosition + rSlot.byyPlacedItemSize*ITEM_HEIGHT - 12 + 2; + rSlot.pNumberLine->SetPosition(ix, iy); + rSlot.pNumberLine->Update(); + rSlot.pNumberLine->Render(); + } + + if (rSlot.pFinishCoolTimeEffect) + { + rSlot.pFinishCoolTimeEffect->SetPosition(rSlot.ixPosition, rSlot.iyPosition); + rSlot.pFinishCoolTimeEffect->Update(); + rSlot.pFinishCoolTimeEffect->Render(); + } + + if (rSlot.bActive) + if (m_pSlotActiveEffect) + { + int ix = m_rect.left + rSlot.ixPosition; + int iy = m_rect.top + rSlot.iyPosition; + m_pSlotActiveEffect->SetPosition(ix, iy); + m_pSlotActiveEffect->Render(); + } + } + + RenderLockedSlot(); +} + +void CSlotWindow::RenderSlotBaseImage() +{ + if (!m_pBaseImageInstance) + return; + + for (TSlotListIterator itor = m_SlotList.begin(); itor != m_SlotList.end(); ++itor) + { + TSlot & rSlot = *itor; + + if (!rSlot.bRenderBaseSlotImage) + continue; + + m_pBaseImageInstance->SetPosition(m_rect.left + rSlot.ixPosition, m_rect.top + rSlot.iyPosition); + m_pBaseImageInstance->Render(); + } +} + +void CSlotWindow::OnRenderPickingSlot() +{ + if (!UI::CWindowManager::Instance().IsAttaching()) + return; + + TSlot * pSlot; + if (!GetSelectedSlotPointer(&pSlot)) + return; + + CPythonGraphic::Instance().SetDiffuseColor(1.0f, 1.0f, 1.0f, 0.5f); + CPythonGraphic::Instance().RenderBar2d(m_rect.left + pSlot->ixPosition, + m_rect.top + pSlot->iyPosition, + m_rect.left + pSlot->ixPosition + pSlot->ixCellSize, + m_rect.top + pSlot->iyPosition + pSlot->iyCellSize); +} + +void CSlotWindow::OnRenderSelectedSlot() +{ + std::list::iterator itor = m_dwSelectedSlotIndexList.begin(); + for (; itor != m_dwSelectedSlotIndexList.end(); ++itor) + { + TSlot * pSlot; + if (!GetSlotPointer(*itor, &pSlot)) + continue; + + CPythonGraphic::Instance().SetDiffuseColor(1.0f, 1.0f, 1.0f, 0.5f); + CPythonGraphic::Instance().RenderBar2d(m_rect.left + pSlot->ixPosition, + m_rect.top + pSlot->iyPosition, + m_rect.left + pSlot->ixPosition + pSlot->ixCellSize, + m_rect.top + pSlot->iyPosition + pSlot->iyCellSize); + } +} + +void CSlotWindow::RenderLockedSlot() +{ + CPythonGraphic::Instance().SetDiffuseColor(0.0f, 0.0f, 0.0f, 0.5f); + for (TSlotListIterator itor = m_SlotList.begin(); itor != m_SlotList.end(); ++itor) + { + TSlot & rSlot = *itor; + + if (!rSlot.isItem) + continue; + + if (rSlot.dwState & SLOT_STATE_LOCK) + { + CPythonGraphic::Instance().RenderBar2d(m_rect.left + rSlot.ixPosition, + m_rect.top + rSlot.iyPosition, + m_rect.left + rSlot.ixPosition + rSlot.ixCellSize, + m_rect.top + rSlot.iyPosition + rSlot.iyCellSize); + } + } +} + +// Check Slot + +BOOL CSlotWindow::GetSlotPointer(DWORD dwIndex, TSlot ** ppSlot) +{ + for (TSlotListIterator itor = m_SlotList.begin(); itor != m_SlotList.end(); ++itor) + { + TSlot & rSlot = *itor; + + if (dwIndex == rSlot.dwSlotNumber) + { + *ppSlot = &rSlot; + return TRUE; + } + } + + return FALSE; +} + +BOOL CSlotWindow::GetSelectedSlotPointer(TSlot ** ppSlot) +{ + long lx, ly; + GetMouseLocalPosition(lx, ly); + + for (TSlotListIterator itor = m_SlotList.begin(); itor != m_SlotList.end(); ++itor) + { + TSlot & rSlot = *itor; + + if (lx >= rSlot.ixPosition) + if (ly >= rSlot.iyPosition) + if (lx <= rSlot.ixPosition + rSlot.ixCellSize) + if (ly <= rSlot.iyPosition + rSlot.iyCellSize) + { + *ppSlot = &rSlot; + return TRUE; + } + } + + return FALSE; +} + +BOOL CSlotWindow::GetPickedSlotPointer(TSlot ** ppSlot) +{ + long lx, ly; + CWindowManager::Instance().GetMousePosition(lx, ly); + + int ixLocal = lx - m_rect.left; + int iyLocal = ly - m_rect.top; + + // NOTE : 왼쪽 맨위 상단 한곳이 기준 이라는 점을 이용해 왼쪽 위에서부터 오른쪽 아래로 + // 차례로 검색해 감으로써 덮혀 있는 Slot은 자동 무시 된다는 특성을 이용한다. - [levites] + for (TSlotListIterator itor = m_SlotList.begin(); itor != m_SlotList.end(); ++itor) + { + TSlot & rSlot = *itor; + + int ixCellSize = rSlot.ixCellSize; + int iyCellSize = rSlot.iyCellSize; + + // NOTE : Item이 Hide 되어있을 경우를 위한.. + if (rSlot.isItem) + { + ixCellSize = max(rSlot.ixCellSize, int(rSlot.byxPlacedItemSize * ITEM_WIDTH)); + iyCellSize = max(rSlot.iyCellSize, int(rSlot.byyPlacedItemSize * ITEM_HEIGHT)); + } + + if (ixLocal >= rSlot.ixPosition) + if (iyLocal >= rSlot.iyPosition) + if (ixLocal <= rSlot.ixPosition + ixCellSize) + if (iyLocal <= rSlot.iyPosition + iyCellSize) + { + *ppSlot = &rSlot; + return TRUE; + } + } + + return FALSE; +} + +void CSlotWindow::SetUseMode(BOOL bFlag) +{ + m_isUseMode = bFlag; +} + +void CSlotWindow::SetUsableItem(BOOL bFlag) +{ + m_isUsableItem = bFlag; +} + +void CSlotWindow::ReserveDestroyCoolTimeFinishEffect(DWORD dwSlotIndex) +{ + m_ReserveDestroyEffectDeque.push_back(dwSlotIndex); +} + +DWORD CSlotWindow::Type() +{ + static int s_Type = GetCRC32("CSlotWindow", strlen("CSlotWindow")); + return s_Type; +} + +BOOL CSlotWindow::OnIsType(DWORD dwType) +{ + if (CSlotWindow::Type() == dwType) + return TRUE; + + return CWindow::OnIsType(dwType); +} + +void CSlotWindow::__CreateToggleSlotImage() +{ + __DestroyToggleSlotImage(); + + m_pToggleSlotImage = new CImageBox(NULL); + m_pToggleSlotImage->LoadImage("d:/ymir work/ui/public/slot_toggle.sub"); + m_pToggleSlotImage->Show(); +} + +void CSlotWindow::__CreateSlotEnableEffect() +{ + __DestroySlotEnableEffect(); + + m_pSlotActiveEffect = new CAniImageBox(NULL); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/00.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/01.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/02.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/03.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/04.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/05.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/06.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/07.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/08.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/09.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/10.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/11.sub"); + m_pSlotActiveEffect->AppendImage("d:/ymir work/ui/public/slotactiveeffect/12.sub"); + m_pSlotActiveEffect->SetRenderingMode(CGraphicExpandedImageInstance::RENDERING_MODE_SCREEN); + m_pSlotActiveEffect->Show(); +} + +void CSlotWindow::__CreateFinishCoolTimeEffect(TSlot * pSlot) +{ + __DestroyFinishCoolTimeEffect(pSlot); + + CAniImageBox * pFinishCoolTimeEffect = new CCoolTimeFinishEffect(this, pSlot->dwSlotNumber); + pFinishCoolTimeEffect->AppendImage("d:/ymir work/ui/public/slotfinishcooltimeeffect/00.sub"); + pFinishCoolTimeEffect->AppendImage("d:/ymir work/ui/public/slotfinishcooltimeeffect/01.sub"); + pFinishCoolTimeEffect->AppendImage("d:/ymir work/ui/public/slotfinishcooltimeeffect/02.sub"); + pFinishCoolTimeEffect->AppendImage("d:/ymir work/ui/public/slotfinishcooltimeeffect/03.sub"); + pFinishCoolTimeEffect->AppendImage("d:/ymir work/ui/public/slotfinishcooltimeeffect/04.sub"); + pFinishCoolTimeEffect->AppendImage("d:/ymir work/ui/public/slotfinishcooltimeeffect/05.sub"); + pFinishCoolTimeEffect->AppendImage("d:/ymir work/ui/public/slotfinishcooltimeeffect/06.sub"); + pFinishCoolTimeEffect->AppendImage("d:/ymir work/ui/public/slotfinishcooltimeeffect/07.sub"); + pFinishCoolTimeEffect->AppendImage("d:/ymir work/ui/public/slotfinishcooltimeeffect/08.sub"); + pFinishCoolTimeEffect->AppendImage("d:/ymir work/ui/public/slotfinishcooltimeeffect/09.sub"); + pFinishCoolTimeEffect->AppendImage("d:/ymir work/ui/public/slotfinishcooltimeeffect/10.sub"); + pFinishCoolTimeEffect->SetRenderingMode(CGraphicExpandedImageInstance::RENDERING_MODE_SCREEN); + pFinishCoolTimeEffect->ResetFrame(); + pFinishCoolTimeEffect->SetDelay(2); + pFinishCoolTimeEffect->Show(); + + pSlot->pFinishCoolTimeEffect = pFinishCoolTimeEffect; +} + +void CSlotWindow::__CreateBaseImage(const char * c_szFileName, float fr, float fg, float fb, float fa) +{ + __DestroyBaseImage(); + + CGraphicImage * pImage = (CGraphicImage *)CResourceManager::Instance().GetResourcePointer(c_szFileName); + m_pBaseImageInstance = CGraphicImageInstance::New(); + m_pBaseImageInstance->SetImagePointer(pImage); + m_pBaseImageInstance->SetDiffuseColor(fr, fg, fb, fa); +} + +void CSlotWindow::__DestroyToggleSlotImage() +{ + if (m_pToggleSlotImage) + { + delete m_pToggleSlotImage; + m_pToggleSlotImage = NULL; + } +} + +void CSlotWindow::__DestroySlotEnableEffect() +{ + if (m_pSlotActiveEffect) + { + delete m_pSlotActiveEffect; + m_pSlotActiveEffect = NULL; + } +} + +void CSlotWindow::__DestroyFinishCoolTimeEffect(TSlot * pSlot) +{ + if (pSlot->pFinishCoolTimeEffect) + { + delete pSlot->pFinishCoolTimeEffect; + pSlot->pFinishCoolTimeEffect = NULL; + } +} + +void CSlotWindow::__DestroyBaseImage() +{ + if (m_pBaseImageInstance) + { + CGraphicImageInstance::Delete(m_pBaseImageInstance); + m_pBaseImageInstance = NULL; + } +} + +void CSlotWindow::__Initialize() +{ + m_dwSlotType = 0; + m_dwSlotStyle = SLOT_STYLE_PICK_UP; + m_dwToolTipSlotNumber = SLOT_NUMBER_NONE; + + m_isUseMode = FALSE; + m_isUsableItem = FALSE; + + m_pToggleSlotImage = NULL; + m_pSlotActiveEffect = NULL; + m_pBaseImageInstance = NULL; +} + +void CSlotWindow::Destroy() +{ + for (TSlotListIterator itor = m_SlotList.begin(); itor != m_SlotList.end(); ++itor) + { + TSlot & rSlot = *itor; + + ClearSlot(&rSlot); + + if (rSlot.pNumberLine) + { + delete rSlot.pNumberLine; + rSlot.pNumberLine = NULL; + } + if (rSlot.pCoverButton) + { + CWindowManager::Instance().DestroyWindow(rSlot.pCoverButton); + } + if (rSlot.pSlotButton) + { + CWindowManager::Instance().DestroyWindow(rSlot.pSlotButton); + } + if (rSlot.pSignImage) + { + CWindowManager::Instance().DestroyWindow(rSlot.pSignImage); + } + if (rSlot.pFinishCoolTimeEffect) + { + CWindowManager::Instance().DestroyWindow(rSlot.pFinishCoolTimeEffect); + } + } + + m_SlotList.clear(); + + __DestroyToggleSlotImage(); + __DestroySlotEnableEffect(); + __DestroyBaseImage(); + + __Initialize(); +} + +CSlotWindow::CSlotWindow(PyObject * ppyObject) : CWindow(ppyObject) +{ + __Initialize(); +} + +CSlotWindow::~CSlotWindow() +{ + Destroy(); +} diff --git a/extension/src/port/EterPythonLib/PythonWindow.cpp b/extension/src/port/EterPythonLib/PythonWindow.cpp new file mode 100644 index 00000000..9c0a2e63 --- /dev/null +++ b/extension/src/port/EterPythonLib/PythonWindow.cpp @@ -0,0 +1,2024 @@ +#include "StdAfx.h" +#include "../EterBase/CRC32.h" +#include "PythonWindow.h" +#include "PythonSlotWindow.h" +#include "PythonWindowManager.h" + +BOOL g_bOutlineBoxEnable = FALSE; + +namespace UI +{ + + CWindow::CWindow(PyObject * ppyObject) : + m_x(0), + m_y(0), + m_lWidth(0), + m_lHeight(0), + m_poHandler(ppyObject), + m_bShow(false), + m_pParent(NULL), + m_dwFlag(0), + m_isUpdatingChildren(FALSE) + { +#ifdef _DEBUG + static DWORD DEBUG_dwGlobalCounter=0; + DEBUG_dwCounter=DEBUG_dwGlobalCounter++; + + m_strName = "!!debug"; +#endif + //assert(m_poHandler != NULL); + m_HorizontalAlign = HORIZONTAL_ALIGN_LEFT; + m_VerticalAlign = VERTICAL_ALIGN_TOP; + m_rect.bottom = m_rect.left = m_rect.right = m_rect.top = 0; + m_limitBiasRect.bottom = m_limitBiasRect.left = m_limitBiasRect.right = m_limitBiasRect.top = 0; + } + + CWindow::~CWindow() + { + } + + DWORD CWindow::Type() + { + static DWORD s_dwType = GetCRC32("CWindow", strlen("CWindow")); + return (s_dwType); + } + + BOOL CWindow::IsType(DWORD dwType) + { + return OnIsType(dwType); + } + + BOOL CWindow::OnIsType(DWORD dwType) + { + if (CWindow::Type() == dwType) + return TRUE; + + return FALSE; + } + + struct FClear + { + void operator () (CWindow * pWin) + { + pWin->Clear(); + } + }; + + void CWindow::Clear() + { + // FIXME : Children을 즉시 Delete하지는 않는다. + // 어차피 Python쪽에서 Destroy가 하나씩 다시 호출 될 것이므로.. + // 하지만 만약을 위해 링크는 끊어 놓는다. + // 더 좋은 형태는 있는가? - [levites] + std::for_each(m_pChildList.begin(), m_pChildList.end(), FClear()); + m_pChildList.clear(); + + m_pParent = NULL; + DestroyHandle(); + Hide(); + } + + void CWindow::DestroyHandle() + { + m_poHandler = NULL; + } + + void CWindow::Show() + { + m_bShow = true; + } + + void CWindow::Hide() + { + m_bShow = false; + } + + // NOTE : IsShow는 "자신이 보이는가?" 이지만, __IsShowing은 "자신이 그려지고 있는가?" 를 체크한다 + // 자신은 Show 지만 Tree 위쪽의 Parent 중 하나는 Hide 일 수 있으므로.. - [levites] + bool CWindow::IsRendering() + { + if (!IsShow()) + return false; + + if (!m_pParent) + return true; + + return m_pParent->IsRendering(); + } + + void CWindow::__RemoveReserveChildren() + { + if (m_pReserveChildList.empty()) + return; + + TWindowContainer::iterator it; + for(it = m_pReserveChildList.begin(); it != m_pReserveChildList.end(); ++it) + { + m_pChildList.remove(*it); + } + m_pReserveChildList.clear(); + } + + void CWindow::Update() + { + if (!IsShow()) + return; + + __RemoveReserveChildren(); + + OnUpdate(); + + m_isUpdatingChildren = TRUE; + TWindowContainer::iterator it; + for(it = m_pChildList.begin(); it != m_pChildList.end();) + { + TWindowContainer::iterator it_next = it; + ++it_next; + (*it)->Update(); + it = it_next; + } + m_isUpdatingChildren = FALSE; + } + + void CWindow::Render() + { + if (!IsShow()) + return; + + OnRender(); + + if (g_bOutlineBoxEnable) + { + CPythonGraphic::Instance().SetDiffuseColor(1.0f, 1.0f, 1.0f); + CPythonGraphic::Instance().RenderBox2d(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom); + } + + std::for_each(m_pChildList.begin(), m_pChildList.end(), std::mem_fn(&CWindow::Render)); + } + + void CWindow::OnUpdate() + { + if (!m_poHandler) + return; + + if (!IsShow()) + return; + + static PyObject* poFuncName_OnUpdate = PyString_InternFromString("OnUpdate"); + + //PyCallClassMemberFunc(m_poHandler, "OnUpdate", BuildEmptyTuple()); + PyCallClassMemberFunc_ByPyString(m_poHandler, poFuncName_OnUpdate, BuildEmptyTuple()); + + } + + void CWindow::OnRender() + { + if (!m_poHandler) + return; + + if (!IsShow()) + return; + + //PyCallClassMemberFunc(m_poHandler, "OnRender", BuildEmptyTuple()); + PyCallClassMemberFunc(m_poHandler, "OnRender", BuildEmptyTuple()); + } + + void CWindow::SetName(const char * c_szName) + { + m_strName = c_szName; + } + + void CWindow::SetSize(long width, long height) + { + m_lWidth = width; + m_lHeight = height; + + m_rect.right = m_rect.left + m_lWidth; + m_rect.bottom = m_rect.top + m_lHeight; + } + + void CWindow::SetHorizontalAlign(DWORD dwAlign) + { + m_HorizontalAlign = (EHorizontalAlign)dwAlign; + UpdateRect(); + } + + void CWindow::SetVerticalAlign(DWORD dwAlign) + { + m_VerticalAlign = (EVerticalAlign)dwAlign; + UpdateRect(); + } + + void CWindow::SetPosition(long x, long y) + { + m_x = x; + m_y = y; + + UpdateRect(); + } + + void CWindow::GetPosition(long * plx, long * ply) + { + *plx = m_x; + *ply = m_y; + } + + long CWindow::UpdateRect() + { + m_rect.top = m_y; + if (m_pParent) + { + switch (m_VerticalAlign) + { + case VERTICAL_ALIGN_BOTTOM: + m_rect.top = m_pParent->GetHeight() - m_rect.top; + break; + case VERTICAL_ALIGN_CENTER: + m_rect.top = (m_pParent->GetHeight() - GetHeight()) / 2 + m_rect.top; + break; + } + m_rect.top += m_pParent->m_rect.top; + } + m_rect.bottom = m_rect.top + m_lHeight; + +#if defined( _USE_CPP_RTL_FLIP ) + if( m_pParent == NULL ) { + m_rect.left = m_x; + m_rect.right = m_rect.left + m_lWidth; + } else { + if( m_pParent->IsFlag(UI::CWindow::FLAG_RTL) == true ) { + m_rect.left = m_pParent->GetWidth() - m_lWidth - m_x; + switch (m_HorizontalAlign) + { + case HORIZONTAL_ALIGN_RIGHT: + m_rect.left = - m_x; + break; + case HORIZONTAL_ALIGN_CENTER: + m_rect.left = m_pParent->GetWidth() / 2 - GetWidth() - m_x; + break; + } + m_rect.left += m_pParent->m_rect.left; + m_rect.right = m_rect.left + m_lWidth; + } else { + m_rect.left = m_x; + switch (m_HorizontalAlign) + { + case HORIZONTAL_ALIGN_RIGHT: + m_rect.left = m_pParent->GetWidth() - m_rect.left; + break; + case HORIZONTAL_ALIGN_CENTER: + m_rect.left = (m_pParent->GetWidth() - GetWidth()) / 2 + m_rect.left; + break; + } + m_rect.left += m_pParent->m_rect.left; + m_rect.right = m_rect.left + m_lWidth; + } + } +#else + m_rect.left = m_x; + if (m_pParent) + { + switch (m_HorizontalAlign) + { + case HORIZONTAL_ALIGN_RIGHT: + m_rect.left = ::abs(m_pParent->GetWidth()) - m_rect.left; + break; + case HORIZONTAL_ALIGN_CENTER: + m_rect.left = m_pParent->GetWidth() / 2 - GetWidth() / 2 + m_rect.left; + break; + } + m_rect.left += 0L < m_pParent->GetWidth() ? m_pParent->m_rect.left : m_pParent->m_rect.right + ::abs(m_pParent->GetWidth()); + } + m_rect.right = m_rect.left + m_lWidth; +#endif + std::for_each(m_pChildList.begin(), m_pChildList.end(), std::mem_fn(&CWindow::UpdateRect)); + + OnChangePosition(); + + return 1; + } + + void CWindow::GetLocalPosition(long & rlx, long & rly) + { + rlx = rlx - m_rect.left; + rly = rly - m_rect.top; + } + + void CWindow::GetMouseLocalPosition(long & rlx, long & rly) + { + CWindowManager::Instance().GetMousePosition(rlx, rly); + rlx = rlx - m_rect.left; + rly = rly - m_rect.top; + } + + void CWindow::AddChild(CWindow * pWin) + { + m_pChildList.push_back(pWin); + pWin->m_pParent = this; + } + + CWindow * CWindow::GetRoot() + { + if (m_pParent) + if (m_pParent->IsWindow()) + return m_pParent->GetRoot(); + + return this; + } + + CWindow * CWindow::GetParent() + { + return m_pParent; + } + + bool CWindow::IsChild(CWindow * pWin) + { + std::list::iterator itor = m_pChildList.begin(); + + while (itor != m_pChildList.end()) + { + if (*itor == pWin) + return true; + + ++itor; + } + + return false; + } + + void CWindow::DeleteChild(CWindow * pWin) + { + if (m_isUpdatingChildren) + { + m_pReserveChildList.push_back(pWin); + } + else + { + m_pChildList.remove(pWin); + } + } + + void CWindow::SetTop(CWindow * pWin) + { + if (!pWin->IsFlag(CWindow::FLAG_FLOAT)) + return; + + TWindowContainer::iterator itor = std::find(m_pChildList.begin(), m_pChildList.end(), pWin); + if (m_pChildList.end() != itor) + { + m_pChildList.push_back(*itor); + m_pChildList.erase(itor); + + pWin->OnTop(); + } + else + { + TraceError(" CWindow::SetTop - Failed to find child window\n"); + } + } + + void CWindow::OnMouseDrag(long lx, long ly) + { + PyCallClassMemberFunc(m_poHandler, "OnMouseDrag", Py_BuildValue("(ii)", lx, ly)); + } + + void CWindow::OnMoveWindow(long lx, long ly) + { + PyCallClassMemberFunc(m_poHandler, "OnMoveWindow", Py_BuildValue("(ii)", lx, ly)); + } + + void CWindow::OnSetFocus() + { + //PyCallClassMemberFunc(m_poHandler, "OnSetFocus", BuildEmptyTuple()); + PyCallClassMemberFunc(m_poHandler, "OnSetFocus", BuildEmptyTuple()); + } + + void CWindow::OnKillFocus() + { + PyCallClassMemberFunc(m_poHandler, "OnKillFocus", BuildEmptyTuple()); + } + + void CWindow::OnMouseOverIn() + { + PyCallClassMemberFunc(m_poHandler, "OnMouseOverIn", BuildEmptyTuple()); + } + + void CWindow::OnMouseOverOut() + { + PyCallClassMemberFunc(m_poHandler, "OnMouseOverOut", BuildEmptyTuple()); + } + + void CWindow::OnMouseOver() + { + } + + void CWindow::OnDrop() + { + PyCallClassMemberFunc(m_poHandler, "OnDrop", BuildEmptyTuple()); + } + + void CWindow::OnTop() + { + PyCallClassMemberFunc(m_poHandler, "OnTop", BuildEmptyTuple()); + } + + void CWindow::OnIMEUpdate() + { + PyCallClassMemberFunc(m_poHandler, "OnIMEUpdate", BuildEmptyTuple()); + } + + BOOL CWindow::RunIMETabEvent() + { + if (!IsRendering()) + return FALSE; + + if (OnIMETabEvent()) + return TRUE; + + TWindowContainer::reverse_iterator itor; + for (itor = m_pChildList.rbegin(); itor != m_pChildList.rend(); ++itor) + { + CWindow * pWindow = *itor; + + if (pWindow->RunIMETabEvent()) + return TRUE; + } + + return FALSE; + } + + BOOL CWindow::RunIMEReturnEvent() + { + if (!IsRendering()) + return FALSE; + + if (OnIMEReturnEvent()) + return TRUE; + + TWindowContainer::reverse_iterator itor; + for (itor = m_pChildList.rbegin(); itor != m_pChildList.rend(); ++itor) + { + CWindow * pWindow = *itor; + + if (pWindow->RunIMEReturnEvent()) + return TRUE; + } + + return FALSE; + } + + BOOL CWindow::RunIMEKeyDownEvent(int ikey) + { + if (!IsRendering()) + return FALSE; + + if (OnIMEKeyDownEvent(ikey)) + return TRUE; + + TWindowContainer::reverse_iterator itor; + for (itor = m_pChildList.rbegin(); itor != m_pChildList.rend(); ++itor) + { + CWindow * pWindow = *itor; + + if (pWindow->RunIMEKeyDownEvent(ikey)) + return TRUE; + } + + return FALSE; + } + + CWindow * CWindow::RunKeyDownEvent(int ikey) + { + if (OnKeyDown(ikey)) + return this; + + TWindowContainer::reverse_iterator itor; + for (itor = m_pChildList.rbegin(); itor != m_pChildList.rend(); ++itor) + { + CWindow * pWindow = *itor; + + if (pWindow->IsShow()) + { + CWindow * pProcessedWindow = pWindow->RunKeyDownEvent(ikey); + if (NULL != pProcessedWindow) + { + return pProcessedWindow; + } + } + } + + return NULL; + } + + BOOL CWindow::RunKeyUpEvent(int ikey) + { + if (OnKeyUp(ikey)) + return TRUE; + + TWindowContainer::reverse_iterator itor; + for (itor = m_pChildList.rbegin(); itor != m_pChildList.rend(); ++itor) + { + CWindow * pWindow = *itor; + + if (pWindow->IsShow()) + if (pWindow->RunKeyUpEvent(ikey)) + return TRUE; + } + + return FALSE; + } + + BOOL CWindow::RunPressEscapeKeyEvent() + { + TWindowContainer::reverse_iterator itor; + for (itor = m_pChildList.rbegin(); itor != m_pChildList.rend(); ++itor) + { + CWindow * pWindow = *itor; + + if (pWindow->IsShow()) + if (pWindow->RunPressEscapeKeyEvent()) + return TRUE; + } + + if (OnPressEscapeKey()) + return TRUE; + + return FALSE; + } + + BOOL CWindow::RunPressExitKeyEvent() + { + TWindowContainer::reverse_iterator itor; + for (itor = m_pChildList.rbegin(); itor != m_pChildList.rend(); ++itor) + { + CWindow * pWindow = *itor; + + if (pWindow->RunPressExitKeyEvent()) + return TRUE; + + if (pWindow->IsShow()) + if (pWindow->OnPressExitKey()) + return TRUE; + } + + return FALSE; + } + + BOOL CWindow::OnMouseLeftButtonDown() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnMouseLeftButtonDown", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnMouseLeftButtonUp() + { + PyCallClassMemberFunc(m_poHandler, "OnMouseLeftButtonUp", BuildEmptyTuple()); + return TRUE; // NOTE : ButtonUp은 예외로 무조건 TRUE + } + + BOOL CWindow::OnMouseLeftButtonDoubleClick() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnMouseLeftButtonDoubleClick", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnMouseRightButtonDown() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnMouseRightButtonDown", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnMouseRightButtonUp() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnMouseRightButtonUp", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnMouseRightButtonDoubleClick() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnMouseRightButtonDoubleClick", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnMouseMiddleButtonDown() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnMouseMiddleButtonDown", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnMouseMiddleButtonUp() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnMouseMiddleButtonUp", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnIMETabEvent() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnIMETab", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnIMEReturnEvent() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnIMEReturn", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnIMEKeyDownEvent(int ikey) + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnIMEKeyDown", Py_BuildValue("(i)", ikey), &lValue)) + if (0 != lValue) + return TRUE; + + 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; + if (PyCallClassMemberFunc(m_poHandler, "OnIMEOpenCandidateList", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnIMECloseCandidateListEvent() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnIMECloseCandidateList", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnIMEOpenReadingWndEvent() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnIMEOpenReadingWnd", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnIMECloseReadingWndEvent() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnIMECloseReadingWnd", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnKeyDown(int ikey) + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnKeyDown", Py_BuildValue("(i)", ikey), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnKeyUp(int ikey) + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnKeyUp", Py_BuildValue("(i)", ikey), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnPressEscapeKey() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnPressEscapeKey", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + BOOL CWindow::OnPressExitKey() + { + long lValue; + if (PyCallClassMemberFunc(m_poHandler, "OnPressExitKey", BuildEmptyTuple(), &lValue)) + if (0 != lValue) + return TRUE; + + return FALSE; + } + + ///// + + bool CWindow::IsIn(long x, long y) + { + if (x >= m_rect.left && x <= m_rect.right) + if (y >= m_rect.top && y <= m_rect.bottom) + return true; + + return false; + } + + bool CWindow::IsIn() + { + long lx, ly; + UI::CWindowManager::Instance().GetMousePosition(lx, ly); + + return IsIn(lx, ly); + } + + CWindow * CWindow::PickWindow(long x, long y) + { + std::list::reverse_iterator ritor = m_pChildList.rbegin(); + for (; ritor != m_pChildList.rend(); ++ritor) + { + CWindow * pWin = *ritor; + if (pWin->IsShow()) + { + if (!pWin->IsFlag(CWindow::FLAG_IGNORE_SIZE)) + { + if (!pWin->IsIn(x, y)) { + if (0L <= pWin->GetWidth()) { + continue; + } + } + } + + CWindow * pResult = pWin->PickWindow(x, y); + if (pResult) + return pResult; + } + } + + if (IsFlag(CWindow::FLAG_NOT_PICK)) + return NULL; + + return (this); + } + + CWindow * CWindow::PickTopWindow(long x, long y) + { + std::list::reverse_iterator ritor = m_pChildList.rbegin(); + for (; ritor != m_pChildList.rend(); ++ritor) + { + CWindow * pWin = *ritor; + if (pWin->IsShow()) + if (pWin->IsIn(x, y)) + if (!pWin->IsFlag(CWindow::FLAG_NOT_PICK)) + return pWin; + } + + return NULL; + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + CBox::CBox(PyObject * ppyObject) : CWindow(ppyObject), m_dwColor(0xff000000) + { + } + CBox::~CBox() + { + } + + void CBox::SetColor(DWORD dwColor) + { + m_dwColor = dwColor; + } + + void CBox::OnRender() + { + CPythonGraphic::Instance().SetDiffuseColor(m_dwColor); + CPythonGraphic::Instance().RenderBox2d(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + CBar::CBar(PyObject * ppyObject) : CWindow(ppyObject), m_dwColor(0xff000000) + { + } + CBar::~CBar() + { + } + + void CBar::SetColor(DWORD dwColor) + { + m_dwColor = dwColor; + } + + void CBar::OnRender() + { + CPythonGraphic::Instance().SetDiffuseColor(m_dwColor); + CPythonGraphic::Instance().RenderBar2d(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + CLine::CLine(PyObject * ppyObject) : CWindow(ppyObject), m_dwColor(0xff000000) + { + } + CLine::~CLine() + { + } + + void CLine::SetColor(DWORD dwColor) + { + m_dwColor = dwColor; + } + + void CLine::OnRender() + { + CPythonGraphic & rkpyGraphic = CPythonGraphic::Instance(); + rkpyGraphic.SetDiffuseColor(m_dwColor); + rkpyGraphic.RenderLine2d(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + DWORD CBar3D::Type() + { + static DWORD s_dwType = GetCRC32("CBar3D", strlen("CBar3D")); + return (s_dwType); + } + + CBar3D::CBar3D(PyObject * ppyObject) : CWindow(ppyObject) + { + m_dwLeftColor = D3DXCOLOR(0.2f, 0.2f, 0.2f, 1.0f); + m_dwRightColor = D3DXCOLOR(0.7f, 0.7f, 0.7f, 1.0f); + m_dwCenterColor = D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f); + } + CBar3D::~CBar3D() + { + } + + void CBar3D::SetColor(DWORD dwLeft, DWORD dwRight, DWORD dwCenter) + { + m_dwLeftColor = dwLeft; + m_dwRightColor = dwRight; + m_dwCenterColor = dwCenter; + } + + void CBar3D::OnRender() + { + CPythonGraphic & rkpyGraphic = CPythonGraphic::Instance(); + + rkpyGraphic.SetDiffuseColor(m_dwCenterColor); + rkpyGraphic.RenderBar2d(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom); + + rkpyGraphic.SetDiffuseColor(m_dwLeftColor); + rkpyGraphic.RenderLine2d(m_rect.left, m_rect.top, m_rect.right, m_rect.top); + rkpyGraphic.RenderLine2d(m_rect.left, m_rect.top, m_rect.left, m_rect.bottom); + + rkpyGraphic.SetDiffuseColor(m_dwRightColor); + rkpyGraphic.RenderLine2d(m_rect.left, m_rect.bottom, m_rect.right, m_rect.bottom); + rkpyGraphic.RenderLine2d(m_rect.right, m_rect.top, m_rect.right, m_rect.bottom); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + CTextLine::CTextLine(PyObject * ppyObject) : CWindow(ppyObject) + { + m_TextInstance.SetColor(0.78f, 0.78f, 0.78f); + m_TextInstance.SetHorizonalAlign(CGraphicTextInstance::HORIZONTAL_ALIGN_LEFT); + m_TextInstance.SetVerticalAlign(CGraphicTextInstance::VERTICAL_ALIGN_TOP); + } + CTextLine::~CTextLine() + { + m_TextInstance.Destroy(); + } + + void CTextLine::SetMax(int iMax) + { + m_TextInstance.SetMax(iMax); + } + void CTextLine::SetHorizontalAlign(int iType) + { + m_TextInstance.SetHorizonalAlign(iType); + } + void CTextLine::SetVerticalAlign(int iType) + { + m_TextInstance.SetVerticalAlign(iType); + } + void CTextLine::SetSecret(BOOL bFlag) + { + m_TextInstance.SetSecret(bFlag ? true : false); + } + void CTextLine::SetOutline(BOOL bFlag) + { + m_TextInstance.SetOutline(bFlag ? true : false); + } + void CTextLine::SetFeather(BOOL bFlag) + { + m_TextInstance.SetFeather(bFlag ? true : false); + } + void CTextLine::SetMultiLine(BOOL bFlag) + { + m_TextInstance.SetMultiLine(bFlag ? true : false); + } + void CTextLine::SetFontName(const char * c_szFontName) + { + std::string stFontName = c_szFontName; + stFontName += ".fnt"; + + CResourceManager& rkResMgr=CResourceManager::Instance(); + CResource* pkRes = rkResMgr.GetTypeResourcePointer(stFontName.c_str()); + CGraphicText* pkResFont=static_cast(pkRes); + m_TextInstance.SetTextPointer(pkResFont); + } + void CTextLine::SetFontColor(DWORD dwColor) + { + m_TextInstance.SetColor(dwColor); + } + void CTextLine::SetLimitWidth(float fWidth) + { + m_TextInstance.SetLimitWidth(fWidth); + } + void CTextLine::SetText(const char * c_szText) + { + OnSetText(c_szText); + } + void CTextLine::GetTextSize(int* pnWidth, int* pnHeight) + { + m_TextInstance.GetTextSize(pnWidth, pnHeight); + } + const char * CTextLine::GetText() + { + return m_TextInstance.GetValueStringReference().c_str(); + } + void CTextLine::ShowCursor() + { + m_TextInstance.ShowCursor(); + } + void CTextLine::HideCursor() + { + m_TextInstance.HideCursor(); + } + int CTextLine::GetCursorPosition() + { + long lx, ly; + CWindow::GetMouseLocalPosition(lx, ly); + return m_TextInstance.PixelPositionToCharacterPosition(lx); + } + + void CTextLine::OnSetText(const char * c_szText) + { + m_TextInstance.SetValue(c_szText); + m_TextInstance.Update(); + } + + void CTextLine::OnUpdate() + { + if (IsShow()) + m_TextInstance.Update(); + } + void CTextLine::OnRender() + { + if (IsShow()) + m_TextInstance.Render(); + } + + 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); + } + else + { + m_TextInstance.SetPosition(m_rect.left, m_rect.top); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + CNumberLine::CNumberLine(PyObject * ppyObject) : CWindow(ppyObject) + { + m_strPath = "d:/ymir work/ui/game/taskbar/"; + m_iHorizontalAlign = HORIZONTAL_ALIGN_LEFT; + m_dwWidthSummary = 0; + } + CNumberLine::CNumberLine(CWindow * pParent) : CWindow(NULL) + { + m_strPath = "d:/ymir work/ui/game/taskbar/"; + m_iHorizontalAlign = HORIZONTAL_ALIGN_LEFT; + m_dwWidthSummary = 0; + + m_pParent = pParent; + } + CNumberLine::~CNumberLine() + { + ClearNumber(); + } + + void CNumberLine::SetPath(const char * c_szPath) + { + m_strPath = c_szPath; + } + void CNumberLine::SetHorizontalAlign(int iType) + { + m_iHorizontalAlign = iType; + } + void CNumberLine::SetNumber(const char * c_szNumber) + { + if (0 == m_strNumber.compare(c_szNumber)) + return; + + ClearNumber(); + + m_strNumber = c_szNumber; + + for (DWORD i = 0; i < m_strNumber.size(); ++i) + { + char cChar = m_strNumber[i]; + std::string strImageFileName; + + if (':' == cChar) + { + strImageFileName = m_strPath + "colon.sub"; + } + else if ('?' == cChar) + { + strImageFileName = m_strPath + "questionmark.sub"; + } + else if ('/' == cChar) + { + strImageFileName = m_strPath + "slash.sub"; + } + else if ('%' == cChar) + { + strImageFileName = m_strPath + "percent.sub"; + } + else if ('+' == cChar) + { + strImageFileName = m_strPath + "plus.sub"; + } + else if ('m' == cChar) + { + strImageFileName = m_strPath + "m.sub"; + } + else if ('g' == cChar) + { + strImageFileName = m_strPath + "g.sub"; + } + else if ('p' == cChar) + { + strImageFileName = m_strPath + "p.sub"; + } + else if (cChar >= '0' && cChar <= '9') + { + strImageFileName = m_strPath; + strImageFileName += cChar; + strImageFileName += ".sub"; + } + else + continue; + + if (!CResourceManager::Instance().IsFileExist(strImageFileName.c_str())) + continue; + + CGraphicImage * pImage = (CGraphicImage *)CResourceManager::Instance().GetResourcePointer(strImageFileName.c_str()); + + CGraphicImageInstance * pInstance = CGraphicImageInstance::New(); + pInstance->SetImagePointer(pImage); + m_ImageInstanceVector.push_back(pInstance); + + m_dwWidthSummary += pInstance->GetWidth(); + } + } + + void CNumberLine::ClearNumber() + { + m_ImageInstanceVector.clear(); + m_dwWidthSummary = 0; + m_strNumber = ""; + } + + void CNumberLine::OnRender() + { + for (DWORD i = 0; i < m_ImageInstanceVector.size(); ++i) + { + m_ImageInstanceVector[i]->Render(); + } + } + + void CNumberLine::OnChangePosition() + { + int ix = m_x; + int iy = m_y; + + if (m_pParent) + { + ix = m_rect.left; + iy = m_rect.top; + } + + switch (m_iHorizontalAlign) + { + case HORIZONTAL_ALIGN_LEFT: + break; + case HORIZONTAL_ALIGN_CENTER: + ix -= int(m_dwWidthSummary) / 2; + break; + case HORIZONTAL_ALIGN_RIGHT: + ix -= int(m_dwWidthSummary); + break; + } + + for (DWORD i = 0; i < m_ImageInstanceVector.size(); ++i) + { + m_ImageInstanceVector[i]->SetPosition(ix, iy); + ix += m_ImageInstanceVector[i]->GetWidth(); + } + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + CImageBox::CImageBox(PyObject * ppyObject) : CWindow(ppyObject) + { + m_pImageInstance = NULL; + } + CImageBox::~CImageBox() + { + OnDestroyInstance(); + } + + void CImageBox::OnCreateInstance() + { + OnDestroyInstance(); + + m_pImageInstance = CGraphicImageInstance::New(); + } + void CImageBox::OnDestroyInstance() + { + if (m_pImageInstance) + { + CGraphicImageInstance::Delete(m_pImageInstance); + m_pImageInstance=NULL; + } + } + + BOOL CImageBox::LoadImage(const char * c_szFileName) + { + if (!c_szFileName[0]) + return FALSE; + + OnCreateInstance(); + + CResource * pResource = CResourceManager::Instance().GetResourcePointer(c_szFileName); + if (!pResource) + return FALSE; + if (!pResource->IsType(CGraphicImage::Type())) + return FALSE; + + m_pImageInstance->SetImagePointer(static_cast(pResource)); + if (m_pImageInstance->IsEmpty()) + return FALSE; + + SetSize(m_pImageInstance->GetWidth(), m_pImageInstance->GetHeight()); + UpdateRect(); + + return TRUE; + } + + void CImageBox::SetDiffuseColor(float fr, float fg, float fb, float fa) + { + if (!m_pImageInstance) + return; + + m_pImageInstance->SetDiffuseColor(fr, fg, fb, fa); + } + + int CImageBox::GetWidth() + { + if (!m_pImageInstance) + return 0; + + return m_pImageInstance->GetWidth(); + } + + int CImageBox::GetHeight() + { + if (!m_pImageInstance) + return 0; + + return m_pImageInstance->GetHeight(); + } + + void CImageBox::OnUpdate() + { + } + void CImageBox::OnRender() + { + if (!m_pImageInstance) + return; + + if (IsShow()) + m_pImageInstance->Render(); + } + void CImageBox::OnChangePosition() + { + if (!m_pImageInstance) + return; + + m_pImageInstance->SetPosition(m_rect.left, m_rect.top); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + // MarkBox - 마크 출력용 UI 윈도우 + /////////////////////////////////////////////////////////////////////////////////////////////// + CMarkBox::CMarkBox(PyObject * ppyObject) : CWindow(ppyObject) + { + m_pMarkInstance = NULL; + } + + CMarkBox::~CMarkBox() + { + OnDestroyInstance(); + } + + void CMarkBox::OnCreateInstance() + { + OnDestroyInstance(); + m_pMarkInstance = CGraphicMarkInstance::New(); + } + + void CMarkBox::OnDestroyInstance() + { + if (m_pMarkInstance) + { + CGraphicMarkInstance::Delete(m_pMarkInstance); + m_pMarkInstance=NULL; + } + } + + void CMarkBox::LoadImage(const char * c_szFilename) + { + OnCreateInstance(); + + m_pMarkInstance->SetImageFileName(c_szFilename); + m_pMarkInstance->Load(); + SetSize(m_pMarkInstance->GetWidth(), m_pMarkInstance->GetHeight()); + + UpdateRect(); + } + + void CMarkBox::SetScale(FLOAT fScale) + { + if (!m_pMarkInstance) + return; + + m_pMarkInstance->SetScale(fScale); + } + + void CMarkBox::SetIndex(UINT uIndex) + { + if (!m_pMarkInstance) + return; + + m_pMarkInstance->SetIndex(uIndex); + } + + void CMarkBox::SetDiffuseColor(float fr, float fg, float fb, float fa) + { + if (!m_pMarkInstance) + return; + + m_pMarkInstance->SetDiffuseColor(fr, fg, fb, fa); + } + + void CMarkBox::OnUpdate() + { + } + + void CMarkBox::OnRender() + { + if (!m_pMarkInstance) + return; + + if (IsShow()) + m_pMarkInstance->Render(); + } + + void CMarkBox::OnChangePosition() + { + if (!m_pMarkInstance) + return; + + m_pMarkInstance->SetPosition(m_rect.left, m_rect.top); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + DWORD CExpandedImageBox::Type() + { + static DWORD s_dwType = GetCRC32("CExpandedImageBox", strlen("CExpandedImageBox")); + return (s_dwType); + } + + BOOL CExpandedImageBox::OnIsType(DWORD dwType) + { + if (CExpandedImageBox::Type() == dwType) + return TRUE; + + return FALSE; + } + + CExpandedImageBox::CExpandedImageBox(PyObject * ppyObject) : CImageBox(ppyObject) + { + } + CExpandedImageBox::~CExpandedImageBox() + { + OnDestroyInstance(); + } + + void CExpandedImageBox::OnCreateInstance() + { + OnDestroyInstance(); + + m_pImageInstance = CGraphicExpandedImageInstance::New(); + } + void CExpandedImageBox::OnDestroyInstance() + { + if (m_pImageInstance) + { + CGraphicExpandedImageInstance::Delete((CGraphicExpandedImageInstance*)m_pImageInstance); + m_pImageInstance=NULL; + } + } + + void CExpandedImageBox::SetScale(float fx, float fy) + { + if (!m_pImageInstance) + return; + + ((CGraphicExpandedImageInstance*)m_pImageInstance)->SetScale(fx, fy); + CWindow::SetSize(long(float(GetWidth())*fx), long(float(GetHeight())*fy)); + } + void CExpandedImageBox::SetOrigin(float fx, float fy) + { + if (!m_pImageInstance) + return; + + ((CGraphicExpandedImageInstance*)m_pImageInstance)->SetOrigin(fx, fy); + } + void CExpandedImageBox::SetRotation(float fRotation) + { + if (!m_pImageInstance) + return; + + ((CGraphicExpandedImageInstance*)m_pImageInstance)->SetRotation(fRotation); + } + void CExpandedImageBox::SetRenderingRect(float fLeft, float fTop, float fRight, float fBottom) + { + if (!m_pImageInstance) + return; + + ((CGraphicExpandedImageInstance*)m_pImageInstance)->SetRenderingRect(fLeft, fTop, fRight, fBottom); + } + + void CExpandedImageBox::SetRenderingMode(int iMode) + { + ((CGraphicExpandedImageInstance*)m_pImageInstance)->SetRenderingMode(iMode); + } + + void CExpandedImageBox::OnUpdate() + { + } + void CExpandedImageBox::OnRender() + { + if (!m_pImageInstance) + return; + + if (IsShow()) + m_pImageInstance->Render(); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + DWORD CAniImageBox::Type() + { + static DWORD s_dwType = GetCRC32("CAniImageBox", strlen("CAniImageBox")); + return (s_dwType); + } + + BOOL CAniImageBox::OnIsType(DWORD dwType) + { + if (CAniImageBox::Type() == dwType) + return TRUE; + + return FALSE; + } + + CAniImageBox::CAniImageBox(PyObject * ppyObject) + : CWindow(ppyObject), + m_bycurDelay(0), + m_byDelay(4), + m_bycurIndex(0) + { + m_ImageVector.clear(); + } + CAniImageBox::~CAniImageBox() + { + for_each(m_ImageVector.begin(), m_ImageVector.end(), CGraphicExpandedImageInstance::DeleteExpandedImageInstance); + } + + void CAniImageBox::SetDelay(int iDelay) + { + m_byDelay = iDelay; + } + void CAniImageBox::AppendImage(const char * c_szFileName) + { + CResource * pResource = CResourceManager::Instance().GetResourcePointer(c_szFileName); + if (!pResource->IsType(CGraphicImage::Type())) + return; + + CGraphicExpandedImageInstance * pImageInstance = CGraphicExpandedImageInstance::New(); + + pImageInstance->SetImagePointer(static_cast(pResource)); + if (pImageInstance->IsEmpty()) + { + CGraphicExpandedImageInstance::Delete(pImageInstance); + return; + } + + m_ImageVector.push_back(pImageInstance); + + m_bycurIndex = static_cast(rand() % m_ImageVector.size()); +// SetSize(pImageInstance->GetWidth(), pImageInstance->GetHeight()); +// UpdateRect(); + } + + struct FSetRenderingRect + { + float fLeft, fTop, fRight, fBottom; + void operator () (CGraphicExpandedImageInstance * pInstance) + { + pInstance->SetRenderingRect(fLeft, fTop, fRight, fBottom); + } + }; + void CAniImageBox::SetRenderingRect(float fLeft, float fTop, float fRight, float fBottom) + { + FSetRenderingRect setRenderingRect; + setRenderingRect.fLeft = fLeft; + setRenderingRect.fTop = fTop; + setRenderingRect.fRight = fRight; + setRenderingRect.fBottom = fBottom; + for_each(m_ImageVector.begin(), m_ImageVector.end(), setRenderingRect); + } + + struct FSetRenderingMode + { + int iMode; + void operator () (CGraphicExpandedImageInstance * pInstance) + { + pInstance->SetRenderingMode(iMode); + } + }; + void CAniImageBox::SetRenderingMode(int iMode) + { + FSetRenderingMode setRenderingMode; + setRenderingMode.iMode = iMode; + for_each(m_ImageVector.begin(), m_ImageVector.end(), setRenderingMode); + } + + void CAniImageBox::ResetFrame() + { + m_bycurIndex = 0; + } + + void CAniImageBox::OnUpdate() + { + ++m_bycurDelay; + if (m_bycurDelay < m_byDelay) + return; + + m_bycurDelay = 0; + + ++m_bycurIndex; + if (m_bycurIndex >= m_ImageVector.size()) + { + m_bycurIndex = 0; + + OnEndFrame(); + } + } + void CAniImageBox::OnRender() + { + if (m_bycurIndex < m_ImageVector.size()) + { + CGraphicExpandedImageInstance * pImage = m_ImageVector[m_bycurIndex]; + pImage->Render(); + } + } + + struct FChangePosition + { + float fx, fy; + void operator () (CGraphicExpandedImageInstance * pInstance) + { + pInstance->SetPosition(fx, fy); + } + }; + + void CAniImageBox::OnChangePosition() + { + FChangePosition changePosition; + changePosition.fx = m_rect.left; + changePosition.fy = m_rect.top; + for_each(m_ImageVector.begin(), m_ImageVector.end(), changePosition); + } + + void CAniImageBox::OnEndFrame() + { + PyCallClassMemberFunc(m_poHandler, "OnEndFrame", BuildEmptyTuple()); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + CButton::CButton(PyObject * ppyObject) + : CWindow(ppyObject), + m_pcurVisual(NULL), + m_bEnable(TRUE), + m_isPressed(FALSE), + m_isFlash(FALSE) + { + CWindow::AddFlag(CWindow::FLAG_NOT_CAPTURE); + } + CButton::~CButton() + { + } + + BOOL CButton::SetUpVisual(const char * c_szFileName) + { + CResource * pResource = CResourceManager::Instance().GetResourcePointer(c_szFileName); + if (!pResource->IsType(CGraphicImage::Type())) + return FALSE; + + m_upVisual.SetImagePointer(static_cast(pResource)); + if (m_upVisual.IsEmpty()) + return FALSE; + + SetSize(m_upVisual.GetWidth(), m_upVisual.GetHeight()); + // + SetCurrentVisual(&m_upVisual); + // + + return TRUE; + } + BOOL CButton::SetOverVisual(const char * c_szFileName) + { + CResource * pResource = CResourceManager::Instance().GetResourcePointer(c_szFileName); + if (!pResource->IsType(CGraphicImage::Type())) + return FALSE; + + m_overVisual.SetImagePointer(static_cast(pResource)); + if (m_overVisual.IsEmpty()) + return FALSE; + + SetSize(m_overVisual.GetWidth(), m_overVisual.GetHeight()); + + return TRUE; + } + BOOL CButton::SetDownVisual(const char * c_szFileName) + { + CResource * pResource = CResourceManager::Instance().GetResourcePointer(c_szFileName); + if (!pResource->IsType(CGraphicImage::Type())) + return FALSE; + + m_downVisual.SetImagePointer(static_cast(pResource)); + if (m_downVisual.IsEmpty()) + return FALSE; + + SetSize(m_downVisual.GetWidth(), m_downVisual.GetHeight()); + + return TRUE; + } + BOOL CButton::SetDisableVisual(const char * c_szFileName) + { + CResource * pResource = CResourceManager::Instance().GetResourcePointer(c_szFileName); + if (!pResource->IsType(CGraphicImage::Type())) + return FALSE; + + m_disableVisual.SetImagePointer(static_cast(pResource)); + if (m_downVisual.IsEmpty()) + return FALSE; + + SetSize(m_disableVisual.GetWidth(), m_disableVisual.GetHeight()); + + return TRUE; + } + + const char * CButton::GetUpVisualFileName() + { + return m_upVisual.GetGraphicImagePointer()->GetFileName(); + } + const char * CButton::GetOverVisualFileName() + { + return m_overVisual.GetGraphicImagePointer()->GetFileName(); + } + const char * CButton::GetDownVisualFileName() + { + return m_downVisual.GetGraphicImagePointer()->GetFileName(); + } + + void CButton::Flash() + { + m_isFlash = TRUE; + } + + void CButton::Enable() + { + SetUp(); + m_bEnable = TRUE; + } + + void CButton::Disable() + { + m_bEnable = FALSE; + if (!m_disableVisual.IsEmpty()) + SetCurrentVisual(&m_disableVisual); + } + + BOOL CButton::IsDisable() + { + return m_bEnable; + } + + void CButton::SetUp() + { + SetCurrentVisual(&m_upVisual); + m_isPressed = FALSE; + } + void CButton::Up() + { + if (IsIn()) + SetCurrentVisual(&m_overVisual); + else + SetCurrentVisual(&m_upVisual); + + PyCallClassMemberFunc(m_poHandler, "CallEvent", BuildEmptyTuple()); + } + void CButton::Over() + { + SetCurrentVisual(&m_overVisual); + } + void CButton::Down() + { + m_isPressed = TRUE; + SetCurrentVisual(&m_downVisual); + PyCallClassMemberFunc(m_poHandler, "DownEvent", BuildEmptyTuple()); + } + + void CButton::OnUpdate() + { + } + void CButton::OnRender() + { + if (!IsShow()) + return; + + if (m_pcurVisual) + { + if (m_isFlash) + if (!IsIn()) + if (int(timeGetTime() / 500)%2) + { + return; + } + + m_pcurVisual->Render(); + } + + PyCallClassMemberFunc(m_poHandler, "OnRender", BuildEmptyTuple()); + } + void CButton::OnChangePosition() + { + if (m_pcurVisual) + m_pcurVisual->SetPosition(m_rect.left, m_rect.top); + } + + BOOL CButton::OnMouseLeftButtonDown() + { + if (!IsEnable()) + return TRUE; + + m_isPressed = TRUE; + Down(); + + return TRUE; + } + BOOL CButton::OnMouseLeftButtonDoubleClick() + { + if (!IsEnable()) + return TRUE; + + OnMouseLeftButtonDown(); + + return TRUE; + } + BOOL CButton::OnMouseLeftButtonUp() + { + if (!IsEnable()) + return TRUE; + if (!IsPressed()) + return TRUE; + + m_isPressed = FALSE; + Up(); + + return TRUE; + } + void CButton::OnMouseOverIn() + { + if (!IsEnable()) + return; + + Over(); + PyCallClassMemberFunc(m_poHandler, "ShowToolTip", BuildEmptyTuple()); + } + void CButton::OnMouseOverOut() + { + if (!IsEnable()) + return; + + SetUp(); + PyCallClassMemberFunc(m_poHandler, "HideToolTip", BuildEmptyTuple()); + } + + void CButton::SetCurrentVisual(CGraphicImageInstance * pVisual) + { + m_pcurVisual = pVisual; + m_pcurVisual->SetPosition(m_rect.left, m_rect.top); + } + + BOOL CButton::IsEnable() + { + return m_bEnable; + } + + BOOL CButton::IsPressed() + { + return m_isPressed; + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + CRadioButton::CRadioButton(PyObject * ppyObject) : CButton(ppyObject) + { + } + CRadioButton::~CRadioButton() + { + } + + BOOL CRadioButton::OnMouseLeftButtonDown() + { + if (!IsEnable()) + return TRUE; + + if (!m_isPressed) + { + Down(); + PyCallClassMemberFunc(m_poHandler, "CallEvent", BuildEmptyTuple()); + } + + return TRUE; + } + BOOL CRadioButton::OnMouseLeftButtonUp() + { + return TRUE; + } + void CRadioButton::OnMouseOverIn() + { + if (!IsEnable()) + return; + + if (!m_isPressed) + { + SetCurrentVisual(&m_overVisual); + } + + PyCallClassMemberFunc(m_poHandler, "ShowToolTip", BuildEmptyTuple()); + } + void CRadioButton::OnMouseOverOut() + { + if (!IsEnable()) + return; + + if (!m_isPressed) + { + SetCurrentVisual(&m_upVisual); + } + + PyCallClassMemberFunc(m_poHandler, "HideToolTip", BuildEmptyTuple()); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + CToggleButton::CToggleButton(PyObject * ppyObject) : CButton(ppyObject) + { + } + CToggleButton::~CToggleButton() + { + } + + BOOL CToggleButton::OnMouseLeftButtonDown() + { + if (!IsEnable()) + return TRUE; + + if (m_isPressed) + { + SetUp(); + if (IsIn()) + SetCurrentVisual(&m_overVisual); + else + SetCurrentVisual(&m_upVisual); + PyCallClassMemberFunc(m_poHandler, "OnToggleUp", BuildEmptyTuple()); + } + else + { + Down(); + PyCallClassMemberFunc(m_poHandler, "OnToggleDown", BuildEmptyTuple()); + } + + return TRUE; + } + BOOL CToggleButton::OnMouseLeftButtonUp() + { + return TRUE; + } + + void CToggleButton::OnMouseOverIn() + { + if (!IsEnable()) + return; + + if (!m_isPressed) + { + SetCurrentVisual(&m_overVisual); + } + + PyCallClassMemberFunc(m_poHandler, "ShowToolTip", BuildEmptyTuple()); + } + void CToggleButton::OnMouseOverOut() + { + if (!IsEnable()) + return; + + if (!m_isPressed) + { + SetCurrentVisual(&m_upVisual); + } + + PyCallClassMemberFunc(m_poHandler, "HideToolTip", BuildEmptyTuple()); + } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////////////////////////// + + CDragButton::CDragButton(PyObject * ppyObject) : CButton(ppyObject) + { + CWindow::RemoveFlag(CWindow::FLAG_NOT_CAPTURE); + m_restrictArea.left = 0; + m_restrictArea.top = 0; + m_restrictArea.right = CWindowManager::Instance().GetScreenWidth(); + m_restrictArea.bottom = CWindowManager::Instance().GetScreenHeight(); + } + CDragButton::~CDragButton() + { + } + + void CDragButton::SetRestrictMovementArea(int ix, int iy, int iwidth, int iheight) + { + m_restrictArea.left = ix; + m_restrictArea.top = iy; + m_restrictArea.right = ix + iwidth; + m_restrictArea.bottom = iy + iheight; + } + + void CDragButton::OnChangePosition() + { + m_x = max(m_x, m_restrictArea.left); + m_y = max(m_y, m_restrictArea.top); + m_x = min(m_x, max(0, m_restrictArea.right - m_lWidth)); + m_y = min(m_y, max(0, m_restrictArea.bottom - m_lHeight)); + + m_rect.left = m_x; + m_rect.top = m_y; + + if (m_pParent) + { + const RECT & c_rRect = m_pParent->GetRect(); + m_rect.left += c_rRect.left; + m_rect.top += c_rRect.top; + } + + m_rect.right = m_rect.left + m_lWidth; + m_rect.bottom = m_rect.top + m_lHeight; + + std::for_each(m_pChildList.begin(), m_pChildList.end(), std::mem_fn(&CWindow::UpdateRect)); + + if (m_pcurVisual) + m_pcurVisual->SetPosition(m_rect.left, m_rect.top); + + if (IsPressed()) + PyCallClassMemberFunc(m_poHandler, "OnMove", BuildEmptyTuple()); + } + + void CDragButton::OnMouseOverIn() + { + if (!IsEnable()) + + return; + + CButton::OnMouseOverIn(); + PyCallClassMemberFunc(m_poHandler, "OnMouseOverIn", BuildEmptyTuple()); + } + + void CDragButton::OnMouseOverOut() + { + if (!IsEnable()) + return; + + CButton::OnMouseOverIn(); + PyCallClassMemberFunc(m_poHandler, "OnMouseOverOut", BuildEmptyTuple()); + } +}; diff --git a/extension/src/port/EterPythonLib/PythonWindowManager.cpp b/extension/src/port/EterPythonLib/PythonWindowManager.cpp new file mode 100644 index 00000000..2e5c3ccf --- /dev/null +++ b/extension/src/port/EterPythonLib/PythonWindowManager.cpp @@ -0,0 +1,1255 @@ +#include "StdAfx.h" +#include "PythonWindow.h" +#include "PythonSlotWindow.h" +#include "PythonGridSlotWindow.h" +#include "PythonWindowManager.h" + +//#define __WINDOW_LEAK_CHECK__ + +BOOL g_bShowOverInWindowName = FALSE; + +namespace UI +{ + static PyObject* gs_poEmptyTuple = NULL; + + PyObject * BuildEmptyTuple() + { + Py_INCREF(gs_poEmptyTuple); + return gs_poEmptyTuple; + } + + std::set gs_kSet_pkWnd; + + CWindowManager::CWindowManager() + : + m_pActiveWindow(NULL), + m_pPointWindow(NULL), + m_pLeftCaptureWindow(NULL), + m_pMiddleCaptureWindow(NULL), + m_pRightCaptureWindow(NULL), + m_pLockWindow(NULL), + m_bAttachingFlag(FALSE), + m_dwAttachingType(0), + m_dwAttachingIndex(0), + m_dwAttachingSlotNumber(0), + m_poMouseHandler(NULL), + m_iHres(0), + m_iVres(0), + m_bOnceIgnoreMouseLeftButtonUpEventFlag(FALSE) + { + m_pRootWindow = new CWindow(NULL); + m_pRootWindow->SetName("root"); + m_pRootWindow->Show(); + + const char * layerTbl[] = {"GAME","UI_BOTTOM","UI","TOP_MOST","CURTAIN"}; + + for(DWORD layer = 0; layer < sizeof(layerTbl)/sizeof(layerTbl[0]); layer++) + { + CWindow * pLayer = new CLayer(NULL); + pLayer->SetName(layerTbl[layer]); + pLayer->Show(); + m_LayerWindowMap.insert(TLayerContainer::value_type(layerTbl[layer], pLayer)); + m_pRootWindow->AddChild(pLayer); + m_LayerWindowList.push_back(pLayer); + } + + m_ActiveWindowList.clear(); + m_LockWindowList.clear(); + + gs_poEmptyTuple = Py_BuildValue("()"); + } + + CWindowManager::~CWindowManager() + { + Py_DECREF(gs_poEmptyTuple); + + stl_wipe_second(m_LayerWindowMap); + m_LayerWindowMap.clear(); + m_LayerWindowList.clear(); + m_KeyCaptureWindowMap.clear(); + + delete m_pRootWindow; + m_pRootWindow = NULL; + } + + void CWindowManager::Destroy() + { + __ClearReserveDeleteWindowList(); +#ifdef __WINDOW_LEAK_CHECK__ + std::set::iterator i; + for (i=gs_kSet_pkWnd.begin(); i!=gs_kSet_pkWnd.end(); ++i) + { + CWindow* pkWnd=*i; + Logf(1, "CWindowManager::Destroy LOST WINDOW %s\n", pkWnd->GetName()); + } +#endif + + } + + void CWindowManager::SetMouseHandler(PyObject * poMouseHandler) + { + m_poMouseHandler = poMouseHandler; + } + + CWindow * CWindowManager::RegisterWindow(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CWindow(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return (pWin); + } + + CWindow * CWindowManager::__NewWindow(PyObject * po, DWORD dwWndType) + { + switch(dwWndType) + { + case WT_SLOT: + return new CSlotWindow(po); + break; + case WT_GRIDSLOT: + return new CGridSlotWindow(po); + break; + case WT_TEXTLINE: + return new CTextLine(po); + break; + case WT_MARKBOX: + return new CMarkBox(po); + break; + case WT_IMAGEBOX: + return new CImageBox(po); + break; + case WT_EXP_IMAGEBOX: + return new CExpandedImageBox(po); + break; + case WT_ANI_IMAGEBOX: + return new CAniImageBox(po); + break; + case WT_BUTTON: + return new CButton(po); + break; + case WT_RATIOBUTTON: + return new CRadioButton(po); + break; + case WT_TOGGLEBUTTON: + return new CToggleButton(po); + break; + case WT_DRAGBUTTON: + return new CDragButton(po); + break; + case WT_BOX: + return new CBox(po); + break; + case WT_BAR: + return new CBar(po); + break; + case WT_LINE: + return new CLine(po); + break; + case WT_BAR3D: + return new CBar3D(po); + break; + case WT_NUMLINE: + return new CNumberLine(po); + break; + default: + assert(!"CWindowManager::__NewWindow"); + break; + } + return new CWindow(po); + } + + CWindow * CWindowManager::RegisterTypeWindow(PyObject * po, DWORD dwWndType, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = __NewWindow(po, dwWndType); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterSlotWindow(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CSlotWindow(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterGridSlotWindow(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CGridSlotWindow(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterTextLine(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CTextLine(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterImageBox(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CImageBox(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterMarkBox(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CMarkBox(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterExpandedImageBox(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CExpandedImageBox(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterAniImageBox(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CAniImageBox(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterButton(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CButton(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterRadioButton(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CRadioButton(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterToggleButton(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CToggleButton(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterDragButton(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CDragButton(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterBox(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CBox(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterBar(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CBar(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterLine(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CLine(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterBar3D(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CBar3D(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + CWindow * CWindowManager::RegisterNumberLine(PyObject * po, const char * c_szLayer) + { + assert(m_LayerWindowMap.end() != m_LayerWindowMap.find(c_szLayer)); + + CWindow * pWin = new CNumberLine(po); + m_LayerWindowMap[c_szLayer]->AddChild(pWin); + +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.insert(pWin); +#endif + return pWin; + } + + void CWindowManager::NotifyDestroyWindow(CWindow * pWindow) + { + if (pWindow == m_pActiveWindow) + m_pActiveWindow = NULL; + + if (pWindow == m_pPointWindow) + m_pPointWindow = NULL; + + if (pWindow == m_pLeftCaptureWindow) + m_pLeftCaptureWindow = NULL; + + if (pWindow == m_pMiddleCaptureWindow) + m_pMiddleCaptureWindow = NULL; + + if (pWindow == m_pRightCaptureWindow) + m_pRightCaptureWindow = NULL; + + if (pWindow == m_pLockWindow) + m_pLockWindow = NULL; + + m_LockWindowList.remove(pWindow); + m_ActiveWindowList.remove(pWindow); + m_PickAlwaysWindowList.remove(pWindow); + + TKeyCaptureWindowMap::iterator itor = m_KeyCaptureWindowMap.begin(); + for (; itor != m_KeyCaptureWindowMap.end();) + { + if (pWindow == itor->second) + { + itor = m_KeyCaptureWindowMap.erase(itor); + } + else + { + ++itor; + } + } + } + + void CWindowManager::DestroyWindow(CWindow * pWin) + { + NotifyDestroyWindow(pWin); + if (pWin->HasParent()) + { + CWindow * pParentWin = pWin->GetParent(); + pParentWin->DeleteChild(pWin); + } + pWin->Clear(); + m_ReserveDeleteWindowList.push_back(pWin); + } + + BOOL CWindowManager::IsDragging() + { + long ldx = abs(m_lMouseX - m_lPickedX); + long ldy = abs(m_lMouseY - m_lPickedY); + if (ldx+ldy < 10) + return FALSE; + + return TRUE; + } + + BOOL CWindowManager::IsAttaching() + { + return m_bAttachingFlag; + } + + DWORD CWindowManager::GetAttachingType() + { + return m_dwAttachingType; + } + + DWORD CWindowManager::GetAttachingIndex() + { + return m_dwAttachingIndex; + } + + DWORD CWindowManager::GetAttachingSlotNumber() + { + return m_dwAttachingSlotNumber; + } + + void CWindowManager::GetAttachingIconSize(BYTE * pbyWidth, BYTE * pbyHeight) + { + *pbyWidth = m_byAttachingIconWidth; + *pbyHeight = m_byAttachingIconHeight; + } + + void CWindowManager::AttachIcon(DWORD dwType, DWORD dwIndex, DWORD dwSlotNumber, BYTE byWidth, BYTE byHeight) + { + m_bAttachingFlag = TRUE; + m_dwAttachingType = dwType; + m_dwAttachingIndex = dwIndex; + m_dwAttachingSlotNumber = dwSlotNumber; + + m_byAttachingIconWidth = byWidth; + m_byAttachingIconHeight = byHeight; + } + + void CWindowManager::SetAttachingFlag(BOOL bFlag) + { + m_bAttachingFlag = bFlag; + } + + void CWindowManager::DeattachIcon() + { + SetAttachingFlag(FALSE); + if (m_poMouseHandler) + PyCallClassMemberFunc(m_poMouseHandler, "DeattachObject", BuildEmptyTuple()); + } + + void CWindowManager::SetParent(CWindow * pWindow, CWindow * pParentWindow) + { + if (!pWindow) + { + assert(!"CWindowManager::SetParent - There is no self window!"); + return; + } + if (!pParentWindow) + { + assert(!"There is no parent window"); + return; + } + + if (pWindow->HasParent()) + { + CWindow * pOldParentWindow = pWindow->GetParent(); + + if (pParentWindow == pOldParentWindow) + return; + + pOldParentWindow->DeleteChild(pWindow); + } + + pParentWindow->AddChild(pWindow); + } + + void CWindowManager::SetPickAlways(CWindow * pWindow) + { + m_PickAlwaysWindowList.push_back(pWindow); + } + + void CWindowManager::OnceIgnoreMouseLeftButtonUpEvent() + { + m_bOnceIgnoreMouseLeftButtonUpEventFlag = TRUE; + m_iIgnoreEndTime = timeGetTime() + 500; + } + + void CWindowManager::LockWindow(CWindow * pWin) + { + if (m_pActiveWindow) + m_pActiveWindow->OnKillFocus(); + + // 이미 락된 윈도우리스트안에 있다면 제거한다.. + m_LockWindowList.remove(pWin); + + if (m_pLockWindow) + { + if (m_pLockWindow==pWin) + return; + + m_LockWindowList.push_back(m_pLockWindow); + } + + m_pLockWindow = pWin; + } + + void CWindowManager::UnlockWindow() + { + if (m_pLockWindow) + { + if (m_LockWindowList.empty()) + { + m_pLockWindow = NULL; + if (m_pActiveWindow) + m_pActiveWindow->OnSetFocus(); + } + else + { + m_pLockWindow = m_LockWindowList.back(); + m_LockWindowList.pop_back(); + } + } + } + + void CWindowManager::ActivateWindow(CWindow * pWin) + { + m_ActiveWindowList.remove(pWin); + + if (pWin == m_pActiveWindow) + return; + + if (m_pActiveWindow) + { + // NOTE : 누적된 Window가 많아지면 Clear를 해줘야 할까? + // 일단은 중복 누적이 안되며 포커스 되는 갯수 자체가 5개 미만이니 굳이 필요하지는 않을 듯.. - [levites] + m_ActiveWindowList.push_back(m_pActiveWindow); + m_pActiveWindow->OnKillFocus(); + } + + m_pActiveWindow = pWin; + + if (m_pActiveWindow) + { + m_pActiveWindow->OnSetFocus(); + } + } + + void CWindowManager::DeactivateWindow() + { + if (m_pActiveWindow) + { + if (m_ActiveWindowList.empty()) + { + m_pActiveWindow->OnKillFocus(); + m_pActiveWindow = NULL; + } + else + { + m_pActiveWindow->OnKillFocus(); + + m_pActiveWindow = m_ActiveWindowList.back(); + m_ActiveWindowList.pop_back(); + + m_pActiveWindow->OnSetFocus(); + } + } + } + + void CWindowManager::SetTop(CWindow * pWin) + { + if (!pWin->HasParent()) + return; + + CWindow * pParentWindow = pWin->GetParent(); + pParentWindow->SetTop(pWin); + + // NOTE : Capture가 리셋된다..? - [levites] + // NOTE : 인벤토리에서 아이템을 드래그 해서 밖에다 놓을때 캡춰가 남아서 창의 버튼을 두번 눌러야 하는 버그를 위해 추가 +// ResetCapture(); + } + + void CWindowManager::SetTopUIWindow() + { + if (m_pLockWindow) + return; + + // GameLayer에 속해 있는 윈도우가 피킹 됐다면 무조건 SetTop을 해준다. + TLayerContainer::iterator itor = m_LayerWindowMap.find("UI"); + if (itor == m_LayerWindowMap.end()) + return; + CWindow * pGameLayer = itor->second; + CWindow * pTopWindow = pGameLayer->PickTopWindow(m_lMouseX, m_lMouseY); + if (pTopWindow) + { + SetTop(pTopWindow); + } + } + + CWindow * CWindowManager::GetActivateWindow() + { + return m_pActiveWindow; + } + + void CWindowManager::ResetCapture() + { + m_pLeftCaptureWindow = NULL; + m_pMiddleCaptureWindow = NULL; + m_pRightCaptureWindow = NULL; + } + + void CWindowManager::SetResolution(int hres, int vres) + { + if (hres<=0 || vres<=0) + return; + + m_iHres = hres; + m_iVres = vres; + } + + float CWindowManager::GetAspect() + { + return (m_iHres)/float(m_iVres); + } + + void CWindowManager::SetScreenSize(long lWidth, long lHeight) + { + m_lWidth = lWidth; + m_lHeight = lHeight; + + for (TLayerContainer::iterator itor = m_LayerWindowMap.begin(); itor != m_LayerWindowMap.end(); ++itor) + { + itor->second->SetSize(lWidth, lHeight); + } + } + + void CWindowManager::__ClearReserveDeleteWindowList() + { + for (TWindowContainer::iterator itor = m_ReserveDeleteWindowList.begin(); itor != m_ReserveDeleteWindowList.end(); ++itor) + { + CWindow * pWin = *itor; +#ifdef __WINDOW_LEAK_CHECK__ + gs_kSet_pkWnd.erase(pWin); +#endif + delete pWin; + } + m_ReserveDeleteWindowList.clear(); + + } + + void CWindowManager::Update() + { + __ClearReserveDeleteWindowList(); + + m_pRootWindow->Update(); + } + + void CWindowManager::Render() + { + m_pRootWindow->Render(); + } + + CWindow * CWindowManager::__PickWindow(long x, long y) + { + if (m_pLockWindow) + { + return m_pLockWindow->PickWindow(x, y); + } + + for (TWindowContainer::iterator itor = m_PickAlwaysWindowList.begin(); itor != m_PickAlwaysWindowList.end(); ++itor) + { + CWindow * pWindow = *itor; + if (pWindow->IsRendering()) + if (pWindow->IsIn(x, y)) + return pWindow; + } + + for (TWindowContainer::reverse_iterator ritor = m_LayerWindowList.rbegin(); ritor != m_LayerWindowList.rend(); ++ritor) + { + CWindow * pLayer = *ritor; + CWindow * pPickedWindow = pLayer->PickWindow(x, y); + + if (pPickedWindow != pLayer) + return pPickedWindow; + } + + return NULL; + } + + void CWindowManager::SetMousePosition(long x, long y) + { + if (m_iHres==0) + return; + + if (m_iVres==0) + return; + + m_lMouseX = m_lWidth * x / m_iHres; + m_lMouseY = m_lHeight * y / m_iVres; + } + + void CWindowManager::GetMousePosition(long & rx, long & ry) + { + rx = m_lMouseX; + ry = m_lMouseY; + } + + void CWindowManager::RunMouseMove(long x, long y) + { + if (IsAttaching()) + { + if (x > m_lWidth) + x = m_lWidth; + if (y > m_lHeight) + y = m_lHeight; + } + + SetMousePosition(x, y); + CWindow * pPointWindow = __PickWindow(m_lMouseX, m_lMouseY); + + if (g_bShowOverInWindowName) + { + if (pPointWindow) + { + static std::string strPickWindowName = ""; + if (0 != strPickWindowName.compare(pPointWindow->GetName())) + { + Tracef(" OverInWindowName [%s]\n", pPointWindow->GetName()); + strPickWindowName = pPointWindow->GetName(); + } + } + } + + if (m_pLeftCaptureWindow) + { + CWindow * pWin = m_pLeftCaptureWindow; + + if (pWin->IsFlag(CWindow::FLAG_MOVABLE)) + { + long x = m_lMouseX - m_lDragX; + long y = m_lMouseY - m_lDragY; + if (pWin->HasParent()) + { + x -= pWin->GetParent()->GetRect().left; + y -= pWin->GetParent()->GetRect().top; + } + + long lx, ly; + pWin->GetPosition(&lx, &ly); + if (pWin->IsFlag(CWindow::FLAG_RESTRICT_X)) + { + x = lx; + } + if (pWin->IsFlag(CWindow::FLAG_RESTRICT_Y)) + { + y = ly; + } + + if (pWin->IsFlag(CWindow::FLAG_LIMIT)) + { + RECT limitRect = pWin->GetLimitBias(); + + limitRect.right = m_lWidth - limitRect.right; + limitRect.bottom = m_lHeight - limitRect.bottom; + + if (x < limitRect.left) + x = limitRect.left; + else if (x + pWin->GetWidth() >= limitRect.right) + x = limitRect.right - pWin->GetWidth(); + + if (y < limitRect.top) + y = limitRect.top; + else if (y + pWin->GetHeight() >= limitRect.bottom) + y = limitRect.bottom - pWin->GetHeight(); + } + + pWin->SetPosition(x, y); + pWin->OnMoveWindow(x, y); + } + else if (m_pLeftCaptureWindow->IsFlag(CWindow::FLAG_DRAGABLE)) + { + long x = m_lMouseX - m_lDragX; + long y = m_lMouseY - m_lDragY; + m_pLeftCaptureWindow->OnMouseDrag(x, y); + } + } + + if (m_pPointWindow != pPointWindow) + { +#ifdef _DEBUG + if (pPointWindow && pPointWindow->GetName()) + Tracenf("PointWindow: %s", pPointWindow->GetName()); +#endif + if (m_pPointWindow) + m_pPointWindow->OnMouseOverOut(); + + m_pPointWindow = pPointWindow; + + if (m_pPointWindow) + m_pPointWindow->OnMouseOverIn(); + } + + if (m_pPointWindow) + { + m_pPointWindow->OnMouseOver(); + } + } + + void CWindowManager::RunMouseLeftButtonDown(long x, long y) + { + SetTopUIWindow(); + + ///// + + SetMousePosition(x, y); + CWindow * pWin = GetPointWindow(); + + if (!pWin) + return; + + // Attach + if (pWin->IsFlag(CWindow::FLAG_ATTACH)) + pWin = pWin->GetRoot(); + + // Drag + if (!pWin->IsFlag(CWindow::FLAG_NOT_CAPTURE)) + m_pLeftCaptureWindow = pWin; + + m_lDragX = m_lMouseX - pWin->GetRect().left; + m_lDragY = m_lMouseY - pWin->GetRect().top; + m_lPickedX = m_lMouseX; + m_lPickedY = m_lMouseY; + + // Event + pWin->OnMouseLeftButtonDown(); + } + + void CWindowManager::RunMouseLeftButtonUp(long x, long y) + { + if (m_bOnceIgnoreMouseLeftButtonUpEventFlag) + { + m_bOnceIgnoreMouseLeftButtonUpEventFlag = FALSE; + + if (timeGetTime() < m_iIgnoreEndTime) + { + return; + } + } + + SetMousePosition(x, y); + + if (m_pLeftCaptureWindow) + { + if (m_pLeftCaptureWindow->OnMouseLeftButtonUp()) + { + // NOTE : 여기서 m_pLeftCaptureWindow가 NULL 일 수 있습니다!! - [levites] + m_pLeftCaptureWindow = NULL; + return; + } + } + + CWindow * pWin = GetPointWindow(); + if (pWin) + pWin->OnMouseLeftButtonUp(); + + m_pLeftCaptureWindow = NULL; + } + + void CWindowManager::RunMouseLeftButtonDoubleClick(long x, long y) + { + SetMousePosition(x, y); + + CWindow * pWin = GetPointWindow(); + if (!pWin) + return; + + pWin->OnMouseLeftButtonDoubleClick(); + } + + void CWindowManager::RunMouseRightButtonDown(long x, long y) + { + SetTopUIWindow(); + + /////////////////////////////////////////////////////////////////////////////////////////// + + SetMousePosition(x, y); + CWindow * pWin = GetPointWindow(); + if (!pWin) + return; + + // Attach + if (pWin->IsFlag(CWindow::FLAG_ATTACH)) + pWin = pWin->GetRoot(); + + // Drag + if (!pWin->IsFlag(CWindow::FLAG_NOT_CAPTURE)) + m_pRightCaptureWindow = pWin; + + pWin->OnMouseRightButtonDown(); + } + + void CWindowManager::RunMouseRightButtonUp(long x, long y) + { + if (m_pRightCaptureWindow) + { + if (m_pRightCaptureWindow->OnMouseRightButtonUp()) + { + m_pRightCaptureWindow = NULL; + return; + } + } + + CWindow * pWin = GetPointWindow(); + if (pWin) + pWin->OnMouseRightButtonUp(); + + m_pRightCaptureWindow = NULL; + DeattachIcon(); + } + + void CWindowManager::RunMouseRightButtonDoubleClick(long x, long y) + { + SetMousePosition(x, y); + + CWindow * pWin = GetPointWindow(); + if (pWin) + { + pWin->OnMouseRightButtonDoubleClick(); + } + } + + void CWindowManager::RunMouseMiddleButtonDown(long x, long y) + { + SetMousePosition(x, y); + + CWindow * pWin = GetPointWindow(); + if (!pWin) + return; + + m_pMiddleCaptureWindow = pWin; + + pWin->OnMouseMiddleButtonDown(); + } + + void CWindowManager::RunMouseMiddleButtonUp(long x, long y) + { + SetMousePosition(x, y); + + if (m_pMiddleCaptureWindow) + { + if (m_pMiddleCaptureWindow->OnMouseMiddleButtonUp()) + { + m_pMiddleCaptureWindow = NULL; + return; + } + } + + CWindow * pWin = GetPointWindow(); + if (!pWin) + return; + + pWin->OnMouseMiddleButtonUp(); + m_pMiddleCaptureWindow = NULL; + } + + // IME + void CWindowManager::RunIMEUpdate() + { + if (m_pLockWindow) + { + m_pLockWindow->OnIMEUpdate(); + return; + } + + if (!m_pActiveWindow) + return; + if (!m_pActiveWindow->IsRendering()) + return; + + m_pActiveWindow->OnIMEUpdate(); + } + + void CWindowManager::RunIMETabEvent() + { + if (m_pLockWindow) + { + m_pLockWindow->OnIMETabEvent(); + return; + } + if (m_pActiveWindow) + if (m_pActiveWindow->IsRendering()) + { + if (m_pActiveWindow->OnIMETabEvent()) + return; + } + + if (!m_pRootWindow->RunIMETabEvent()) + { + if (!m_ActiveWindowList.empty()) + { + CWindow * pWindow = *(m_ActiveWindowList.begin()); + ActivateWindow(pWindow); + + ///////////////////////////////////////////// + + CWindow * pParentWindow = pWindow; + CWindow * pCurrentWindow = pWindow->GetParent(); + + DWORD dwMaxLoopCount = 20; + for (DWORD i = 0; i < dwMaxLoopCount; ++i) + { + if (!pParentWindow) + break; + + if (pParentWindow == m_LayerWindowMap["GAME"]) + { + SetTop(pCurrentWindow); + break; + } + + pCurrentWindow = pParentWindow; + pParentWindow = pCurrentWindow->GetParent(); + } + } + } + } + + void CWindowManager::RunIMEReturnEvent() + { + if (m_pLockWindow) + { + m_pLockWindow->OnIMEReturnEvent(); + return; + } + if (m_pActiveWindow) + if (m_pActiveWindow->IsRendering()) + { + if (m_pActiveWindow->OnIMEReturnEvent()) + return; + } + + m_pRootWindow->RunIMEReturnEvent(); + } + + void CWindowManager::RunIMEKeyDown(int vkey) + { + if (m_pLockWindow) + { + m_pLockWindow->OnKeyDown(vkey); + return; + } + if (m_pActiveWindow) + if (m_pActiveWindow->IsRendering()) + { + if (m_pActiveWindow->OnIMEKeyDownEvent(vkey)) + return; + } + + // NOTE : 전체로 돌리지 않고 Activate되어있는 EditLine에만 보내는 이벤트 + } + + void CWindowManager::RunChangeCodePage() + { + if (m_pActiveWindow) + if (m_pActiveWindow->IsRendering()) + { + if (m_pActiveWindow->OnIMEChangeCodePage()) + return; + } + } + void CWindowManager::RunOpenCandidate() + { + if (m_pLockWindow) + { + m_pLockWindow->OnIMEOpenCandidateListEvent(); + return; + } + if (m_pActiveWindow) + if (m_pActiveWindow->IsRendering()) + { + if (m_pActiveWindow->OnIMEOpenCandidateListEvent()) + return; + } + } + + void CWindowManager::RunCloseCandidate() + { + if (m_pLockWindow) + { + m_pLockWindow->OnIMECloseCandidateListEvent(); + return; + } + if (m_pActiveWindow) + if (m_pActiveWindow->IsRendering()) + { + if (m_pActiveWindow->OnIMECloseCandidateListEvent()) + return; + } + } + + void CWindowManager::RunOpenReading() + { + if (m_pLockWindow) + { + m_pLockWindow->OnIMEOpenReadingWndEvent(); + return; + } + if (m_pActiveWindow) + if (m_pActiveWindow->IsRendering()) + { + if (m_pActiveWindow->OnIMEOpenReadingWndEvent()) + return; + } + } + + void CWindowManager::RunCloseReading() + { + if (m_pLockWindow) + { + m_pLockWindow->OnIMECloseReadingWndEvent(); + return; + } + if (m_pActiveWindow) + if (m_pActiveWindow->IsRendering()) + { + if (m_pActiveWindow->OnIMECloseReadingWndEvent()) + return; + } + } + // IME + + void CWindowManager::RunKeyDown(int vkey) + { + if (m_pLockWindow) + { + m_pLockWindow->OnKeyDown(vkey); + m_KeyCaptureWindowMap.insert(std::make_pair(vkey, m_pLockWindow)); + return; + } + if (m_pActiveWindow) + if (m_pActiveWindow->IsShow()) + { + if (m_pActiveWindow->OnKeyDown(vkey)) + { + m_KeyCaptureWindowMap.insert(std::make_pair(vkey, m_pActiveWindow)); + return; + } + } + + CWindow * pKeyCaptureWindow = m_pRootWindow->RunKeyDownEvent(vkey); + if (pKeyCaptureWindow) + if (m_ReserveDeleteWindowList.end() == std::find(m_ReserveDeleteWindowList.begin(), m_ReserveDeleteWindowList.end(), pKeyCaptureWindow)) + { + m_KeyCaptureWindowMap.insert(TKeyCaptureWindowMap::value_type(vkey, pKeyCaptureWindow)); + } + } + + void CWindowManager::RunKeyUp(int vkey) + { + TKeyCaptureWindowMap::iterator itor = m_KeyCaptureWindowMap.find(vkey); + if (m_KeyCaptureWindowMap.end() != itor) + { + CWindow * pKeyCaptureWindow = itor->second; + if (pKeyCaptureWindow) + pKeyCaptureWindow->OnKeyUp(vkey); + + m_KeyCaptureWindowMap.erase(itor); + return; + } + + if (m_pLockWindow) + { + m_pLockWindow->OnKeyUp(vkey); + return; + } + + if (m_pActiveWindow) + { + if (m_pActiveWindow->OnKeyUp(vkey)) + return; + } + + m_pRootWindow->RunKeyUpEvent(vkey); + } + + void CWindowManager::RunPressEscapeKey() + { + if (m_pLockWindow) + { + m_pLockWindow->OnPressEscapeKey(); + return; + } + + m_pRootWindow->RunPressEscapeKeyEvent(); + } + + void CWindowManager::RunPressExitKey() + { + if (m_pLockWindow) + { + m_pLockWindow->OnPressExitKey(); + return; + } + if (m_pActiveWindow) + { + if (m_pActiveWindow->OnPressExitKey()) + return; + } + + m_pRootWindow->RunPressExitKeyEvent(); + } +} diff --git a/extension/tests/port_window_tree_test.cpp b/extension/tests/port_window_tree_test.cpp new file mode 100644 index 00000000..33bbf698 --- /dev/null +++ b/extension/tests/port_window_tree_test.cpp @@ -0,0 +1,319 @@ +// port/EterPythonLib 的窗口树(批次 2V0-b):UI::CWindow / UI::CWindowManager 在真解释器上跑一遍。 +// +// 这一层是 40250 整个 UI 的骨架:Python 侧每个窗口对象背后都是一个 CWindow,布局(UpdateRect 的 +// 对齐规则)、命中(PickWindow 的 flag 语义)、拖动、焦点、按键捕获全在 C++ 里,Python 只收事件。 +// wndMgr 模块(2V0-c)只是把这些函数包一层,所以这里直接按 C++ API 驱动,验的是同一份逻辑。 +// +// 渲染不碰:Render()/OnRender() 需要 CPythonGraphic 和图形设备,那是 2V0-f 的事。解释器是必须的 —— +// CWindowManager 的构造函数就 Py_BuildValue("()"),事件也确实要发到 Python 处理器上。 +// +// port_window_tree_test +// +// 缺 python27.zip 时退 77(ctest SKIP),MT_ASSETS_STRICT=1 时改成失败。 +#include "EterPythonLib/StdAfx.h" +#include "EterPythonLib/PythonWindow.h" +#include "EterPythonLib/PythonWindowManager.h" +#include "ScriptLib/PythonLauncher.h" +#include "../src/platform/ScriptLib/PythonHost.h" + +#include +#include +#include + +static int g_failures = 0; +#define CHECK(cond) \ + do { \ + if (!(cond)) { \ + std::fprintf(stderr, "%s:%d: CHECK(%s)\n", __FILE__, __LINE__, #cond); \ + ++g_failures; \ + } \ + } while (0) + +// Python 侧的处理器:每个事件往 LOG 里记一条,C++ 这边取出来比对。这正是 40250 的 ui.py 做的事情 +// (Window 类的 OnMouseOverIn / OnKeyDown ... 都是普通的 Python 方法)。 +static const char* const kHandlerScript = + "LOG = []\n" + "class Handler:\n" + " def __init__(self, name, eat = 0):\n" + " self.name = name\n" + " self.eat = eat\n" + " def OnMouseOverIn(self): LOG.append(self.name + ':in')\n" + " def OnMouseOverOut(self): LOG.append(self.name + ':out')\n" + " def OnMouseLeftButtonDown(self): LOG.append(self.name + ':down')\n" + " def OnMouseLeftButtonUp(self): LOG.append(self.name + ':up')\n" + " def OnSetFocus(self): LOG.append(self.name + ':focus')\n" + " def OnKillFocus(self): LOG.append(self.name + ':blur')\n" + " def OnUpdate(self): LOG.append(self.name + ':update')\n" + " def OnKeyDown(self, key):\n" + " LOG.append('%s:kd%d' % (self.name, key))\n" + " return self.eat\n" + " def OnKeyUp(self, key):\n" + " LOG.append('%s:ku%d' % (self.name, key))\n" + " return 1\n" + "A = Handler('A')\n" + "B = Handler('B')\n" + "C = Handler('C', 1)\n"; + +static PyObject* main_dict() +{ + return PyModule_GetDict(PyImport_AddModule((char*) "__main__")); +} + +static PyObject* handler(const char* name) +{ + PyObject* object = PyDict_GetItemString(main_dict(), name); // Borrowed; __main__ 一直持有 + if (!object) + std::fprintf(stderr, "handler('%s') missing\n", name); + return object; +} + +// LOG 的内容,取完清空 —— 每个检查点只看自己那一段。 +static std::string take_log() +{ + PyObject* log = PyDict_GetItemString(main_dict(), "LOG"); + if (!log || !PyList_Check(log)) + return ""; + std::string text; + for (Py_ssize_t i = 0; i < PyList_Size(log); ++i) + { + PyObject* item = PyList_GetItem(log, i); + if (!text.empty()) + text += ' '; + text += PyString_Check(item) ? PyString_AS_STRING(item) : "?"; + } + PyList_SetSlice(log, 0, PyList_Size(log), NULL); + return text; +} + +static bool rect_is(UI::CWindow* window, long left, long top, long right, long bottom) +{ + const RECT& rect = window->GetRect(); + if (rect.left == left && rect.top == top && rect.right == right && rect.bottom == bottom) + return true; + std::fprintf(stderr, "rect(%s) = %ld,%ld,%ld,%ld, expected %ld,%ld,%ld,%ld\n", window->GetName(), + (long) rect.left, (long) rect.top, (long) rect.right, (long) rect.bottom, + left, top, right, bottom); + return false; +} + +static void run(UI::CWindowManager& wm) +{ + // 40250 是先 SetScreenSize 再 SetResolution(UserInterface 的 OnSizeChange)。分辨率为 0 时 + // SetMousePosition 直接 return,鼠标坐标永远是 0 —— 这条顺序是有意义的。 + wm.SetScreenSize(800, 600); + wm.SetResolution(800, 600); + CHECK(wm.GetScreenWidth() == 800 && wm.GetScreenHeight() == 600); + long hres = 0, vres = 0; + wm.GetResolution(hres, vres); + CHECK(hres == 800 && vres == 600); + CHECK(wm.GetAspect() == 800.0f / 600.0f); + + // ---- 层与树 ---- + UI::CWindow* a = wm.RegisterWindow(handler("A"), "UI"); + a->SetName("A"); + CHECK(std::string(a->GetParent()->GetName()) == "UI"); + // 五个层(GAME/UI_BOTTOM/UI/TOP_MOST/CURTAIN)是 CLayer,IsWindow() 为 FALSE,所以注册到层上的 + // 窗口自己就是 root —— Python 侧的 GetRoot() 从来拿不到层。 + CHECK(a->GetRoot() == a); + CHECK(!a->IsShow()); + a->SetSize(100, 50); + a->SetPosition(10, 20); + a->Show(); + CHECK(rect_is(a, 10, 20, 110, 70)); + + UI::CWindow* b = wm.RegisterWindow(handler("B"), "UI"); + b->SetName("B"); + wm.SetParent(b, a); + CHECK(b->GetParent() == a && a->GetChildCount() == 1); + CHECK(b->GetRoot() == a); + b->SetSize(20, 10); + b->SetPosition(5, 5); + b->Show(); + CHECK(rect_is(b, 15, 25, 35, 35)); + + // ---- UpdateRect 的对齐规则(父窗口 100x50 @ 10,20,子窗口 20x10 @ 5,5)---- + b->SetHorizontalAlign(UI::CWindow::HORIZONTAL_ALIGN_RIGHT); // left = |100| - 5 + 10 + CHECK(rect_is(b, 105, 25, 125, 35)); + b->SetHorizontalAlign(UI::CWindow::HORIZONTAL_ALIGN_CENTER); // left = 100/2 - 20/2 + 5 + 10 + CHECK(rect_is(b, 55, 25, 75, 35)); + b->SetVerticalAlign(UI::CWindow::VERTICAL_ALIGN_BOTTOM); // top = 50 - 5 + 20 + CHECK(rect_is(b, 55, 65, 75, 75)); + b->SetVerticalAlign(UI::CWindow::VERTICAL_ALIGN_CENTER); // top = (50 - 10)/2 + 5 + 20 + CHECK(rect_is(b, 55, 45, 75, 55)); + b->SetHorizontalAlign(UI::CWindow::HORIZONTAL_ALIGN_LEFT); + b->SetVerticalAlign(UI::CWindow::VERTICAL_ALIGN_TOP); + CHECK(rect_is(b, 15, 25, 35, 35)); + + // 父窗口移动,子窗口跟着走(UpdateRect 会 for_each 到所有子窗口)。 + a->SetPosition(20, 30); + CHECK(rect_is(a, 20, 30, 120, 80) && rect_is(b, 25, 35, 45, 45)); + a->SetPosition(10, 20); + + // IsRendering:自己 Show 不够,链路上每一级都要 Show。 + CHECK(a->IsRendering() && b->IsRendering()); + a->Hide(); + CHECK(b->IsShow() && !b->IsRendering()); + a->Show(); + + // ---- 命中 ---- + UI::CWindow* c = wm.RegisterWindow(handler("C"), "UI"); + c->SetName("C"); + c->SetSize(100, 50); + c->SetPosition(10, 20); + c->Show(); + take_log(); + + // 同层后注册的在上面(PickWindow 反向遍历子链表)。 + wm.RunMouseMove(50, 40); + CHECK(wm.GetPointWindow() == c); + CHECK(take_log() == "C:in"); + // 鼠标坐标按 屏幕尺寸/分辨率 换算,这里 1:1。 + long mx = 0, my = 0; + wm.GetMousePosition(mx, my); + CHECK(mx == 50 && my == 40); + + // C 藏起来,命中落到 A 的子树上。 + c->Hide(); + wm.RunMouseMove(20, 28); + CHECK(wm.GetPointWindow() == b); + CHECK(take_log() == "C:out B:in"); + + // FLAG_NOT_PICK:这个窗口自己不被选中,但仍然往下找子窗口 —— 结果落回父窗口。 + b->AddFlag(UI::CWindow::FLAG_NOT_PICK); + wm.RunMouseMove(20, 28); + CHECK(wm.GetPointWindow() == a); + CHECK(take_log() == "B:out A:in"); + b->RemoveFlag(UI::CWindow::FLAG_NOT_PICK); + + // FLAG_IGNORE_SIZE:不做 IsIn 判断,只要父窗口被命中就轮到它。 + b->AddFlag(UI::CWindow::FLAG_IGNORE_SIZE); + wm.RunMouseMove(100, 65); // 在 A 里,不在 B 的矩形里 + CHECK(wm.GetPointWindow() == b); + b->RemoveFlag(UI::CWindow::FLAG_IGNORE_SIZE); + wm.RunMouseMove(100, 65); + CHECK(wm.GetPointWindow() == a); + take_log(); + + // 层外面不命中任何窗口。 + wm.RunMouseMove(700, 500); + CHECK(wm.GetPointWindow() == NULL); + take_log(); + + // SetPickAlways:不管挡在前面的是谁,只要在矩形里就先拿到(工具提示、拖动图标用的)。 + c->Show(); + wm.SetPickAlways(b); + wm.RunMouseMove(20, 28); + CHECK(wm.GetPointWindow() == b); + take_log(); + + // ---- SetTop:只对 FLAG_FLOAT 的窗口生效 ---- + CHECK(!a->IsFlag(UI::CWindow::FLAG_FLOAT)); + wm.SetTop(a); // 没有 FLAG_FLOAT,什么也不做 + a->AddFlag(UI::CWindow::FLAG_FLOAT); + wm.SetTop(a); // A 挪到层的链表末尾,压过 C + wm.RunMouseMove(90, 65); // A 和 C 都覆盖这里 + CHECK(wm.GetPointWindow() == a); + take_log(); + + // ---- 拖动:FLAG_MOVABLE 时窗口管理器直接改坐标 ---- + a->AddFlag(UI::CWindow::FLAG_MOVABLE); + wm.RunMouseLeftButtonDown(90, 65); + CHECK(take_log() == "A:down"); + wm.RunMouseMove(100, 75); // 位移 +10,+10 + CHECK(a->GetPositionX() == 20 && a->GetPositionY() == 30); + + // FLAG_LIMIT:窗口不许离开屏幕,LimitBias 是四边的留白。 + a->AddFlag(UI::CWindow::FLAG_LIMIT); + a->SetLimitBias(0, 0, 0, 0); + wm.RunMouseMove(2000, 2000); + CHECK(a->GetPositionX() == 800 - a->GetWidth() && a->GetPositionY() == 600 - a->GetHeight()); + wm.RunMouseMove(-2000, -2000); + CHECK(a->GetPositionX() == 0 && a->GetPositionY() == 0); + wm.RunMouseLeftButtonUp(-2000, -2000); + a->RemoveFlag(UI::CWindow::FLAG_LIMIT); + a->RemoveFlag(UI::CWindow::FLAG_MOVABLE); + a->SetPosition(10, 20); + take_log(); + + // ---- 焦点 ---- + CHECK(!wm.IsFocus()); + wm.ActivateWindow(a); + CHECK(wm.IsFocus() && wm.IsFocusWindow(a) && wm.GetActivateWindow() == a); + CHECK(take_log() == "A:focus"); + wm.ActivateWindow(c); + CHECK(wm.IsFocusWindow(c) && !wm.IsFocusWindow(a)); + CHECK(take_log() == "A:blur C:focus"); + wm.DeactivateWindow(); + CHECK(!wm.IsFocus()); + take_log(); + + // ---- 按键:RunKeyDownEvent 从 root 往下走,第一个 OnKeyDown 返回真的窗口吃掉它并被记成捕获者 ---- + a->Hide(); // A 的处理器返回 0,藏起来让这段日志只剩 C + wm.RunKeyDown(65); + CHECK(take_log() == "C:kd65"); + // KeyUp 只发给捕获者,不再重新查找。 + wm.RunKeyUp(65); + CHECK(take_log() == "C:ku65"); + // 没人捕获的键:RunKeyUpEvent 从 root 往下发一轮(C 的 OnKeyUp 返回 1,到此为止)。 + wm.RunKeyUp(66); + CHECK(take_log() == "C:ku66"); + a->Show(); + + // ---- Update 沿着树走,Hide 的分支整支跳过 ---- + take_log(); + wm.Update(); + CHECK(take_log() == "A:update B:update C:update"); + b->Hide(); + wm.Update(); + CHECK(take_log() == "A:update C:update"); + b->Show(); + + // ---- 销毁:先从管理器的各个指针里摘干净,再从父窗口摘掉,真正的 delete 留到下一次 Update ---- + wm.RunMouseMove(90, 65); + CHECK(wm.GetPointWindow() == a); + wm.ActivateWindow(a); + wm.RunKeyDown(65); // A 的处理器返回 0,捕获者还是 C + take_log(); + wm.DestroyWindow(c); + CHECK(wm.GetActivateWindow() != c); + wm.DestroyWindow(a); // B 是 A 的子窗口,Clear() 只断链不删 + CHECK(wm.GetPointWindow() == NULL); + CHECK(!b->HasParent() && !b->IsShow()); + wm.Update(); // 这里才 delete,a/c 从此不可用 + CHECK(take_log() == ""); + delete b; // 40250 也不管子窗口,Python 那边各自 Destroy +} + +int main(int argc, char** argv) +{ + const char* strict = std::getenv("MT_ASSETS_STRICT"); + const bool is_strict = strict && std::string(strict) == "1"; + const std::string stdlib = argc > 1 ? argv[1] : PythonHost::DefaultStdLibPath(); + if (stdlib.empty() || std::fopen(stdlib.c_str(), "rb") == NULL) + { + std::fprintf(stderr, "port_window_tree_test: no python27.zip at '%s'\n", stdlib.c_str()); + return is_strict ? 1 : 77; + } + + PythonHost::Configure(); + { + CPythonLauncher launcher; // 和 40250 Main() 一样在栈上,构造即 Py_Initialize + CHECK(launcher.Create()); + std::string error; + CHECK(PythonHost::InstallStdLib(stdlib.c_str(), &error)); + if (!error.empty()) + std::fprintf(stderr, "InstallStdLib: %s\n", error.c_str()); + CHECK(launcher.RunLine(kHandlerScript)); + + { + UI::CWindowManager wm; // 构造函数建 root + 五个层,析构函数 Py_DECREF 空元组 + run(wm); + } + CHECK(PyErr_Occurred() == NULL); + launcher.Clear(); + } + CHECK(!Py_IsInitialized()); + + std::printf("%s: %d failure(s)\n", argv[0], g_failures); + return g_failures == 0 ? 0 : 1; +} diff --git a/project/auth_connect_bridge_test.gd.uid b/project/auth_connect_bridge_test.gd.uid new file mode 100644 index 00000000..e57e7595 --- /dev/null +++ b/project/auth_connect_bridge_test.gd.uid @@ -0,0 +1 @@ +uid://bdcaheq2nmoqg diff --git a/project/auth_peer_close_bridge_test.gd.uid b/project/auth_peer_close_bridge_test.gd.uid new file mode 100644 index 00000000..06b54b90 --- /dev/null +++ b/project/auth_peer_close_bridge_test.gd.uid @@ -0,0 +1 @@ +uid://8alojuolcg5f diff --git a/project/ui/quiet_button.gd.uid b/project/ui/quiet_button.gd.uid new file mode 100644 index 00000000..3af109a4 --- /dev/null +++ b/project/ui/quiet_button.gd.uid @@ -0,0 +1 @@ +uid://b3uq3sf8dy087 diff --git a/project/ui/quiet_panel.gd.uid b/project/ui/quiet_panel.gd.uid new file mode 100644 index 00000000..b4bece28 --- /dev/null +++ b/project/ui/quiet_panel.gd.uid @@ -0,0 +1 @@ +uid://st31pbybiodp