Files
scummvm-cursorfix/engines/bagel/mfc/scrollbar.cpp
2026-02-02 04:50:13 +01:00

246 lines
6.3 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/textconsole.h"
#include "bagel/mfc/afxwin.h"
namespace Bagel {
namespace MFC {
IMPLEMENT_DYNAMIC(CScrollBar, CWnd)
BEGIN_MESSAGE_MAP(CScrollBar, CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_MOUSELEAVE()
END_MESSAGE_MAP()
bool CScrollBar::Create(uint32 dwStyle, const RECT &rect, CWnd *pParentWnd, unsigned int nID) {
return CWnd::Create("SCROLLBAR", nullptr, dwStyle,
rect, pParentWnd, nID);
}
int CScrollBar::GetScrollPos() const {
return _value;
}
int CScrollBar::SetScrollPos(int nPos, bool bRedraw) {
int oldPos = _value;
_value = CLIP(nPos, _minValue, _maxValue);
Invalidate();
return oldPos;
}
void CScrollBar::GetScrollRange(int *lpMinPos, int *lpMaxPos) const {
if (lpMinPos)
*lpMinPos = _minValue;
if (lpMaxPos)
*lpMaxPos = _maxValue;
}
void CScrollBar::SetScrollRange(int nMinPos, int nMaxPos, bool bRedraw) {
_minValue = nMinPos;
_maxValue = nMaxPos;
_pageSize = MAX<int>((_maxValue - _minValue + 1) / 10, 1);
Invalidate();
}
bool CScrollBar::SetScrollInfo(LPSCROLLINFO lpScrollInfo, bool bRedraw) {
assert(lpScrollInfo->cbSize == sizeof(SCROLLINFO));
_minValue = lpScrollInfo->nMin;
_maxValue = lpScrollInfo->nMax;
_pageSize = lpScrollInfo->nPage;
_value = lpScrollInfo->nPos;
if (bRedraw)
Invalidate();
return true;
}
void CScrollBar::ShowScrollBar(bool bShow) {
warning("TODO: CScrollBar::ShowScrollBar");
}
void CScrollBar::OnPaint() {
CPaintDC dc(this);
CRect clientRect;
GetClientRect(&clientRect);
const int thumbSize = clientRect.bottom;
// Clear background and draw border edge
dc.FillSolidRect(&clientRect, RGB(211, 211, 211));
CBrush borderBrush(RGB(0, 0, 0));
dc.FrameRect(&clientRect, &borderBrush);
CRect left(0, 0, thumbSize, clientRect.bottom);
drawSquare(dc, left);
drawArrow(dc, left, true);
CRect right(clientRect.right - thumbSize, 0,
clientRect.right, clientRect.bottom);
drawSquare(dc, right);
drawArrow(dc, right, false);
drawSquare(dc, getThumbRect());
}
void CScrollBar::drawSquare(CPaintDC &dc, const CRect &r) {
CBrush black(RGB(0, 0, 0));
dc.FrameRect(&r, &black);
CBrush darkGrey(RGB(169, 169, 169));
CBrush white(RGB(255, 255, 255));
CBrush *oldBrush = dc.SelectObject(&darkGrey);
dc.MoveTo(r.left + 2, r.bottom - 3);
dc.LineTo(r.right - 2, r.bottom - 3);
dc.MoveTo(r.left + 1, r.bottom - 2);
dc.LineTo(r.right - 2, r.bottom - 2);
dc.MoveTo(r.right - 3, r.top + 1);
dc.LineTo(r.right - 3, r.bottom - 2);
dc.MoveTo(r.right - 2, r.top + 1);
dc.LineTo(r.right - 2, r.bottom - 2);
dc.MoveTo(r.left + 1, r.top + 1);
dc.LineTo(r.right - 3, r.top + 1);
dc.MoveTo(r.left + 1, r.top + 1);
dc.MoveTo(r.left + 1, r.bottom - 3);
dc.SelectObject(oldBrush);
}
void CScrollBar::drawArrow(CPaintDC &dc, const CRect &r, bool leftArrow) {
int xCenter = (r.left + r.right) / 2;
int yCenter = r.bottom / 2;
int xDelta = leftArrow ? 1 : -1;
int x = leftArrow ? xCenter - 3 : xCenter + 3;
CBrush black(RGB(0, 0, 0));
CBrush *oldBrush = dc.SelectObject(&black);
for (int xCtr = 0; xCtr < 7; ++xCtr, x += xDelta) {
int yDiff = (xCtr >= 4) ? 1 : xCtr;
dc.MoveTo(x, yCenter - yDiff);
dc.LineTo(x, yCenter + yDiff);
}
dc.SelectObject(oldBrush);
}
CRect CScrollBar::getThumbRect() const {
CRect clientRect;
GetClientRect(&clientRect);
// The thumb will start after the left arrow button,
// and at most, it will be drawn before the right arrow
int slideArea = clientRect.right -
(clientRect.bottom * 3) + 1;
int xStart = clientRect.bottom +
slideArea * (_value - _minValue) /
(_maxValue - _minValue);
return CRect(xStart, 0, xStart + clientRect.bottom,
clientRect.bottom);
}
int CScrollBar::getIndexFromX(int xp) const {
CRect clientRect;
GetClientRect(&clientRect);
int slideStart = clientRect.bottom;
int slideFinish = clientRect.right - (clientRect.bottom * 2) + 1;
int slideArea = clientRect.right - (clientRect.bottom * 3) + 1;
if (xp < slideStart)
return _minValue;
if (xp >= slideFinish)
return _maxValue;
return _minValue + (xp - slideStart)
* (_maxValue - _minValue) / slideArea;
}
void CScrollBar::OnLButtonDown(unsigned int nFlags, CPoint point) {
CRect clientRect;
GetClientRect(&clientRect);
if (point.x < clientRect.bottom) {
// Left arrow button
if (_value > _minValue) {
SetScrollPos(_value - 1);
scrollEvent(SB_LINELEFT);
}
} else if (point.x >= (clientRect.right - clientRect.bottom)) {
// Right arrow button
if (_value < _maxValue) {
SetScrollPos(_value + 1);
scrollEvent(SB_LINERIGHT);
}
} else {
// We're in the slider area
CRect thumbRect = getThumbRect();
if (point.x < thumbRect.left) {
// Left of thumb, page left
SetScrollPos(_value - _pageSize);
scrollEvent(SB_PAGELEFT);
} else if (point.x >= thumbRect.right) {
// Right of thumb, page right
SetScrollPos(_value + _pageSize);
scrollEvent(SB_PAGERIGHT);
} else {
// Directly on thumb, so start dragging it
SetScrollPos(getIndexFromX(point.x));
SetCapture();
scrollEvent(SB_THUMBTRACK);
}
}
}
void CScrollBar::OnLButtonUp(unsigned int nFlags, CPoint point) {
if (GetCapture() == m_hWnd) {
ReleaseCapture();
scrollEvent(SB_THUMBPOSITION);
}
scrollEvent(SB_ENDSCROLL);
}
void CScrollBar::OnMouseMove(unsigned int, CPoint point) {
if (GetCapture() == m_hWnd) {
SetScrollPos(getIndexFromX(point.x));
scrollEvent(SB_THUMBTRACK);
}
}
void CScrollBar::scrollEvent(int action) {
m_pParentWnd->SendMessage(WM_HSCROLL,
MAKEWPARAM(action, _value),
(LPARAM)m_hWnd);
}
} // namespace MFC
} // namespace Bagel