This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Tools/W3DView/Toolbar.cpp

514 lines
13 KiB
C++
Raw Permalink Normal View History

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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/>.
*/
//////////////////////////////////////////////////////////////////////
//
// Toolbar.CPP
//
// Implementation of a 'fancy' toolbar using hi-color buttons
//
#include "stdafx.h"
#include "Toolbar.H"
BEGIN_MESSAGE_MAP(CFancyToolbar, CControlBar)
//{{AFX_MSG_MAP(CFancyToolbar)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////
//
// Local Constants
//
const TCHAR * const TOOLBAR_CLASS_NAME = TEXT ("FANCYTOOLBAR");
//////////////////////////////////////////////////////////////
//
// CFancyToolbar
//
CFancyToolbar::CFancyToolbar (void)
: m_iButtons (0),
m_iCurrentButton (-1)
{
// Ensure that the toolbar window class is registered
RegisterFancyToolbarClass ();
::memset (m_pButtonArray, 0, sizeof (m_pButtonArray));
return ;
}
//////////////////////////////////////////////////////////////
//
// ~CFancyToolbar
//
CFancyToolbar::~CFancyToolbar (void)
{
for (int iButton = 0; iButton < m_iButtons; iButton ++)
{
if (m_pButtonArray[iButton].hBMPUp)
{
// Free the BMP for this button
::DeleteObject (m_pButtonArray[iButton].hBMPUp);
m_pButtonArray[iButton].hBMPUp = NULL;
}
if (m_pButtonArray[iButton].hBMPDn)
{
// Free the BMP for this button
::DeleteObject (m_pButtonArray[iButton].hBMPDn);
m_pButtonArray[iButton].hBMPDn = NULL;
}
}
return ;
}
//////////////////////////////////////////////////////////////
//
// RegisterFancyToolbarClass
//
void
CFancyToolbar::RegisterFancyToolbarClass (void)
{
// Is this class already registered?
WNDCLASS classInfo = { 0 };
if (::GetClassInfo (::AfxGetInstanceHandle (),
TOOLBAR_CLASS_NAME,
&classInfo) != TRUE)
{
classInfo.style = CS_PARENTDC;
classInfo.lpfnWndProc = ::DefWindowProc;
classInfo.hInstance = ::AfxGetInstanceHandle ();
classInfo.hCursor = ::LoadCursor (NULL, IDC_ARROW);
classInfo.hbrBackground = (HBRUSH)COLOR_BTNFACE;
classInfo.lpszClassName = TOOLBAR_CLASS_NAME;
// Register the class with windows
::RegisterClass (&classInfo);
}
return ;
}
//////////////////////////////////////////////////////////////
//
// Create
//
void
CFancyToolbar::OnPaint ()
{
Paint ();
return ;
}
//////////////////////////////////////////////////////////////
//
// Create
//
BOOL
CFancyToolbar::Create
(
LPCTSTR pszWindowName,
CWnd *pCParentWnd,
UINT uiID
)
{
// Create the toolbar window using our own special window class
RECT rect = { 0 };
BOOL bReturn = CWnd::Create (TOOLBAR_CLASS_NAME, pszWindowName, WS_CHILD | WS_VISIBLE, rect, pCParentWnd, uiID);
// Were we successful?
ASSERT (bReturn);
if (bReturn)
{
// Set the bar style, but don't allow docking
SetBarStyle (GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
EnableDocking (CBRS_ALIGN_ANY);
}
// Return the TRUE/FALSE result code
return bReturn;
}
//////////////////////////////////////////////////////////////
//
// DrawButton
//
void
CFancyToolbar::DrawButton
(
HDC hDC,
int iXPos,
int iYPos,
HBITMAP hBMP
)
{
// Create a screen-compatible DC
HDC hMemDC = ::CreateCompatibleDC (hDC);
if (hMemDC)
{
// Select the BMP to paint into the DC
HBITMAP hOldBMP = (HBITMAP)::SelectObject (hMemDC, hBMP);
// Paint the BMP in its slot
::BitBlt (hDC, iXPos, iYPos, BUTTON_WIDTH, BUTTON_HEIGHT, hMemDC, 0, 0, SRCCOPY);
// Select the old BMP back into the DC and free the DC
::SelectObject (hMemDC, hOldBMP);
DeleteDC (hMemDC);
}
return ;
}
//////////////////////////////////////////////////////////////
//
// AddButton
//
void
CFancyToolbar::AddButton
(
UINT iBMPUp,
UINT iBMPDn,
int iCommandID,
BUTTON_TYPE buttonType
)
{
// Increment the button count
int iButton = m_iButtons ++;
// Fill in the internal button structure for this entry
m_pButtonArray[iButton].hBMPUp = ::LoadBitmap (::AfxGetResourceHandle (), MAKEINTRESOURCE (iBMPUp));
m_pButtonArray[iButton].hBMPDn = ::LoadBitmap (::AfxGetResourceHandle (), MAKEINTRESOURCE (iBMPDn));
m_pButtonArray[iButton].iCommandID = iCommandID;
m_pButtonArray[iButton].buttonType = buttonType;
m_pButtonArray[iButton].currentState = StateUp;
m_pButtonArray[iButton].bVisible = TRUE;
return ;
}
//////////////////////////////////////////////////////////////
//
// Paint
//
void
CFancyToolbar::Paint (void)
{
// Get the window's DC
HDC hDC = ::GetDC (m_hWnd);
if (hDC)
{
// Get the bounding rectangle of the window
RECT rect;
::GetClientRect (m_hWnd, &rect);
// Paint the background light gray
HBRUSH hBrush = ::CreateSolidBrush (RGB (192, 192, 192));
::FillRect (hDC, &rect, hBrush);
::DeleteObject (hBrush);
// Loop through each button and paint it
int iXPos = BORDER_LEFT;
for (int iButton = 0; iButton < m_iButtons; iButton ++)
{
// Is this button visible?
if (m_pButtonArray[iButton].bVisible)
{
// Determine which BMP to use
HBITMAP hBMP = m_pButtonArray[iButton].hBMPUp;
if (m_pButtonArray[iButton].currentState == StateDn)
{
hBMP = m_pButtonArray[iButton].hBMPDn;
}
// Draw this button
DrawButton (hDC,
iXPos,
((rect.bottom-rect.top) >> 1) - BUTTON_MIDDLE,
hBMP);
// Increment the current x position
iXPos += BUTTON_WIDTH;
}
}
// Free the windows DC
::ReleaseDC (m_hWnd, hDC);
}
// Let the window know its done painting
::ValidateRect (m_hWnd, NULL);
return ;
}
//////////////////////////////////////////////////////////////
//
// ButtonFromPoint
//
int
CFancyToolbar::ButtonFromPoint (const CPoint &point)
{
int iIndex = -1;
// Loop through all the buttons until we've found the
// one we're looking for
int iXPos = BORDER_LEFT;
for (int iButton = 0; (iButton < m_iButtons) && (iIndex == -1); iButton ++)
{
// Is this the button we're looking for?
if (m_pButtonArray[iButton].bVisible &&
(point.x >= iXPos) && (point.x <= iXPos + BUTTON_WIDTH) &&
(point.y >= BORDER_TOP) && (point.y <= BORDER_TOP+BUTTON_HEIGHT))
{
// Yup, this is the button we're looking for
iIndex = iButton;
}
// Increment the current position
iXPos += BUTTON_WIDTH;
}
// Return the zero based index of the button we're looking for
return iIndex;
}
//////////////////////////////////////////////////////////////
//
// HandleLButtonUp
//
void
CFancyToolbar::OnLButtonDown
(
UINT nFlags,
CPoint point
)
{
// Determine which button was clicked
int iButton = ButtonFromPoint (point);
if (iButton >= 0)
{
// Flip the button state
m_pButtonArray[iButton].currentState = (STATE_INFO)!m_pButtonArray[iButton].currentState;
// Determine which BMP to paint
HBITMAP hBMP = m_pButtonArray[iButton].hBMPUp;
if (m_pButtonArray[iButton].currentState == StateDn)
{
hBMP = m_pButtonArray[iButton].hBMPDn;
}
// Get the DC for the window
HDC hDC = ::GetDC (m_hWnd);
if (hDC)
{
// Get the bounding rectangle for the window
RECT rect;
::GetClientRect (m_hWnd, &rect);
// Draw the selected button
DrawButton (hDC,
BORDER_LEFT + iButton*BUTTON_WIDTH,
((rect.bottom-rect.top) >> 1) - BUTTON_MIDDLE,
hBMP);
// Release the window's DC
::ReleaseDC (m_hWnd, hDC);
}
// Is this a 'normal' or 2 state button?
if (m_pButtonArray[iButton].buttonType == TypeNormal)
{
// Normal button, so trap all mouse message so if the user
// lets up the mouse button outside the button rectangle we don't do anything
m_iCurrentButton = iButton;
::SetCapture (m_hWnd);
}
else
{
// 2 state button
m_iCurrentButton = -1;
// Send the message to the window's parent to let them know a command has occured
::AfxGetMainWnd ()->PostMessage (WM_COMMAND,
MAKELONG (m_pButtonArray[iButton].iCommandID, BN_CLICKED),
(LPARAM)m_hWnd);
}
}
else
{
CControlBar::OnLButtonDown (nFlags, point);
}
return ;
}
//////////////////////////////////////////////////////////////
//
// HandleLButtonUp
//
void
CFancyToolbar::OnLButtonUp
(
UINT nFlags,
CPoint point
)
{
// Were we currently processing a button?
if (m_iCurrentButton >= 0)
{
// Which button were we processing?
int iButton = ButtonFromPoint (point);
if (iButton == m_iCurrentButton)
{
// Fire a command to the parent
::AfxGetMainWnd ()->PostMessage (WM_COMMAND,
MAKELONG (m_pButtonArray[iButton].iCommandID, BN_CLICKED),
(LPARAM)m_hWnd);
}
// Reset the button state
m_pButtonArray[m_iCurrentButton].currentState = StateUp;
// Get the window's DC
HDC hDC = ::GetDC (m_hWnd);
if (hDC)
{
// Get the bounding rectangle of the window
RECT rect;
::GetClientRect (m_hWnd, &rect);
// Paint the button
DrawButton (hDC,
BORDER_LEFT + m_iCurrentButton*BUTTON_WIDTH,
((rect.bottom-rect.top) >> 1) - BUTTON_MIDDLE,
m_pButtonArray[m_iCurrentButton].hBMPUp);
// Free the window's DC
::ReleaseDC (m_hWnd, hDC);
}
// Let go of the mouse capture
::ReleaseCapture ();
}
else
{
CControlBar::OnLButtonUp (nFlags, point);
}
return ;
}
//////////////////////////////////////////////////////////////
//
// OnDraw
//
void
CFancyToolbar::OnDraw (CDC* pDC)
{
return ;
}
//////////////////////////////////////////////////////////////
//
// PreCreateWindow
//
BOOL
CFancyToolbar::PreCreateWindow (CREATESTRUCT& cs)
{
// Allow the base class to process this message
return CControlBar::PreCreateWindow (cs);
}
//////////////////////////////////////////////////////////////
//
// SetButtonState
//
void
CFancyToolbar::SetButtonState
(
int iCommandID,
STATE_INFO newState,
BOOL bRepaint
)
{
BOOL bFound = FALSE;
// Loop through all the buttons until we've found the one we're looking for
for (int iButton = 0;
(iButton < m_iButtons) && (bFound == FALSE);
iButton ++)
{
if (m_pButtonArray[iButton].iCommandID == iCommandID)
{
// Set the new state
m_pButtonArray[iButton].currentState = newState;
if (bRepaint)
{
// Repaint the toolbar
//Paint ();
InvalidateRect (NULL);
UpdateWindow ();
}
// Found it!
bFound = TRUE;
}
}
return ;
}
//////////////////////////////////////////////////////////////
//
// GetButtonState
//
CFancyToolbar::STATE_INFO
CFancyToolbar::GetButtonState (int iCommandID) const
{
STATE_INFO stateInfo = StateUp;
// Loop through all the buttons until we've found the one we're looking for
BOOL bFound = FALSE;
for (int iButton = 0;
(iButton < m_iButtons) && (bFound == FALSE);
iButton ++)
{
if (m_pButtonArray[iButton].iCommandID == iCommandID)
{
// Return the current state to the caller
stateInfo = m_pButtonArray[iButton].currentState;
// Found it!
bFound = TRUE;
}
}
// Return the state of the requested button
return stateInfo;
}