2035 lines
54 KiB
C++
2035 lines
54 KiB
C++
#include "StdAfx.h"
|
||
#include <shlwapi.h>
|
||
|
||
namespace ui
|
||
{
|
||
|
||
typedef struct tagFINDTABINFO
|
||
{
|
||
Control* pFocus;
|
||
Control* pLast;
|
||
bool bForward;
|
||
bool bNextIsIt;
|
||
} FINDTABINFO;
|
||
|
||
typedef struct tagFINDSHORTCUT
|
||
{
|
||
TCHAR ch;
|
||
bool bPickNext;
|
||
} FINDSHORTCUT;
|
||
|
||
|
||
//////////////////////////////////////////////////////////////////////////
|
||
///
|
||
Window::Window() :
|
||
m_hWnd(nullptr),
|
||
m_pRoot(nullptr),
|
||
OnEvent(),
|
||
m_OldWndProc(::DefWindowProc),
|
||
m_bSubclassed(false),
|
||
m_nAlpha(255),
|
||
m_renderOffset(),
|
||
m_hDcPaint(nullptr),
|
||
m_hwndTooltip(nullptr),
|
||
m_ToolTip(),
|
||
m_pFocus(nullptr),
|
||
m_pNewHover(nullptr),
|
||
m_pEventHover(nullptr),
|
||
m_pEventClick(nullptr),
|
||
m_pEventKey(nullptr),
|
||
m_ptLastMousePos(-1, -1),
|
||
m_pEventTouch(nullptr),
|
||
m_ptLastTouchPos(-1, -1),
|
||
m_pEventPointer(nullptr),
|
||
m_bHandlePointer(true),
|
||
m_szMinWindow(),
|
||
m_szMaxWindow(),
|
||
m_szInitWindowSize(),
|
||
m_rcMaximizeInfo(0, 0, 0, 0),
|
||
m_rcSizeBox(),
|
||
m_rcAlphaFix(0, 0, 0, 0),
|
||
m_szRoundCorner(),
|
||
m_rcCaption(),
|
||
m_uTimerID(0x1000),
|
||
m_bFirstLayout(true),
|
||
m_bIsArranged(false),
|
||
m_bFocusNeeded(false),
|
||
m_bMouseTracking(false),
|
||
m_bMouseCapture(false),
|
||
m_bIsLayeredWindow(true),
|
||
m_aPreMessageFilters(),
|
||
m_aMessageFilters(),
|
||
m_aDelayedCleanup(),
|
||
m_aFoundControls(),
|
||
m_mNameHash(),
|
||
m_mOptionGroup(),
|
||
m_defaultFontInfo(),
|
||
m_defaultAttrHash(),
|
||
m_strWindowResourcePath(),
|
||
m_aTranslateAccelerator(),
|
||
m_heightPercent(0),
|
||
m_closeFlag()
|
||
{
|
||
LOGFONT lf = { 0 };
|
||
::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lf);
|
||
lf.lfCharSet = DEFAULT_CHARSET;
|
||
if (GlobalManager::GetDefaultFontName().length() > 0)
|
||
_tcscpy_s(lf.lfFaceName, LF_FACESIZE, GlobalManager::GetDefaultFontName().c_str());
|
||
|
||
HFONT hDefaultFont = ::CreateFontIndirect(&lf);
|
||
m_defaultFontInfo.hFont = hDefaultFont;
|
||
m_defaultFontInfo.sFontName = lf.lfFaceName;
|
||
m_defaultFontInfo.iSize = -lf.lfHeight;
|
||
m_defaultFontInfo.bBold = (lf.lfWeight >= FW_BOLD);
|
||
m_defaultFontInfo.bUnderline = (lf.lfUnderline == TRUE);
|
||
m_defaultFontInfo.bItalic = (lf.lfItalic == TRUE);
|
||
::ZeroMemory(&m_defaultFontInfo.tm, sizeof(m_defaultFontInfo.tm));
|
||
}
|
||
|
||
Window::~Window()
|
||
{
|
||
// Delete the control-tree structures
|
||
for (auto it = m_aDelayedCleanup.begin(); it != m_aDelayedCleanup.end(); it++) delete *it;
|
||
|
||
delete m_pRoot;
|
||
::DeleteObject(m_defaultFontInfo.hFont);
|
||
RemoveAllClass();
|
||
RemoveAllOptionGroups();
|
||
|
||
// Reset other parts...
|
||
if (m_hwndTooltip != NULL) ::DestroyWindow(m_hwndTooltip);
|
||
if (m_hDcPaint != NULL) ::ReleaseDC(m_hWnd, m_hDcPaint);
|
||
}
|
||
|
||
HWND Window::GetHWND() const
|
||
{
|
||
return m_hWnd;
|
||
}
|
||
|
||
bool Window::RegisterWindowClass()
|
||
{
|
||
WNDCLASS wc = { 0 };
|
||
wc.style = GetClassStyle();
|
||
wc.cbClsExtra = 0;
|
||
wc.cbWndExtra = 0;
|
||
wc.hIcon = NULL;
|
||
wc.lpfnWndProc = Window::__WndProc;
|
||
wc.hInstance = ::GetModuleHandle(NULL);
|
||
wc.hCursor = ::LoadCursor(NULL, IDC_ARROW);
|
||
wc.hbrBackground = NULL;
|
||
wc.lpszMenuName = NULL;
|
||
std::wstring className = GetWindowClassName();
|
||
wc.lpszClassName = className.c_str();
|
||
ATOM ret = ::RegisterClass(&wc);
|
||
ASSERT(ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS);
|
||
return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
|
||
}
|
||
|
||
bool Window::RegisterSuperClass()
|
||
{
|
||
// Get the class information from an existing
|
||
// window so we can subclass it later on...
|
||
WNDCLASSEX wc = { 0 };
|
||
wc.cbSize = sizeof(WNDCLASSEX);
|
||
std::wstring superClassName = GetSuperClassName();
|
||
if (!::GetClassInfoEx(NULL, superClassName.c_str(), &wc)) {
|
||
if (!::GetClassInfoEx(::GetModuleHandle(NULL), superClassName.c_str(), &wc)) {
|
||
ASSERT(!"Unable to locate window class");
|
||
return false;
|
||
}
|
||
}
|
||
m_OldWndProc = wc.lpfnWndProc;
|
||
wc.lpfnWndProc = Window::__ControlProc;
|
||
wc.hInstance = ::GetModuleHandle(NULL);
|
||
std::wstring className = GetWindowClassName();
|
||
wc.lpszClassName = className.c_str();
|
||
ATOM ret = ::RegisterClassEx(&wc);
|
||
ASSERT(ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS);
|
||
return ret != NULL || ::GetLastError() == ERROR_CLASS_ALREADY_EXISTS;
|
||
}
|
||
|
||
std::wstring Window::GetWindowClassName() const
|
||
{
|
||
ASSERT(FALSE);
|
||
return L"";
|
||
}
|
||
|
||
std::wstring Window::GetSuperClassName() const
|
||
{
|
||
return std::wstring();
|
||
}
|
||
|
||
UINT Window::GetClassStyle() const
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
HWND Window::Subclass(HWND hWnd)
|
||
{
|
||
ASSERT(::IsWindow(hWnd));
|
||
ASSERT(m_hWnd == NULL);
|
||
m_OldWndProc = SubclassWindow(hWnd, __WndProc);
|
||
if (m_OldWndProc == NULL) return NULL;
|
||
m_bSubclassed = true;
|
||
m_hWnd = hWnd;
|
||
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(this));
|
||
return m_hWnd;
|
||
}
|
||
|
||
void Window::Unsubclass()
|
||
{
|
||
ASSERT(::IsWindow(m_hWnd));
|
||
if (!::IsWindow(m_hWnd)) return;
|
||
if (!m_bSubclassed) return;
|
||
SubclassWindow(m_hWnd, m_OldWndProc);
|
||
m_OldWndProc = ::DefWindowProc;
|
||
m_bSubclassed = false;
|
||
}
|
||
|
||
HWND Window::Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, bool isLayeredWindow, const UiRect& rc)
|
||
{
|
||
if( !GetSuperClassName().empty() && !RegisterSuperClass() ) return NULL;
|
||
if( GetSuperClassName().empty() && !RegisterWindowClass() ) return NULL;
|
||
std::wstring className = GetWindowClassName();
|
||
m_bIsLayeredWindow = isLayeredWindow;
|
||
if (m_bIsLayeredWindow) {
|
||
dwExStyle |= WS_EX_LAYERED;
|
||
}
|
||
|
||
m_hWnd = ::CreateWindowEx(dwExStyle, className.c_str(), pstrName, dwStyle,
|
||
rc.left, rc.top, rc.GetWidth(), rc.GetHeight(), hwndParent, NULL, ::GetModuleHandle(NULL), this);
|
||
LONG nWindowLong = GetWindowLong( m_hWnd, GWL_STYLE );
|
||
if( nWindowLong & WS_CAPTION ) {
|
||
SetWindowLong( m_hWnd, GWL_STYLE, nWindowLong & ~WS_CAPTION );
|
||
}
|
||
|
||
ASSERT(m_hWnd!=NULL);
|
||
return m_hWnd;
|
||
}
|
||
|
||
void Window::Close(UINT nRet)
|
||
{
|
||
if (m_bFakeModal)
|
||
{
|
||
auto parent_hwnd = GetWindowOwner(m_hWnd);
|
||
ASSERT(::IsWindow(parent_hwnd));
|
||
::EnableWindow(parent_hwnd, TRUE);
|
||
::SetFocus(parent_hwnd);
|
||
m_bFakeModal = false;
|
||
}
|
||
ASSERT(::IsWindow(m_hWnd));
|
||
if (!::IsWindow(m_hWnd)) return;
|
||
|
||
if (m_pRoot && IsWindowsVistaOrGreater()) {
|
||
m_pRoot->SetVisible(false);
|
||
auto closeCallback = [this, nRet]() {
|
||
this->PostMessage(WM_CLOSE, (WPARAM)nRet, 0L);
|
||
};
|
||
TimerManager::GetInstance()->AddCancelableTimer(m_closeFlag.GetWeakFlag(), closeCallback, 300, 1);
|
||
}
|
||
else {
|
||
PostMessage(WM_CLOSE, (WPARAM)nRet, 0L);
|
||
}
|
||
}
|
||
|
||
void Window::ShowWindow(bool bShow /*= true*/, bool bTakeFocus /*= false*/)
|
||
{
|
||
ASSERT(::IsWindow(m_hWnd));
|
||
if( !::IsWindow(m_hWnd) ) return;
|
||
::ShowWindow(m_hWnd, bShow ? (bTakeFocus ? SW_SHOWNORMAL : SW_SHOWNOACTIVATE) : SW_HIDE);
|
||
}
|
||
|
||
void Window::ShowModalFake(HWND parent_hwnd)
|
||
{
|
||
ASSERT(::IsWindow(m_hWnd));
|
||
ASSERT(::IsWindow(parent_hwnd));
|
||
auto p_hwnd = GetWindowOwner(m_hWnd);
|
||
ASSERT(::IsWindow(p_hwnd));
|
||
ASSERT(p_hwnd == parent_hwnd);
|
||
::EnableWindow(parent_hwnd, FALSE);
|
||
ShowWindow();
|
||
m_bFakeModal = true;
|
||
}
|
||
|
||
void Window::CenterWindow()
|
||
{
|
||
ASSERT(::IsWindow(m_hWnd));
|
||
ASSERT((GetWindowStyle(m_hWnd)&WS_CHILD)==0);
|
||
UiRect rcDlg;
|
||
::GetWindowRect(m_hWnd, &rcDlg);
|
||
UiRect rcArea;
|
||
UiRect rcCenter;
|
||
HWND hWnd = GetHWND();
|
||
HWND hWndCenter = ::GetWindowOwner(m_hWnd);
|
||
if (hWndCenter!=NULL)
|
||
hWnd=hWndCenter;
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><CABE>ģʽ<C4A3><CABD><EFBFBD><EFBFBD>Ļ<EFBFBD><C4BB><EFBFBD><EFBFBD>
|
||
MONITORINFO oMonitor = {};
|
||
oMonitor.cbSize = sizeof(oMonitor);
|
||
::GetMonitorInfo(::MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST), &oMonitor);
|
||
rcArea = oMonitor.rcWork;
|
||
|
||
if( hWndCenter == NULL )
|
||
rcCenter = rcArea;
|
||
else if( ::IsIconic(hWndCenter) )
|
||
rcCenter = rcArea;
|
||
else
|
||
::GetWindowRect(hWndCenter, &rcCenter);
|
||
|
||
int DlgWidth = rcDlg.right - rcDlg.left;
|
||
int DlgHeight = rcDlg.bottom - rcDlg.top;
|
||
|
||
// Find dialog's upper left based on rcCenter
|
||
int xLeft = (rcCenter.left + rcCenter.right) / 2 - DlgWidth / 2;
|
||
int yTop = (rcCenter.top + rcCenter.bottom) / 2 - DlgHeight / 2;
|
||
|
||
// The dialog is outside the screen, move it inside
|
||
if( xLeft < rcArea.left ) xLeft = rcArea.left;
|
||
else if( xLeft + DlgWidth > rcArea.right ) xLeft = rcArea.right - DlgWidth;
|
||
if( yTop < rcArea.top ) yTop = rcArea.top;
|
||
else if( yTop + DlgHeight > rcArea.bottom ) yTop = rcArea.bottom - DlgHeight;
|
||
::SetWindowPos(m_hWnd, NULL, xLeft, yTop, -1, -1, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
|
||
}
|
||
|
||
void Window::SetIcon(UINT nRes)
|
||
{
|
||
HICON hIcon = (HICON)::LoadImage(::GetModuleHandle(NULL), MAKEINTRESOURCE(nRes), IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR | LR_SHARED);
|
||
ASSERT(hIcon);
|
||
::SendMessage(m_hWnd, WM_SETICON, (WPARAM) TRUE, (LPARAM) hIcon);
|
||
hIcon = (HICON)::LoadImage(::GetModuleHandle(NULL), MAKEINTRESOURCE(nRes), IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR | LR_SHARED);
|
||
ASSERT(hIcon);
|
||
::SendMessage(m_hWnd, WM_SETICON, (WPARAM) FALSE, (LPARAM) hIcon);
|
||
}
|
||
|
||
LRESULT Window::SendMessage(UINT uMsg, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
|
||
{
|
||
ASSERT(::IsWindow(m_hWnd));
|
||
return ::SendMessage(m_hWnd, uMsg, wParam, lParam);
|
||
}
|
||
|
||
LRESULT Window::PostMessage(UINT uMsg, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
|
||
{
|
||
ASSERT(::IsWindow(m_hWnd));
|
||
return ::PostMessage(m_hWnd, uMsg, wParam, lParam);
|
||
}
|
||
|
||
void Window::AttachWindowClose(const EventCallback& callback)
|
||
{
|
||
OnEvent[kEventWindowClose] += callback;
|
||
}
|
||
|
||
void Window::OnFinalMessage(HWND hWnd)
|
||
{
|
||
UnregisterTouchWindowWrapper(m_hWnd);
|
||
SendNotify(kEventWindowClose);
|
||
}
|
||
|
||
LRESULT CALLBACK Window::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
Window* pThis = NULL;
|
||
if( uMsg == WM_NCCREATE ) {
|
||
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
|
||
pThis = static_cast<Window*>(lpcs->lpCreateParams);
|
||
pThis->m_hWnd = hWnd;
|
||
::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(pThis));
|
||
}
|
||
else {
|
||
pThis = reinterpret_cast<Window*>(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
|
||
if( uMsg == WM_NCDESTROY && pThis != NULL ) {
|
||
LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
|
||
::SetWindowLongPtr(pThis->m_hWnd, GWLP_USERDATA, 0L);
|
||
if( pThis->m_bSubclassed ) pThis->Unsubclass();
|
||
pThis->OnFinalMessage(hWnd);
|
||
return lRes;
|
||
}
|
||
}
|
||
|
||
if( pThis != NULL) {
|
||
return pThis->HandleMessage(uMsg, wParam, lParam);
|
||
}
|
||
else {
|
||
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||
}
|
||
}
|
||
|
||
LRESULT CALLBACK Window::__ControlProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
Window* pThis = NULL;
|
||
if( uMsg == WM_NCCREATE ) {
|
||
LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
|
||
pThis = static_cast<Window*>(lpcs->lpCreateParams);
|
||
::SetProp(hWnd, _T("WndX"), (HANDLE) pThis);
|
||
pThis->m_hWnd = hWnd;
|
||
}
|
||
else {
|
||
pThis = reinterpret_cast<Window*>(::GetProp(hWnd, _T("WndX")));
|
||
if( uMsg == WM_NCDESTROY && pThis != NULL ) {
|
||
LRESULT lRes = ::CallWindowProc(pThis->m_OldWndProc, hWnd, uMsg, wParam, lParam);
|
||
if( pThis->m_bSubclassed ) pThis->Unsubclass();
|
||
::SetProp(hWnd, _T("WndX"), NULL);
|
||
pThis->m_hWnd = NULL;
|
||
pThis->OnFinalMessage(hWnd);
|
||
return lRes;
|
||
}
|
||
}
|
||
if( pThis != NULL ) {
|
||
return pThis->HandleMessage(uMsg, wParam, lParam);
|
||
}
|
||
else {
|
||
return ::DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||
}
|
||
}
|
||
|
||
/////////////////////////////////////////////////////////////////////////////////////
|
||
//
|
||
//
|
||
|
||
void Window::Init(HWND hWnd)
|
||
{
|
||
m_hWnd = hWnd;
|
||
ASSERT(::IsWindow(hWnd));
|
||
// Remember the window context we came from
|
||
m_hDcPaint = ::GetDC(hWnd);
|
||
m_renderContext = GlobalManager::CreateRenderContext();
|
||
|
||
RegisterTouchWindowWrapper(hWnd, 0);
|
||
}
|
||
|
||
bool Window::AttachDialog(Box* pRoot)
|
||
{
|
||
ASSERT(::IsWindow(m_hWnd));
|
||
// Reset any previous attachment
|
||
SetFocus(NULL);
|
||
m_pEventKey = NULL;
|
||
m_pNewHover = NULL;
|
||
m_pEventHover = NULL;
|
||
m_pEventClick = NULL;
|
||
m_pEventTouch = NULL;
|
||
m_pEventPointer = NULL;
|
||
// Remove the existing control-tree. We might have gotten inside this function as
|
||
// a result of an event fired or similar, so we cannot just delete the objects and
|
||
// pull the internal memory of the calling code. We'll delay the cleanup.
|
||
if (m_pRoot != NULL) {
|
||
AddDelayedCleanup(m_pRoot);
|
||
}
|
||
// Set the dialog root element
|
||
m_pRoot = pRoot;
|
||
// Go ahead...
|
||
m_bIsArranged = true;
|
||
m_bFirstLayout = true;
|
||
m_bFocusNeeded = true;
|
||
// Initiate all control
|
||
return InitControls(m_pRoot);
|
||
}
|
||
|
||
bool Window::InitControls(Control* pControl, Box* pParent /*= NULL*/)
|
||
{
|
||
ASSERT(pControl);
|
||
if (pControl == NULL) return false;
|
||
pControl->SetWindow(this, pParent != NULL ? pParent : pControl->GetParent(), true);
|
||
pControl->FindControl(__FindControlFromNameHash, this, UIFIND_ALL);
|
||
return true;
|
||
}
|
||
|
||
void Window::ReapObjects(Control* pControl)
|
||
{
|
||
if (!pControl) {
|
||
return;
|
||
}
|
||
if (pControl == m_pEventKey) m_pEventKey = NULL;
|
||
if (pControl == m_pEventHover) m_pEventHover = NULL;
|
||
if (pControl == m_pNewHover) m_pNewHover = NULL;
|
||
if (pControl == m_pEventClick) m_pEventClick = NULL;
|
||
if (pControl == m_pEventTouch) m_pEventTouch = NULL;
|
||
if (pControl == m_pEventPointer) m_pEventPointer = NULL;
|
||
if (pControl == m_pFocus) m_pFocus = NULL;
|
||
std::wstring sName = pControl->GetName();
|
||
if (!sName.empty()) {
|
||
auto it = m_mNameHash.find(sName);
|
||
if (it != m_mNameHash.end())
|
||
{
|
||
m_mNameHash.erase(it);
|
||
}
|
||
}
|
||
}
|
||
|
||
std::wstring Window::GetWindowResourcePath()
|
||
{
|
||
return m_strWindowResourcePath;
|
||
}
|
||
|
||
void Window::SetWindowResourcePath(const std::wstring& strPath)
|
||
{
|
||
m_strWindowResourcePath = strPath;
|
||
if (m_strWindowResourcePath.empty()) return;
|
||
TCHAR cEnd = m_strWindowResourcePath.at(m_strWindowResourcePath.length() - 1);
|
||
if (cEnd != _T('\\') && cEnd != _T('/')) m_strWindowResourcePath += _T('\\');
|
||
}
|
||
|
||
TFontInfo* Window::GetDefaultFontInfo()
|
||
{
|
||
if (m_defaultFontInfo.tm.tmHeight == 0) {
|
||
HFONT hOldFont = (HFONT) ::SelectObject(m_hDcPaint, m_defaultFontInfo.hFont);
|
||
::GetTextMetrics(m_hDcPaint, &m_defaultFontInfo.tm);
|
||
::SelectObject(m_hDcPaint, hOldFont);
|
||
}
|
||
return &m_defaultFontInfo;
|
||
}
|
||
|
||
void Window::AddClass(const std::wstring& strClassName, const std::wstring& strControlAttrList)
|
||
{
|
||
ASSERT(!strClassName.empty());
|
||
ASSERT(!strControlAttrList.empty());
|
||
m_defaultAttrHash[strClassName] = strControlAttrList;
|
||
}
|
||
|
||
const std::map<std::wstring, std::wstring>* Window::GetClassMap()
|
||
{
|
||
return &m_defaultAttrHash;
|
||
}
|
||
|
||
std::wstring Window::GetClassAttributes(const std::wstring& strClassName) const
|
||
{
|
||
auto it = m_defaultAttrHash.find(strClassName);
|
||
if (it != m_defaultAttrHash.end())
|
||
{
|
||
return it->second;
|
||
}
|
||
|
||
return L"";
|
||
}
|
||
|
||
bool Window::RemoveClass(const std::wstring& strClassName)
|
||
{
|
||
auto it = m_defaultAttrHash.find(strClassName);
|
||
if (it != m_defaultAttrHash.end())
|
||
{
|
||
m_defaultAttrHash.erase(it);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
void Window::RemoveAllClass()
|
||
{
|
||
m_defaultAttrHash.clear();
|
||
}
|
||
|
||
bool Window::AddOptionGroup(const std::wstring& strGroupName, Control* pControl)
|
||
{
|
||
auto it = m_mOptionGroup.find(strGroupName);
|
||
if (it != m_mOptionGroup.end()) {
|
||
auto it2 = std::find(it->second.begin(), it->second.end(), pControl);
|
||
if (it2 != it->second.end())
|
||
{
|
||
return false;
|
||
}
|
||
it->second.push_back(pControl);
|
||
}
|
||
else {
|
||
m_mOptionGroup[strGroupName].push_back(pControl);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
std::vector<Control*>* Window::GetOptionGroup(const std::wstring& strGroupName)
|
||
{
|
||
auto it = m_mOptionGroup.find(strGroupName);
|
||
if (it != m_mOptionGroup.end()) return &(it->second);
|
||
return NULL;
|
||
}
|
||
|
||
void Window::RemoveOptionGroup(const std::wstring& strGroupName, Control* pControl)
|
||
{
|
||
ASSERT(!strGroupName.empty());
|
||
ASSERT(pControl);
|
||
auto it = m_mOptionGroup.find(strGroupName);
|
||
if (it != m_mOptionGroup.end()) {
|
||
auto it2 = std::find(it->second.begin(), it->second.end(), pControl);
|
||
if (it2 != it->second.end())
|
||
{
|
||
it->second.erase(it2);
|
||
}
|
||
|
||
if (it->second.empty()) {
|
||
m_mOptionGroup.erase(it);
|
||
}
|
||
}
|
||
}
|
||
|
||
void Window::RemoveAllOptionGroups()
|
||
{
|
||
m_mOptionGroup.clear();
|
||
}
|
||
|
||
void Window::ClearImageCache()
|
||
{
|
||
Control *pRoot = m_shadow.GetRoot();
|
||
if (pRoot)
|
||
pRoot->ClearImageCache();
|
||
else
|
||
m_pRoot->ClearImageCache();
|
||
}
|
||
|
||
POINT Window::GetMousePos() const
|
||
{
|
||
return m_ptLastMousePos;
|
||
}
|
||
|
||
UiRect Window::GetSizeBox()
|
||
{
|
||
return m_rcSizeBox;
|
||
}
|
||
|
||
void Window::SetSizeBox(const UiRect& rcSizeBox)
|
||
{
|
||
m_rcSizeBox = rcSizeBox;
|
||
}
|
||
|
||
UiRect Window::GetCaptionRect() const
|
||
{
|
||
return m_rcCaption;
|
||
}
|
||
|
||
void Window::SetCaptionRect(UiRect& rcCaption)
|
||
{
|
||
DpiManager::GetInstance()->ScaleRect(rcCaption);
|
||
m_rcCaption = rcCaption;
|
||
}
|
||
|
||
CSize Window::GetRoundCorner() const
|
||
{
|
||
return m_szRoundCorner;
|
||
}
|
||
|
||
void Window::SetRoundCorner(int cx, int cy)
|
||
{
|
||
DpiManager::GetInstance()->ScaleInt(cx);
|
||
DpiManager::GetInstance()->ScaleInt(cy);
|
||
m_szRoundCorner.cx = cx;
|
||
m_szRoundCorner.cy = cy;
|
||
}
|
||
|
||
UiRect Window::GetMaximizeInfo() const
|
||
{
|
||
return m_rcMaximizeInfo;
|
||
}
|
||
|
||
void Window::SetMaximizeInfo(UiRect& rcMaximize)
|
||
{
|
||
DpiManager::GetInstance()->ScaleRect(rcMaximize);
|
||
m_rcMaximizeInfo = rcMaximize;
|
||
}
|
||
|
||
UiRect Window::GetAlphaFixCorner() const
|
||
{
|
||
return m_rcAlphaFix;
|
||
}
|
||
|
||
void Window::SetAlphaFixCorner(UiRect& rc)
|
||
{
|
||
DpiManager::GetInstance()->ScaleRect(rc);
|
||
m_rcAlphaFix = rc;
|
||
}
|
||
|
||
double Window::GetHeightPercent() const
|
||
{
|
||
return m_heightPercent;
|
||
}
|
||
|
||
void Window::SetHeightPercent(double heightPercent)
|
||
{
|
||
m_heightPercent = heightPercent;
|
||
}
|
||
|
||
void Window::SetTextId(const std::wstring& strTextId)
|
||
{
|
||
::SetWindowText(m_hWnd, MutiLanSupport::GetInstance()->GetStringViaID(strTextId).c_str());
|
||
}
|
||
|
||
void Window::SetShadowAttached(bool bShadowAttached)
|
||
{
|
||
m_shadow.SetShadowAttached(bShadowAttached);
|
||
}
|
||
|
||
std::wstring Window::GetShadowImage() const
|
||
{
|
||
return m_shadow.GetShadowImage();
|
||
}
|
||
|
||
void Window::SetShadowImage(const std::wstring &strImage)
|
||
{
|
||
m_shadow.SetShadowImage(strImage);
|
||
}
|
||
|
||
UiRect Window::GetShadowCorner() const
|
||
{
|
||
return m_shadow.GetShadowCorner();
|
||
}
|
||
|
||
void Window::SetShadowCorner(const UiRect rect)
|
||
{
|
||
m_shadow.SetShadowCorner(rect);
|
||
}
|
||
|
||
UiRect Window::GetPos(bool bContainShadow) const
|
||
{
|
||
UiRect rcPos;
|
||
::GetWindowRect(m_hWnd, &rcPos);
|
||
|
||
if (!bContainShadow) {
|
||
UiRect padding = m_shadow.GetShadowCorner();
|
||
rcPos.left += padding.left;
|
||
rcPos.right -= padding.right;
|
||
rcPos.top += padding.top;
|
||
rcPos.bottom -= padding.bottom;
|
||
}
|
||
return rcPos;
|
||
}
|
||
|
||
void Window::SetPos(const UiRect& rc, bool bNeedDpiScale, UINT uFlags, HWND hWndInsertAfter, bool bContainShadow)
|
||
{
|
||
UiRect rcNewPos = rc;
|
||
if (bNeedDpiScale)
|
||
DpiManager::GetInstance()->ScaleRect(rcNewPos);
|
||
|
||
ASSERT(::IsWindow(m_hWnd));
|
||
if (!bContainShadow) {
|
||
rcNewPos.Inflate(m_shadow.GetShadowCorner());
|
||
}
|
||
::SetWindowPos(m_hWnd, hWndInsertAfter, rcNewPos.left, rcNewPos.top, rcNewPos.GetWidth(), rcNewPos.GetHeight(), uFlags);
|
||
}
|
||
|
||
CSize Window::GetMinInfo(bool bContainShadow) const
|
||
{
|
||
CSize xy = m_szMinWindow;
|
||
if (!bContainShadow) {
|
||
UiRect rcShadow = m_shadow.GetShadowCorner();
|
||
if (xy.cx != 0) {
|
||
xy.cx -= rcShadow.left + rcShadow.right;
|
||
}
|
||
if (xy.cy != 0) {
|
||
xy.cy -= rcShadow.top + rcShadow.bottom;
|
||
}
|
||
}
|
||
|
||
return xy;
|
||
}
|
||
|
||
void Window::SetMinInfo(int cx, int cy, bool bContainShadow)
|
||
{
|
||
DpiManager::GetInstance()->ScaleInt(cx);
|
||
DpiManager::GetInstance()->ScaleInt(cy);
|
||
|
||
ASSERT(cx >= 0 && cy >= 0);
|
||
|
||
if (!bContainShadow) {
|
||
UiRect rcShadow = m_shadow.GetShadowCorner();
|
||
if (cx != 0) {
|
||
cx += rcShadow.left + rcShadow.right;
|
||
}
|
||
if (cy != 0) {
|
||
cy += rcShadow.top + rcShadow.bottom;
|
||
}
|
||
}
|
||
m_szMinWindow.cx = cx;
|
||
m_szMinWindow.cy = cy;
|
||
}
|
||
|
||
CSize Window::GetMaxInfo(bool bContainShadow) const
|
||
{
|
||
CSize xy = m_szMaxWindow;
|
||
if (!bContainShadow) {
|
||
UiRect rcShadow = m_shadow.GetShadowCorner();
|
||
if (xy.cx != 0) {
|
||
xy.cx -= rcShadow.left + rcShadow.right;
|
||
}
|
||
if (xy.cy != 0) {
|
||
xy.cy -= rcShadow.top + rcShadow.bottom;
|
||
}
|
||
}
|
||
|
||
return xy;
|
||
}
|
||
|
||
void Window::SetMaxInfo(int cx, int cy, bool bContainShadow)
|
||
{
|
||
DpiManager::GetInstance()->ScaleInt(cx);
|
||
DpiManager::GetInstance()->ScaleInt(cy);
|
||
|
||
ASSERT(cx >= 0 && cy >= 0);
|
||
|
||
if (!bContainShadow) {
|
||
UiRect rcShadow = m_shadow.GetShadowCorner();
|
||
if (cx != 0) {
|
||
cx += rcShadow.left + rcShadow.right;
|
||
}
|
||
if (cy != 0) {
|
||
cy += rcShadow.top + rcShadow.bottom;
|
||
}
|
||
}
|
||
m_szMaxWindow.cx = cx;
|
||
m_szMaxWindow.cy = cy;
|
||
}
|
||
|
||
CSize Window::GetInitSize(bool bContainShadow) const
|
||
{
|
||
CSize xy = m_szInitWindowSize;
|
||
if (!bContainShadow) {
|
||
UiRect rcShadow = m_shadow.GetShadowCorner();
|
||
if (xy.cx != 0) {
|
||
xy.cx -= rcShadow.left + rcShadow.right;
|
||
}
|
||
if (xy.cy != 0) {
|
||
xy.cy -= rcShadow.top + rcShadow.bottom;
|
||
}
|
||
}
|
||
|
||
return xy;
|
||
}
|
||
|
||
void Window::SetInitSize(int cx, int cy, bool bContainShadow, bool bNeedDpiScale)
|
||
{
|
||
if (bNeedDpiScale)
|
||
{
|
||
DpiManager::GetInstance()->ScaleInt(cy);
|
||
DpiManager::GetInstance()->ScaleInt(cx);
|
||
}
|
||
|
||
if (!bContainShadow) {
|
||
UiRect rcShadow = m_shadow.GetShadowCorner();
|
||
cx += rcShadow.left + rcShadow.right;
|
||
cy += rcShadow.top + rcShadow.bottom;
|
||
}
|
||
m_szInitWindowSize.cx = cx;
|
||
m_szInitWindowSize.cy = cy;
|
||
if( m_pRoot == NULL && m_hWnd != NULL ) {
|
||
::SetWindowPos(m_hWnd, NULL, 0, 0, m_szInitWindowSize.cx, m_szInitWindowSize.cy, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
|
||
}
|
||
}
|
||
|
||
bool Window::AddMessageFilter(IUIMessageFilter* pFilter)
|
||
{
|
||
ASSERT(std::find(m_aMessageFilters.begin(), m_aMessageFilters.end(), pFilter) == m_aMessageFilters.end());
|
||
m_aMessageFilters.push_back(pFilter);
|
||
return true;
|
||
}
|
||
bool Window::RemoveMessageFilter(IUIMessageFilter* pFilter)
|
||
{
|
||
for (auto it = m_aMessageFilters.begin(); it != m_aMessageFilters.end(); it++) {
|
||
if (*it == pFilter) {
|
||
m_aMessageFilters.erase(it);
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
bool Window::AddControlFromPointFinder(IControlFromPointFinder* pFinder)
|
||
{
|
||
ASSERT(std::find(m_aIControlFromPointFinder.begin(), m_aIControlFromPointFinder.end(), pFinder) == m_aIControlFromPointFinder.end());
|
||
m_aIControlFromPointFinder.emplace_back(pFinder);
|
||
return true;
|
||
}
|
||
bool Window::RemoveControlFromPointFinder(IControlFromPointFinder* pFinder)
|
||
{
|
||
auto it = std::find_if(m_aIControlFromPointFinder.begin(), m_aIControlFromPointFinder.end(), [&](IControlFromPointFinder* item) {
|
||
return pFinder == item;
|
||
});
|
||
if (it != m_aIControlFromPointFinder.end())
|
||
{
|
||
m_aIControlFromPointFinder.erase(it);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
bool Window::AddTranslateAccelerator(ITranslateAccelerator *pTranslateAccelerator)
|
||
{
|
||
ASSERT(std::find(m_aTranslateAccelerator.begin(), m_aTranslateAccelerator.end(), pTranslateAccelerator) == m_aTranslateAccelerator.end());
|
||
m_aTranslateAccelerator.push_back(pTranslateAccelerator);
|
||
return true;
|
||
}
|
||
|
||
bool Window::RemoveTranslateAccelerator(ITranslateAccelerator *pTranslateAccelerator)
|
||
{
|
||
for (auto it = m_aTranslateAccelerator.begin(); it != m_aTranslateAccelerator.end(); it++) {
|
||
if (*it == pTranslateAccelerator)
|
||
{
|
||
m_aTranslateAccelerator.erase(it);
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
bool Window::TranslateAccelerator(LPMSG pMsg)
|
||
{
|
||
for (auto it = m_aTranslateAccelerator.begin(); it != m_aTranslateAccelerator.end(); it++) {
|
||
LRESULT lResult = (*it)->TranslateAccelerator(pMsg);
|
||
if (lResult == S_OK) return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
LRESULT Window::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
bool handled = false;
|
||
LRESULT ret = DoHandlMessage(uMsg, wParam, lParam, handled);
|
||
if (handled) {
|
||
return ret;
|
||
}
|
||
else {
|
||
return CallWindowProc(uMsg, wParam, lParam);
|
||
}
|
||
}
|
||
|
||
LRESULT Window::DoHandlMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, bool& handled)
|
||
{
|
||
handled = false;
|
||
// Cycle through listeners
|
||
for (auto it = m_aMessageFilters.begin(); it != m_aMessageFilters.end(); it++)
|
||
{
|
||
BOOL bHandled = false;
|
||
LRESULT lResult = (*it)->MessageHandler(uMsg, wParam, lParam, bHandled);
|
||
if (bHandled && uMsg != WM_MOUSEMOVE) {
|
||
handled = true;
|
||
return lResult;
|
||
}
|
||
}
|
||
// Custom handling of events
|
||
switch (uMsg) {
|
||
case WM_APP + 1:
|
||
{
|
||
for (auto it = m_aDelayedCleanup.begin(); it != m_aDelayedCleanup.end(); it++) delete *it;
|
||
m_aDelayedCleanup.clear();
|
||
}
|
||
break;
|
||
case WM_CLOSE:
|
||
{
|
||
// Make sure all matching "closing" events are sent
|
||
if (m_pEventHover != NULL) {
|
||
m_pEventHover->HandleMessageTemplate(kEventMouseLeave);
|
||
}
|
||
if (m_pEventClick != NULL) {
|
||
m_pEventClick->HandleMessageTemplate(kEventMouseButtonUp);
|
||
}
|
||
if (m_pEventTouch != NULL) {
|
||
m_pEventTouch->HandleMessageTemplate(kEventMouseButtonUp);
|
||
}
|
||
if (m_pEventPointer != NULL) {
|
||
m_pEventPointer->HandleMessageTemplate(kEventMouseButtonUp);
|
||
}
|
||
SetFocus(NULL);
|
||
|
||
// Hmmph, the usual Windows tricks to avoid
|
||
// focus loss...
|
||
HWND hwndParent = GetWindowOwner(m_hWnd);
|
||
if (hwndParent != NULL) ::SetFocus(hwndParent);
|
||
}
|
||
break;
|
||
case WM_ERASEBKGND:
|
||
{
|
||
handled = true;
|
||
return 1;
|
||
}
|
||
case WM_PAINT:
|
||
{
|
||
Paint();
|
||
handled = true;
|
||
return 0;
|
||
|
||
}
|
||
// If any of the painting requested a resize again, we'll need
|
||
// to invalidate the entire window once more.
|
||
if (m_bIsArranged) {
|
||
::InvalidateRect(m_hWnd, NULL, FALSE);
|
||
}
|
||
handled = true;
|
||
return 0;
|
||
case WM_SIZE:
|
||
{
|
||
if (m_pFocus != NULL) {
|
||
m_pFocus->HandleMessageTemplate(kEventWindowSize);
|
||
}
|
||
if (m_pRoot != NULL) m_pRoot->Arrange();
|
||
|
||
if (wParam == SIZE_MAXIMIZED) {
|
||
m_shadow.MaximizedOrRestored(true);
|
||
}
|
||
else if (wParam == SIZE_RESTORED) {
|
||
m_shadow.MaximizedOrRestored(false);
|
||
}
|
||
}
|
||
handled = true;
|
||
return 0;
|
||
case WM_MOUSEHOVER:
|
||
{
|
||
m_bMouseTracking = false;
|
||
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||
Control* pHover = FindControl(pt);
|
||
if (pHover == NULL) break;
|
||
// Generate mouse hover event
|
||
if (m_pEventHover != NULL) {
|
||
m_pEventHover->HandleMessageTemplate(kEventMouseHover, 0, 0, 0, pt);
|
||
}
|
||
// Create tooltip information
|
||
std::wstring sToolTip = pHover->GetToolTipText();
|
||
//if( sToolTip.empty() ) {
|
||
// handled = true;
|
||
// return 0;
|
||
//}
|
||
::ZeroMemory(&m_ToolTip, sizeof(TOOLINFO));
|
||
m_ToolTip.cbSize = sizeof(TOOLINFO);
|
||
m_ToolTip.uFlags = TTF_IDISHWND;
|
||
m_ToolTip.hwnd = m_hWnd;
|
||
m_ToolTip.uId = (UINT_PTR)m_hWnd;
|
||
m_ToolTip.hinst = ::GetModuleHandle(NULL);
|
||
m_ToolTip.lpszText = const_cast<LPTSTR>((LPCTSTR)sToolTip.c_str());
|
||
m_ToolTip.rect = pHover->GetPos();
|
||
if (m_hwndTooltip == NULL) {
|
||
m_hwndTooltip = ::CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT,
|
||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hWnd, NULL, ::GetModuleHandle(NULL), NULL);
|
||
::SendMessage(m_hwndTooltip, TTM_ADDTOOL, 0, (LPARAM)&m_ToolTip);
|
||
}
|
||
::SendMessage(m_hwndTooltip, TTM_SETMAXTIPWIDTH, 0, pHover->GetToolTipWidth());
|
||
::SendMessage(m_hwndTooltip, TTM_SETTOOLINFO, 0, (LPARAM)&m_ToolTip);
|
||
::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&m_ToolTip);
|
||
}
|
||
handled = true;
|
||
return 0;
|
||
case WM_MOUSELEAVE:
|
||
{
|
||
if (m_hwndTooltip != NULL) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM)&m_ToolTip);
|
||
if (m_bMouseTracking) ::SendMessage(m_hWnd, WM_MOUSEMOVE, 0, (LPARAM)-1);
|
||
m_bMouseTracking = false;
|
||
}
|
||
break;
|
||
case WM_MOUSEMOVE:
|
||
{
|
||
if (m_pEventTouch != NULL || m_pEventPointer != NULL)
|
||
break;
|
||
|
||
// Start tracking this entire window again...
|
||
if (!m_bMouseTracking) {
|
||
TRACKMOUSEEVENT tme = { 0 };
|
||
tme.cbSize = sizeof(TRACKMOUSEEVENT);
|
||
tme.dwFlags = TME_HOVER | TME_LEAVE;
|
||
tme.hwndTrack = m_hWnd;
|
||
tme.dwHoverTime = m_hwndTooltip == NULL ? 400UL : (DWORD) ::SendMessage(m_hwndTooltip, TTM_GETDELAYTIME, TTDT_INITIAL, 0L);
|
||
_TrackMouseEvent(&tme);
|
||
m_bMouseTracking = true;
|
||
}
|
||
// Generate the appropriate mouse messages
|
||
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||
m_ptLastMousePos = pt;
|
||
|
||
if (!HandleMouseEnterLeave(pt, wParam, lParam)) break;
|
||
|
||
if (m_pEventClick != NULL) {
|
||
m_pEventClick->HandleMessageTemplate(kEventMouseMove, wParam, lParam, 0, pt);
|
||
}
|
||
else if (m_pNewHover != NULL) {
|
||
m_pNewHover->HandleMessageTemplate(kEventMouseMove, wParam, lParam, 0, pt);
|
||
}
|
||
}
|
||
break;
|
||
case WM_LBUTTONDOWN:
|
||
{
|
||
if (m_pEventTouch != NULL || m_pEventPointer != NULL)
|
||
break;
|
||
|
||
// We alway set focus back to our app (this helps
|
||
// when Win32 child windows are placed on the dialog
|
||
// and we need to remove them on focus change).
|
||
::SetFocus(m_hWnd);
|
||
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||
m_ptLastMousePos = pt;
|
||
Control* pControl = FindControl(pt);
|
||
if (pControl == NULL) break;
|
||
if (pControl->GetWindow() != this) break;
|
||
m_pEventClick = pControl;
|
||
pControl->SetFocus();
|
||
SetCapture();
|
||
|
||
pControl->HandleMessageTemplate(kEventMouseButtonDown, wParam, lParam, 0, pt);
|
||
}
|
||
break;
|
||
case WM_RBUTTONDOWN:
|
||
{
|
||
if (m_pEventTouch != NULL || m_pEventPointer != NULL)
|
||
break;
|
||
|
||
::SetFocus(m_hWnd);
|
||
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||
m_ptLastMousePos = pt;
|
||
Control* pControl = FindControl(pt);
|
||
if (pControl == NULL) break;
|
||
if (pControl->GetWindow() != this) break;
|
||
m_pEventClick = pControl;
|
||
pControl->SetFocus();
|
||
SetCapture();
|
||
|
||
pControl->HandleMessageTemplate(kEventMouseRightButtonDown, wParam, lParam, 0, pt);
|
||
}
|
||
break;
|
||
case WM_LBUTTONDBLCLK:
|
||
{
|
||
if (m_pEventTouch != NULL || m_pEventPointer != NULL)
|
||
break;
|
||
|
||
::SetFocus(m_hWnd);
|
||
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||
m_ptLastMousePos = pt;
|
||
Control* pControl = FindControl(pt);
|
||
if (pControl == NULL) break;
|
||
if (pControl->GetWindow() != this) break;
|
||
m_pEventClick = pControl;
|
||
SetCapture();
|
||
|
||
pControl->HandleMessageTemplate(kEventInternalDoubleClick, wParam, lParam, 0, pt);
|
||
}
|
||
break;
|
||
case WM_LBUTTONUP:
|
||
{
|
||
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||
m_ptLastMousePos = pt;
|
||
ReleaseCapture();
|
||
if (m_pEventClick == NULL) break;
|
||
|
||
m_pEventClick->HandleMessageTemplate(kEventMouseButtonUp, wParam, lParam, 0, pt);
|
||
m_pEventClick = NULL;
|
||
}
|
||
break;
|
||
case WM_RBUTTONUP:
|
||
{
|
||
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||
m_ptLastMousePos = pt;
|
||
ReleaseCapture();
|
||
if (m_pEventClick == NULL) break;
|
||
|
||
m_pEventClick->HandleMessageTemplate(kEventMouseRightButtonUp, wParam, lParam, 0, pt);
|
||
//m_pEventClick = NULL;
|
||
}
|
||
break;
|
||
case WM_IME_STARTCOMPOSITION:
|
||
{
|
||
if (m_pFocus == NULL) break;
|
||
m_pFocus->HandleMessageTemplate(kEventImeStartComposition, wParam, lParam, wParam);
|
||
}
|
||
break;
|
||
case WM_IME_ENDCOMPOSITION:
|
||
{
|
||
if (m_pFocus == NULL) break;
|
||
m_pFocus->HandleMessageTemplate(kEventImeEndComposition, wParam, lParam, wParam);
|
||
}
|
||
break;
|
||
case WM_MOUSEWHEEL:
|
||
{
|
||
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||
::ScreenToClient(m_hWnd, &pt);
|
||
m_ptLastMousePos = pt;
|
||
Control* pControl = FindControl(pt);
|
||
if (pControl == NULL) break;
|
||
if (pControl->GetWindow() != this) break;
|
||
int zDelta = (int)(short)HIWORD(wParam);
|
||
|
||
pControl->HandleMessageTemplate(kEventMouseScrollWheel, zDelta, lParam);
|
||
}
|
||
break;
|
||
case WM_TOUCH:
|
||
{
|
||
unsigned int nNumInputs = (int)wParam;
|
||
TOUCHINPUT* pInputs = new TOUCHINPUT[nNumInputs];
|
||
|
||
// ֻ<><D6BB><EFBFBD>ĵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
|
||
if (nNumInputs >= 1 && GetTouchInputInfoWrapper((HTOUCHINPUT)lParam, nNumInputs, pInputs, sizeof(TOUCHINPUT)))
|
||
{
|
||
if (pInputs[0].dwID != 0)
|
||
{
|
||
POINT pt;
|
||
pt.x = TOUCH_COORD_TO_PIXEL(pInputs[0].x);
|
||
pt.y = TOUCH_COORD_TO_PIXEL(pInputs[0].y);
|
||
ScreenToClient(m_hWnd, &pt);
|
||
|
||
if (pInputs[0].dwFlags & TOUCHEVENTF_DOWN)
|
||
{
|
||
if (m_pEventClick != NULL || m_pEventPointer != NULL)
|
||
break;
|
||
|
||
::SetFocus(m_hWnd);
|
||
m_ptLastTouchPos = pt;
|
||
Control *pControl = FindControl(pt);
|
||
if (pControl == NULL) break;
|
||
if (pControl->GetWindow() != this) break;
|
||
m_pEventTouch = pControl;
|
||
pControl->SetFocus();
|
||
SetCapture();
|
||
|
||
pControl->HandleMessageTemplate(kEventTouchDown, 0, lParam, 0, pt);
|
||
}
|
||
else if (pInputs[0].dwFlags & TOUCHEVENTF_MOVE)
|
||
{
|
||
if (m_pEventClick != NULL || m_pEventPointer != NULL)
|
||
break;
|
||
|
||
if (m_ptLastTouchPos.x == pt.x && m_ptLastTouchPos.y == pt.y)
|
||
break;
|
||
|
||
m_ptLastTouchPos = pt;
|
||
if (m_pEventTouch == NULL) break;
|
||
|
||
if (!HandleMouseEnterLeave(pt, wParam, lParam)) break;
|
||
|
||
m_pEventTouch->HandleMessageTemplate(kEventTouchMove, 0, 0, 0, pt);
|
||
}
|
||
else if (pInputs[0].dwFlags & TOUCHEVENTF_UP)
|
||
{
|
||
m_ptLastTouchPos = pt;
|
||
ReleaseCapture();
|
||
if (m_pEventTouch == NULL) break;
|
||
|
||
m_pEventTouch->HandleMessageTemplate(kEventTouchUp, 0, lParam, 0, pt);
|
||
m_pEventTouch = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
CloseTouchInputHandleWrapper((HTOUCHINPUT)lParam);
|
||
delete[] pInputs;
|
||
}
|
||
break;
|
||
case WM_POINTERDOWN:
|
||
case WM_POINTERUP:
|
||
case WM_POINTERUPDATE:
|
||
case WM_POINTERLEAVE:
|
||
case WM_POINTERCAPTURECHANGED:
|
||
{
|
||
if (!m_bHandlePointer) {
|
||
break;
|
||
}
|
||
|
||
// ֻ<><D6BB><EFBFBD>ĵ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if (!IS_POINTER_PRIMARY_WPARAM(wParam)) {
|
||
handled = true;
|
||
break;
|
||
}
|
||
|
||
UINT32 pointerId = GET_POINTERID_WPARAM(wParam);
|
||
POINTER_INPUT_TYPE type;
|
||
if (!GetPointerTypeWrapper(pointerId, &type)) {
|
||
return 0;
|
||
}
|
||
|
||
POINT pt = { 0 };
|
||
FLOAT pressure = 0.0f;
|
||
|
||
switch (type)
|
||
{
|
||
case PT_TOUCH:
|
||
POINTER_TOUCH_INFO touchInfo;
|
||
if (!GetPointerTouchInfoWrapper(pointerId, &touchInfo)) {
|
||
return 0;
|
||
}
|
||
|
||
pt = touchInfo.pointerInfo.ptPixelLocationRaw;
|
||
pressure = (float)touchInfo.pressure / 1024;
|
||
break;
|
||
case PT_PEN:
|
||
POINTER_PEN_INFO penInfo;
|
||
if (!GetPointerPenInfoWrapper(pointerId, &penInfo)) {
|
||
return 0;
|
||
}
|
||
|
||
pt = penInfo.pointerInfo.ptPixelLocationRaw;
|
||
pressure = (float)penInfo.pressure / 1024;
|
||
break;
|
||
default:
|
||
return 0;
|
||
break;
|
||
}
|
||
ScreenToClient(m_hWnd, &pt);
|
||
|
||
switch (uMsg)
|
||
{
|
||
case WM_POINTERDOWN:
|
||
{
|
||
if (m_pEventClick != NULL || m_pEventTouch != NULL) {
|
||
handled = true;
|
||
break;
|
||
}
|
||
|
||
::SetFocus(m_hWnd);
|
||
m_ptLastMousePos = pt;
|
||
Control *pControl = FindControl(pt);
|
||
if (pControl == NULL) break;
|
||
if (pControl->GetWindow() != this) break;
|
||
m_pEventPointer = pControl;
|
||
pControl->SetFocus();
|
||
SetCapture();
|
||
|
||
pControl->HandleMessageTemplate(kEventPointDown, 0, lParam, 0, pt, pressure);
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD>֧<EFBFBD>ִ<EFBFBD><D6B4><EFBFBD>WM_POINTERUPDATE<54><45>Ϣ<EFBFBD><CFA2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>handled<65><64><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>WM_BUTTON<4F><4E><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if (m_pEventPointer && m_pEventPointer->IsReceivePointerMsg()) {
|
||
handled = true;
|
||
}
|
||
}
|
||
break;
|
||
case WM_POINTERUPDATE:
|
||
if (m_pEventClick != NULL || m_pEventTouch != NULL) {
|
||
handled = true;
|
||
break;
|
||
}
|
||
|
||
m_ptLastMousePos = pt;
|
||
// <20><><EFBFBD><EFBFBD>û<EFBFBD>а<EFBFBD><D0B0>£<EFBFBD><C2A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>handled<65><64><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>ΪWM_BUTTON<4F><4E><EFBFBD><EFBFBD>Ϣ
|
||
if (m_pEventPointer == NULL) break;
|
||
|
||
if (!HandleMouseEnterLeave(pt, wParam, lParam)) break;
|
||
|
||
m_pEventPointer->HandleMessageTemplate(kEventPointMove, 0, 0, 0, pt, pressure);
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD>֧<EFBFBD>ִ<EFBFBD><D6B4><EFBFBD>WM_POINTERUPDATE<54><45>Ϣ<EFBFBD><CFA2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>handled<65><64><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>WM_MOUSEMOVE<56><45><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if (m_pEventPointer && m_pEventPointer->IsReceivePointerMsg()) {
|
||
handled = true;
|
||
}
|
||
break;
|
||
case WM_POINTERUP:
|
||
case WM_POINTERLEAVE:
|
||
case WM_POINTERCAPTURECHANGED:
|
||
m_ptLastMousePos = pt;
|
||
// <20><><EFBFBD><EFBFBD>û<EFBFBD>а<EFBFBD><D0B0>£<EFBFBD><C2A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>handled<65><64><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD><D7AA>ΪWM_BUTTON<4F><4E><EFBFBD><EFBFBD>Ϣ
|
||
ReleaseCapture();
|
||
if (m_pEventPointer == NULL) break;
|
||
|
||
m_pEventPointer->HandleMessageTemplate(kEventPointUp, 0, lParam, 0, pt, pressure);
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD>֧<EFBFBD>ִ<EFBFBD><D6B4><EFBFBD>WM_POINTERUPDATE<54><45>Ϣ<EFBFBD><CFA2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>handled<65><64><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>WM_BUTTON<4F><4E><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if (m_pEventPointer && m_pEventPointer->IsReceivePointerMsg()) {
|
||
handled = true;
|
||
}
|
||
m_pEventPointer = NULL;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
break;
|
||
case WM_SETFOCUS:
|
||
{
|
||
|
||
}
|
||
break;
|
||
case WM_KILLFOCUS:
|
||
{
|
||
Control *pControl = m_pEventClick ? m_pEventClick : NULL;
|
||
pControl = m_pEventTouch ? m_pEventTouch : pControl;
|
||
pControl = m_pEventPointer ? m_pEventPointer : pControl;
|
||
|
||
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||
m_ptLastMousePos = pt;
|
||
if (pControl == NULL || !pControl->IsNeedButtonUpWhenKillFocus()) break;
|
||
ReleaseCapture();
|
||
|
||
pControl->HandleMessageTemplate(kEventMouseButtonUp, wParam, lParam, 0, pt);
|
||
m_pEventClick = NULL;
|
||
m_pEventTouch = NULL;
|
||
m_pEventPointer = NULL;
|
||
}
|
||
break;
|
||
case WM_CONTEXTMENU:
|
||
{
|
||
POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
|
||
::ScreenToClient(m_hWnd, &pt);
|
||
m_ptLastMousePos = pt;
|
||
if (m_pEventClick == NULL) break;
|
||
ReleaseCapture();
|
||
|
||
m_pEventClick->HandleMessageTemplate(kEventInternalMenu, wParam, (LPARAM)m_pEventClick, 0, pt);
|
||
m_pEventClick = NULL;
|
||
}
|
||
break;
|
||
case WM_CHAR:
|
||
{
|
||
if (m_pFocus == NULL) break;
|
||
|
||
m_pFocus->HandleMessageTemplate(kEventChar, wParam, lParam, wParam);
|
||
}
|
||
break;
|
||
case WM_KEYDOWN:
|
||
{
|
||
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_pFocus->HandleMessageTemplate(kEventKeyDown, wParam, lParam, wParam);
|
||
}
|
||
break;
|
||
case WM_KEYUP:
|
||
{
|
||
if (m_pEventKey == NULL) break;
|
||
|
||
m_pEventKey->HandleMessageTemplate(kEventKeyUp, wParam, lParam, wParam);
|
||
m_pEventKey = NULL;
|
||
}
|
||
break;
|
||
case WM_SETCURSOR:
|
||
{
|
||
if (LOWORD(lParam) != HTCLIENT) break;
|
||
if (m_pEventClick != NULL || m_pEventTouch != NULL || m_pEventPointer != NULL) {
|
||
handled = true;
|
||
return 0;
|
||
}
|
||
|
||
POINT pt = { 0 };
|
||
::GetCursorPos(&pt);
|
||
::ScreenToClient(m_hWnd, &pt);
|
||
m_ptLastMousePos = pt;
|
||
Control* pControl = FindControl(pt);
|
||
if (pControl == NULL) break;
|
||
pControl->HandleMessageTemplate(kEventSetCursor, wParam, lParam, 0, pt);
|
||
}
|
||
handled = true;
|
||
return 0;
|
||
case WM_NOTIFY:
|
||
{
|
||
LPNMHDR lpNMHDR = (LPNMHDR)lParam;
|
||
if (lpNMHDR != NULL) return ::SendMessage(lpNMHDR->hwndFrom, OCM__BASE + uMsg, wParam, lParam);
|
||
handled = true;
|
||
return 0;
|
||
}
|
||
break;
|
||
case WM_COMMAND:
|
||
{
|
||
if (lParam == 0) break;
|
||
HWND hWndChild = (HWND)lParam;
|
||
handled = true;
|
||
return ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam);
|
||
}
|
||
break;
|
||
case WM_CTLCOLOREDIT:
|
||
case WM_CTLCOLORSTATIC:
|
||
{
|
||
// Refer To: http://msdn.microsoft.com/en-us/library/bb761691(v=vs.85).aspx
|
||
// Read-only or disabled edit controls do not send the WM_CTLCOLOREDIT message; instead, they send the WM_CTLCOLORSTATIC message.
|
||
if (lParam == 0) break;
|
||
HWND hWndChild = (HWND)lParam;
|
||
handled = true;
|
||
return ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
LRESULT Window::CallWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
return ::CallWindowProc(m_OldWndProc, m_hWnd, uMsg, wParam, lParam);
|
||
}
|
||
|
||
bool Window::HandleMouseEnterLeave(const POINT &pt, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
m_pNewHover = FindControl(pt);
|
||
if (m_pNewHover != NULL && m_pNewHover->GetWindow() != this) return false;;
|
||
|
||
if (m_pNewHover != m_pEventHover && m_pEventHover != NULL) {
|
||
m_pEventHover->HandleMessageTemplate(kEventMouseLeave, 0, 0, 0, pt);
|
||
m_pEventHover = NULL;
|
||
if (m_hwndTooltip != NULL) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM)&m_ToolTip);
|
||
}
|
||
if (m_pNewHover != m_pEventHover && m_pNewHover != NULL) {
|
||
m_pNewHover->HandleMessageTemplate(kEventMouseEnter, wParam, lParam, 0, pt);
|
||
m_pEventHover = m_pNewHover;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
Control* Window::GetFocus() const
|
||
{
|
||
return m_pFocus;
|
||
}
|
||
|
||
void Window::SetFocus(Control* pControl)
|
||
{
|
||
// Paint manager window has focus?
|
||
HWND hFocusWnd = ::GetFocus();
|
||
if (hFocusWnd != m_hWnd && pControl != m_pFocus && pControl != NULL) ::SetFocus(m_hWnd);
|
||
// Already has focus?
|
||
if (pControl == m_pFocus) return;
|
||
// Remove focus from old control
|
||
if (m_pFocus != NULL) {
|
||
m_pFocus->HandleMessageTemplate(kEventInternalKillFocus);
|
||
Control* tmp = m_pFocus;
|
||
m_pFocus = NULL;
|
||
SendNotify(tmp, kEventKillFocus);
|
||
}
|
||
if (pControl == NULL) return;
|
||
// Set focus to new control
|
||
if (pControl != NULL
|
||
&& pControl->GetWindow() == this
|
||
&& pControl->IsVisible()
|
||
&& pControl->IsEnabled())
|
||
{
|
||
m_pFocus = pControl;
|
||
|
||
if (m_pFocus) {
|
||
m_pFocus->HandleMessageTemplate(kEventInternalSetFocus);
|
||
}
|
||
if (m_pFocus) {
|
||
SendNotify(m_pFocus, kEventSetFocus);
|
||
}
|
||
}
|
||
}
|
||
|
||
void Window::SetFocusNeeded(Control* pControl)
|
||
{
|
||
::SetFocus(m_hWnd);
|
||
if (pControl == NULL) return;
|
||
if (m_pFocus != NULL) {
|
||
m_pFocus->HandleMessageTemplate(kEventInternalKillFocus);
|
||
SendNotify(m_pFocus, kEventKillFocus);
|
||
m_pFocus = NULL;
|
||
}
|
||
FINDTABINFO info = { 0 };
|
||
info.pFocus = pControl;
|
||
info.bForward = false;
|
||
m_pFocus = m_pRoot->FindControl(__FindControlFromTab, &info, UIFIND_VISIBLE | UIFIND_ENABLED | UIFIND_ME_FIRST);
|
||
m_bFocusNeeded = true;
|
||
if (m_pRoot != NULL) m_pRoot->Arrange();
|
||
}
|
||
|
||
void Window::KillFocus()
|
||
{
|
||
if (m_pFocus != NULL)
|
||
{
|
||
m_pFocus->HandleMessageTemplate(kEventInternalKillFocus);
|
||
SendNotify(m_pFocus, kEventKillFocus);
|
||
m_pFocus = NULL;
|
||
}
|
||
}
|
||
|
||
void Window::SetCapture()
|
||
{
|
||
::SetCapture(m_hWnd);
|
||
m_bMouseCapture = true;
|
||
}
|
||
|
||
void Window::ReleaseCapture()
|
||
{
|
||
::ReleaseCapture();
|
||
m_bMouseCapture = false;
|
||
}
|
||
|
||
bool Window::IsCaptureControl(const ui::Control* pControl)
|
||
{
|
||
return m_pEventClick == pControl || m_pEventTouch == pControl || m_pEventPointer == pControl;
|
||
}
|
||
|
||
bool Window::IsCaptured() const
|
||
{
|
||
return m_bMouseCapture;
|
||
}
|
||
|
||
ui::Control* Window::GetNewHover()
|
||
{
|
||
return m_pNewHover;
|
||
}
|
||
|
||
POINT Window::GetLastMousePos() const
|
||
{
|
||
return m_ptLastMousePos;
|
||
}
|
||
|
||
HWND Window::GetTooltipWindow() const
|
||
{
|
||
return m_hwndTooltip;
|
||
}
|
||
|
||
bool Window::SetNextTabControl(bool bForward)
|
||
{
|
||
// If we're in the process of restructuring the layout we can delay the
|
||
// focus calulation until the next repaint.
|
||
if (m_bIsArranged && bForward) {
|
||
m_bFocusNeeded = true;
|
||
::InvalidateRect(m_hWnd, NULL, FALSE);
|
||
return true;
|
||
}
|
||
// Find next/previous tabbable control
|
||
FINDTABINFO info1 = { 0 };
|
||
info1.pFocus = m_pFocus;
|
||
info1.bForward = bForward;
|
||
Control* pControl = m_pRoot->FindControl(__FindControlFromTab, &info1, UIFIND_VISIBLE | UIFIND_ENABLED | UIFIND_ME_FIRST);
|
||
if (pControl == NULL) {
|
||
if (bForward) {
|
||
// Wrap around
|
||
FINDTABINFO info2 = { 0 };
|
||
info2.pFocus = bForward ? NULL : info1.pLast;
|
||
info2.bForward = bForward;
|
||
pControl = m_pRoot->FindControl(__FindControlFromTab, &info2, UIFIND_VISIBLE | UIFIND_ENABLED | UIFIND_ME_FIRST);
|
||
}
|
||
else {
|
||
pControl = info1.pLast;
|
||
}
|
||
}
|
||
if (pControl != NULL) SetFocus(pControl);
|
||
m_bFocusNeeded = false;
|
||
return true;
|
||
}
|
||
|
||
Control* Window::GetRoot() const
|
||
{
|
||
return m_pRoot;
|
||
}
|
||
|
||
void Window::SetArrange(bool bArrange)
|
||
{
|
||
m_bIsArranged = bArrange;
|
||
}
|
||
|
||
void Window::AddDelayedCleanup(Control* pControl)
|
||
{
|
||
pControl->SetWindow(this, NULL, false);
|
||
m_aDelayedCleanup.push_back(pControl);
|
||
::PostMessage(m_hWnd, WM_APP + 1, 0, 0L);
|
||
}
|
||
|
||
Control* Window::FindControl(POINT pt) const
|
||
{
|
||
ASSERT(m_pRoot);
|
||
Control* pFindedControl = NULL;
|
||
for (auto it : m_aIControlFromPointFinder)
|
||
{
|
||
if ((pFindedControl = it->FindControlFromPoint(pt)) != NULL)
|
||
return pFindedControl;
|
||
}
|
||
return m_pRoot->FindControl(__FindControlFromPoint, &pt, UIFIND_VISIBLE | UIFIND_HITTEST | UIFIND_TOP_FIRST);
|
||
}
|
||
|
||
Control* Window::FindControl(const std::wstring& strName) const
|
||
{
|
||
ASSERT(m_pRoot);
|
||
Control* pFindedControl = NULL;
|
||
auto it = m_mNameHash.find(strName);
|
||
if (it != m_mNameHash.end()) {
|
||
pFindedControl = it->second;
|
||
}
|
||
|
||
return pFindedControl;
|
||
}
|
||
|
||
Control* Window::FindSubControlByPoint(Control* pParent, POINT pt) const
|
||
{
|
||
if (pParent == NULL) pParent = GetRoot();
|
||
ASSERT(pParent);
|
||
return pParent->FindControl(__FindControlFromPoint, &pt, UIFIND_VISIBLE | UIFIND_HITTEST | UIFIND_TOP_FIRST);
|
||
}
|
||
|
||
Control* Window::FindSubControlByName(Control* pParent, const std::wstring& strName) const
|
||
{
|
||
if (pParent == NULL) pParent = GetRoot();
|
||
ASSERT(pParent);
|
||
return pParent->FindControl(__FindControlFromName, (LPVOID)strName.c_str(), UIFIND_ALL);
|
||
}
|
||
|
||
Control* Window::FindSubControlByClass(Control* pParent, const type_info& typeinfo, int iIndex)
|
||
{
|
||
if (pParent == NULL) pParent = GetRoot();
|
||
ASSERT(pParent);
|
||
m_aFoundControls.clear();
|
||
m_aFoundControls.resize(iIndex + 1);
|
||
return pParent->FindControl(__FindControlFromClass, (LPVOID)&typeinfo, UIFIND_ALL);
|
||
}
|
||
|
||
std::vector<Control*>* Window::FindSubControlsByClass(Control* pParent, const type_info& typeinfo)
|
||
{
|
||
if (pParent == NULL) pParent = GetRoot();
|
||
ASSERT(pParent);
|
||
m_aFoundControls.clear();
|
||
pParent->FindControl(__FindControlsFromClass, (LPVOID)&typeinfo, UIFIND_ALL);
|
||
return &m_aFoundControls;
|
||
}
|
||
|
||
std::vector<Control*>* Window::GetSubControlsByClass()
|
||
{
|
||
return &m_aFoundControls;
|
||
}
|
||
|
||
bool Window::SendNotify(EventType eventType, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
EventArgs msg;
|
||
msg.pSender = nullptr;
|
||
msg.Type = eventType;
|
||
msg.ptMouse = GetMousePos();
|
||
msg.dwTimestamp = ::GetTickCount();
|
||
msg.wParam = wParam;
|
||
msg.lParam = lParam;
|
||
|
||
auto callback = OnEvent.find(msg.Type);
|
||
if (callback != OnEvent.end()) {
|
||
callback->second(&msg);
|
||
}
|
||
|
||
callback = OnEvent.find(kEventAll);
|
||
if (callback != OnEvent.end()) {
|
||
callback->second(&msg);
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
bool Window::SendNotify(Control* pControl, EventType msgType, WPARAM wParam, LPARAM lParam)
|
||
{
|
||
EventArgs msg;
|
||
msg.pSender = pControl;
|
||
msg.Type = msgType;
|
||
msg.ptMouse = GetMousePos();
|
||
msg.dwTimestamp = ::GetTickCount();
|
||
msg.wParam = wParam;
|
||
msg.lParam = lParam;
|
||
pControl->HandleMessageTemplate(msg);
|
||
|
||
return true;
|
||
}
|
||
|
||
HDC Window::GetPaintDC() const
|
||
{
|
||
return m_hDcPaint;
|
||
}
|
||
|
||
ui::IRenderContext* Window::GetRenderContext() const
|
||
{
|
||
return m_renderContext.get();
|
||
}
|
||
|
||
void Window::Invalidate(const UiRect& rcItem)
|
||
{
|
||
::InvalidateRect(m_hWnd, &rcItem, FALSE);
|
||
// Invalidating a layered window will not trigger a WM_PAINT message,
|
||
// thus we have to post WM_PAINT by ourselves.
|
||
if (m_bIsLayeredWindow) {
|
||
::PostMessage(m_hWnd, WM_PAINT, (LPARAM)&rcItem, (WPARAM)FALSE);
|
||
}
|
||
}
|
||
|
||
void Window::Paint()
|
||
{
|
||
if (::IsIconic(m_hWnd) || !m_pRoot) {
|
||
PAINTSTRUCT ps = { 0 };
|
||
::BeginPaint(m_hWnd, &ps);
|
||
::EndPaint(m_hWnd, &ps);
|
||
return;
|
||
}
|
||
|
||
if (m_bIsArranged && m_pRoot->IsArranged() && (m_pRoot->GetFixedWidth() == DUI_LENGTH_AUTO || m_pRoot->GetFixedHeight() == DUI_LENGTH_AUTO)) {
|
||
CSize maxSize(99999, 99999);
|
||
CSize needSize = m_pRoot->EstimateSize(maxSize);
|
||
if (needSize.cx < m_pRoot->GetMinWidth()) needSize.cx = m_pRoot->GetMinWidth();
|
||
if (m_pRoot->GetMaxWidth() >= 0 && needSize.cx > m_pRoot->GetMaxWidth()) needSize.cx = m_pRoot->GetMaxWidth();
|
||
if (needSize.cy < m_pRoot->GetMinHeight()) needSize.cy = m_pRoot->GetMinHeight();
|
||
if (needSize.cy > m_pRoot->GetMaxHeight()) needSize.cy = m_pRoot->GetMaxHeight();
|
||
UiRect rect;
|
||
::GetWindowRect(m_hWnd, &rect);
|
||
::MoveWindow(m_hWnd, rect.left, rect.top, needSize.cx, needSize.cy, TRUE);
|
||
}
|
||
|
||
// Should we paint?
|
||
UiRect rcPaint;
|
||
if (!::GetUpdateRect(m_hWnd, &rcPaint, FALSE) && !m_bFirstLayout) {
|
||
return;
|
||
}
|
||
|
||
UiRect rcClient;
|
||
::GetClientRect(m_hWnd, &rcClient);
|
||
UiRect rcWindow;
|
||
::GetWindowRect(m_hWnd, &rcWindow);
|
||
|
||
//ʹ<>ò㴰<C3B2><E3B4B0>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD>ڲ<EFBFBD><DAB2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD><C4BB>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><D0A7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ļ<EFBFBD>ڵIJ<DAB5><C4B2>֣<EFBFBD><D6A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if (m_bIsLayeredWindow) {
|
||
int xScreen = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
||
int yScreen = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
||
int cxScreen = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
||
int cyScreen = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
||
if (rcWindow.left < xScreen && rcWindow.left + rcPaint.left == xScreen)
|
||
rcPaint.left = rcClient.left;
|
||
if (rcWindow.top < yScreen && rcWindow.top + rcPaint.top == yScreen)
|
||
rcPaint.top = rcClient.top;
|
||
if (rcWindow.right > cxScreen && rcWindow.left + rcPaint.right == xScreen + cxScreen)
|
||
rcPaint.right = rcClient.right;
|
||
if (rcWindow.bottom > cyScreen && rcWindow.top + rcPaint.bottom == yScreen + cyScreen)
|
||
rcPaint.bottom = rcClient.bottom;
|
||
}
|
||
|
||
PAINTSTRUCT ps = { 0 };
|
||
::BeginPaint(m_hWnd, &ps);
|
||
|
||
if (m_bIsArranged)
|
||
{
|
||
m_bIsArranged = false;
|
||
if (!::IsRectEmpty(&rcClient))
|
||
{
|
||
if (m_pRoot->IsArranged())
|
||
{
|
||
m_pRoot->SetPos(rcClient);
|
||
}
|
||
else
|
||
{
|
||
Control* pControl = NULL;
|
||
while ((pControl = m_pRoot->FindControl(__FindControlFromUpdate, NULL, UIFIND_VISIBLE | UIFIND_ME_FIRST)) != nullptr)
|
||
{
|
||
pControl->SetPos(pControl->GetPos());
|
||
}
|
||
}
|
||
|
||
if (m_bFirstLayout) {
|
||
m_bFirstLayout = false;
|
||
OnInitLayout();
|
||
}
|
||
}
|
||
}
|
||
|
||
int width = rcClient.right - rcClient.left;
|
||
int height = rcClient.bottom - rcClient.top;
|
||
if (m_renderContext->Resize(width, height))
|
||
{
|
||
// ʹ<><CAB9><EFBFBD><EFBFBD>Ӱ<EFBFBD><D3B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD>alphaͨ<61><CDA8><EFBFBD><EFBFBD><EFBFBD>Ͳ<EFBFBD><CDB2><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><CDB8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
m_renderContext->SetRenderTransparent(!m_shadow.IsShadowAttached());
|
||
rcPaint.left = 0;
|
||
rcPaint.top = 0;
|
||
rcPaint.right = width;
|
||
rcPaint.bottom = height;
|
||
}
|
||
|
||
// ȥ<><C8A5>alphaͨ<61><CDA8>
|
||
if (m_bIsLayeredWindow) {
|
||
m_renderContext->ClearAlpha(rcPaint);
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD>
|
||
AutoClip rectClip(m_renderContext.get(), rcPaint, true);
|
||
CPoint ptOldWindOrg = m_renderContext->OffsetWindowOrg(m_renderOffset);
|
||
m_pRoot->Paint(m_renderContext.get(), rcPaint);
|
||
m_pRoot->PaintChild(m_renderContext.get(), rcPaint);
|
||
m_renderContext->SetWindowOrg(ptOldWindOrg);
|
||
|
||
// alpha<68><EFBFBD>
|
||
if (m_bIsLayeredWindow) {
|
||
if (m_shadow.IsShadowAttached() && m_renderOffset.x == 0 && m_renderOffset.y == 0) {
|
||
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Gdi<64><69><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɵ<EFBFBD>alphaͨ<61><CDA8>Ϊ0
|
||
UiRect rcNewPaint = rcPaint;
|
||
rcNewPaint.Intersect(m_pRoot->GetPaddingPos());
|
||
UiRect rcRootPadding = m_pRoot->GetLayout()->GetPadding();
|
||
|
||
//<2F><><EFBFBD><EFBFBD>Բ<EFBFBD><D4B2>
|
||
rcRootPadding.left += 1;
|
||
rcRootPadding.top += 1;
|
||
rcRootPadding.right += 1;
|
||
rcRootPadding.bottom += 1;
|
||
|
||
m_renderContext->RestoreAlpha(rcNewPaint, rcRootPadding);
|
||
}
|
||
else {
|
||
UiRect rcAlphaFixCorner = GetAlphaFixCorner();
|
||
if (rcAlphaFixCorner.left > 0 || rcAlphaFixCorner.top > 0 || rcAlphaFixCorner.right > 0 || rcAlphaFixCorner.bottom > 0)
|
||
{
|
||
UiRect rcNewPaint = rcPaint;
|
||
UiRect rcRootPaddingPos = m_pRoot->GetPaddingPos();
|
||
rcRootPaddingPos.Deflate(rcAlphaFixCorner);
|
||
rcNewPaint.Intersect(rcRootPaddingPos);
|
||
|
||
UiRect rcRootPadding;
|
||
m_renderContext->RestoreAlpha(rcNewPaint, rcRootPadding);
|
||
}
|
||
}
|
||
}
|
||
|
||
// <20><>Ⱦ<EFBFBD><C8BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if (m_bIsLayeredWindow) {
|
||
CPoint pt(rcWindow.left, rcWindow.top);
|
||
CSize szWindow(rcClient.right - rcClient.left, rcClient.bottom - rcClient.top);
|
||
CPoint ptSrc;
|
||
BLENDFUNCTION bf = { AC_SRC_OVER, 0, m_nAlpha, AC_SRC_ALPHA };
|
||
::UpdateLayeredWindow(m_hWnd, NULL, &pt, &szWindow, m_renderContext->GetDC(), &ptSrc, 0, &bf, ULW_ALPHA);
|
||
}
|
||
else {
|
||
::BitBlt(ps.hdc, rcPaint.left, rcPaint.top, rcPaint.GetWidth(),
|
||
rcPaint.GetHeight(), m_renderContext->GetDC(), rcPaint.left, rcPaint.top, SRCCOPY);
|
||
}
|
||
|
||
::EndPaint(m_hWnd, &ps);
|
||
}
|
||
|
||
void Window::SetAlpha(int nAlpha)
|
||
{
|
||
ASSERT(nAlpha >= 0 && nAlpha <= 255);
|
||
if (m_pRoot) {
|
||
m_nAlpha = nAlpha;
|
||
Invalidate(m_pRoot->GetPos());
|
||
}
|
||
}
|
||
|
||
bool Window::IsRenderTransparent() const
|
||
{
|
||
return m_renderContext->IsRenderTransparent();
|
||
}
|
||
|
||
bool Window::SetRenderTransparent(bool bCanvasTransparent)
|
||
{
|
||
return m_renderContext->SetRenderTransparent(bCanvasTransparent);
|
||
}
|
||
|
||
void Window::SetRenderOffset(CPoint renderOffset)
|
||
{
|
||
if (m_pRoot) {
|
||
m_renderOffset = renderOffset;
|
||
Invalidate(m_pRoot->GetPos());
|
||
}
|
||
}
|
||
|
||
void Window::SetRenderOffsetX(int renderOffsetX)
|
||
{
|
||
if (m_pRoot) {
|
||
m_renderOffset.x = renderOffsetX;
|
||
Invalidate(m_pRoot->GetPos());
|
||
}
|
||
}
|
||
|
||
void Window::SetRenderOffsetY(int renderOffsetY)
|
||
{
|
||
if (m_pRoot) {
|
||
m_renderOffset.y = renderOffsetY;
|
||
Invalidate(m_pRoot->GetPos());
|
||
}
|
||
}
|
||
|
||
void Window::OnInitLayout()
|
||
{
|
||
if (m_pRoot && IsWindowsVistaOrGreater()) {
|
||
AnimationPlayer* animationArgs = m_pRoot->GetAnimationManager().SetFadeAlpha(true);
|
||
m_nAlpha = 0;
|
||
std::function<void(int)> playCallback = nbase::Bind(&Window::SetAlpha, this, std::placeholders::_1);
|
||
animationArgs->SetCallback(playCallback);
|
||
m_pRoot->SetVisible(true);
|
||
}
|
||
|
||
//auto fromLeftAnimationPlayer = m_pRoot->GetAnimationManager().GetAnimationPlayer(kAnimationInoutXFromLeft);
|
||
//if (!fromLeftAnimationPlayer && m_shadow.IsShadowAttached()) {
|
||
// Control* tmpRoot = m_pRoot->GetItemAt(0);
|
||
// fromLeftAnimationPlayer = tmpRoot->GetAnimationManager().GetAnimationPlayer(kAnimationInoutXFromLeft);
|
||
//}
|
||
//auto fromRightAnimationPlayer = m_pRoot->GetAnimationManager().GetAnimationPlayer(kAnimationInoutXFromRight);
|
||
//if (!fromRightAnimationPlayer && m_shadow.IsShadowAttached()) {
|
||
// Control* tmpRoot = m_pRoot->GetItemAt(0);
|
||
// fromRightAnimationPlayer = tmpRoot->GetAnimationManager().GetAnimationPlayer(kAnimationInoutXFromRight);
|
||
//}
|
||
//AnimationPlayer* fadeInoutXPlayer = nullptr;
|
||
//if (fromLeftAnimationPlayer) {
|
||
// fadeInoutXPlayer = m_pRoot->GetAnimationManager().SetFadeInOutX(true, false);
|
||
//}
|
||
//if (fromRightAnimationPlayer) {
|
||
// fadeInoutXPlayer = m_pRoot->GetAnimationManager().SetFadeInOutX(true, true);
|
||
//}
|
||
//if (fadeInoutXPlayer) {
|
||
// std::function<void(int)> playCallback = nbase::Bind(&Window::SetRenderOffsetX, this, std::placeholders::_1);
|
||
// fadeInoutXPlayer->SetCallback(playCallback);
|
||
// fadeInoutXPlayer->SetMaxTotalMillSeconds(250);
|
||
// m_pRoot->SetVisible(true);
|
||
//}
|
||
}
|
||
|
||
Control* CALLBACK Window::__FindControlFromNameHash(Control* pThis, LPVOID pData)
|
||
{
|
||
Window* pManager = static_cast<Window*>(pData);
|
||
std::wstring sName = pThis->GetName();
|
||
if( sName.empty() ) return NULL;
|
||
// Add this control to the hash list
|
||
pManager->m_mNameHash[sName] = pThis;
|
||
return NULL; // Attempt to add all controls
|
||
}
|
||
|
||
Control* CALLBACK Window::__FindControlFromCount(Control* /*pThis*/, LPVOID pData)
|
||
{
|
||
int* pnCount = static_cast<int*>(pData);
|
||
(*pnCount)++;
|
||
return NULL; // Count all controls
|
||
}
|
||
|
||
Control* CALLBACK Window::__FindControlFromPoint(Control* pThis, LPVOID pData)
|
||
{
|
||
LPPOINT pPoint = static_cast<LPPOINT>(pData);
|
||
UiRect pos = pThis->GetPos();
|
||
return ::PtInRect(&pos, *pPoint) ? pThis : NULL;
|
||
}
|
||
|
||
Control* CALLBACK Window::__FindControlFromTab(Control* pThis, LPVOID pData)
|
||
{
|
||
FINDTABINFO* pInfo = static_cast<FINDTABINFO*>(pData);
|
||
if (pInfo->pFocus == pThis) {
|
||
if (pInfo->bForward) pInfo->bNextIsIt = true;
|
||
return pInfo->bForward ? NULL : pInfo->pLast;
|
||
}
|
||
if ((pThis->GetControlFlags() & UIFLAG_TABSTOP) == 0) return NULL;
|
||
pInfo->pLast = pThis;
|
||
if (pInfo->bNextIsIt) return pThis;
|
||
if (pInfo->pFocus == NULL) return pThis;
|
||
return NULL; // Examine all controls
|
||
}
|
||
|
||
//Control* CALLBACK Window::__FindControlFromShortcut(Control* pThis, LPVOID pData)
|
||
//{
|
||
// if( !pThis->IsVisible() ) return NULL;
|
||
// FINDSHORTCUT* pFS = static_cast<FINDSHORTCUT*>(pData);
|
||
// if( pFS->ch == toupper(pThis->GetShortcut()) ) pFS->bPickNext = true;
|
||
// if( typeid(*pThis) == typeid(Label) ) return NULL; // Labels never get focus!
|
||
// return pFS->bPickNext ? pThis : NULL;
|
||
//}
|
||
|
||
Control* CALLBACK Window::__FindControlFromUpdate(Control* pThis, LPVOID pData)
|
||
{
|
||
return pThis->IsArranged() ? pThis : NULL;
|
||
}
|
||
|
||
Control* CALLBACK Window::__FindControlFromName(Control* pThis, LPVOID pData)
|
||
{
|
||
LPCTSTR pstrName = static_cast<LPCTSTR>(pData);
|
||
const std::wstring& sName = pThis->GetName();
|
||
if( sName.empty() ) return NULL;
|
||
return (_tcsicmp(sName.c_str(), pstrName) == 0) ? pThis : NULL;
|
||
}
|
||
|
||
Control* CALLBACK Window::__FindControlFromClass(Control* pThis, LPVOID pData)
|
||
{
|
||
type_info* pTypeInfo = static_cast<type_info*>(pData);
|
||
std::vector<Control*>* pFoundControls = pThis->GetWindow()->GetSubControlsByClass();
|
||
if( typeid(*pThis) == *pTypeInfo ) {
|
||
int iIndex = -1;
|
||
while( (*pFoundControls)[++iIndex] != NULL ) ;
|
||
if( (std::size_t)iIndex < pFoundControls->size() ) (*pFoundControls)[iIndex] = pThis;
|
||
}
|
||
if( (*pFoundControls)[pFoundControls->size() - 1] != NULL ) return pThis;
|
||
return NULL;
|
||
}
|
||
|
||
Control* CALLBACK Window::__FindControlsFromClass(Control* pThis, LPVOID pData)
|
||
{
|
||
type_info* pTypeInfo = static_cast<type_info*>(pData);
|
||
if( typeid(*pThis) == *pTypeInfo )
|
||
pThis->GetWindow()->GetSubControlsByClass()->push_back(pThis);
|
||
return NULL;
|
||
}
|
||
|
||
} // namespace ui
|