Support switch controls focus when press TAB
- Delete old messages loop. - Delete ShowModal function. - Enable SetNextTabControl function to support switch controls focus when press TAB. Signed-off-by: jiajia_deng <2894220@gmail.com>
This commit is contained in:
parent
a57f4597eb
commit
bef5c9ac8e
@ -181,6 +181,7 @@ bool TabBox::SelectItem(int iIndex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if( m_pWindow != NULL ) {
|
if( m_pWindow != NULL ) {
|
||||||
|
m_pWindow->SetNextTabControl();
|
||||||
m_pWindow->SendNotify(this, kEventSelect, m_iCurSel, iOldSel);
|
m_pWindow->SendNotify(this, kEventSelect, m_iCurSel, iOldSel);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -14,6 +14,7 @@ public:
|
|||||||
/// 重写父类方法,提供个性化功能,请参考父类声明
|
/// 重写父类方法,提供个性化功能,请参考父类声明
|
||||||
virtual void Activate() override;
|
virtual void Activate() override;
|
||||||
virtual void HandleMessage(EventArgs& event) override;
|
virtual void HandleMessage(EventArgs& event) override;
|
||||||
|
virtual UINT GetControlFlags() const override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 绑定鼠标点击处理函数
|
* @brief 绑定鼠标点击处理函数
|
||||||
@ -23,6 +24,12 @@ public:
|
|||||||
void AttachClick(const EventCallback& callback) { this->OnEvent[kEventClick] += callback; }
|
void AttachClick(const EventCallback& callback) { this->OnEvent[kEventClick] += callback; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename InheritType>
|
||||||
|
UINT ui::ButtonTemplate<InheritType>::GetControlFlags() const
|
||||||
|
{
|
||||||
|
return IsKeyboardEnabled() && IsEnabled() ? UIFLAG_TABSTOP : UIFLAG_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename InheritType>
|
template<typename InheritType>
|
||||||
ButtonTemplate<InheritType>::ButtonTemplate()
|
ButtonTemplate<InheritType>::ButtonTemplate()
|
||||||
{
|
{
|
||||||
|
@ -2268,6 +2268,11 @@ void RichEdit::SetPos(UiRect rc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT RichEdit::GetControlFlags() const
|
||||||
|
{
|
||||||
|
return IsEnabled() ? UIFLAG_TABSTOP : UIFLAG_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
void RichEdit::HandleMessage(EventArgs& event)
|
void RichEdit::HandleMessage(EventArgs& event)
|
||||||
{
|
{
|
||||||
if ((!IsMouseEnabled() && event.Type > kEventMouseBegin && event.Type < kEventMouseEnd) ||
|
if ((!IsMouseEnabled() && event.Type > kEventMouseBegin && event.Type < kEventMouseEnd) ||
|
||||||
|
@ -686,6 +686,7 @@ public:
|
|||||||
virtual void SetEnabled(bool bEnable = true) override;
|
virtual void SetEnabled(bool bEnable = true) override;
|
||||||
virtual CSize EstimateSize(CSize szAvailable) override;
|
virtual CSize EstimateSize(CSize szAvailable) override;
|
||||||
virtual void SetPos(UiRect rc) override;
|
virtual void SetPos(UiRect rc) override;
|
||||||
|
virtual UINT GetControlFlags() const override;
|
||||||
virtual void HandleMessage(EventArgs& event) override;
|
virtual void HandleMessage(EventArgs& event) override;
|
||||||
void OnSetCursor(EventArgs& event);
|
void OnSetCursor(EventArgs& event);
|
||||||
void OnSetFocus(EventArgs& event);
|
void OnSetFocus(EventArgs& event);
|
||||||
|
@ -735,6 +735,11 @@ void Box::ClearImageCache()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT Box::GetControlFlags() const
|
||||||
|
{
|
||||||
|
return UIFLAG_DEFAULT; // Box 默认不支持 TAB 切换焦点
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
@ -119,8 +119,10 @@ public:
|
|||||||
virtual void InvokeLoadImageCache() override;
|
virtual void InvokeLoadImageCache() override;
|
||||||
virtual void UnLoadImageCache() override;
|
virtual void UnLoadImageCache() override;
|
||||||
virtual void ClearImageCache() override;
|
virtual void ClearImageCache() override;
|
||||||
|
virtual UINT GetControlFlags() const override;
|
||||||
|
|
||||||
/// 容器自有方法 */
|
|
||||||
|
/// 容器自有方法
|
||||||
/**
|
/**
|
||||||
* @brief 查找指定子控件
|
* @brief 查找指定子控件
|
||||||
* @param[in] pstrSubControlName 子控件名称
|
* @param[in] pstrSubControlName 子控件名称
|
||||||
|
@ -540,6 +540,11 @@ void Control::SetFocus()
|
|||||||
if( m_pWindow != NULL ) m_pWindow->SetFocus(this);
|
if( m_pWindow != NULL ) m_pWindow->SetFocus(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT Control::GetControlFlags() const
|
||||||
|
{
|
||||||
|
return UIFLAG_TABSTOP;
|
||||||
|
}
|
||||||
|
|
||||||
void Control::SetNoFocus()
|
void Control::SetNoFocus()
|
||||||
{
|
{
|
||||||
m_bNoFocus = true;
|
m_bNoFocus = true;
|
||||||
@ -798,11 +803,13 @@ void Control::HandleMessage(EventArgs& msg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (msg.Type == kEventInternalSetFocus) {
|
else if (msg.Type == kEventInternalSetFocus) {
|
||||||
|
SetState(kControlStateHot);
|
||||||
m_bFocused = true;
|
m_bFocused = true;
|
||||||
Invalidate();
|
Invalidate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (msg.Type == kEventInternalKillFocus) {
|
else if (msg.Type == kEventInternalKillFocus) {
|
||||||
|
SetState(kControlStateNormal);
|
||||||
m_bFocused = false;
|
m_bFocused = false;
|
||||||
Invalidate();
|
Invalidate();
|
||||||
return;
|
return;
|
||||||
|
@ -423,6 +423,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void SetFocus();
|
virtual void SetFocus();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 返回控件的标识,用于判断是否可以响应 TAB 切换事件
|
||||||
|
* @return 返回控件的标识类型
|
||||||
|
*/
|
||||||
|
virtual UINT GetControlFlags() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 让控件设置永远获取不到焦点
|
* @brief 让控件设置永远获取不到焦点
|
||||||
* @return 无
|
* @return 无
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#include <shlwapi.h>
|
#include <shlwapi.h>
|
||||||
#include "Utils/UnZip.h"
|
#include "Utils/UnZip.h"
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
|
|
||||||
std::wstring GlobalManager::m_pStrResourcePath;
|
std::wstring GlobalManager::m_pStrResourcePath;
|
||||||
@ -60,7 +60,7 @@ void GlobalManager::Startup(const std::wstring& strResourcePath, const CreateCon
|
|||||||
else {
|
else {
|
||||||
MutiLanSupport::GetInstance()->LoadStringTable(strResourcePath + language + L"\\gdstrings.ini");
|
MutiLanSupport::GetInstance()->LoadStringTable(strResourcePath + language + L"\\gdstrings.ini");
|
||||||
}
|
}
|
||||||
|
|
||||||
GdiplusStartup(&g_gdiplusToken, &g_gdiplusStartupInput, NULL);
|
GdiplusStartup(&g_gdiplusToken, &g_gdiplusStartupInput, NULL);
|
||||||
// Boot Windows Common Controls (for the ToolTip control)
|
// Boot Windows Common Controls (for the ToolTip control)
|
||||||
::InitCommonControls();
|
::InitCommonControls();
|
||||||
@ -80,27 +80,27 @@ void GlobalManager::Shutdown()
|
|||||||
|
|
||||||
std::wstring GlobalManager::GetCurrentPath()
|
std::wstring GlobalManager::GetCurrentPath()
|
||||||
{
|
{
|
||||||
TCHAR tszModule[MAX_PATH + 1] = { 0 };
|
TCHAR tszModule[MAX_PATH + 1] = { 0 };
|
||||||
::GetCurrentDirectory(MAX_PATH, tszModule);
|
::GetCurrentDirectory(MAX_PATH, tszModule);
|
||||||
return tszModule;
|
return tszModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring GlobalManager::GetResourcePath()
|
std::wstring GlobalManager::GetResourcePath()
|
||||||
{
|
{
|
||||||
return m_pStrResourcePath;
|
return m_pStrResourcePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalManager::SetCurrentPath(const std::wstring& strPath)
|
void GlobalManager::SetCurrentPath(const std::wstring& strPath)
|
||||||
{
|
{
|
||||||
::SetCurrentDirectory(strPath.c_str());
|
::SetCurrentDirectory(strPath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalManager::SetResourcePath(const std::wstring& strPath)
|
void GlobalManager::SetResourcePath(const std::wstring& strPath)
|
||||||
{
|
{
|
||||||
m_pStrResourcePath = strPath;
|
m_pStrResourcePath = strPath;
|
||||||
if( m_pStrResourcePath.empty() ) return;
|
if (m_pStrResourcePath.empty()) return;
|
||||||
TCHAR cEnd = m_pStrResourcePath.at(m_pStrResourcePath.length() - 1);
|
TCHAR cEnd = m_pStrResourcePath.at(m_pStrResourcePath.length() - 1);
|
||||||
if( cEnd != _T('\\') && cEnd != _T('/') ) m_pStrResourcePath += _T('\\');
|
if (cEnd != _T('\\') && cEnd != _T('/')) m_pStrResourcePath += _T('\\');
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalManager::LoadGlobalResource()
|
void GlobalManager::LoadGlobalResource()
|
||||||
@ -165,78 +165,6 @@ std::unique_ptr<ui::IPath> GlobalManager::CreatePath()
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GlobalManager::MessageLoop()
|
|
||||||
{
|
|
||||||
MSG msg = { 0 };
|
|
||||||
while( ::GetMessage(&msg, NULL, 0, 0) ) {
|
|
||||||
if( !GlobalManager::TranslateMessage(&msg) ) {
|
|
||||||
::TranslateMessage(&msg);
|
|
||||||
::DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GlobalManager::TranslateMessage(const LPMSG pMsg)
|
|
||||||
{
|
|
||||||
// Pretranslate Message takes care of system-wide messages, such as
|
|
||||||
// tabbing and shortcut key-combos. We'll look for all messages for
|
|
||||||
// each window and any child control attached.
|
|
||||||
UINT uStyle = GetWindowStyle(pMsg->hwnd);
|
|
||||||
UINT uChildRes = uStyle & WS_CHILD;
|
|
||||||
LRESULT lRes = 0;
|
|
||||||
if (uChildRes != 0)
|
|
||||||
{
|
|
||||||
HWND hWndParent = ::GetParent(pMsg->hwnd);
|
|
||||||
|
|
||||||
for( auto it = m_aPreMessages.begin(); it != m_aPreMessages.end(); it++ ) {
|
|
||||||
auto pT = *it;
|
|
||||||
HWND hTempParent = hWndParent;
|
|
||||||
while(hTempParent)
|
|
||||||
{
|
|
||||||
if(pMsg->hwnd == pT->GetHWND() || hTempParent == pT->GetHWND()) {
|
|
||||||
if (pT->TranslateAccelerator(pMsg))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if( pT->PreMessageHandler(pMsg->message, pMsg->wParam, pMsg->lParam, lRes) )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
hTempParent = GetParent(hTempParent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for( auto it = m_aPreMessages.begin(); it != m_aPreMessages.end(); it++ ) {
|
|
||||||
auto pT = *it;
|
|
||||||
if(pMsg->hwnd == pT->GetHWND()) {
|
|
||||||
if (pT->TranslateAccelerator(pMsg))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if( pT->PreMessageHandler(pMsg->message, pMsg->wParam, pMsg->lParam, lRes) )
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GlobalManager::AddPreMessage(Window* pWindow)
|
|
||||||
{
|
|
||||||
m_aPreMessages.push_back(pWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GlobalManager::RemovePreMessage(Window* pWindow)
|
|
||||||
{
|
|
||||||
auto it = std::find(m_aPreMessages.begin(), m_aPreMessages.end(), pWindow);
|
|
||||||
if (it != m_aPreMessages.end()) {
|
|
||||||
m_aPreMessages.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GlobalManager::AddClass(const std::wstring& strClassName, const std::wstring& strControlAttrList)
|
void GlobalManager::AddClass(const std::wstring& strClassName, const std::wstring& strControlAttrList)
|
||||||
{
|
{
|
||||||
ASSERT(!strClassName.empty());
|
ASSERT(!strClassName.empty());
|
||||||
@ -373,14 +301,14 @@ HFONT GlobalManager::AddFont(const std::wstring& strFontId, const std::wstring&
|
|||||||
if (strNewFontId.empty())
|
if (strNewFontId.empty())
|
||||||
{
|
{
|
||||||
strNewFontId = std::to_wstring(m_mCustomFonts.size());
|
strNewFontId = std::to_wstring(m_mCustomFonts.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto iter = m_mCustomFonts.find(strNewFontId);
|
auto iter = m_mCustomFonts.find(strNewFontId);
|
||||||
ASSERT(iter == m_mCustomFonts.end());
|
ASSERT(iter == m_mCustomFonts.end());
|
||||||
|
|
||||||
static bool bOsOverXp = IsWindowsVistaOrGreater();
|
static bool bOsOverXp = IsWindowsVistaOrGreater();
|
||||||
std::wstring fontName = strFontName;
|
std::wstring fontName = strFontName;
|
||||||
if ( fontName == L"system" ) {
|
if (fontName == L"system") {
|
||||||
fontName = bOsOverXp ? L"΢ÈíÑźÚ" : L"ÐÂËÎÌå";
|
fontName = bOsOverXp ? L"΢ÈíÑźÚ" : L"ÐÂËÎÌå";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,14 +317,14 @@ HFONT GlobalManager::AddFont(const std::wstring& strFontId, const std::wstring&
|
|||||||
_tcscpy(lf.lfFaceName, fontName.c_str());
|
_tcscpy(lf.lfFaceName, fontName.c_str());
|
||||||
lf.lfCharSet = DEFAULT_CHARSET;
|
lf.lfCharSet = DEFAULT_CHARSET;
|
||||||
lf.lfHeight = -DpiManager::GetInstance()->ScaleInt(nSize);
|
lf.lfHeight = -DpiManager::GetInstance()->ScaleInt(nSize);
|
||||||
if( bBold ) lf.lfWeight += FW_BOLD;
|
if (bBold) lf.lfWeight += FW_BOLD;
|
||||||
if( bUnderline ) lf.lfUnderline = TRUE;
|
if (bUnderline) lf.lfUnderline = TRUE;
|
||||||
if( bItalic ) lf.lfItalic = TRUE;
|
if (bItalic) lf.lfItalic = TRUE;
|
||||||
HFONT hFont = ::CreateFontIndirect(&lf);
|
HFONT hFont = ::CreateFontIndirect(&lf);
|
||||||
if( hFont == NULL ) return NULL;
|
if (hFont == NULL) return NULL;
|
||||||
|
|
||||||
TFontInfo* pFontInfo = new TFontInfo;
|
TFontInfo* pFontInfo = new TFontInfo;
|
||||||
if( !pFontInfo ) return false;
|
if (!pFontInfo) return false;
|
||||||
pFontInfo->hFont = hFont;
|
pFontInfo->hFont = hFont;
|
||||||
pFontInfo->sFontName = fontName;
|
pFontInfo->sFontName = fontName;
|
||||||
pFontInfo->iSize = nSize;
|
pFontInfo->iSize = nSize;
|
||||||
@ -440,8 +368,8 @@ HFONT GlobalManager::GetFont(const std::wstring& strFontName, int nSize, bool bB
|
|||||||
{
|
{
|
||||||
for (auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++) {
|
for (auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++) {
|
||||||
auto pFontInfo = it->second;
|
auto pFontInfo = it->second;
|
||||||
if( pFontInfo->sFontName == strFontName && pFontInfo->iSize == nSize &&
|
if (pFontInfo->sFontName == strFontName && pFontInfo->iSize == nSize &&
|
||||||
pFontInfo->bBold == bBold && pFontInfo->bUnderline == bUnderline && pFontInfo->bItalic == bItalic)
|
pFontInfo->bBold == bBold && pFontInfo->bUnderline == bUnderline && pFontInfo->bItalic == bItalic)
|
||||||
return pFontInfo->hFont;
|
return pFontInfo->hFont;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -450,7 +378,7 @@ HFONT GlobalManager::GetFont(const std::wstring& strFontName, int nSize, bool bB
|
|||||||
TFontInfo* GlobalManager::GetFontInfo(const std::wstring& strFontId, HDC hDcPaint)
|
TFontInfo* GlobalManager::GetFontInfo(const std::wstring& strFontId, HDC hDcPaint)
|
||||||
{
|
{
|
||||||
TFontInfo* pFontInfo = GetTFontInfo(strFontId);
|
TFontInfo* pFontInfo = GetTFontInfo(strFontId);
|
||||||
if( pFontInfo->tm.tmHeight == 0 ) {
|
if (pFontInfo->tm.tmHeight == 0) {
|
||||||
HFONT hOldFont = (HFONT) ::SelectObject(hDcPaint, pFontInfo->hFont);
|
HFONT hOldFont = (HFONT) ::SelectObject(hDcPaint, pFontInfo->hFont);
|
||||||
::GetTextMetrics(hDcPaint, &pFontInfo->tm);
|
::GetTextMetrics(hDcPaint, &pFontInfo->tm);
|
||||||
::SelectObject(hDcPaint, hOldFont);
|
::SelectObject(hDcPaint, hOldFont);
|
||||||
@ -460,10 +388,10 @@ TFontInfo* GlobalManager::GetFontInfo(const std::wstring& strFontId, HDC hDcPain
|
|||||||
|
|
||||||
TFontInfo* GlobalManager::GetFontInfo(HFONT hFont, HDC hDcPaint)
|
TFontInfo* GlobalManager::GetFontInfo(HFONT hFont, HDC hDcPaint)
|
||||||
{
|
{
|
||||||
for( auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++ ) {
|
for (auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++) {
|
||||||
auto pFontInfo = it->second;
|
auto pFontInfo = it->second;
|
||||||
if( pFontInfo->hFont == hFont ) {
|
if (pFontInfo->hFont == hFont) {
|
||||||
if( pFontInfo->tm.tmHeight == 0 ) {
|
if (pFontInfo->tm.tmHeight == 0) {
|
||||||
HFONT hOldFont = (HFONT) ::SelectObject(hDcPaint, pFontInfo->hFont);
|
HFONT hOldFont = (HFONT) ::SelectObject(hDcPaint, pFontInfo->hFont);
|
||||||
::GetTextMetrics(hDcPaint, &pFontInfo->tm);
|
::GetTextMetrics(hDcPaint, &pFontInfo->tm);
|
||||||
::SelectObject(hDcPaint, hOldFont);
|
::SelectObject(hDcPaint, hOldFont);
|
||||||
@ -478,9 +406,9 @@ TFontInfo* GlobalManager::GetFontInfo(HFONT hFont, HDC hDcPaint)
|
|||||||
|
|
||||||
bool GlobalManager::FindFont(HFONT hFont)
|
bool GlobalManager::FindFont(HFONT hFont)
|
||||||
{
|
{
|
||||||
for( auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++ ) {
|
for (auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++) {
|
||||||
auto pFontInfo = it->second;
|
auto pFontInfo = it->second;
|
||||||
if( pFontInfo->hFont == hFont )
|
if (pFontInfo->hFont == hFont)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -490,8 +418,8 @@ bool GlobalManager::FindFont(const std::wstring& strFontName, int nSize, bool bB
|
|||||||
{
|
{
|
||||||
for (auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++) {
|
for (auto it = m_mCustomFonts.begin(); it != m_mCustomFonts.end(); it++) {
|
||||||
auto pFontInfo = it->second;
|
auto pFontInfo = it->second;
|
||||||
if( pFontInfo->sFontName == strFontName && pFontInfo->iSize == nSize &&
|
if (pFontInfo->sFontName == strFontName && pFontInfo->iSize == nSize &&
|
||||||
pFontInfo->bBold == bBold && pFontInfo->bUnderline == bUnderline && pFontInfo->bItalic == bItalic)
|
pFontInfo->bBold == bBold && pFontInfo->bUnderline == bUnderline && pFontInfo->bItalic == bItalic)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -104,11 +104,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
static std::unique_ptr<IPath> CreatePath();
|
static std::unique_ptr<IPath> CreatePath();
|
||||||
|
|
||||||
static void MessageLoop();
|
|
||||||
static bool TranslateMessage(const LPMSG pMsg);
|
|
||||||
static void AddPreMessage(Window* pWindow);
|
|
||||||
static void RemovePreMessage(Window* pWindow);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 添加一个全局 class 属性
|
* @brief 添加一个全局 class 属性
|
||||||
* @param[in] strClassName 全局 class 名称
|
* @param[in] strClassName 全局 class 名称
|
||||||
|
@ -99,8 +99,6 @@ Window::~Window()
|
|||||||
// Reset other parts...
|
// Reset other parts...
|
||||||
if (m_hwndTooltip != NULL) ::DestroyWindow(m_hwndTooltip);
|
if (m_hwndTooltip != NULL) ::DestroyWindow(m_hwndTooltip);
|
||||||
if (m_hDcPaint != NULL) ::ReleaseDC(m_hWnd, m_hDcPaint);
|
if (m_hDcPaint != NULL) ::ReleaseDC(m_hWnd, m_hDcPaint);
|
||||||
|
|
||||||
GlobalManager::RemovePreMessage(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND Window::GetHWND() const
|
HWND Window::GetHWND() const
|
||||||
@ -241,33 +239,6 @@ void Window::ShowWindow(bool bShow /*= true*/, bool bTakeFocus /*= false*/)
|
|||||||
::ShowWindow(m_hWnd, bShow ? (bTakeFocus ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE) : SW_HIDE);
|
::ShowWindow(m_hWnd, bShow ? (bTakeFocus ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE) : SW_HIDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT Window::ShowModal()
|
|
||||||
{
|
|
||||||
ASSERT(::IsWindow(m_hWnd));
|
|
||||||
UINT nRet = 0;
|
|
||||||
HWND hWndParent = GetWindowOwner(m_hWnd);
|
|
||||||
::ShowWindow(m_hWnd, SW_SHOWNORMAL);
|
|
||||||
::EnableWindow(hWndParent, FALSE);
|
|
||||||
MSG msg = { 0 };
|
|
||||||
HWND hTempWnd = m_hWnd;
|
|
||||||
while( ::IsWindow(hTempWnd) && ::GetMessage(&msg, NULL, 0, 0) ) {
|
|
||||||
if( msg.message == WM_CLOSE && msg.hwnd == m_hWnd ) {
|
|
||||||
nRet = msg.wParam;
|
|
||||||
::EnableWindow(hWndParent, TRUE);
|
|
||||||
::SetFocus(hWndParent);
|
|
||||||
}
|
|
||||||
if( !GlobalManager::TranslateMessage(&msg) ) {
|
|
||||||
::TranslateMessage(&msg);
|
|
||||||
::DispatchMessage(&msg);
|
|
||||||
}
|
|
||||||
if( msg.message == WM_QUIT ) break;
|
|
||||||
}
|
|
||||||
::EnableWindow(hWndParent, TRUE);
|
|
||||||
::SetFocus(hWndParent);
|
|
||||||
if( msg.message == WM_QUIT ) ::PostQuitMessage(msg.wParam);
|
|
||||||
return nRet;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Window::ShowModalFake(HWND parent_hwnd)
|
void Window::ShowModalFake(HWND parent_hwnd)
|
||||||
{
|
{
|
||||||
ASSERT(::IsWindow(m_hWnd));
|
ASSERT(::IsWindow(m_hWnd));
|
||||||
@ -420,8 +391,6 @@ void Window::Init(HWND hWnd)
|
|||||||
ASSERT(::IsWindow(hWnd));
|
ASSERT(::IsWindow(hWnd));
|
||||||
// Remember the window context we came from
|
// Remember the window context we came from
|
||||||
m_hDcPaint = ::GetDC(hWnd);
|
m_hDcPaint = ::GetDC(hWnd);
|
||||||
// We'll want to filter messages globally too
|
|
||||||
GlobalManager::AddPreMessage(this);
|
|
||||||
m_renderContext = GlobalManager::CreateRenderContext();
|
m_renderContext = GlobalManager::CreateRenderContext();
|
||||||
|
|
||||||
RegisterTouchWindowWrapper(hWnd, 0);
|
RegisterTouchWindowWrapper(hWnd, 0);
|
||||||
@ -840,24 +809,6 @@ void Window::SetInitSize(int cx, int cy, bool bContainShadow, bool bNeedDpiScale
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Window::AddPreMessageFilter(IUIMessageFilter* pFilter)
|
|
||||||
{
|
|
||||||
ASSERT(std::find(m_aPreMessageFilters.begin(), m_aPreMessageFilters.end(), pFilter) == m_aPreMessageFilters.end());
|
|
||||||
m_aPreMessageFilters.push_back(pFilter);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Window::RemovePreMessageFilter(IUIMessageFilter* pFilter)
|
|
||||||
{
|
|
||||||
for (auto it = m_aPreMessageFilters.begin(); it != m_aPreMessageFilters.end(); it++) {
|
|
||||||
if (*it == pFilter) {
|
|
||||||
m_aPreMessageFilters.erase(it);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Window::AddMessageFilter(IUIMessageFilter* pFilter)
|
bool Window::AddMessageFilter(IUIMessageFilter* pFilter)
|
||||||
{
|
{
|
||||||
ASSERT(std::find(m_aMessageFilters.begin(), m_aMessageFilters.end(), pFilter) == m_aMessageFilters.end());
|
ASSERT(std::find(m_aMessageFilters.begin(), m_aMessageFilters.end(), pFilter) == m_aMessageFilters.end());
|
||||||
@ -920,28 +871,6 @@ bool Window::TranslateAccelerator(LPMSG pMsg)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Window::PreMessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& /*lRes*/)
|
|
||||||
{
|
|
||||||
for (auto it = m_aPreMessageFilters.begin(); it != m_aPreMessageFilters.end(); it++)
|
|
||||||
{
|
|
||||||
BOOL bHandled = false;
|
|
||||||
(*it)->MessageHandler(uMsg, wParam, lParam, bHandled);
|
|
||||||
if( bHandled ) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch( uMsg ) {
|
|
||||||
case WM_SYSKEYDOWN:
|
|
||||||
{
|
|
||||||
if( m_pFocus != NULL ) {
|
|
||||||
m_pFocus->HandleMessageTemplate(kEventSystemKey, 0, 0, wParam);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LRESULT Window::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
LRESULT Window::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
bool handled = false;
|
bool handled = false;
|
||||||
@ -1433,6 +1362,15 @@ LRESULT Window::DoHandlMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& ha
|
|||||||
{
|
{
|
||||||
if (m_pFocus == NULL) break;
|
if (m_pFocus == NULL) break;
|
||||||
|
|
||||||
|
// Tabbing between controls
|
||||||
|
if (wParam == VK_TAB) {
|
||||||
|
if (m_pFocus && m_pFocus->IsVisible() && m_pFocus->IsEnabled() && dynamic_cast<RichEdit*>(m_pFocus) != nullptr) {
|
||||||
|
if (dynamic_cast<RichEdit*>(m_pFocus)->IsWantTab()) return false;
|
||||||
|
}
|
||||||
|
SetNextTabControl(::GetKeyState(VK_SHIFT) >= 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
m_pEventKey = m_pFocus;
|
m_pEventKey = m_pFocus;
|
||||||
m_pFocus->HandleMessageTemplate(kEventKeyDown, wParam, lParam, wParam);
|
m_pFocus->HandleMessageTemplate(kEventKeyDown, wParam, lParam, wParam);
|
||||||
}
|
}
|
||||||
@ -1459,8 +1397,6 @@ LRESULT Window::DoHandlMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& ha
|
|||||||
m_ptLastMousePos = pt;
|
m_ptLastMousePos = pt;
|
||||||
Control* pControl = FindControl(pt);
|
Control* pControl = FindControl(pt);
|
||||||
if (pControl == NULL) break;
|
if (pControl == NULL) break;
|
||||||
//if( (pControl->GetControlFlags() & UIFLAG_SETCURSOR) == 0 ) break;
|
|
||||||
|
|
||||||
pControl->HandleMessageTemplate(kEventSetCursor, wParam, lParam, 0, pt);
|
pControl->HandleMessageTemplate(kEventSetCursor, wParam, lParam, 0, pt);
|
||||||
}
|
}
|
||||||
handled = true;
|
handled = true;
|
||||||
@ -1571,7 +1507,7 @@ void Window::SetFocusNeeded(Control* pControl)
|
|||||||
FINDTABINFO info = { 0 };
|
FINDTABINFO info = { 0 };
|
||||||
info.pFocus = pControl;
|
info.pFocus = pControl;
|
||||||
info.bForward = false;
|
info.bForward = false;
|
||||||
m_pFocus = nullptr; //m_pRoot->FindControl(__FindControlFromTab, &info, UIFIND_VISIBLE | UIFIND_ENABLED | UIFIND_ME_FIRST);
|
m_pFocus = m_pRoot->FindControl(__FindControlFromTab, &info, UIFIND_VISIBLE | UIFIND_ENABLED | UIFIND_ME_FIRST);
|
||||||
m_bFocusNeeded = true;
|
m_bFocusNeeded = true;
|
||||||
if (m_pRoot != NULL) m_pRoot->Arrange();
|
if (m_pRoot != NULL) m_pRoot->Arrange();
|
||||||
}
|
}
|
||||||
@ -1623,36 +1559,36 @@ HWND Window::GetTooltipWindow() const
|
|||||||
return m_hwndTooltip;
|
return m_hwndTooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
//bool Window::SetNextTabControl(bool bForward)
|
bool Window::SetNextTabControl(bool bForward)
|
||||||
//{
|
{
|
||||||
// // If we're in the process of restructuring the layout we can delay the
|
// If we're in the process of restructuring the layout we can delay the
|
||||||
// // focus calulation until the next repaint.
|
// focus calulation until the next repaint.
|
||||||
// if( m_bIsArranged && bForward ) {
|
if (m_bIsArranged && bForward) {
|
||||||
// m_bFocusNeeded = true;
|
m_bFocusNeeded = true;
|
||||||
// ::InvalidateRect(m_hWnd, NULL, FALSE);
|
::InvalidateRect(m_hWnd, NULL, FALSE);
|
||||||
// return true;
|
return true;
|
||||||
// }
|
}
|
||||||
// // Find next/previous tabbable control
|
// Find next/previous tabbable control
|
||||||
// FINDTABINFO info1 = { 0 };
|
FINDTABINFO info1 = { 0 };
|
||||||
// info1.pFocus = m_pFocus;
|
info1.pFocus = m_pFocus;
|
||||||
// info1.bForward = bForward;
|
info1.bForward = bForward;
|
||||||
// Control* pControl = m_pRoot->FindControl(__FindControlFromTab, &info1, UIFIND_VISIBLE | UIFIND_ENABLED | UIFIND_ME_FIRST);
|
Control* pControl = m_pRoot->FindControl(__FindControlFromTab, &info1, UIFIND_VISIBLE | UIFIND_ENABLED | UIFIND_ME_FIRST);
|
||||||
// if( pControl == NULL ) {
|
if (pControl == NULL) {
|
||||||
// if( bForward ) {
|
if (bForward) {
|
||||||
// // Wrap around
|
// Wrap around
|
||||||
// FINDTABINFO info2 = { 0 };
|
FINDTABINFO info2 = { 0 };
|
||||||
// info2.pFocus = bForward ? NULL : info1.pLast;
|
info2.pFocus = bForward ? NULL : info1.pLast;
|
||||||
// info2.bForward = bForward;
|
info2.bForward = bForward;
|
||||||
// pControl = m_pRoot->FindControl(__FindControlFromTab, &info2, UIFIND_VISIBLE | UIFIND_ENABLED | UIFIND_ME_FIRST);
|
pControl = m_pRoot->FindControl(__FindControlFromTab, &info2, UIFIND_VISIBLE | UIFIND_ENABLED | UIFIND_ME_FIRST);
|
||||||
// }
|
}
|
||||||
// else {
|
else {
|
||||||
// pControl = info1.pLast;
|
pControl = info1.pLast;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// if( pControl != NULL ) SetFocus(pControl);
|
if (pControl != NULL) SetFocus(pControl);
|
||||||
// m_bFocusNeeded = false;
|
m_bFocusNeeded = false;
|
||||||
// return true;
|
return true;
|
||||||
//}
|
}
|
||||||
|
|
||||||
Control* Window::GetRoot() const
|
Control* Window::GetRoot() const
|
||||||
{
|
{
|
||||||
@ -2038,19 +1974,19 @@ Control* CALLBACK Window::__FindControlFromPoint(Control* pThis, LPVOID pData)
|
|||||||
return ::PtInRect(&pos, *pPoint) ? pThis : NULL;
|
return ::PtInRect(&pos, *pPoint) ? pThis : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Control* CALLBACK Window::__FindControlFromTab(Control* pThis, LPVOID pData)
|
Control* CALLBACK Window::__FindControlFromTab(Control* pThis, LPVOID pData)
|
||||||
//{
|
{
|
||||||
// FINDTABINFO* pInfo = static_cast<FINDTABINFO*>(pData);
|
FINDTABINFO* pInfo = static_cast<FINDTABINFO*>(pData);
|
||||||
// if( pInfo->pFocus == pThis ) {
|
if (pInfo->pFocus == pThis) {
|
||||||
// if( pInfo->bForward ) pInfo->bNextIsIt = true;
|
if (pInfo->bForward) pInfo->bNextIsIt = true;
|
||||||
// return pInfo->bForward ? NULL : pInfo->pLast;
|
return pInfo->bForward ? NULL : pInfo->pLast;
|
||||||
// }
|
}
|
||||||
// if( (pThis->GetControlFlags() & UIFLAG_TABSTOP) == 0 ) return NULL;
|
if ((pThis->GetControlFlags() & UIFLAG_TABSTOP) == 0) return NULL;
|
||||||
// pInfo->pLast = pThis;
|
pInfo->pLast = pThis;
|
||||||
// if( pInfo->bNextIsIt ) return pThis;
|
if (pInfo->bNextIsIt) return pThis;
|
||||||
// if( pInfo->pFocus == NULL ) return pThis;
|
if (pInfo->pFocus == NULL) return pThis;
|
||||||
// return NULL; // Examine all controls
|
return NULL; // Examine all controls
|
||||||
//}
|
}
|
||||||
|
|
||||||
//Control* CALLBACK Window::__FindControlFromShortcut(Control* pThis, LPVOID pData)
|
//Control* CALLBACK Window::__FindControlFromShortcut(Control* pThis, LPVOID pData)
|
||||||
//{
|
//{
|
||||||
|
@ -8,6 +8,10 @@ namespace ui
|
|||||||
|
|
||||||
class Box;
|
class Box;
|
||||||
|
|
||||||
|
// Flags for Control::GetControlFlags()
|
||||||
|
#define UIFLAG_DEFAULT 0x00000000 // 默认状态
|
||||||
|
#define UIFLAG_TABSTOP 0x00000001 // 标识控件是否在收到 TAB 切换焦点时允许设置焦点
|
||||||
|
|
||||||
// Flags for FindControl()
|
// Flags for FindControl()
|
||||||
#define UIFIND_ALL 0x00000000
|
#define UIFIND_ALL 0x00000000
|
||||||
#define UIFIND_VISIBLE 0x00000001
|
#define UIFIND_VISIBLE 0x00000001
|
||||||
@ -16,14 +20,6 @@ class Box;
|
|||||||
#define UIFIND_TOP_FIRST 0x00000008
|
#define UIFIND_TOP_FIRST 0x00000008
|
||||||
#define UIFIND_ME_FIRST 0x80000000
|
#define UIFIND_ME_FIRST 0x80000000
|
||||||
|
|
||||||
// Flags for the CDialogLayout stretching
|
|
||||||
#define UISTRETCH_NEWGROUP 0x00000001
|
|
||||||
#define UISTRETCH_NEWLINE 0x00000002
|
|
||||||
#define UISTRETCH_MOVE_X 0x00000004
|
|
||||||
#define UISTRETCH_MOVE_Y 0x00000008
|
|
||||||
#define UISTRETCH_SIZE_X 0x00000010
|
|
||||||
#define UISTRETCH_SIZE_Y 0x00000020
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
@ -147,12 +143,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void ShowWindow(bool bShow = true, bool bTakeFocus = true);
|
virtual void ShowWindow(bool bShow = true, bool bTakeFocus = true);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 显示模态对话框(不推荐)
|
|
||||||
* @return 接收到的消息
|
|
||||||
*/
|
|
||||||
UINT ShowModal();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 显示模态对话框(推荐)
|
* @brief 显示模态对话框(推荐)
|
||||||
* @param[in] parent_hwnd 父窗口句柄
|
* @param[in] parent_hwnd 父窗口句柄
|
||||||
@ -537,21 +527,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
void SetInitSize(int cx, int cy, bool bContainShadow = false, bool bNeedDpiScale = true);
|
void SetInitSize(int cx, int cy, bool bContainShadow = false, bool bNeedDpiScale = true);
|
||||||
|
|
||||||
/// 窗口内部消息处理
|
|
||||||
/**
|
|
||||||
* @brief 添加一个消息被派发到窗口前的消息过滤器
|
|
||||||
* @param[in] pFilter 一个继承了 IUIMessageFilter 的对象实例,需要实现 MessageHandler 方法
|
|
||||||
* @return 始终返回 true
|
|
||||||
*/
|
|
||||||
bool AddPreMessageFilter(IUIMessageFilter* pFilter);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 移除一个消息被派发到窗口前的消息过滤器
|
|
||||||
* @param[in] pFilter 一个继承了 IUIMessageFilter 的对象实例
|
|
||||||
* @return 返回 true 表示移除成功,否则可能该过滤器不存在
|
|
||||||
*/
|
|
||||||
bool RemovePreMessageFilter(IUIMessageFilter* pFilter);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 添加一个消息过滤器,此时消息已经派发
|
* @brief 添加一个消息过滤器,此时消息已经派发
|
||||||
* @param[in] pFilter 一个继承了 IUIMessageFilter 的对象实例,需要实现 MessageHandler 方法
|
* @param[in] pFilter 一个继承了 IUIMessageFilter 的对象实例,需要实现 MessageHandler 方法
|
||||||
@ -601,16 +576,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool TranslateAccelerator(LPMSG pMsg);
|
bool TranslateAccelerator(LPMSG pMsg);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief 执行派发消前的过滤器
|
|
||||||
* @param[in] uMsg 消息体
|
|
||||||
* @param[in] wParam 消息附加参数
|
|
||||||
* @param[in] lParam 消息附加参数
|
|
||||||
* @param[in] lRes 处理结果
|
|
||||||
* @return 返回 true 则继续派发该消息,否则不再派发该消息
|
|
||||||
*/
|
|
||||||
bool PreMessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 窗口消息的派发函数
|
* @brief 窗口消息的派发函数
|
||||||
* @param[in] uMsg 消息体
|
* @param[in] uMsg 消息体
|
||||||
@ -726,7 +691,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
HWND GetTooltipWindow() const;
|
HWND GetTooltipWindow() const;
|
||||||
|
|
||||||
//bool SetNextTabControl(bool bForward = true);
|
/**
|
||||||
|
* @brief 切换控件焦点到下一个(或上一个)控件
|
||||||
|
* @param[in] bForward true 为上一个控件,否则为 false,默认为 true
|
||||||
|
* @return 始终返回 true,暂无参考意义
|
||||||
|
*/
|
||||||
|
bool SetNextTabControl(bool bForward = true);
|
||||||
|
|
||||||
/// 控件相关
|
/// 控件相关
|
||||||
/**
|
/**
|
||||||
@ -877,7 +847,7 @@ private:
|
|||||||
static Control* CALLBACK __FindControlFromNameHash(Control* pThis, LPVOID pData);
|
static Control* CALLBACK __FindControlFromNameHash(Control* pThis, LPVOID pData);
|
||||||
static Control* CALLBACK __FindControlFromCount(Control* pThis, LPVOID pData);
|
static Control* CALLBACK __FindControlFromCount(Control* pThis, LPVOID pData);
|
||||||
static Control* CALLBACK __FindControlFromPoint(Control* pThis, LPVOID pData);
|
static Control* CALLBACK __FindControlFromPoint(Control* pThis, LPVOID pData);
|
||||||
//static Control* CALLBACK __FindControlFromTab(Control* pThis, LPVOID pData);
|
static Control* CALLBACK __FindControlFromTab(Control* pThis, LPVOID pData);
|
||||||
//static Control* CALLBACK __FindControlFromShortcut(Control* pThis, LPVOID pData);
|
//static Control* CALLBACK __FindControlFromShortcut(Control* pThis, LPVOID pData);
|
||||||
static Control* CALLBACK __FindControlFromUpdate(Control* pThis, LPVOID pData);
|
static Control* CALLBACK __FindControlFromUpdate(Control* pThis, LPVOID pData);
|
||||||
static Control* CALLBACK __FindControlFromName(Control* pThis, LPVOID pData);
|
static Control* CALLBACK __FindControlFromName(Control* pThis, LPVOID pData);
|
||||||
|
@ -17,7 +17,6 @@ WindowImplBase::~WindowImplBase()
|
|||||||
void WindowImplBase::OnFinalMessage( HWND hWnd )
|
void WindowImplBase::OnFinalMessage( HWND hWnd )
|
||||||
{
|
{
|
||||||
__super::OnFinalMessage(hWnd);
|
__super::OnFinalMessage(hWnd);
|
||||||
RemovePreMessageFilter(this);
|
|
||||||
ReapObjects(GetRoot());
|
ReapObjects(GetRoot());
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
@ -289,7 +288,6 @@ LRESULT WindowImplBase::OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&
|
|||||||
::SetWindowLong(this->GetHWND(), GWL_STYLE, GetStyle());
|
::SetWindowLong(this->GetHWND(), GWL_STYLE, GetStyle());
|
||||||
|
|
||||||
Init(m_hWnd);
|
Init(m_hWnd);
|
||||||
AddPreMessageFilter(this);
|
|
||||||
SetWindowResourcePath(GetSkinFolder());
|
SetWindowResourcePath(GetSkinFolder());
|
||||||
|
|
||||||
WindowBuilder builder;
|
WindowBuilder builder;
|
||||||
|
Loading…
Reference in New Issue
Block a user