2025-11-28 00:35:46 +09:00

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;
}
}
}