Files
2026-02-02 04:50:13 +01:00

287 lines
6.5 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(CButton, CWnd)
BEGIN_MESSAGE_MAP(CButton, CWnd)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_MESSAGE(BM_CLICK, CButton::OnBnClicked)
ON_MESSAGE(BM_SETCHECK, CButton::OnBnSetCheck)
END_MESSAGE_MAP()
bool CButton::Create(const char *lpszCaption, uint32 dwStyle,
const RECT &rect, CWnd *pParentWnd, unsigned int nID) {
return CWnd::Create("BUTTON", lpszCaption, dwStyle, rect,
pParentWnd, nID);
}
int CButton::GetCheck() const {
return (_itemState & ODS_CHECKED) != 0 ?
BST_CHECKED : BST_UNCHECKED;
}
void CButton::SetCheck(int nCheck) {
SendMessage(BM_SETCHECK, nCheck);
}
void CButton::SetButtonStyle(unsigned int nStyle, bool bRedraw) {
m_nStyle = (m_nStyle & ~0xf) | nStyle;
Invalidate();
}
unsigned int CButton::GetButtonStyle() const {
return GetStyle() & 0xf;
}
void CButton::OnPaint() {
switch (GetButtonStyle()) {
case BS_PUSHBUTTON:
case BS_DEFPUSHBUTTON:
OnPushButtonPaint();
break;
case BS_PUSHBOX:
OnPushBoxPaint();
break;
case BS_OWNERDRAW:
OnOwnerDrawPaint();
break;
default: {
// Fallback for unhandled button types
RECT clientRect;
GetClientRect(&clientRect);
CPaintDC dc(this);
dc.FillSolidRect(&clientRect, RGB(255, 255, 255));
break;
}
}
}
void CButton::OnPushButtonPaint() {
CPaintDC dc(this);
// Get the client rectangle of the window
CRect rect;
GetClientRect(&rect);
// Determine state
bool isEnabled = IsWindowEnabled();
// Choose background color based on state
COLORREF bgColor = isEnabled ? RGB(240, 240, 240) : RGB(200, 200, 200);
dc.FillSolidRect(rect, bgColor);
if (_pressed) {
dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT);
} else {
dc.DrawEdge(&rect, EDGE_RAISED, BF_RECT);
}
// Draw text
CString text;
GetWindowText(text);
dc.SetBkMode(TRANSPARENT);
dc.DrawText(text, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
void CButton::OnPushBoxPaint() {
CPaintDC dc(this);
CRect rect;
GetClientRect(&rect);
// Choose colors
COLORREF clrFace = GetSysColor(COLOR_BTNFACE);
COLORREF clrHighlight = GetSysColor(COLOR_BTNHIGHLIGHT); // Top/left
COLORREF clrShadow = GetSysColor(COLOR_BTNSHADOW); // Bottom/right
COLORREF clrText = GetSysColor(COLOR_BTNTEXT);
// Fill background
dc.FillSolidRect(rect, clrFace);
// Draw 3D border
if (_pressed) {
// Inset border (pressed look)
dc.Draw3dRect(rect, clrShadow, clrHighlight);
rect.DeflateRect(1, 1);
dc.Draw3dRect(rect, clrShadow, clrHighlight);
} else {
// Raised border (normal look)
dc.Draw3dRect(rect, clrHighlight, clrShadow);
rect.DeflateRect(1, 1);
dc.Draw3dRect(rect, clrHighlight, clrShadow);
}
// Adjust text position if pressed
CPoint offset = _pressed ? CPoint(1, 1) : CPoint(0, 0);
// Draw button text
dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(clrText);
dc.SelectObject(GetStockObject(SYSTEM_FONT));
CRect textRect = rect;
textRect.OffsetRect(offset);
dc.DrawText(_windowText, &textRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
// Draw focus rectangle
if (_hasFocus) {
CRect focusRect = rect;
focusRect.DeflateRect(3, 3);
dc.DrawFocusRect(&focusRect);
}
}
void CButton::OnOwnerDrawPaint() {
// Prepare the draw item struct
DRAWITEMSTRUCT dis = { 0, 0, 0, 0, 0, 0, 0, { 0, 0, 0, 0 }, 0 };
dis.CtlType = ODT_BUTTON;
dis.CtlID = GetDlgCtrlID();
dis.itemID = 0;
dis.itemAction = ODA_DRAWENTIRE;
dis.itemState = 0;
if (IsWindowEnabled())
dis.itemState |= ODS_ENABLED;
else
dis.itemState |= ODS_DISABLED;
if ((GetState() & ODS_CHECKED) != 0 || _pressed)
dis.itemState |= ODS_SELECTED;
if (GetFocus() == this)
dis.itemState |= ODS_FOCUS;
dis.hwndItem = m_hWnd;
// Get the client rect for the button
GetClientRect(&dis.rcItem);
// Get a DC for drawing
PAINTSTRUCT paintStruct;
HDC hdc = BeginPaint(&paintStruct);
dis.hDC = hdc;
// Send WM_DRAWITEM to the parent window
GetParent()->SendMessage(WM_DRAWITEM,
dis.CtlID, (LPARAM)&dis);
EndPaint(&paintStruct);
}
void CButton::OnLButtonDown(unsigned int nFlags, CPoint point) {
if (!(_itemState & ODS_DISABLED)) {
SetCapture();
_pressed = true;
Invalidate();
}
}
void CButton::OnLButtonUp(unsigned int nFlags, CPoint point) {
if (GetCapture() == this)
ReleaseCapture();
if (!_pressed)
return;
_pressed = false;
// Redraw the button immediately, before we trigger any actions
Invalidate();
UpdateWindow();
switch (GetButtonStyle()) {
case BS_PUSHBUTTON:
case BS_DEFPUSHBUTTON:
case BS_PUSHBOX:
case BS_OWNERDRAW:
SendMessage(BM_CLICK);
break;
case BS_CHECKBOX:
SetCheck(_itemState & BST_CHECKED ?
BST_CHECKED : BST_UNCHECKED);
SendMessage(BM_SETCHECK, _itemState & BST_CHECKED);
break;
case BS_AUTORADIOBUTTON:
SetCheck(BST_CHECKED);
SendMessage(BM_SETCHECK, BST_CHECKED);
break;
default:
error("Unhandled button type");
break;
}
}
void CButton::OnMouseMove(unsigned int nFlags, CPoint point) {
if (GetCapture() == this) {
if (_pressed != PointInClientRect(point)) {
_pressed = !_pressed;
Invalidate();
}
}
}
LRESULT CButton::OnBnClicked(WPARAM wParam, LPARAM lParam) {
GetParent()->SendMessage(WM_COMMAND, GetDlgCtrlID(),
MAKELPARAM(0, BN_CLICKED));
return 0;
}
LRESULT CButton::OnBnSetCheck(WPARAM wParam, LPARAM lParam) {
if (wParam == BST_UNCHECKED) {
// Uncheck the button
_itemState &= ~BST_CHECKED;
} else {
// Check the button
_itemState |= BST_CHECKED;
// Need to clear all of the others
CWnd *pParent = GetParent();
CWnd *pWnd = this;
for (;;) {
pWnd = pParent->GetNextDlgGroupItem(pWnd, true);
if (pWnd == this)
// No more to do
break;
pWnd->SendMessage(BM_SETCHECK, false);
}
}
Invalidate();
return 0;
}
} // namespace MFC
} // namespace Bagel