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.

1162 lines
31 KiB
C++

// XTPMarkupButton.cpp: implementation of the CXTPMarkupButton class.
//
// This file is a part of the XTREME TOOLKIT PRO 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/XTPWinThemeWrapper.h"
#include "XTPMarkupObject.h"
#include "XTPMarkupInputElement.h"
#include "XTPMarkupUIElement.h"
#include "XTPMarkupFrameworkElement.h"
#include "XTPMarkupControl.h"
#include "XTPMarkupContext.h"
#include "XTPMarkupDrawingContext.h"
#include "XTPMarkupScrollViewer.h"
#include "XTPMarkupBuilder.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define XTP_HTSCROLLUP 60 // <combine CXTPScrollBase::HitTestScrollBar@POINT>
#define XTP_HTSCROLLDOWN 61 // <combine CXTPScrollBase::HitTestScrollBar@POINT>
#define XTP_HTSCROLLUPPAGE 62 // <combine CXTPScrollBase::HitTestScrollBar@POINT>
#define XTP_HTSCROLLDOWNPAGE 63 // <combine CXTPScrollBase::HitTestScrollBar@POINT>
#define XTP_HTSCROLLTHUMB 64 // <combine CXTPScrollBase::HitTestScrollBar@POINT>
#define XTP_HTSCROLLPOPUP 65 // <combine CXTPScrollBase::HitTestScrollBar@POINT>
#define IDSYS_SCROLL 63345
IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupScrollBar, CXTPMarkupControl)
void CXTPMarkupScrollBar::RegisterMarkupClass()
{
}
CXTPMarkupScrollBar::CXTPMarkupScrollBar()
{
m_orientation = xtpMarkupOrientationVertical;
m_pSBTrack = NULL;
ZeroMemory(&m_spi, sizeof(m_spi));
ZeroMemory(&m_si, sizeof(m_si));
}
void CXTPMarkupScrollBar::SetScrollInfo(SCROLLINFO* pScrollInfo)
{
if (m_si.nMax != pScrollInfo->nMax || m_si.nPage != pScrollInfo->nPage || m_si.nPos != pScrollInfo->nPos)
{
m_si = *pScrollInfo;
m_bArrangeDirty = TRUE;
}
}
void CXTPMarkupScrollBar::GetScrollInfo(SCROLLINFO* pScrollInfo)
{
*pScrollInfo = m_si;
}
int CXTPMarkupScrollBar::HitTestScrollBar(POINT pt) const
{
if (!IsEnabled())
return HTNOWHERE;
int px = m_spi.fVert ? pt.y : pt.x;
if (!::PtInRect(&m_spi.rc, pt))
return HTNOWHERE;
if (px < m_spi.pxUpArrow)
return XTP_HTSCROLLUP;
if (m_spi.pxPopup > 0 && px > m_spi.pxPopup)
return XTP_HTSCROLLPOPUP;
if (px >= m_spi.pxDownArrow)
return XTP_HTSCROLLDOWN;
if (px < m_spi.pxThumbTop)
return XTP_HTSCROLLUPPAGE;
if (px < m_spi.pxThumbBottom)
return XTP_HTSCROLLTHUMB;
if (px < m_spi.pxDownArrow)
return XTP_HTSCROLLDOWNPAGE;
return HTERROR;
}
//////////////////////////////////////////////////////////////////////////
// Scrolling
void CXTPMarkupScrollBar::EndScroll(BOOL fCancel)
{
SCROLLBARTRACKINFO* pSBTrack = m_pSBTrack;
if (pSBTrack)
{
pSBTrack->cmdSB = 0;
GetMarkupContext()->ReleaseMouseCapture(this);
if (pSBTrack->bTrackThumb)
{
if (fCancel)
{
pSBTrack->posOld = pSBTrack->pSBInfo->pos;
}
DoScroll(SB_THUMBPOSITION, pSBTrack->posOld);
RedrawScrollBar();
}
else
{
if (pSBTrack->hTimerSB != 0)
{
::KillTimer(pSBTrack->hWndTrack, pSBTrack->hTimerSB);
pSBTrack->hTimerSB = 0;
}
}
DoScroll(SB_ENDSCROLL, 0);
}
}
int CXTPMarkupScrollBar::SBPosFromPx(CXTPMarkupScrollBar::SCROLLBARPOSINFO* pSBInfo, int px)
{
if (px < pSBInfo->pxMin)
{
return pSBInfo->posMin;
}
if (px >= pSBInfo->pxMin + pSBInfo->cpx)
{
return (pSBInfo->posMax - (pSBInfo->page ? pSBInfo->page - 1 : 0));
}
if (pSBInfo->cpx)
return (pSBInfo->posMin + MulDiv(pSBInfo->posMax - pSBInfo->posMin -
(pSBInfo->page ? pSBInfo->page - 1 : 0),
px - pSBInfo->pxMin, pSBInfo->cpx));
else
return (pSBInfo->posMin - 1);
}
void CXTPMarkupScrollBar::MoveThumb(int px)
{
SCROLLBARTRACKINFO* pSBTrack = m_pSBTrack;
if ((pSBTrack == NULL) || (px == pSBTrack->pxOld))
return;
SCROLLBARPOSINFO* pSBInfo = m_pSBTrack->pSBInfo;
pxReCalc:
pSBTrack->posNew = SBPosFromPx(pSBInfo, px);
if (pSBTrack->posNew != pSBTrack->posOld)
{
DoScroll(SB_THUMBTRACK, pSBTrack->posNew);
pSBTrack->posOld = pSBTrack->posNew;
if (px >= pSBInfo->pxMin + pSBInfo->cpx)
{
px = pSBInfo->pxMin + pSBInfo->cpx;
goto pxReCalc;
}
}
pSBInfo->pxThumbTop = px;
pSBInfo->pxThumbBottom = pSBInfo->pxThumbTop + pSBInfo->cpxThumb;
pSBTrack->pxOld = px;
RedrawScrollBar();
}
void CXTPMarkupScrollBar::TrackThumb(UINT message, CPoint pt)
{
SCROLLBARTRACKINFO* pSBTrack = m_pSBTrack;
if (!pSBTrack)
return;
SCROLLBARPOSINFO* pSBInfo = pSBTrack->pSBInfo;
if (HIBYTE(message) != HIBYTE(WM_MOUSEFIRST))
return;
if (pSBInfo == NULL)
return;
int px;
if (!PtInRect(&pSBTrack->rcTrack, pt))
px = pSBInfo->pxStart;
else
{
px = (pSBTrack->pSBInfo->fVert ? pt.y : pt.x) + pSBTrack->dpxThumb;
if (px < pSBInfo->pxMin)
px = pSBInfo->pxMin;
else if (px >= pSBInfo->pxMin + pSBInfo->cpx)
px = pSBInfo->pxMin + pSBInfo->cpx;
}
MoveThumb(px);
if (message == WM_LBUTTONUP || GetKeyState(VK_LBUTTON) >= 0)
{
EndScroll(FALSE);
}
}
void CXTPMarkupScrollBar::TrackBox(UINT message, CPoint point)
{
SCROLLBARTRACKINFO* pSBTrack = m_pSBTrack;
if (pSBTrack == NULL)
return;
if (message != WM_NULL && HIBYTE(message) != HIBYTE(WM_MOUSEFIRST))
return;
if ((pSBTrack->cmdSB == SB_PAGEUP || pSBTrack->cmdSB == SB_PAGEDOWN))
{
int* pLength = (int *)&pSBTrack->rcTrack;
if (pSBTrack->pSBInfo->fVert)
pLength++;
if (pSBTrack->cmdSB == SB_PAGEUP)
pLength[2] = pSBTrack->pSBInfo->pxThumbTop;
else
pLength[0] = pSBTrack->pSBInfo->pxThumbBottom;
}
BOOL fHit = PtInRect(&pSBTrack->rcTrack, point);
BOOL fHitChanged = fHit != (BOOL)pSBTrack->fHitOld;
if (fHitChanged)
{
pSBTrack->fHitOld = fHit;
RedrawScrollBar();
}
int cmsTimer = GetDoubleClickTime() / 10;
switch (message)
{
case WM_LBUTTONUP:
EndScroll(FALSE);
break;
case WM_LBUTTONDOWN:
pSBTrack->hTimerSB = 0;
cmsTimer = GetDoubleClickTime() * 4 / 5;
/*
*** FALL THRU **
*/
case WM_MOUSEMOVE:
if (fHit && fHitChanged)
{
pSBTrack->hTimerSB = ::SetTimer(m_pSBTrack->hWndTrack, IDSYS_SCROLL, cmsTimer, NULL);
DoScroll(pSBTrack->cmdSB, 0);
}
}
}
void CXTPMarkupScrollBar::ContScroll()
{
SCROLLBARTRACKINFO* pSBTrack = m_pSBTrack;
ASSERT(pSBTrack);
if (pSBTrack == NULL)
return;
CPoint pt;
GetCursorPos(&pt);
ScreenToClient(m_pSBTrack->hWndTrack, &pt);
TrackBox(WM_NULL, pt);
if (pSBTrack->fHitOld)
{
pSBTrack->hTimerSB = ::SetTimer(m_pSBTrack->hWndTrack, IDSYS_SCROLL, GetDoubleClickTime() / 10, NULL);
DoScroll(pSBTrack->cmdSB, 0);
}
}
void CXTPMarkupScrollBar::CalcTrackDragRect(SCROLLBARTRACKINFO* pSBTrack) const
{
int cx;
int cy;
LPINT pwX, pwY;
pwX = pwY = (LPINT)&pSBTrack->rcTrack;
if (pSBTrack->pSBInfo->fVert)
{
cy = GetSystemMetrics(SM_CYVTHUMB);
pwY++;
}
else
{
cy = GetSystemMetrics(SM_CXHTHUMB);
pwX++;
}
cx = (pSBTrack->pSBInfo->pxRight - pSBTrack->pSBInfo->pxLeft) * 8;
cy *= 2;
*(pwX + 0) = pSBTrack->pSBInfo->pxLeft - cx;
*(pwY + 0) = pSBTrack->pSBInfo->pxTop - cy;
*(pwX + 2) = pSBTrack->pSBInfo->pxRight + cx;
*(pwY + 2) = pSBTrack->pSBInfo->pxBottom + cy;
}
void CXTPMarkupScrollBar::DoScroll(int cmd, int pos)
{
CXTPMarkupScrollViewer* pViewer = MARKUP_DYNAMICCAST(CXTPMarkupScrollViewer, GetLogicalParent());
if (pViewer)
{
pViewer->Scroll(m_spi.fVert ? SB_VERT : SB_HORZ, cmd, pos);
}
}
void CXTPMarkupScrollBar::ScreenToClient(HWND hWnd, LPPOINT lpPoint)
{
::ScreenToClient(hWnd, lpPoint);
CXTPMarkupMouseEventArgs e(0);
e.m_hWnd = hWnd;
e.m_point = *lpPoint;
*lpPoint = e.GetPosition(this);
}
void CXTPMarkupScrollBar::PerformTrackInit(HWND hWnd, CPoint point, SCROLLBARPOSINFO* pSBInfo, BOOL bDirect)
{
CXTPMarkupContext* pMarkupContext = GetMarkupContext();
int px = m_spi.fVert ? point.y : point.x;
SCROLLBARTRACKINFO* pSBTrack = new SCROLLBARTRACKINFO;
memset(pSBTrack, 0, sizeof(SCROLLBARTRACKINFO));
pSBTrack->cmdSB = (UINT)-1;
pSBTrack->bTrackThumb = FALSE;
pSBTrack->pSBInfo = pSBInfo;
pSBTrack->hWndTrack = hWnd;
m_pSBTrack = pSBTrack;
RECT rcSB;
LPINT pwX = (LPINT)&rcSB;
LPINT pwY = pwX + 1;
if (!pSBInfo->fVert)
pwX = pwY--;
*(pwX + 0) = pSBInfo->pxLeft;
*(pwY + 0) = pSBInfo->pxTop;
*(pwX + 2) = pSBInfo->pxRight;
*(pwY + 2) = pSBInfo->pxBottom;
if (px < pSBInfo->pxUpArrow)
{
pSBInfo->ht = XTP_HTSCROLLUP;
pSBTrack->cmdSB = SB_LINEUP;
*(pwY + 2) = pSBInfo->pxUpArrow;
}
else if (px >= pSBInfo->pxDownArrow)
{
pSBInfo->ht = XTP_HTSCROLLDOWN;
pSBTrack->cmdSB = SB_LINEDOWN;
*(pwY + 0) = pSBInfo->pxDownArrow;
}
else if (px < pSBInfo->pxThumbTop)
{
pSBInfo->ht = XTP_HTSCROLLUPPAGE;
pSBTrack->cmdSB = SB_PAGEUP;
*(pwY + 0) = pSBInfo->pxUpArrow;
*(pwY + 2) = pSBInfo->pxThumbTop;
}
else if (px < pSBInfo->pxThumbBottom)
{
pSBInfo->ht = XTP_HTSCROLLTHUMB;
DoThumbPos:
if (pSBInfo->pxDownArrow - pSBInfo->pxUpArrow <= pSBInfo->cpxThumb)
{
delete m_pSBTrack;
m_pSBTrack = NULL;
return;
}
pSBTrack->cmdSB = SB_THUMBPOSITION;
CalcTrackDragRect(pSBTrack);
pSBTrack->pxOld = pSBInfo->pxStart = pSBInfo->pxThumbTop;
pSBTrack->posNew = pSBTrack->posOld = pSBInfo->pos;
pSBTrack->dpxThumb = pSBInfo->pxStart - px;
pSBTrack->bTrackThumb = TRUE;
pMarkupContext->CaptureMouse(this);
DoScroll(SB_THUMBTRACK, pSBTrack->posOld);
}
else if (px < pSBInfo->pxDownArrow)
{
pSBInfo->ht = XTP_HTSCROLLDOWNPAGE;
pSBTrack->cmdSB = SB_PAGEDOWN;
*(pwY + 0) = pSBInfo->pxThumbBottom;
*(pwY + 2) = pSBInfo->pxDownArrow;
}
if ((bDirect && pSBTrack->cmdSB != SB_LINEUP && pSBTrack->cmdSB != SB_LINEDOWN))
{
if (pSBTrack->cmdSB != SB_THUMBPOSITION)
{
goto DoThumbPos;
}
pSBTrack->dpxThumb = -(pSBInfo->cpxThumb / 2);
}
pMarkupContext->CaptureMouse(this);
if (pSBTrack->cmdSB != SB_THUMBPOSITION)
{
CopyRect(&pSBTrack->rcTrack, &rcSB);
}
if (!pSBTrack->bTrackThumb)
{
TrackBox(WM_LBUTTONDOWN, point);
}
else
{
TrackThumb(WM_LBUTTONDOWN, point);
}
while (pMarkupContext->GetMouseCapture() == this)
{
MSG msg;
if (!::GetMessage(&msg, NULL, 0, 0))
{
AfxPostQuitMessage((int)msg.wParam);
break;
}
if (!IsWindow(hWnd))
break;
UINT cmd = msg.message;
if (cmd == WM_TIMER && msg.wParam == IDSYS_SCROLL)
{
ContScroll();
}
else if (cmd >= WM_MOUSEFIRST && cmd <= WM_MOUSELAST)
{
CPoint ptScreen = msg.pt;
ScreenToClient(hWnd, &ptScreen);
if (!pSBTrack->bTrackThumb)
{
TrackBox(cmd, ptScreen);
}
else
{
TrackThumb(cmd, ptScreen);
}
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
if (pSBTrack->hTimerSB != 0)
{
::KillTimer(hWnd, pSBTrack->hTimerSB);
}
delete m_pSBTrack;
m_pSBTrack = NULL;
if (IsWindow(hWnd))
{
GetCursorPos(&point);
ScreenToClient(hWnd, &point);
m_spi.ht = HitTestScrollBar(point);
RedrawScrollBar();
}
}
void CXTPMarkupScrollBar::OnMouseLeave(CXTPMarkupMouseEventArgs* e)
{
if (m_spi.ht != HTNOWHERE)
{
m_spi.ht = HTNOWHERE;
RedrawScrollBar();
}
CXTPMarkupControl::OnMouseLeave(e);
}
void CXTPMarkupScrollBar::OnMouseEnter(CXTPMarkupMouseEventArgs* e)
{
CXTPMarkupControl::OnMouseEnter(e);
}
void CXTPMarkupScrollBar::OnMouseMove(CXTPMarkupMouseEventArgs* e)
{
int ht = HitTestScrollBar(e->GetPosition(this));
if (ht != m_spi.ht)
{
m_spi.ht = ht;
RedrawScrollBar();
}
e->SetHandled();
}
void CXTPMarkupScrollBar::OnMouseLeftButtonUp(CXTPMarkupMouseButtonEventArgs* e)
{
CXTPMarkupControl::OnMouseLeftButtonUp(e);
}
void CXTPMarkupScrollBar::OnMouseLeftButtonDown(CXTPMarkupMouseButtonEventArgs* e)
{
e->SetHandled();
if (IsEnabled())
{
PerformTrackInit(e->m_hWnd, e->GetPosition(this), &m_spi, (GetKeyState(VK_SHIFT) < 0) ? TRUE : FALSE);
}
}
void CXTPMarkupScrollBar::RedrawScrollBar()
{
InvalidateVisual();
}
void CXTPMarkupScrollBar::CalcScrollBarInfo(LPRECT lprc, SCROLLBARPOSINFO* pSBInfo, SCROLLINFO* pSI)
{
int cpx;
DWORD dwRange;
int denom;
BOOL fVert = pSBInfo->fVert = (m_orientation == xtpMarkupOrientationVertical);
pSBInfo->rc = *lprc;
pSBInfo->pxPopup = 0;
if (fVert)
{
pSBInfo->pxTop = lprc->top;
pSBInfo->pxBottom = lprc->bottom;
pSBInfo->pxLeft = lprc->left;
pSBInfo->pxRight = lprc->right;
pSBInfo->cpxThumb = GetSystemMetrics(SM_CYVSCROLL);
}
else
{
pSBInfo->pxTop = lprc->left;
pSBInfo->pxBottom = lprc->right;
pSBInfo->pxLeft = lprc->top;
pSBInfo->pxRight = lprc->bottom;
pSBInfo->cpxThumb = GetSystemMetrics(SM_CXHSCROLL);
}
pSBInfo->pos = pSI->nPos;
pSBInfo->page = pSI->nPage;
pSBInfo->posMin = pSI->nMin;
pSBInfo->posMax = pSI->nMax;
dwRange = ((DWORD)(pSBInfo->posMax - pSBInfo->posMin)) + 1;
cpx = min((pSBInfo->pxBottom - pSBInfo->pxTop) / 2, pSBInfo->cpxThumb);
pSBInfo->pxUpArrow = pSBInfo->pxTop + cpx;
pSBInfo->pxDownArrow = pSBInfo->pxBottom - cpx;
if ((pSBInfo->page != 0) && (dwRange != 0))
{
int i = MulDiv(pSBInfo->pxDownArrow - pSBInfo->pxUpArrow,
pSBInfo->page, dwRange);
pSBInfo->cpxThumb = max(max(16, pSBInfo->cpxThumb / 2), i);
}
pSBInfo->pxMin = pSBInfo->pxTop + cpx;
pSBInfo->cpx = pSBInfo->pxBottom - cpx - pSBInfo->cpxThumb - pSBInfo->pxMin;
denom = dwRange - (pSBInfo->page ? pSBInfo->page : 1);
if (denom)
pSBInfo->pxThumbTop = MulDiv(pSBInfo->pos - pSBInfo->posMin,
pSBInfo->cpx, denom) + pSBInfo->pxMin;
else
pSBInfo->pxThumbTop = pSBInfo->pxMin;
pSBInfo->pxThumbBottom = pSBInfo->pxThumbTop + pSBInfo->cpxThumb;
}
CSize CXTPMarkupScrollBar::ArrangeOverride(CSize szFinalSize)
{
CalcScrollBarInfo(CRect(0, 0, szFinalSize.cx, szFinalSize.cy), &m_spi, &m_si);
return szFinalSize;
}
CSize CXTPMarkupScrollBar::MeasureOverride(CXTPMarkupDrawingContext* /*pDC*/, CSize /*szAvailableSize*/)
{
BOOL bHorizontal = (m_orientation == xtpMarkupOrientationHorizontal);
if (bHorizontal)
return CSize(0, GetSystemMetrics(SM_CYHSCROLL));
return CSize(GetSystemMetrics(SM_CXVSCROLL), 0);
}
BOOL CXTPMarkupScrollBar::IsEnabled() const
{
return m_spi.posMax - m_spi.posMin - m_spi.page + 1 > 0;
}
void CXTPMarkupScrollBar::OnRender(CXTPMarkupDrawingContext* pDC)
{
#define GETPARTSTATE(ht, pressed, hot, normal, disabled) \
(!bEnabled ? disabled : nPressetHt == ht ? pressed : nHotHt == ht ? hot : normal)
SCROLLBARTRACKINFO* pSBTrack = m_pSBTrack;
SCROLLBARPOSINFO* pSBInfo = &m_spi;
BOOL nPressetHt = pSBTrack ? (pSBTrack->bTrackThumb || pSBTrack->fHitOld ? pSBInfo->ht : -1) : -1;
BOOL nHotHt = pSBTrack ? -1 : pSBInfo->ht;
int cWidth = (pSBInfo->pxRight - pSBInfo->pxLeft);
if (cWidth <= 0)
{
return;
}
BOOL bEnabled = IsEnabled();
int nBtnTrackSize = pSBInfo->pxThumbBottom - pSBInfo->pxThumbTop;
int nBtnTrackPos = pSBInfo->pxThumbTop - pSBInfo->pxUpArrow;
if (!bEnabled || pSBInfo->pxThumbBottom > pSBInfo->pxDownArrow)
nBtnTrackPos = nBtnTrackSize = 0;
BOOL bUseVisualStyle = TRUE;
CXTPWinThemeWrapper m_themeScrollBar;
m_themeScrollBar.OpenTheme(0, L"SCROLLBAR");
COLORREF clrFace = GetSysColor(COLOR_3DFACE);
COLORREF m_crBackHilite = clrFace, m_crBackPushed = clrFace, m_crBack = clrFace;
HDC hDC = pDC->GetDC();
if (pSBInfo->fVert)
{
CRect rcVScroll(pSBInfo->rc);
CRect rcArrowUp(rcVScroll.left, rcVScroll.top, rcVScroll.right, pSBInfo->pxUpArrow);
CRect rcArrowDown(rcVScroll.left, pSBInfo->pxDownArrow, rcVScroll.right, rcVScroll.bottom);
CRect rcTrack(rcVScroll.left, rcArrowUp.bottom, rcVScroll.right, rcArrowDown.top);
CRect rcLowerTrack(rcTrack.left, rcTrack.top, rcTrack.right, rcTrack.top + nBtnTrackPos);
CRect rcBtnTrack(rcTrack.left, rcLowerTrack.bottom, rcTrack.right, rcLowerTrack.bottom + nBtnTrackSize);
CRect rcUpperTrack(rcTrack.left, rcBtnTrack.bottom, rcTrack.right, rcTrack.bottom);
if (bUseVisualStyle && m_themeScrollBar.IsAppThemed())
{
m_themeScrollBar.DrawThemeBackground(hDC, SBP_ARROWBTN, GETPARTSTATE(XTP_HTSCROLLUP, ABS_UPPRESSED, ABS_UPHOT, ABS_UPNORMAL, ABS_UPDISABLED), rcArrowUp, NULL);
m_themeScrollBar.DrawThemeBackground(hDC, SBP_ARROWBTN, GETPARTSTATE(XTP_HTSCROLLDOWN, ABS_DOWNPRESSED, ABS_DOWNHOT, ABS_DOWNNORMAL, ABS_DOWNDISABLED), rcArrowDown, NULL);
if (!rcTrack.IsRectEmpty())
{
if (!rcLowerTrack.IsRectEmpty())
m_themeScrollBar.DrawThemeBackground(hDC, SBP_LOWERTRACKVERT, GETPARTSTATE(XTP_HTSCROLLUPPAGE, SCRBS_PRESSED, SCRBS_HOT, SCRBS_NORMAL, SCRBS_DISABLED), rcLowerTrack, NULL);
if (!rcBtnTrack.IsRectEmpty())
{
m_themeScrollBar.DrawThemeBackground(hDC, SBP_THUMBBTNVERT, GETPARTSTATE(XTP_HTSCROLLTHUMB, SCRBS_PRESSED, SCRBS_HOT, SCRBS_NORMAL, SCRBS_DISABLED), rcBtnTrack, NULL);
if (rcBtnTrack.Height() > 13)
m_themeScrollBar.DrawThemeBackground(hDC, SBP_GRIPPERVERT, GETPARTSTATE(XTP_HTSCROLLTHUMB, SCRBS_PRESSED, SCRBS_HOT, SCRBS_NORMAL, SCRBS_DISABLED), rcBtnTrack, NULL);
}
if (!rcUpperTrack.IsRectEmpty())
m_themeScrollBar.DrawThemeBackground(hDC, SBP_UPPERTRACKVERT, GETPARTSTATE(XTP_HTSCROLLDOWNPAGE, SCRBS_PRESSED, SCRBS_HOT, SCRBS_NORMAL, SCRBS_DISABLED), rcUpperTrack, NULL);
}
}
else
{
{
DrawFrameControl(hDC, &rcArrowUp, DFC_SCROLL, DFCS_SCROLLUP | (!bEnabled ? DFCS_INACTIVE : 0) | (nPressetHt == XTP_HTSCROLLUP ? DFCS_PUSHED : 0));
DrawFrameControl(hDC, &rcArrowDown, DFC_SCROLL, DFCS_SCROLLDOWN | (!bEnabled ? DFCS_INACTIVE : 0) | (nPressetHt == XTP_HTSCROLLDOWN ? DFCS_PUSHED : 0));
}
HBRUSH hbrRet = (HBRUSH)SendMessage(::GetDesktopWindow(), WM_CTLCOLORSCROLLBAR, (WPARAM)hDC, 0);
::SetBkColor(hDC, GetSysColor(COLOR_3DHILIGHT));
::SetTextColor(hDC, GetSysColor(COLOR_BTNFACE));
::FillRect(hDC, &rcTrack, hbrRet);
if (nPressetHt == XTP_HTSCROLLUPPAGE)
{
::InvertRect(hDC, &rcLowerTrack);
}
if (!rcTrack.IsRectEmpty() && !rcBtnTrack.IsRectEmpty())
{
::SetBkColor(hDC, nPressetHt == XTP_HTSCROLLTHUMB ? m_crBackPushed : nHotHt == XTP_HTSCROLLTHUMB ? m_crBackHilite : m_crBack);
::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, rcBtnTrack, NULL, 0, NULL);
::DrawEdge(hDC, &rcBtnTrack, EDGE_RAISED, (UINT)(BF_ADJUST | BF_RECT));
}
if (nPressetHt == XTP_HTSCROLLDOWNPAGE)
{
::InvertRect(hDC, &rcUpperTrack);
}
}
}
else
{
CRect rcHScroll(pSBInfo->rc);
CRect rcArrowLeft(rcHScroll.left, rcHScroll.top, pSBInfo->pxUpArrow, rcHScroll.bottom);
CRect rcArrowRight(pSBInfo->pxDownArrow, rcHScroll.top, rcHScroll.right, rcHScroll.bottom);
CRect rcTrack(rcArrowLeft.right, rcHScroll.top, rcArrowRight.left, rcHScroll.bottom);
CRect rcLowerTrack(rcTrack.left, rcTrack.top, rcTrack.left + nBtnTrackPos, rcTrack.bottom);
CRect rcBtnTrack(rcLowerTrack.right, rcTrack.top, rcLowerTrack.right + nBtnTrackSize, rcTrack.bottom);
CRect rcUpperTrack(rcBtnTrack.right, rcTrack.top, rcTrack.right, rcTrack.bottom);
if (bUseVisualStyle && m_themeScrollBar.IsAppThemed())
{
m_themeScrollBar.DrawThemeBackground(hDC, SBP_ARROWBTN, GETPARTSTATE(XTP_HTSCROLLUP, ABS_LEFTPRESSED, ABS_LEFTHOT, ABS_LEFTNORMAL, ABS_LEFTDISABLED), rcArrowLeft, NULL);
m_themeScrollBar.DrawThemeBackground(hDC, SBP_ARROWBTN, GETPARTSTATE(XTP_HTSCROLLDOWN, ABS_RIGHTPRESSED, ABS_RIGHTHOT, ABS_RIGHTNORMAL, ABS_RIGHTDISABLED), rcArrowRight, NULL);
if (!rcTrack.IsRectEmpty())
{
if (!rcLowerTrack.IsRectEmpty())
m_themeScrollBar.DrawThemeBackground(hDC, SBP_LOWERTRACKHORZ, GETPARTSTATE(XTP_HTSCROLLUPPAGE, SCRBS_PRESSED, SCRBS_HOT, SCRBS_NORMAL, SCRBS_DISABLED), rcLowerTrack, NULL);
if (!rcBtnTrack.IsRectEmpty())
{
m_themeScrollBar.DrawThemeBackground(hDC, SBP_THUMBBTNHORZ, GETPARTSTATE(XTP_HTSCROLLTHUMB, SCRBS_PRESSED, SCRBS_HOT, SCRBS_NORMAL, SCRBS_DISABLED), rcBtnTrack, NULL);
if (rcBtnTrack.Width() > 13)
m_themeScrollBar.DrawThemeBackground(hDC, SBP_GRIPPERHORZ, GETPARTSTATE(XTP_HTSCROLLTHUMB, SCRBS_PRESSED, SCRBS_HOT, SCRBS_NORMAL, SCRBS_DISABLED), rcBtnTrack, NULL);
}
if (!rcUpperTrack.IsRectEmpty())
m_themeScrollBar.DrawThemeBackground(hDC, SBP_UPPERTRACKHORZ, GETPARTSTATE(XTP_HTSCROLLDOWNPAGE, SCRBS_PRESSED, SCRBS_HOT, SCRBS_NORMAL, SCRBS_DISABLED), rcUpperTrack, NULL);
}
}
else
{
{
DrawFrameControl(hDC, &rcArrowLeft, DFC_SCROLL, DFCS_SCROLLLEFT | (!bEnabled ? DFCS_INACTIVE : 0) | (nPressetHt == XTP_HTSCROLLUP ? DFCS_PUSHED : 0));
DrawFrameControl(hDC, &rcArrowRight, DFC_SCROLL, DFCS_SCROLLRIGHT | (!bEnabled ? DFCS_INACTIVE : 0) | (nPressetHt == XTP_HTSCROLLDOWN ? DFCS_PUSHED : 0));
}
HBRUSH hbrRet = (HBRUSH)SendMessage(::GetDesktopWindow(), WM_CTLCOLORSCROLLBAR, (WPARAM)hDC, 0);
::SetBkColor(hDC, GetSysColor(COLOR_3DHILIGHT));
::SetTextColor(hDC, GetSysColor(COLOR_BTNFACE));
::FillRect(hDC, &rcTrack, hbrRet);
if (nPressetHt == XTP_HTSCROLLUPPAGE)
{
::InvertRect(hDC, &rcLowerTrack);
}
if (!rcTrack.IsRectEmpty() && !rcBtnTrack.IsRectEmpty())
{
::SetBkColor(hDC, nPressetHt == XTP_HTSCROLLTHUMB ? m_crBackPushed : nHotHt == XTP_HTSCROLLTHUMB ? m_crBackHilite : m_crBack);
::ExtTextOut(hDC, 0, 0, ETO_OPAQUE, rcBtnTrack, NULL, 0, NULL);
::DrawEdge(hDC, &rcBtnTrack, EDGE_RAISED, (UINT)(BF_ADJUST | BF_RECT));
}
if (nPressetHt == XTP_HTSCROLLDOWNPAGE)
{
::InvertRect(hDC, &rcUpperTrack);
}
}
}
pDC->ReleaseDC(hDC);
}
//////////////////////////////////////////////////////////////////////////
// CXTPMarkupScrollBarGripper
class CXTPMarkupScrollBarGripper : public CXTPMarkupUIElement
{
DECLARE_MARKUPCLASS(CXTPMarkupScrollBarGripper)
public:
void OnRender(CXTPMarkupDrawingContext* pDC);
};
IMPLEMENT_MARKUPCLASS(NULL, CXTPMarkupScrollBarGripper, CXTPMarkupUIElement)
void CXTPMarkupScrollBarGripper::RegisterMarkupClass()
{
}
void CXTPMarkupScrollBarGripper::OnRender(CXTPMarkupDrawingContext* pDC)
{
CRect rc(GetFinalRect());
pDC->FillSolidRect(rc, GetSysColor(COLOR_BTNFACE));
}
//////////////////////////////////////////////////////////////////////////
// CXTPMarkupScrollViewer
CXTPMarkupDependencyProperty* CXTPMarkupScrollViewer::m_pVerticalScrollBarVisibilityProperty = NULL;
CXTPMarkupDependencyProperty* CXTPMarkupScrollViewer::m_pHorizontalScrollBarVisibilityProperty = NULL;
IMPLEMENT_MARKUPCLASS(L"ScrollViewer", CXTPMarkupScrollViewer, CXTPMarkupContentControl)
void CXTPMarkupScrollViewer::RegisterMarkupClass()
{
m_pVerticalScrollBarVisibilityProperty = CXTPMarkupDependencyProperty::Register(L"VerticalScrollBarVisibility", MARKUP_TYPE(CXTPMarkupEnum), MARKUP_TYPE(CXTPMarkupScrollViewer),
new CXTPMarkupPropertyMetadata(NULL, &CXTPMarkupBuilder::ConvertScrollBarVisibility, CXTPMarkupPropertyMetadata::flagAffectsMeasure));
m_pHorizontalScrollBarVisibilityProperty = CXTPMarkupDependencyProperty::Register(L"HorizontalScrollBarVisibility", MARKUP_TYPE(CXTPMarkupEnum), MARKUP_TYPE(CXTPMarkupScrollViewer),
new CXTPMarkupPropertyMetadata(NULL, &CXTPMarkupBuilder::ConvertScrollBarVisibility, CXTPMarkupPropertyMetadata::flagAffectsMeasure));
}
CXTPMarkupScrollViewer::CXTPMarkupScrollViewer()
{
m_pVerticalScrollBar = NULL;
m_pHorizontalScrollBar = NULL;
m_pScrollBarGripper = NULL;
m_xOffset = m_yOffset = 0;
SetValue(m_pClipToBoundsProperty, CXTPMarkupBool::CreateTrueValue());
}
CXTPMarkupScrollViewer::~CXTPMarkupScrollViewer()
{
MARKUP_RELEASE(m_pVerticalScrollBar);
MARKUP_RELEASE(m_pHorizontalScrollBar);
MARKUP_RELEASE(m_pScrollBarGripper);
}
int CXTPMarkupScrollViewer::GetVisualChildrenCount() const
{
return (GetContent() != NULL ? 1 : 0) + (m_pVerticalScrollBar ? 1 : 0) + (m_pHorizontalScrollBar ? 1 : 0) + (m_pScrollBarGripper ? 1 : 0);
}
CXTPMarkupVisual* CXTPMarkupScrollViewer::GetVisualChild(int nIndex) const
{
CXTPMarkupVisual* pContent = GetContent();
if (pContent) if (nIndex == 0) return pContent; else nIndex--;
if (m_pVerticalScrollBar) if (nIndex == 0) return m_pVerticalScrollBar; else nIndex--;
if (m_pHorizontalScrollBar) if (nIndex == 0) return m_pHorizontalScrollBar; else nIndex--;
return m_pScrollBarGripper;
}
CSize CXTPMarkupScrollViewer::ArrangeOverride(CSize szFinalSize)
{
CXTPMarkupUIElement* pContent = GetContent();
if (!pContent)
return szFinalSize;
CSize szViewport(szFinalSize);
if (m_pVerticalScrollBar) szViewport.cx -= m_pVerticalScrollBar->GetDesiredSize().cx;
if (m_pHorizontalScrollBar) szViewport.cy -= m_pHorizontalScrollBar->GetDesiredSize().cy;;
if (m_pVerticalScrollBar)
{
if (m_yOffset > 0 && pContent->GetDesiredSize().cy < m_yOffset + szViewport.cy)
{
m_yOffset = max(0, pContent->GetDesiredSize().cy - szViewport.cy);
}
SCROLLINFO si;
ZeroMemory(&si, sizeof(SCROLLINFO));
si.nMax = pContent->GetDesiredSize().cy - 1;
si.nPage = szViewport.cy;
si.nPos = m_yOffset;
m_pVerticalScrollBar->SetScrollInfo(&si);
m_pVerticalScrollBar->Arrange(CRect(szFinalSize.cx - m_pVerticalScrollBar->GetDesiredSize().cx, 0, szFinalSize.cx, szViewport.cy));
}
if (m_pHorizontalScrollBar)
{
if (m_xOffset > 0 && pContent->GetDesiredSize().cx < m_xOffset + szViewport.cx)
{
m_xOffset = max(0, pContent->GetDesiredSize().cx - szViewport.cx);
}
SCROLLINFO si;
ZeroMemory(&si, sizeof(SCROLLINFO));
si.nMax = pContent->GetDesiredSize().cx - 1;
si.nPage = szViewport.cx;
si.nPos = m_xOffset;
m_pHorizontalScrollBar->SetScrollInfo(&si);
m_pHorizontalScrollBar->Arrange(CRect(0, szFinalSize.cy - m_pHorizontalScrollBar->GetDesiredSize().cy, szViewport.cx, szFinalSize.cy));
}
if (m_pScrollBarGripper && m_pHorizontalScrollBar && m_pVerticalScrollBar)
{
m_pScrollBarGripper->Arrange(CRect(szFinalSize.cx - m_pVerticalScrollBar->GetDesiredSize().cx, szFinalSize.cy - m_pHorizontalScrollBar->GetDesiredSize().cy, szFinalSize.cx, szFinalSize.cy));
}
CRect rcContent(0, 0, max(szViewport.cx, pContent->GetDesiredSize().cx), max(szViewport.cy, pContent->GetDesiredSize().cy));
rcContent.OffsetRect(-m_xOffset, -m_yOffset);
pContent->Arrange(rcContent);
return szFinalSize;
}
void CXTPMarkupScrollViewer::CreateScrollBar(int nBar)
{
if (nBar == SB_VERT && m_pVerticalScrollBar == NULL)
{
m_pVerticalScrollBar = (CXTPMarkupScrollBar*)m_pMarkupContext->CreateMarkupObject(MARKUP_TYPE(CXTPMarkupScrollBar));
m_pVerticalScrollBar->SetOrientation(xtpMarkupOrientationVertical);
m_pVerticalScrollBar->SetLogicalParent(this);
}
if (nBar == SB_HORZ && m_pHorizontalScrollBar == NULL)
{
m_pHorizontalScrollBar = (CXTPMarkupScrollBar*)m_pMarkupContext->CreateMarkupObject(MARKUP_TYPE(CXTPMarkupScrollBar));
m_pHorizontalScrollBar->SetOrientation(xtpMarkupOrientationHorizontal);
m_pHorizontalScrollBar->SetLogicalParent(this);
}
}
CSize CXTPMarkupScrollViewer::MeasureOverride(CXTPMarkupDrawingContext* pDC, CSize szAvailableSize)
{
CXTPMarkupUIElement* pContent = GetContent();
if (!pContent)
return CSize(0, 0);
CSize szScroll(0, 0);
XTPMarkupScrollBarVisibility verticalBarVisibility = GetVerticalScrollBarVisibility();
XTPMarkupScrollBarVisibility horizontalBarVisibility = GetHorizontalScrollBarVisibility();
CSize szViewportSize(INT_MAX, INT_MAX);
if (horizontalBarVisibility == xtpMarkupScrollBarDisabled) szViewportSize.cx = szAvailableSize.cx;
if (verticalBarVisibility == xtpMarkupScrollBarDisabled) szViewportSize.cy = szAvailableSize.cy;
if (verticalBarVisibility == xtpMarkupScrollBarAuto)
{
pContent->Measure(pDC, szViewportSize);
verticalBarVisibility = (pContent->GetDesiredSize().cy > szAvailableSize.cy) ? xtpMarkupScrollBarVisible : xtpMarkupScrollBarDisabled;
}
if (verticalBarVisibility == xtpMarkupScrollBarVisible)
{
CreateScrollBar(SB_VERT);
m_pVerticalScrollBar->Measure(pDC, szAvailableSize);
szScroll.cx = m_pVerticalScrollBar->GetDesiredSize().cx;
if (szViewportSize.cx != INT_MAX) szViewportSize.cx = max(0, szViewportSize.cx - szScroll.cx);
}
else
{
MARKUP_RELEASE(m_pVerticalScrollBar);
m_yOffset = 0;
}
if (horizontalBarVisibility == xtpMarkupScrollBarAuto)
{
pContent->Measure(pDC, szViewportSize);
horizontalBarVisibility = (pContent->GetDesiredSize().cx > szAvailableSize.cx - szScroll.cx) ? xtpMarkupScrollBarVisible : xtpMarkupScrollBarDisabled;
}
if (horizontalBarVisibility == xtpMarkupScrollBarVisible)
{
CreateScrollBar(SB_HORZ);
m_pHorizontalScrollBar->Measure(pDC, szAvailableSize);
szScroll.cy = m_pHorizontalScrollBar->GetDesiredSize().cy;
if (szViewportSize.cy != INT_MAX) szViewportSize.cy = max(0, szViewportSize.cy - szScroll.cy);
}
else
{
MARKUP_RELEASE(m_pHorizontalScrollBar);
m_xOffset = 0;
}
if (m_pVerticalScrollBar && m_pHorizontalScrollBar)
{
if (m_pScrollBarGripper == NULL)
{
m_pScrollBarGripper = (CXTPMarkupScrollBarGripper*)m_pMarkupContext->CreateMarkupObject(MARKUP_TYPE(CXTPMarkupScrollBarGripper));
m_pScrollBarGripper->SetLogicalParent(this);
}
}
else
{
MARKUP_RELEASE(m_pScrollBarGripper);
}
pContent->Measure(pDC, szViewportSize);
return CSize(min(szAvailableSize.cx, pContent->GetDesiredSize().cx + szScroll.cx), min(szAvailableSize.cy, pContent->GetDesiredSize().cy + szScroll.cy));
}
void CXTPMarkupScrollViewer::Scroll(int nBar, int nSBCode, int pos)
{
CXTPMarkupScrollBar* pScrollBar = nBar == SB_VERT ? m_pVerticalScrollBar : m_pHorizontalScrollBar;
if (!pScrollBar)
return;
SCROLLINFO si;
pScrollBar->GetScrollInfo(&si);
int nCurPos = si.nPos;
int nPage = (int)si.nPage;
int nLimit = max(0, si.nMax - max(nPage - 1, 0));
// decide what to do for each different scroll event
switch (nSBCode)
{
case SB_TOP:
nCurPos = 0;
break;
case SB_BOTTOM:
nCurPos = nLimit;
break;
case SB_LINEUP:
nCurPos = max(nCurPos - 16, 0);
break;
case SB_LINEDOWN:
nCurPos = min(nCurPos + 16, nLimit);
break;
case SB_PAGEUP:
nCurPos = max(nCurPos - nPage, 0);
break;
case SB_PAGEDOWN:
nCurPos = min(nCurPos + nPage, nLimit);
break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION:
nCurPos = pos;
break;
}
SetScrollPos(nBar, nCurPos);
}
int CXTPMarkupScrollViewer::GetScrollPos(int nBar)
{
return (nBar == SB_VERT) ? m_yOffset : m_xOffset;
}
int CXTPMarkupScrollViewer::GetScrollLimit(int nBar)
{
CXTPMarkupScrollBar* pScrollBar = nBar == SB_VERT ? m_pVerticalScrollBar : m_pHorizontalScrollBar;
if (!pScrollBar)
return 0;
SCROLLINFO si;
pScrollBar->GetScrollInfo(&si);
int nPage = (int)si.nPage;
int nLimit = max(0, si.nMax - max(nPage - 1, 0));
return nLimit;
}
void CXTPMarkupScrollViewer::SetScrollPos(int nBar, int pos)
{
int& nOffset = (nBar == SB_VERT) ? m_yOffset : m_xOffset;
if (!m_bNeverArranged && !m_bArrangeDirty)
{
int nLimit = GetScrollLimit(nBar);
if (pos > nLimit) pos = nLimit;
}
if (pos < 0) pos = 0;
if (nOffset != pos)
{
nOffset = pos;
InvalidateArrange();
}
}
void CXTPMarkupScrollViewer::OnMouseWheel(CXTPMarkupMouseWheelEventArgs* e)
{
SetScrollPos(SB_VERT, e->m_nDelta < 0 ? GetScrollPos(SB_VERT) + 48 : GetScrollPos(SB_VERT) - 48);
e->SetHandled();
}