You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1299 lines
27 KiB
C++
1299 lines
27 KiB
C++
// 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);
|
|
}
|