// XTPPopupControl.cpp: implementation of the CXTPPopupControl class. // // This file is a part of the XTREME CONTROLS MFC class library. // (c)1998-2012 Codejock Software, All Rights Reserved. // // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN // CONSENT OF CODEJOCK SOFTWARE. // // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A // SINGLE COMPUTER. // // CONTACT INFORMATION: // support@codejock.com // http://www.codejock.com // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Common/Resource.h" #include "Common/XTPDrawHelpers.h" #include "Common/XTPImageManager.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPVC80Helpers.h" #include "Common/XTPMarkupRender.h" #include "Common/XTPResourceManager.h" #include "Common/XTPColorManager.h" #include "../Defines.h" #include "XTPPopupControl.h" #include "XTPPopupItem.h" #include "XTPPopupPaintManager.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define TID_EXPANDING 0x128L #define TID_COLLAPSING 0x129L #define TID_SHOWDELAY 0x130L //this define from new SDK implementation //not supported by Visual C++ 6.0 #ifndef LWA_ALPHA #define LWA_ALPHA 0x00000002 #endif #ifndef WS_EX_LAYERED #define WS_EX_LAYERED 0x00080000 #endif //end #ifndef IDC_HAND #define IDC_HAND MAKEINTRESOURCE(32649) #endif ///////////////////////////////////////////////////////////////////////////// // CXTPPopupControl CXTPPopupControl::CXTPPopupControl(BOOL bAutoDelete/*=FALSE*/) : m_bAutoDelete(bAutoDelete) { //set default paint manager m_pPaintManager = new CXTPPopupThemeOffice2000(); m_paintTheme = xtpPopupThemeOffice2000; m_pPaintManager->RefreshMetrics(); //init handels and flags for mouse operation m_pSelected = NULL; m_pPressed = NULL; m_bCapture = FALSE; //default state popup window m_popupAnimation = xtpPopupAnimationNone; m_popupState = xtpPopupStateClosed; //select def transparency value m_nCurrentTransparency = m_nTransparency = 255; m_pfnSetLayeredWindowAttributes = NULL; m_pfnUpdateLayeredWindow = NULL; m_bLayered = FALSE; //init animation vars m_nAnimationInterval = 16; m_uShowDelay = 5000L; m_uAnimationDelay = 256L; m_nStep = 0; m_bRightToLeft = FALSE; m_nBackgroundBitmap = 0; //popup pos&size init m_szPopup = CSize(170, 130); m_ptPopup = CPoint(-1, -1); m_bSplashScreenMode = FALSE; //init layered function (for Win98 compatible) HMODULE hLib = GetModuleHandle(_T("USER32")); if (hLib) { m_pfnSetLayeredWindowAttributes = (PFNSETLAYEREDWINDOWATTRIBUTES) ::GetProcAddress(hLib, "SetLayeredWindowAttributes"); m_pfnUpdateLayeredWindow = (LPFNUPDATELAYEREDWINDOW) GetProcAddress(hLib, "UpdateLayeredWindow"); } m_bAllowMove = FALSE; m_pImageManager = new CXTPImageManager; m_pMarkupContext = NULL; m_nPopupLocation = xtpPopupLocationNearTaskBar; // load the system hand cursor for hyperlink items. m_hHandCursor = AfxGetApp()->LoadStandardCursor(IDC_HAND); // if not found, use the toolkit version if (m_hHandCursor == NULL) m_hHandCursor = XTPResourceManager()->LoadCursor(XTP_IDC_HAND); } CXTPPopupControl::~CXTPPopupControl() { //Destroy CWnd object Close(); //clear all items RemoveAllItems(); //delete paint manager if (m_pPaintManager) delete m_pPaintManager; if (m_pImageManager) m_pImageManager->InternalRelease(); XTPMarkupReleaseContext(m_pMarkupContext); } void CXTPPopupControl::PostNcDestroy() { if (m_bAutoDelete) delete this; } CPoint CXTPPopupControl::GetPopupPos() const { if (m_ptPopup != CPoint(-1, -1)) return m_ptPopup; if (m_nPopupLocation == xtpPopupLocationNearTaskBar) { APPBARDATA abd; ZeroMemory(&abd, sizeof(APPBARDATA)); abd.cbSize = sizeof(APPBARDATA); if (SHAppBarMessage(ABM_GETTASKBARPOS, &abd)) { CRect rc = XTPMultiMonitor()->GetWorkArea(&abd.rc); if (rc.CenterPoint().y < abd.rc.top) return CPoint(rc.right, rc.bottom); if (rc.CenterPoint().x > abd.rc.right) return CPoint(rc.left + m_szPopup.cx, rc.bottom); if (rc.CenterPoint().y > abd.rc.bottom) return CPoint(rc.right, rc.top + m_szPopup.cy); if (rc.CenterPoint().x < abd.rc.left) return CPoint(rc.right, rc.bottom); } } //get desktop parameters CRect rcDeskWnd; ::SystemParametersInfo(SPI_GETWORKAREA, 0, &rcDeskWnd, 0); if (m_nPopupLocation == xtpPopupLocationCenter) { return CPoint(rcDeskWnd.CenterPoint().x + m_szPopup.cx / 2, rcDeskWnd.CenterPoint().y + m_szPopup.cy / 2); } //set position return rcDeskWnd.BottomRight(); } void CXTPPopupControl::SetRegionAlphaLayer(CXTPImageManagerIcon* pIcon) { if (!pIcon) return; if (!m_pfnUpdateLayeredWindow) return; CXTPImageManagerIconHandle hShadow; hShadow.CopyHandle(pIcon->GetIcon()); if (!hShadow.PreMultiply()) return; PBYTE pBits = hShadow.PreMultiply(); CSize szIcon = hShadow.GetExtent(); int cx = szIcon.cx; int cy = szIcon.cy; BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.SourceConstantAlpha = 255; bf.AlphaFormat = 0x01; POINT pt = {0, 0}; CClientDC cDC(this); CDC dc; dc.CreateCompatibleDC(&cDC); UINT* pvBits = NULL; HBITMAP hBitmap = CXTPImageManager::Create32BPPDIBSection(cDC, cx, cy, (LPBYTE*)&pvBits); if (pvBits == NULL || hBitmap == NULL) return; MEMCPY_S(pvBits, pBits, cx * cy* 4); HBITMAP hOld = (HBITMAP)SelectObject(dc, hBitmap); ModifyStyleEx(0, WS_EX_LAYERED); m_pfnUpdateLayeredWindow((HWND)GetSafeHwnd(), (HDC)0, 0, &szIcon, dc.GetSafeHdc(), &pt, 0, &bf, 0x02); SelectObject(dc, hOld); DeleteObject(hBitmap); dc.DeleteDC(); m_bLayered = TRUE; } HRGN CXTPPopupControl::BitmapToRegion(CXTPImageManagerIcon* pIcon) { HRGN hRgn = NULL; if (!pIcon) return NULL; // Create a memory DC inside which we will scan the bitmap content CDC dcMemDC; if (!dcMemDC.CreateCompatibleDC(NULL)) return NULL; int nWidth = pIcon->GetWidth(); int nHeight = pIcon->GetHeight(); LPBYTE lpBits = NULL; HBITMAP hbm32 = CXTPImageManager::Create32BPPDIBSection(dcMemDC, nWidth, nHeight, &lpBits); if (!hbm32 || lpBits == NULL) return NULL; HBITMAP holdBmp = (HBITMAP)SelectObject(dcMemDC, hbm32); dcMemDC.FillSolidRect(0, 0, nWidth, nHeight, 0xFF00FF); pIcon->Draw(&dcMemDC, CPoint(0, 0)); SelectObject(dcMemDC, holdBmp); const DWORD nAlloc = 100; DWORD mMaxRects = nAlloc; RGNDATA *pData = (RGNDATA *)malloc(sizeof(RGNDATAHEADER) + (sizeof(RECT) * mMaxRects)); if (!pData) { DeleteObject(hbm32); return NULL; } pData->rdh.dwSize = sizeof(RGNDATAHEADER); pData->rdh.iType = RDH_RECTANGLES; pData->rdh.nCount = pData->rdh.nRgnSize = 0; SetRect(&pData->rdh.rcBound, 0, 0, nWidth, nHeight); BYTE *p32 = (BYTE *)lpBits + (nHeight - 1) * nWidth * 4; for (int y = 0; y < nHeight; y++) { for (int x = 0; x < nWidth; x++) { int x0 = x; COLORREF* p = (COLORREF*)p32 + x; while (x < nWidth) { if (*p == 0xFF00FF) break; p++; x++; } if (x > x0) { if (pData->rdh.nCount >= mMaxRects) { mMaxRects += nAlloc; RGNDATA* pReData = (RGNDATA*)realloc(pData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * mMaxRects)); if (!pReData) { DeleteObject(hbm32); free(pData); return NULL; } pData = pReData; } RECT *pr = (RECT *)&pData->Buffer; SetRect(&pr[pData->rdh.nCount], x0, y, x, y + 1); pData->rdh.nCount++; if (pData->rdh.nCount > 2000) { HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * mMaxRects), pData); if (hRgn) { CombineRgn(hRgn, hRgn, h, RGN_OR); DeleteObject(h); } else { hRgn = h; } pData->rdh.nCount = 0; } } } p32 -= nWidth * 4; } HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * mMaxRects), pData); if (hRgn) { CombineRgn(hRgn, hRgn, h, RGN_OR); DeleteObject(h); } else { hRgn = h; } free(pData); DeleteObject(hbm32); return hRgn; } void CXTPPopupControl::UpdateBitmapRegion() { if (!GetSafeHwnd()) return; m_bLayered = FALSE; if (m_nBackgroundBitmap <= 0) { SetWindowRgn(NULL, FALSE); return; } CXTPImageManagerIcon* pImage = m_pImageManager->GetImage(m_nBackgroundBitmap, 0); if (!pImage) { SetWindowRgn(NULL, FALSE); return; } if (pImage->IsAlpha()) { SetWindowRgn(NULL, FALSE); SetRegionAlphaLayer(pImage); } else { HRGN hRgn = BitmapToRegion(pImage); if (!hRgn) return; SetWindowRgn(hRgn, FALSE); } } BOOL CXTPPopupControl::Create(CWnd* pParentWnd) { //if hwnd already exist - return TRUE; if (GetSafeHwnd()) return TRUE; //init extended wnd style (for Win98 compatible) DWORD dwExStyle = m_pfnSetLayeredWindowAttributes && (m_nTransparency < 255 || m_popupAnimation == xtpPopupAnimationFade) ? WS_EX_LAYERED : 0; //Create popup Wnd if (!CreateEx(dwExStyle | WS_EX_TOOLWINDOW | WS_EX_TOPMOST | (m_bRightToLeft ? WS_EX_LAYOUTRTL : 0), AfxRegisterWndClass(NULL, AfxGetApp()->LoadStandardCursor(IDC_ARROW)), NULL, WS_POPUP, CRect(0, 0, 0, 0), pParentWnd, NULL)) return FALSE; if (m_pMarkupContext) { XTPMarkupAssignHandle(m_pMarkupContext, m_hWnd); } m_nCurrentTransparency = 255; SetOwner(pParentWnd); UpdateBitmapRegion(); //Set begining state for creating window m_popupState = xtpPopupStateClosed; return TRUE; } void CXTPPopupControl::SetTheme(CXTPPopupPaintManager* pPaintManager) { //delete old theme object delete m_pPaintManager; //store point to new theme object m_pPaintManager = pPaintManager; m_pPaintManager->RefreshMetrics(); //redraw all controls RedrawControl(); } void CXTPPopupControl::SetTheme(XTPPopupPaintTheme theme) { //set new theme switch (theme) { case xtpPopupThemeMSN: SetTheme(new CXTPPopupThemeMSN()); break; case xtpPopupThemeOffice2003: SetTheme(new CXTPPopupThemeOffice2003()); break; case xtpPopupThemeResource: SetTheme(new CXTPPopupThemeResource()); break; case xtpPopupThemeOfficeXP: SetTheme(new CXTPPopupThemeOfficeXP()); break; case xtpPopupThemeOffice2000: SetTheme(new CXTPPopupThemeOffice2000()); break; case xtpPopupThemeCustom: default: //error case!!! SetTheme(new CXTPPopupPaintManager()); break; } m_paintTheme = theme; } void CXTPPopupControl::RedrawControl() { if (m_hWnd) //call WM_PAINT message Invalidate(FALSE); } CXTPPopupItem* CXTPPopupControl::AddItem(CXTPPopupItem* pItem) { //insert item to item's queue pItem->m_nIndex = (int)m_arrItems.Add(pItem); //init control handler pItem->m_pControl = this; //notify to item about adding inside CXTPPopupControl pItem->OnItemInserted(); return pItem; } void CXTPPopupControl::RemoveAllItems() { //dealocate memory for all items for (int i = 0; i < GetItemCount(); i++) m_arrItems[i]->InternalRelease(); //clear item's array m_arrItems.RemoveAll(); //reset selected and pressed pointers m_pSelected = NULL; m_pPressed = NULL; } void CXTPPopupControl::RemoveItem(CXTPPopupItem* pItem) { ASSERT(pItem); CXTPPopupItem* pCurrItem = NULL; //find item pointer in item's queue for (int i = 0; i < GetItemCount(); i++) { pCurrItem = GetItem(i); if (pCurrItem == pItem) { RemoveItem(i); break; } } } void CXTPPopupControl::RemoveItem(int nIndex) { if (nIndex < 0 || nIndex >= GetItemCount()) return; CXTPPopupItem* pCurrItem = m_arrItems[nIndex]; ASSERT(pCurrItem); if (!pCurrItem) return; //remove pointer from item's queue m_arrItems.RemoveAt(nIndex); //deallocate memory pCurrItem->InternalRelease(); //if pointer was selected - reset selected pointer if (m_pSelected == pCurrItem) m_pSelected = NULL; //if pointer was pressed - reset pressed pointer if (m_pPressed == pCurrItem) m_pPressed = NULL; //redraw all valid items RedrawControl(); } CXTPPopupItem* CXTPPopupControl::GetItem(int nIndex) const { //return item on an index return m_arrItems[nIndex]; } int CXTPPopupControl::GetItemCount() const { //return count of valid items return (int)m_arrItems.GetSize(); } CXTPPopupItem* CXTPPopupControl::HitTest(CPoint pt) const { //look over a item's pointers in item's queue for (int i = GetItemCount() - 1; i >= 0; i--) { CXTPPopupItem* pItem = GetItem(i); //test item rect to XY location if (pItem->GetRect().PtInRect(pt)) //if OK return pointer return pItem; } return NULL; } BOOL CXTPPopupControl::SetLayeredWindowAttributes(int bAlpha) { if (bAlpha > 255) bAlpha = 255; if (bAlpha == m_nCurrentTransparency) return TRUE; m_nCurrentTransparency = bAlpha; if (m_pfnSetLayeredWindowAttributes && (GetExStyle() & WS_EX_LAYERED)) { if (m_bLayered) { BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.SourceConstantAlpha = (BYTE)bAlpha; bf.AlphaFormat = 0x01; return m_pfnUpdateLayeredWindow(m_hWnd, (HDC)0, 0, 0, 0, 0, 0, &bf, 0x02); } //if pointer to transparent func - valid return m_pfnSetLayeredWindowAttributes(m_hWnd, 0x00, (BYTE)bAlpha, LWA_ALPHA); } return FALSE; } XTPPopupState CXTPPopupControl::GetPopupState() const { //return current popup state return m_popupState; } void CXTPPopupControl::SetPopupState(XTPPopupState popupState) { if (m_popupState == popupState) return; //set new popup state m_popupState = popupState; //else if CWnd object exist // - notify to parent window about change state Notify(XTP_PCN_STATECHANGED, (LPARAM)this); } void CXTPPopupControl::UpdateState(BOOL /*bInit*/) { //Get current popup wnd rect CRect rc = m_stateCurrent.rcPopup; //set current pos and size SetWindowPos(NULL, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOSENDCHANGING | SWP_SHOWWINDOW); //redraw all items RedrawControl(); //if mouse is capture - window is opaque (return from UpdateState proc) //else, will be need to set current transparent value if (!m_bCapture) SetLayeredWindowAttributes(m_stateCurrent.nTransparency); UpdateWindow(); } BOOL CXTPPopupControl::Close() { //reset capture flag m_bCapture = FALSE; //reset selected and pressed state m_pSelected = m_pPressed = NULL; if (!m_hWnd) return FALSE; EndModalLoop(0); if (m_bAutoDelete) { SetPopupState(xtpPopupStateClosed); return DestroyWindow(); } //destroy m_hWnd object BOOL bResult = DestroyWindow(); //set close state SetPopupState(xtpPopupStateClosed); return bResult; } void CXTPPopupControl::Hide() { //if popup state "Show" - collapsing window if (m_popupState == xtpPopupStateShow) { KillTimer(TID_SHOWDELAY); OnCollapsing(); } } void CXTPPopupControl::OnShow() { //set SHOW state SetPopupState(xtpPopupStateShow); CPoint ptPopup = GetPopupPos(); m_stateCurrent.rcPopup = CRect(CPoint(ptPopup.x - m_szPopup.cx, ptPopup.y - m_szPopup.cy), m_szPopup); m_stateCurrent.nTransparency = m_nTransparency; //start SHOW timer if (m_uShowDelay != (UINT)-1) { SetTimer(TID_SHOWDELAY, m_uShowDelay, NULL); } } void CXTPPopupControl::OnCollapsing() { //set COLLAPSING state SetPopupState(xtpPopupStateCollapsing); //if no-animation mode if (m_popupAnimation == xtpPopupAnimationNone || m_uAnimationDelay <= 0) { //close & destroy popup window Close(); return; } //if Fage animation mode else if (m_popupAnimation == xtpPopupAnimationFade) { //set target transparensy value m_stateTarget.nTransparency = 0; } //if Slide animation mode else if (m_popupAnimation == xtpPopupAnimationSlide) { //set rectangular of target CPoint ptPopup = GetPopupPos(); m_stateTarget.rcPopup = CRect(ptPopup.x - m_szPopup.cx, ptPopup.y, ptPopup.x, ptPopup.y); } //if Unfold animation mode else if (m_popupAnimation == xtpPopupAnimationUnfold) { //set rectangular of target CPoint ptPopup = GetPopupPos(); m_stateTarget.rcPopup = CRect(ptPopup, CSize(0)); } //calc step m_nStep = max(1, m_uAnimationDelay/m_nAnimationInterval); //set collapsing timer SetTimer(TID_COLLAPSING, m_nAnimationInterval, NULL); //update view state UpdateState(TRUE); } void CXTPPopupControl::OnExpanding(BOOL bUpdateCurrent) { //set Expanding state SetPopupState(xtpPopupStateExpanding); CPoint ptPopup = GetPopupPos(); //reinit target rect m_stateTarget.rcPopup = CRect(CPoint(ptPopup.x - m_szPopup.cx, ptPopup.y - m_szPopup.cy), m_szPopup); m_stateTarget.nTransparency = m_nTransparency; //if updating flag is set if (bUpdateCurrent) { //reinit curent state object m_stateCurrent = m_stateTarget; //if no-animation mode if (m_popupAnimation == xtpPopupAnimationNone || m_uAnimationDelay <= 0) { //update view UpdateState(TRUE); //show popup OnShow(); //return from proc return; } //if Fage animation mode else if (m_popupAnimation == xtpPopupAnimationFade) { //set target transparensy value m_stateCurrent.nTransparency = 0; } //if Slide animation mode if (m_popupAnimation == xtpPopupAnimationSlide) { //set rectangular of target m_stateCurrent.rcPopup = CRect(ptPopup.x - m_szPopup.cx, ptPopup.y, ptPopup.x, ptPopup.y); } //if Unfold animation mode else if (m_popupAnimation == xtpPopupAnimationUnfold) { //set rectangular of target m_stateCurrent.rcPopup = CRect(ptPopup, CSize(0)); } //calc step m_nStep = max(1, m_uAnimationDelay/m_nAnimationInterval); } else { //calc step m_nStep = max(1, m_uAnimationDelay/m_nAnimationInterval - m_nStep); } //set expanding timer SetTimer(TID_EXPANDING, m_nAnimationInterval, NULL); //update view state UpdateState(TRUE); } BOOL CXTPPopupControl::Show(CWnd* pParent) { //create popup wnd if (!Create(pParent)) return FALSE; //check popup state - return if popup state is wrong if (m_popupState != xtpPopupStateClosed) return FALSE; //set expanding OnExpanding(TRUE); return TRUE; } BOOL CXTPPopupControl::ShowModal(CWnd* pParent) { CWinApp* pApp = AfxGetApp(); if (pApp != NULL) pApp->EnableModeless(FALSE); HWND hWndTop = 0; #if (_MSC_VER <= 1100) CWnd* pParentWnd = CWnd::GetSafeOwner(pParent, &hWndTop); HWND hWndParent = pParentWnd->GetSafeHwnd(); #else HWND hWndParent = CWnd::GetSafeOwner_(pParent->GetSafeHwnd(), &hWndTop); #endif BOOL bEnableParent = FALSE; if (hWndParent != NULL && ::IsWindowEnabled(hWndParent)) { ::EnableWindow(hWndParent, FALSE); bEnableParent = TRUE; } //create popup wnd if (Show(pParent)) { SetFocus(); RunModalLoop(MLF_NOIDLEMSG | MLF_NOKICKIDLE); } if (bEnableParent) ::EnableWindow(hWndParent, TRUE); if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd) ::SetActiveWindow(hWndParent); DestroyWindow(); // re-enable windows if (::IsWindow(hWndTop)) ::EnableWindow(hWndTop, TRUE); hWndTop = NULL; if (pApp != NULL) pApp->EnableModeless(TRUE); return TRUE; } #define MOVETO(A, B, Step) if (A != B) A += max(1, abs(A - B)/Step) * (A > B ? -1 : 1); void CXTPPopupControl::Animate(int nStep) { // if step == 0 set current state to target state if (nStep < 1) { m_stateCurrent = m_stateTarget; } else { //move MOVETO(m_stateCurrent.rcPopup.top, m_stateTarget.rcPopup.top, nStep); MOVETO(m_stateCurrent.rcPopup.left, m_stateTarget.rcPopup.left, nStep); MOVETO(m_stateCurrent.rcPopup.right, m_stateTarget.rcPopup.right, nStep); MOVETO(m_stateCurrent.rcPopup.bottom, m_stateTarget.rcPopup.bottom, nStep); MOVETO(m_stateCurrent.nTransparency, m_stateTarget.nTransparency, nStep); } //update view state UpdateState(); } BEGIN_MESSAGE_MAP(CXTPPopupControl, CWnd) //{{AFX_MSG_MAP(CXTPPopupControl) ON_WM_ERASEBKGND() ON_WM_PAINT() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_CAPTURECHANGED() ON_WM_MOUSEMOVE() ON_WM_TIMER() ON_WM_SETCURSOR() //}}AFX_MSG_MAP ON_MESSAGE_VOID(WM_MOUSELEAVE, OnMouseLeave) ON_WM_MOUSEACTIVATE() END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CXTPPopupControl message handlers int CXTPPopupControl::OnMouseActivate(CWnd* /*pDesktopWnd*/, UINT /*nHitTest*/, UINT /*message*/) { return MA_NOACTIVATE; } void CXTPPopupControl::OnTimer(UINT_PTR nIDEvent) { CWnd::OnTimer(nIDEvent); switch (nIDEvent) { //if expand ore collapsing state case TID_EXPANDING: case TID_COLLAPSING: //animate from current to target Animate(m_nStep); m_nStep--; //if end step if (m_nStep <= 0) { //kill timer event KillTimer(nIDEvent); //change popup state if (nIDEvent == TID_EXPANDING) OnShow(); else Close(); } break; //if popup wnd shown case TID_SHOWDELAY: //if mouse cursor is not capture if (!m_bCapture) { //kill timer event KillTimer(TID_SHOWDELAY); //set collapsing state OnCollapsing(); } break; } } BOOL CXTPPopupControl::OnEraseBkgnd(CDC* /*pDC*/) { return TRUE; } void CXTPPopupControl::OnPaint() { //Get context CDC object CPaintDC dcPaint(this); //init client rect CRect rc(0, 0, m_szPopup.cx, m_szPopup.cy); //init temp buffer CDC object CXTPBufferDC dc(dcPaint, rc); //draw background m_pPaintManager->DrawBackground(&dc, this, rc); //draw all valid items for (int i = 0; i < GetItemCount(); i++) { CXTPPopupItem* pItem = GetItem(i); pItem->Draw(&dc); } } void CXTPPopupControl::Notify(WPARAM wParam, LPARAM lParam) { //get parent CWnd object HWND hWndOwner = m_hWndOwner; if (hWndOwner && ::IsWindow(hWndOwner)) { //send message to parent ::SendMessage(hWndOwner, XTPWM_POPUPCONTROL_NOTIFY, wParam, lParam); } } void CXTPPopupControl::OnClick(CXTPPopupItem* pItem) { if (pItem->GetID() == XTP_ID_POPUP_CLOSE) Close(); else Notify(XTP_PCN_ITEMCLICK, (LPARAM)pItem); } void CXTPPopupControl::TrackMove() { SetCapture(); CPoint ptStart; GetCursorPos(&ptStart); CXTPWindowRect rcStart(this); while (GetCapture() == this) { MSG msg; if (!::GetMessage(&msg, NULL, 0, 0)) { AfxPostQuitMessage((int)msg.wParam); break; } if (msg.message == WM_LBUTTONUP) break; else if (msg.message == WM_MOUSEMOVE) { CPoint pt(msg.pt); CRect rc(rcStart); rc.OffsetRect(pt - ptStart); CRect rcDeskWnd = XTPMultiMonitor()->GetWorkArea(msg.pt); if (rc.left < rcDeskWnd.left) rc.OffsetRect(rcDeskWnd.left - rc.left, 0); if (rc.top < rcDeskWnd.top) rc.OffsetRect(0, rcDeskWnd.top - rc.top); if (rc.right > rcDeskWnd.right) rc.OffsetRect(rcDeskWnd.right - rc.right, 0); if (rc.bottom > rcDeskWnd.bottom) rc.OffsetRect(0, rcDeskWnd.bottom - rc.bottom); MoveWindow(rc); } else if (msg.message == WM_KEYDOWN) { if (msg.wParam == VK_ESCAPE) break; } else DispatchMessage(&msg); } ReleaseCapture(); m_stateTarget.rcPopup = m_stateCurrent.rcPopup = CXTPWindowRect(this); m_ptPopup = m_stateCurrent.rcPopup.BottomRight(); Notify(XTP_PCN_POSCHANGED, (LPARAM)this); } void CXTPPopupControl::OnLButtonDown(UINT nFlags, CPoint point) { if ((GetPopupState() == xtpPopupStateExpanding) && !m_bSplashScreenMode) { m_nStep = 0; Animate(0); //kill timer event KillTimer(TID_EXPANDING); OnShow(); } //test point to pressed controll CXTPPopupItem* pPressed = HitTest(point); if (m_bAllowMove && (!pPressed || (!pPressed->GetID() && !pPressed->IsButton() && (pPressed->GetCaption().IsEmpty() || !pPressed->IsHyperLink())))) { TrackMove(); return; } //if success test if (pPressed) { m_pPressed = pPressed; //set capture SetCapture(); //redraw all valide controls RedrawControl(); } CWnd::OnLButtonDown(nFlags, point); } void CXTPPopupControl::OnLButtonUp(UINT /*nFlags*/, CPoint point) { //if there is pressed control if (m_pPressed) { //store popup pointer CXTPPopupItem* pPressed = m_pPressed; m_pPressed = NULL; //free mouse event ReleaseCapture(); RedrawControl(); //if selected pointer equal pressed pointer - it is clik on item if (pPressed == m_pSelected) { //redraw all valid items OnClick(pPressed); } else { OnMouseMove(0, point); } } } void CXTPPopupControl::OnCaptureChanged(CWnd* pWnd) { //if m_pPressed - reset pointer if (m_pPressed) { m_pPressed = NULL; RedrawControl(); } CWnd::OnCaptureChanged(pWnd); } void CXTPPopupControl::OnMouseMove(UINT nFlags, CPoint point) { if (!m_bSplashScreenMode) { CXTPClientRect rc(this); //test client rect if no-pressed BOOL bInRect = rc.PtInRect(point) || m_pPressed != NULL; //if test successfull and already not capture if (bInRect && !m_bCapture) { //set capture m_bCapture = TRUE; //opaque window SetLayeredWindowAttributes(255); //capture mouse leave event TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, m_hWnd, 0 }; _TrackMouseEvent(&tme); } //else if test fail and there is pressed and selected control if (!bInRect && m_bCapture && m_pPressed == NULL) { //free capture m_bCapture = FALSE; //set current transparent SetLayeredWindowAttributes(m_nTransparency); } //if collapsing state - expand popup window if (m_popupState == xtpPopupStateCollapsing) { //kill collapsing timer KillTimer(TID_COLLAPSING); if (m_popupAnimation == xtpPopupAnimationFade) { OnShow(); } else { OnExpanding(FALSE); } } } //test point to controled items CXTPPopupItem* pSelected = HitTest(point); //if detect new selected item ore lose selection (NULL) if (pSelected != m_pSelected) { //select new item ore set NULL m_pSelected = (m_pPressed == 0 || m_pPressed == pSelected || pSelected == NULL) ? pSelected : NULL; //redraw all items RedrawControl(); } CWnd::OnMouseMove(nFlags, point); } BOOL CXTPPopupControl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { CXTPPopupItem* pItem = HitTest(CXTPClientCursorPos(this)); if (pItem && pItem->IsHyperLink()) { if (m_hHandCursor) { ::SetCursor(m_hHandCursor); return TRUE; } } return CWnd::OnSetCursor(pWnd, nHitTest, message); } void CXTPPopupControl::OnMouseLeave() { //reset mouse vars OnMouseMove(0, CPoint(-1, -1)); } CXTPImageManager* CXTPPopupControl::GetImageManager() const { return m_pImageManager; } void CXTPPopupControl::SetImageManager(CXTPImageManager* pImageManager) { if (m_pImageManager) m_pImageManager->InternalRelease(); m_pImageManager = pImageManager; RedrawControl(); } void CXTPPopupControl::SetLayoutRTL(BOOL bRightToLeft) { if (XTPSystemVersion()->IsLayoutRTLSupported()) { m_bRightToLeft = bRightToLeft; } } void CXTPPopupControl::SetPopupAnimation() { SetPopupAnimation(m_pfnSetLayeredWindowAttributes ? xtpPopupAnimationFade : xtpPopupAnimationSlide); } void CXTPPopupControl::EnableMarkup(BOOL bEnableMarkup) { if (!bEnableMarkup) { XTPMarkupReleaseContext(m_pMarkupContext); } else if (!m_pMarkupContext) { m_pMarkupContext = XTPMarkupCreateContext(0); } } BOOL CXTPPopupControl::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) { if (m_pMarkupContext) { CPoint ptMouse(0); GetCursorPos(&ptMouse); ScreenToClient(&ptMouse); BOOL bRelay = FALSE; CXTPPopupItem* pItem = HitTest(ptMouse); if (pItem && pItem->GetMarkupUIElement()) { bRelay = TRUE; if (XTPMarkupRelayMessage(pItem->GetMarkupUIElement(), message, wParam, lParam, pResult)) return TRUE; } if (!bRelay) { if (XTPMarkupRelayMessage(GetMarkupContext(), message, wParam, lParam, pResult)) return TRUE; } } return CWnd::OnWndMsg(message, wParam, lParam, pResult); }