650 lines
15 KiB
C++
650 lines
15 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved
|
|
|
|
#include "Private.h"
|
|
#include "Globals.h"
|
|
#include "BaseWindow.h"
|
|
#include "ScrollBarWindow.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CScrollBarWindowFactory class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
CScrollBarWindowFactory* CScrollBarWindowFactory::_instance;
|
|
|
|
CScrollBarWindowFactory::CScrollBarWindowFactory()
|
|
{
|
|
_instance = nullptr;
|
|
}
|
|
|
|
CScrollBarWindowFactory* CScrollBarWindowFactory::Instance()
|
|
{
|
|
if (nullptr == _instance)
|
|
{
|
|
_instance = new (std::nothrow) CScrollBarWindowFactory();
|
|
}
|
|
|
|
return _instance;
|
|
}
|
|
|
|
CScrollBarWindow* CScrollBarWindowFactory::MakeScrollBarWindow(SHELL_MODE shellMode)
|
|
{
|
|
CScrollBarWindow* pScrollBarWindow = nullptr;
|
|
|
|
switch (shellMode)
|
|
{
|
|
case STOREAPP:
|
|
pScrollBarWindow = new (std::nothrow) CScrollBarWindow();
|
|
break;
|
|
|
|
case DESKTOP:
|
|
pScrollBarWindow = new (std::nothrow) CScrollBarNullWindow();
|
|
break;
|
|
|
|
default:
|
|
pScrollBarWindow = new (std::nothrow) CScrollBarNullWindow();
|
|
break;
|
|
}
|
|
return pScrollBarWindow;
|
|
}
|
|
|
|
void CScrollBarWindowFactory::Release()
|
|
{
|
|
if (_instance)
|
|
{
|
|
delete _instance;
|
|
_instance = nullptr;
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CScrollBarWindow class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// ctor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CScrollBarWindow::CScrollBarWindow()
|
|
{
|
|
_pBtnUp = nullptr;
|
|
_pBtnDn = nullptr;
|
|
|
|
_scrollDir = SCROLL_NONE_DIR;
|
|
|
|
_sizeOfScrollBtn.cx = GetSystemMetrics(SM_CXVSCROLL) * 2;
|
|
_sizeOfScrollBtn.cy = GetSystemMetrics(SM_CYVSCROLL) * 2;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// dtor
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CScrollBarWindow::~CScrollBarWindow()
|
|
{
|
|
if (_pBtnUp)
|
|
{
|
|
delete _pBtnUp;
|
|
_pBtnUp = nullptr;
|
|
}
|
|
if (_pBtnDn)
|
|
{
|
|
delete _pBtnDn;
|
|
_pBtnDn = nullptr;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _Create
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CScrollBarWindow::_Create(ATOM atom, DWORD dwExStyle, DWORD dwStyle, CBaseWindow *pParent, int wndWidth, int wndHeight)
|
|
{
|
|
if (!CBaseWindow::_Create(atom, dwExStyle, dwStyle, pParent, wndWidth, wndHeight))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
_pBtnUp = new (std::nothrow) CScrollButtonWindow(dwStyle & WS_HSCROLL ? DFCS_SCROLLLEFT : DFCS_SCROLLUP);
|
|
if (_pBtnUp == nullptr)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
_pBtnUp->_Create(NULL, 0, 0, this);
|
|
_pBtnUp->_SetUIWnd(_GetUIWnd());
|
|
|
|
_pBtnDn = new (std::nothrow) CScrollButtonWindow(dwStyle & WS_HSCROLL ? DFCS_SCROLLRIGHT : DFCS_SCROLLDOWN);
|
|
if (_pBtnDn == nullptr)
|
|
{
|
|
delete _pBtnUp;
|
|
_pBtnUp = nullptr;
|
|
return FALSE;
|
|
}
|
|
|
|
_pBtnDn->_Create(NULL, 0, 0, this);
|
|
_pBtnDn->_SetUIWnd(_GetUIWnd());
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _WindowProcCallback
|
|
//
|
|
// Scrollbar window proc.
|
|
//----------------------------------------------------------------------------
|
|
|
|
LRESULT CALLBACK CScrollBarWindow::_WindowProcCallback(_In_ HWND wndHandle, _In_ UINT uMsg, _In_ WPARAM wParam, _In_ LPARAM lParam)
|
|
{
|
|
switch (uMsg)
|
|
{
|
|
case WM_PAINT:
|
|
{
|
|
HDC dcHandle = nullptr;
|
|
PAINTSTRUCT ps;
|
|
|
|
dcHandle = BeginPaint(wndHandle, &ps);
|
|
|
|
// paint itself at first
|
|
_OnPaint(dcHandle, &ps);
|
|
|
|
// paint all children
|
|
_pBtnUp->_OnPaint(dcHandle, &ps);
|
|
_pBtnDn->_OnPaint(dcHandle, &ps);
|
|
|
|
EndPaint(wndHandle, &ps);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
return DefWindowProc(wndHandle, uMsg, wParam, lParam);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _OnPaint
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_OnPaint(_In_ HDC dcHandle, _In_ PAINTSTRUCT *pps)
|
|
{
|
|
HBRUSH hBrush = nullptr;
|
|
CBaseWindow* pUIWnd = _GetUIWnd();
|
|
|
|
if (pUIWnd != nullptr && pUIWnd->_GetWnd())
|
|
{
|
|
hBrush = (HBRUSH)DefWindowProc(pUIWnd->_GetWnd(), WM_CTLCOLORSCROLLBAR, (WPARAM)dcHandle, (LPARAM)pUIWnd->_GetWnd());
|
|
}
|
|
|
|
if (hBrush == nullptr)
|
|
{
|
|
hBrush = GetSysColorBrush(COLOR_SCROLLBAR);
|
|
}
|
|
|
|
FillRect(dcHandle, &pps->rcPaint, hBrush);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _OnLButtonDown
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_OnLButtonDown(POINT pt)
|
|
{
|
|
_StartCapture();
|
|
|
|
RECT rc = {0, 0, 0, 0};
|
|
|
|
_pBtnUp->_GetClientRect(&rc);
|
|
if (PtInRect(&rc, pt))
|
|
{
|
|
_pBtnUp->_OnLButtonDown(pt);
|
|
}
|
|
else
|
|
{
|
|
_pBtnDn->_GetClientRect(&rc);
|
|
if (PtInRect(&rc, pt))
|
|
{
|
|
_pBtnDn->_OnLButtonDown(pt);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _OnLButtonUp
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_OnLButtonUp(POINT pt)
|
|
{
|
|
if (_IsCapture())
|
|
{
|
|
CBaseWindow* pUIWnd = _GetTopmostUIWnd();
|
|
if (pUIWnd)
|
|
{
|
|
CBaseWindow *pCapture = pUIWnd->_GetCaptureObject();
|
|
if (pCapture && pCapture != this)
|
|
{
|
|
pCapture->_OnLButtonUp(pt);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RECT rc = {0, 0, 0, 0};
|
|
|
|
_pBtnUp->_GetClientRect(&rc);
|
|
if (PtInRect(&rc, pt))
|
|
{
|
|
_pBtnUp->_OnLButtonUp(pt);
|
|
}
|
|
else
|
|
{
|
|
_pBtnDn->_GetClientRect(&rc);
|
|
if (PtInRect(&rc, pt))
|
|
{
|
|
_pBtnDn->_OnLButtonUp(pt);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (_IsCapture())
|
|
{
|
|
_EndCapture();
|
|
}
|
|
if (_IsTimer())
|
|
{
|
|
_EndTimer();
|
|
}
|
|
|
|
_scrollDir = SCROLL_NONE_DIR;
|
|
_InvalidateRect();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _OnMouseMove
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_OnMouseMove(POINT pt)
|
|
{
|
|
RECT rc = {0, 0, 0, 0};
|
|
|
|
_pBtnUp->_GetClientRect(&rc);
|
|
if (PtInRect(&rc, pt))
|
|
{
|
|
_pBtnUp->_OnMouseMove(pt);
|
|
}
|
|
else
|
|
{
|
|
_pBtnDn->_GetClientRect(&rc);
|
|
if (PtInRect(&rc, pt))
|
|
{
|
|
_pBtnDn->_OnMouseMove(pt);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _OnOwnerWndMoved
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_OnOwnerWndMoved(BOOL isResized)
|
|
{
|
|
isResized;
|
|
|
|
if (IsWindow(_GetWnd()) && IsWindowVisible(_GetWnd()))
|
|
{
|
|
_AdjustWindowPos();
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _Resize
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_Resize(int x, int y, int cx, int cy)
|
|
{
|
|
CBaseWindow::_Resize(x, y, cx, cy);
|
|
|
|
RECT rc = {0, 0, 0, 0};
|
|
|
|
_GetBtnUpRect(&rc);
|
|
_pBtnUp->_Resize(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top);
|
|
|
|
_GetBtnDnRect(&rc);
|
|
_pBtnDn->_Resize(rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _Show
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_Show(BOOL isShowWnd)
|
|
{
|
|
if (_IsWindowVisible() != isShowWnd)
|
|
{
|
|
CBaseWindow::_Show(isShowWnd);
|
|
|
|
_pBtnUp->_Show(isShowWnd);
|
|
_pBtnDn->_Show(isShowWnd);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _Enable
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_Enable(BOOL isEnable)
|
|
{
|
|
if (_IsEnabled() != isEnable)
|
|
{
|
|
CBaseWindow::_Enable(isEnable);
|
|
|
|
_pBtnUp->_Enable(isEnable);
|
|
_pBtnDn->_Enable(isEnable);
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _AdjustWindowPos
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_AdjustWindowPos()
|
|
{
|
|
if (!IsWindow(_GetWnd()))
|
|
{
|
|
return;
|
|
}
|
|
|
|
RECT rc = {0, 0, 0, 0};
|
|
CBaseWindow* pParent = _GetParent();
|
|
if (pParent == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
GetWindowRect(pParent->_GetWnd(), &rc);
|
|
SetWindowPos(_GetWnd(), pParent->_GetWnd(),
|
|
rc.left,
|
|
rc.top,
|
|
rc.right - rc.left,
|
|
rc.bottom - rc.top,
|
|
SWP_NOOWNERZORDER | SWP_NOACTIVATE);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _SetScrollInfo
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_SetScrollInfo(_In_ CScrollInfo *lpsi)
|
|
{
|
|
_scrollInfo = *lpsi;
|
|
|
|
BOOL isEnable = (_scrollInfo.nMax > _scrollInfo.nPage);
|
|
|
|
_Enable(isEnable);
|
|
|
|
_scrollDir = SCROLL_NONE_DIR;
|
|
|
|
_SetCurPos(_scrollInfo.nPos, -1);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetScrollInfo
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_GetScrollInfo(_Out_ CScrollInfo *lpsi)
|
|
{
|
|
*lpsi = _scrollInfo;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetBtnUpRect
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CScrollBarWindow::_GetBtnUpRect(_Out_ RECT *prc)
|
|
{
|
|
RECT rc = {0, 0, 0, 0};
|
|
|
|
_GetClientRect(&rc);
|
|
|
|
if (prc == nullptr)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
prc->left = rc.left;
|
|
prc->top = rc.top;
|
|
prc->right = rc.right;
|
|
prc->bottom = rc.top + min(_sizeOfScrollBtn.cy, (rc.bottom - rc.top)/2);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetBtnDnRect
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CScrollBarWindow::_GetBtnDnRect(_Out_ RECT *prc)
|
|
{
|
|
RECT rc = {0, 0, 0, 0};
|
|
|
|
_GetClientRect(&rc);
|
|
|
|
if (prc == nullptr)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
prc->left = rc.left;
|
|
prc->top = rc.bottom - min(_sizeOfScrollBtn.cy, (rc.bottom - rc.top)/2);
|
|
prc->right = rc.right;
|
|
prc->bottom = rc.bottom;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _GetScrollArea
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_GetScrollArea(_Out_ RECT *prc)
|
|
{
|
|
RECT rcBtnUp = {0, 0, 0, 0};
|
|
RECT rcBtnDn = {0, 0, 0, 0};
|
|
|
|
_GetBtnUpRect(&rcBtnUp);
|
|
_GetBtnDnRect(&rcBtnDn);
|
|
|
|
RECT rc = {0, 0, 0, 0};
|
|
|
|
_GetClientRect(&rc);
|
|
|
|
if (prc == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
prc->left = rc.left;
|
|
prc->top = rc.top + (rcBtnUp.bottom - rcBtnUp.top);
|
|
prc->right = rc.right;
|
|
prc->bottom = rc.bottom - (rcBtnDn.bottom - rcBtnDn.top);
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _SetCurPos
|
|
//
|
|
// param: dwSB - SB_xxx for WM_VSCROLL or WM_HSCROLL.
|
|
// if -1 is specified, function doesn't send WM_xSCROLL message
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollBarWindow::_SetCurPos(int nPos, int dwSB)
|
|
{
|
|
int posMax = (_scrollInfo.nMax <= _scrollInfo.nPage) ? 0 : _scrollInfo.nMax - _scrollInfo.nPage;
|
|
|
|
nPos = min(nPos, posMax);
|
|
nPos = max(nPos, 0);
|
|
|
|
_scrollInfo.nPos = nPos;
|
|
|
|
if (_IsWindowVisible()) {
|
|
_InvalidateRect();
|
|
}
|
|
|
|
if ((_IsCapture() && dwSB != -1) || (dwSB == SB_THUMBPOSITION))
|
|
{
|
|
_NotifyCommand(WM_VSCROLL, dwSB, nPos);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CScrollButtonWindow class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _OnPaint
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollButtonWindow::_OnPaint(_In_ HDC dcHandle, _In_ PAINTSTRUCT *pps)
|
|
{
|
|
pps;
|
|
|
|
RECT rc = {0, 0, 0, 0};
|
|
|
|
_GetClientRect(&rc);
|
|
|
|
DrawFrameControl(dcHandle, &rc, DFC_SCROLL, subTypeOfControl | typeOfControl | (!_IsEnabled() ? DFCS_INACTIVE : 0));
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _OnLButtonDown
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollButtonWindow::_OnLButtonDown(POINT pt)
|
|
{
|
|
CButtonWindow::_OnLButtonDown(pt);
|
|
|
|
CScrollBarWindow* pParent = (CScrollBarWindow*)_GetParent(); // more secure w/ dynamic_cast
|
|
if (pParent == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch (subTypeOfControl)
|
|
{
|
|
case DFCS_SCROLLDOWN:
|
|
_NotifyCommand(WM_VSCROLL, SB_LINEDOWN, 0);
|
|
pParent->_ShiftLine(+1, FALSE);
|
|
break;
|
|
case DFCS_SCROLLUP:
|
|
_NotifyCommand(WM_VSCROLL, SB_LINEUP, 0);
|
|
pParent->_ShiftLine(-1, FALSE);
|
|
break;
|
|
}
|
|
|
|
_StartTimer(_GetScrollDelay());
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _OnLButtonUp
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollButtonWindow::_OnLButtonUp(POINT pt)
|
|
{
|
|
CButtonWindow::_OnLButtonUp(pt);
|
|
|
|
_InvalidateRect();
|
|
|
|
if (_IsTimer())
|
|
{
|
|
_EndTimer();
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// _OnTimer : Speed up page Down/Up while holding Down/Up Button
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CScrollButtonWindow::_OnTimer()
|
|
{
|
|
POINT pt = {0, 0};
|
|
CScrollBarWindow* pParent = (CScrollBarWindow*)_GetParent(); // more secure w/ dynamic_cast
|
|
if (pParent == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// start another faster timer
|
|
_StartTimer(_GetScrollSpeed());
|
|
|
|
GetCursorPos(&pt);
|
|
MapWindowPoints(HWND_DESKTOP, pParent->_GetWnd(), &pt, 1);
|
|
|
|
RECT rc = {0, 0, 0, 0};
|
|
|
|
_GetClientRect(&rc);
|
|
|
|
if (PtInRect(&rc, pt))
|
|
{
|
|
switch (subTypeOfControl)
|
|
{
|
|
case DFCS_SCROLLDOWN:
|
|
_NotifyCommand(WM_VSCROLL, SB_LINEDOWN, 0);
|
|
pParent->_ShiftLine(+1, FALSE);
|
|
break;
|
|
case DFCS_SCROLLUP:
|
|
_NotifyCommand(WM_VSCROLL, SB_LINEUP, 0);
|
|
pParent->_ShiftLine(-1, FALSE);
|
|
break;
|
|
}
|
|
}
|
|
} |