/*
** Command & Conquer Generals Zero Hour(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 .
*/
////////////////////////////////////////////////////////////////////////////////
// //
// (c) 2001-2003 Electronic Arts Inc. //
// //
////////////////////////////////////////////////////////////////////////////////
// FILE: RadioButton.cpp //////////////////////////////////////////////////////
//-----------------------------------------------------------------------------
//
// Westwood Studios Pacific.
//
// Confidential Information
// Copyright (C) 2001 - All Rights Reserved
//
//-----------------------------------------------------------------------------
//
// Project: RTS3
//
// File name: \projects\RTS\code\gameengine\Source\GameClient\GUI\Gadget\GadgetTabControl.cpp
//
// Created: Graham Smallwood, November 2001
//
// Desc: Tab Set GUI control
//
//-----------------------------------------------------------------------------
///////////////////////////////////////////////////////////////////////////////
// SYSTEM INCLUDES ////////////////////////////////////////////////////////////
#include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
// USER INCLUDES //////////////////////////////////////////////////////////////
#include "Common/Language.h"
#include "Gameclient/GameWindowManager.h"
#include "GameClient/Gadget.h"
#include "GameClient/GadgetTabControl.h"
// DEFINES ////////////////////////////////////////////////////////////////////
// PRIVATE TYPES //////////////////////////////////////////////////////////////
// PRIVATE DATA ///////////////////////////////////////////////////////////////
// PUBLIC DATA ////////////////////////////////////////////////////////////////
// PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
// GadgetTabControlInput =====================================================
/** Handle input for TabControl */
//=============================================================================
WindowMsgHandledType GadgetTabControlInput( GameWindow *tabControl, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
// WinInstanceData *instData = tabControl->winGetInstanceData();
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
Int tabX, tabY;
tabControl->winGetScreenPosition( &tabX, &tabY );
Int mouseX = LOLONGTOSHORT(mData1) - tabX;//mData1 is packedMouseCoords in screen space
Int mouseY = HILONGTOSHORT(mData1) - tabY;
Int tabsLeft = tabData->tabsLeftLimit;
Int tabsRight = tabData->tabsRightLimit;
Int tabsBottom = tabData->tabsBottomLimit;
Int tabsTop = tabData->tabsTopLimit;
switch( msg )
{
case GWM_LEFT_DOWN:
{
if( (mouseX < tabsLeft)
|| (mouseX > tabsRight)
|| (mouseY < tabsTop)
|| (mouseY > tabsBottom)
)
{//I eat input on myself that isn't a tab (a button click would mean I don't see the input ever.)
return MSG_HANDLED;
}
Int distanceIn;
Int tabSize;
if( (tabData->tabEdge == TP_RIGHT_SIDE) || (tabData->tabEdge == TP_LEFT_SIDE) )
{//scan down to find which button
distanceIn = mouseY - tabsTop;
tabSize = tabData->tabHeight;
}
else
{//scan right to find which button
distanceIn = mouseX - tabsLeft;
tabSize = tabData->tabWidth;
}
Int tabPressed = distanceIn / tabSize;
if( ! tabData->subPaneDisabled[tabPressed] && (tabPressed != tabData->activeTab) )
GadgetTabControlShowSubPane( tabControl, tabPressed );
}
default:
{
return MSG_IGNORED;
}
}
return MSG_HANDLED;
} // end GadgetTabControlInput
// GadgetTabControlSystem ====================================================
/** Handle system messages for TabControl */
//=============================================================================
WindowMsgHandledType GadgetTabControlSystem( GameWindow *tabControl, UnsignedInt msg,
WindowMsgData mData1, WindowMsgData mData2 )
{
switch( msg )
{
// ------------------------------------------------------------------------
case GWM_CREATE:
break;
// ------------------------------------------------------------------------
case GWM_DESTROY:
{
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
// free tab control user data
delete tabData;
break;
} // end destroy
case GGM_RESIZED:
{//On resize, we need to upkeep the pane sizes and tabs since they are bound to us
GadgetTabControlResizeSubPanes( tabControl );
GadgetTabControlComputeTabRegion( tabControl );
break;
}
case GBM_SELECTED:
{//Pass buttons messages up
GameWindow *parent = tabControl->winGetParent();
if( parent )
return TheWindowManager->winSendSystemMsg( parent, msg, mData1, mData2 );
}
default:
return MSG_IGNORED;
} // end switch( msg )
return MSG_HANDLED;
} // end GadgetTabControlSystem
void GadgetTabControlComputeTabRegion( GameWindow *tabControl )///< Recalc the tab positions based on userData
{
Int winWidth, winHeight;
tabControl->winGetSize( &winWidth, &winHeight );
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
Int horzOffset = 0, vertOffset = 0;
if( (tabData->tabEdge == TP_TOP_SIDE) || (tabData->tabEdge == TP_BOTTOM_SIDE) )
{
if( tabData->tabOrientation == TP_CENTER )
{
horzOffset = winWidth - ( 2 * tabData->paneBorder ) - ( tabData->tabCount * tabData->tabWidth );
horzOffset /= 2;
}
else if( tabData->tabOrientation == TP_BOTTOMRIGHT )
{
horzOffset = winWidth - ( 2 * tabData->paneBorder ) - ( tabData->tabCount * tabData->tabWidth );
}
else if( tabData->tabOrientation == TP_TOPLEFT )
{
horzOffset = 0;
}
}
else
{
if( tabData->tabOrientation == TP_CENTER )
{
vertOffset = winHeight - ( 2 * tabData->paneBorder ) - ( tabData->tabCount * tabData->tabHeight );
vertOffset /= 2;
}
else if( tabData->tabOrientation == TP_BOTTOMRIGHT )
{
vertOffset = winHeight - ( 2 * tabData->paneBorder ) - ( tabData->tabCount * tabData->tabHeight );
}
else if( tabData->tabOrientation == TP_TOPLEFT )
{
vertOffset = 0;
}
}
if( tabData->tabEdge == TP_TOP_SIDE )
{
tabData->tabsTopLimit = tabData->paneBorder;
tabData->tabsBottomLimit = tabData->paneBorder + tabData->tabHeight;
tabData->tabsLeftLimit = tabData->paneBorder + horzOffset;
tabData->tabsRightLimit = tabData->paneBorder + horzOffset + ( tabData->tabWidth * tabData->tabCount );
}
else if( tabData->tabEdge == TP_BOTTOM_SIDE )
{
tabData->tabsTopLimit = winHeight - tabData->paneBorder - tabData->tabHeight;
tabData->tabsBottomLimit = winHeight - tabData->paneBorder;
tabData->tabsLeftLimit = tabData->paneBorder + horzOffset;
tabData->tabsRightLimit = tabData->paneBorder + horzOffset + ( tabData->tabWidth * tabData->tabCount );
}
else if( tabData->tabEdge == TP_RIGHT_SIDE )
{
tabData->tabsLeftLimit = winWidth - tabData->paneBorder - tabData->tabWidth;
tabData->tabsRightLimit = winWidth - tabData->paneBorder;
tabData->tabsTopLimit = tabData->paneBorder + vertOffset;
tabData->tabsBottomLimit = tabData->paneBorder + vertOffset + ( tabData->tabHeight * tabData->tabCount );
}
else if( tabData->tabEdge == TP_LEFT_SIDE )
{
tabData->tabsLeftLimit = tabData->paneBorder;
tabData->tabsRightLimit = tabData->paneBorder + tabData->tabWidth;
tabData->tabsTopLimit = tabData->paneBorder + vertOffset;
tabData->tabsBottomLimit = tabData->paneBorder + vertOffset + ( tabData->tabHeight * tabData->tabCount );
}
}
void GadgetTabControlComputeSubPaneSize( GameWindow *tabControl, Int *width, Int *height, Int *x, Int *y )
{
Int winWidth, winHeight;
tabControl->winGetSize( &winWidth, &winHeight );
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
if( (tabData->tabEdge == TP_TOP_SIDE) || (tabData->tabEdge == TP_BOTTOM_SIDE) )
*height = winHeight - (2 * tabData->paneBorder) - tabData->tabHeight;
else
*height = winHeight - (2 * tabData->paneBorder);
if( (tabData->tabEdge == TP_LEFT_SIDE) || (tabData->tabEdge == TP_RIGHT_SIDE) )
*width = winWidth - (2 * tabData->paneBorder) - tabData->tabWidth;
else
*width = winWidth - (2 * tabData->paneBorder);
if( tabData->tabEdge == TP_LEFT_SIDE )
*x = tabData->paneBorder + tabData->tabWidth;
else
*x = tabData->paneBorder;
if( tabData->tabEdge == TP_TOP_SIDE )
*y = tabData->paneBorder + tabData->tabHeight;
else
*y = tabData->paneBorder;
}
void GadgetTabControlShowSubPane( GameWindow *tabControl, Int whichPane)
{
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
for( Int paneIndex = 0; paneIndex < NUM_TAB_PANES; paneIndex++ )
{
if( tabData->subPanes[paneIndex] != NULL )
tabData->subPanes[paneIndex]->winHide( true );
}
if( tabData->subPanes[whichPane] )
tabData->activeTab = whichPane;
else
tabData->activeTab = 0;
tabData->activeTab = min( tabData->activeTab, tabData->tabCount - 1 );
tabData->subPanes[tabData->activeTab]->winHide( false );
}
void GadgetTabControlCreateSubPanes( GameWindow *tabControl )///< Create User Windows attached to userData as Panes
{//These two funcs are called after all the Editor set data is updated
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
Int width, height, x, y;
GadgetTabControlComputeSubPaneSize(tabControl, &width, &height, &x, &y);
for( Int paneIndex = 0; paneIndex < NUM_TAB_PANES; paneIndex++ )
{
if( (tabData->subPanes[paneIndex] == NULL) )//This one is blank
{
tabData->subPanes[paneIndex] = TheWindowManager->winCreate( tabControl,
WIN_STATUS_NONE, x, y,
width, height,
PassSelectedButtonsToParentSystem,
NULL);
WinInstanceData *instData = tabData->subPanes[paneIndex]->winGetInstanceData();
BitSet( instData->m_style, GWS_TAB_PANE );
char buffer[20];
sprintf( buffer, "Pane %d", paneIndex );
instData->m_decoratedNameString = buffer;
//set enabled status to that of Parent
tabData->subPanes[paneIndex]->winEnable( BitTest(tabControl->winGetStatus(), WIN_STATUS_ENABLED) );
}
else//this one exists, tabCount will control keeping extra panes perma-hidden
{
tabData->subPanes[paneIndex]->winSetSize( width, height );
tabData->subPanes[paneIndex]->winSetPosition( x, y );
}
}
GadgetTabControlShowSubPane( tabControl, tabData->activeTab );
}
void GadgetTabControlResizeSubPanes( GameWindow *tabControl )
{
TabControlData *tabData = (TabControlData *)tabControl->winGetUserData();
Int width, height, x, y;
GadgetTabControlComputeSubPaneSize(tabControl, &width, &height, &x, &y);
for( Int paneIndex = 0; paneIndex < NUM_TAB_PANES; paneIndex++ )
{
if( tabData->subPanes[paneIndex] )
{
tabData->subPanes[paneIndex]->winSetSize( width, height );
tabData->subPanes[paneIndex]->winSetPosition( x, y );
}
}
}
///winGetUserData();
GameWindow *child = tabControl->winGetChild();
if( child )
{//need to write down children, and they are reversed from our array
while( child->winGetNext() != NULL )
{
child = child->winGetNext();
}
while( child )
{
tabData->subPanes[childIndex] = child;
childIndex++;
child = child->winGetPrev();
}
}
}