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

