/*
**	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/>.
*/

/***********************************************************************************************
 ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : Combat																		  *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/wwui/tabctrl.cpp           $*
 *                                                                                             *
 *                       Author:: Patrick Smith                                                *
 *                                                                                             *
 *                     $Modtime:: 9/19/01 11:30a                                              $*
 *                                                                                             *
 *                    $Revision:: 17                                                          $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

// Disable warning about exception handling not being enabled. It's used as part of STL - in a part of STL we don't use.
#pragma warning(disable : 4530)

#include "tabctrl.h"
#include "assetmgr.h"
#include "refcount.h"
#include "mousemgr.h"
#include "dialogmgr.h"
#include "dialogbase.h"
#include "stylemgr.h"
#include "texture.h"
#include "ww3d.h"
#include "font3d.h"
#include "childdialog.h"



////////////////////////////////////////////////////////////////
//	Local constants
////////////////////////////////////////////////////////////////
static const RectClass	BarUVs				(1, 1, 26, 255);
static const RectClass	SelUVs				(28, 1, 254, 69);
static const RectClass	UnfocusUVs			(28, 236, 42, 250);
static const RectClass	FocusUVs				(43, 236, 57, 250);

static const RectClass	BarTopUVs			(1, 1, 26, 79);
static const RectClass	BarBottomUVs		(1, 169, 26, 255);
static const RectClass	BarTileUVs			(1, 80, 26, 168);

static const float		BUBBLE_OFFSET_X	= 23;
static const float		BUBBLE_OFFSET_Y	= 25;
static const float		BAR_OFFSET			= 25;
static const float		TEXT_OFFSET			= 60;
static const float		SEL_TEXT_OFFSET	= 75;
static const float		TEXT_RADIUS			= 40;
static const float		ANGLE_MIN			= 115;
static const float		ANGLE_MAX			= 245;
static const float		BLINK_DELAY			= 500;
static const float		PAGE_AREA_OFFSET	= 245;
static const float		PIXELS_PER_SEC		= 500;


////////////////////////////////////////////////////////////////
//
//	TabCtrlClass
//
////////////////////////////////////////////////////////////////
TabCtrlClass::TabCtrlClass (void)	:
	CurrTabIndex (0),
	NextBlinkTime (0),
	SelectorPos (0),
	SelRect (0, 0, 0, 0),
	ScaleX (0),
	ScaleY (0),
	IsBubbleDisplayed (false)
{
	//
	//	Determine what scale to use
	//
	ScaleX = Render2DClass::Get_Screen_Resolution().Width () / 800;
	ScaleY = Render2DClass::Get_Screen_Resolution().Height () / 600;

	//
	//	Assign the font to the text renderers
	//
	StyleMgrClass::Assign_Font (&TextRenderer,			StyleMgrClass::FONT_HEADER);
	StyleMgrClass::Assign_Font (&GlowRenderer,			StyleMgrClass::FONT_HEADER);
	StyleMgrClass::Assign_Font (&HilightRenderer,		StyleMgrClass::FONT_BIG_HEADER);
	StyleMgrClass::Assign_Font (&HilightGlowRenderer,	StyleMgrClass::FONT_BIG_HEADER);

	//
	//	Configure the renderers
	//
	StyleMgrClass::Configure_Renderer (&ControlRenderer);

	//
	//	Load the texture for the control
	//
	TextureClass *texture = WW3DAssetManager::Get_Instance ()->Get_Texture ("IF_MENUPARTS9.TGA", TextureClass::MIP_LEVELS_1);
	ControlRenderer.Set_Texture (texture);
	REF_PTR_RELEASE (texture);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	~TabCtrlClass
//
////////////////////////////////////////////////////////////////
TabCtrlClass::~TabCtrlClass (void)
{
	Free_Tabs ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Create_Text_Renderer
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::Create_Text_Renderer (void)
{
	//
	//	Reset the renderers
	//
	GlowRenderer.Reset ();
	TextRenderer.Reset ();
	HilightRenderer.Reset ();
	HilightGlowRenderer.Reset ();

	float text_left	= ClientRect.Left + (TEXT_OFFSET * ScaleX);
	float height		= ClientRect.Height ();
	float tab_height	= height / max (TabList.Count (), 1);

	//
	//	Setup some variables we can use to simulate a semi-circle for the text
	//
	float angle_min	= DEG_TO_RADF (ANGLE_MIN);
	float angle_max	= DEG_TO_RADF (ANGLE_MAX);
	float radius		= TEXT_RADIUS * ScaleX;

	//
	//	Render the tab names
	//
	float y_pos = ClientRect.Top;
	for (int index = 0; index < TabList.Count (); index ++) {

		//
		//	Calculate a "semi-circular" x-offset for the text
		//
		float angle = angle_min + ((angle_max - angle_min) * ((float)index / float(TabList.Count()-1)));
		float x_offset = WWMath::Cos (angle) * radius;

		//
		//	Calculate what rectangle to render to
		//
		RectClass text_rect;
		text_rect.Left		= (int)(text_left + (radius + x_offset));
		text_rect.Top		= (int)y_pos;
		text_rect.Right	= (int)ClientRect.Right;
		text_rect.Bottom	= int(y_pos + tab_height);

		//
		//	Get the title from the child dialog
		//
		WideStringClass title;
		TabList[index]->Get_Title (&title);

		//
		//	Is this the selected tab?
		//
		if (index == CurrTabIndex) {

			//
			//	Move the hilighted text in a bit
			//
			text_rect.Left = SelRect.Left + (SEL_TEXT_OFFSET * ScaleX);

			//
			//	Render the hilighted text and its glow
			//
			HilightRenderer.Build_Sentence (title);
			HilightGlowRenderer.Build_Sentence (title);
			//StyleMgrClass::Render_Text (title, &HilightRenderer, text_rect, true, true);

			StyleMgrClass::Render_Text (title, &HilightRenderer,
									StyleMgrClass::Get_Tab_Text_Color (),
									StyleMgrClass::Get_Text_Shadow_Color (),
									text_rect, true, true);

				/*HilightRenderer.Set_Clipping_Rect (text_rect);

				//
				//	Get the extents of the text we will be drawing
				//
				Vector2 text_extent = HilightRenderer.Get_Text_Extents (title);

				//
				//	Assume left justification
				//
				int x_pos = text_rect.Left + 1;
				int y_pos = int(text_rect.Top + (text_rect.Height () / 2) - (text_extent.Y / 2));

				//
				//	Construct the textures needed to render the text
				//
				HilightRenderer.Build_Sentence (title);

				HilightRenderer.Set_Location (Vector2 (x_pos - 1, y_pos - 1));
				HilightRenderer.Draw_Sentence (RGB_TO_INT32 (255, 255, 255));

				HilightRenderer.Set_Location (Vector2 (x_pos + 1, y_pos + 1));
				HilightRenderer.Draw_Sentence (RGB_TO_INT32 (0, 0, 0));

				//
				//	Render the text
				//
				HilightRenderer.Set_Location (Vector2 (x_pos, y_pos));
				HilightRenderer.Draw_Sentence (RGB_TO_INT32 (147, 155, 153));*/


			StyleMgrClass::Render_Glow (title, &HilightGlowRenderer, text_rect, 7, 7,
									StyleMgrClass::Get_Tab_Glow_Color ());

		} else {
			
			//
			//	Render the text and its glow
			//
			TextRenderer.Build_Sentence (title);
			GlowRenderer.Build_Sentence (title);
			StyleMgrClass::Render_Text (title, &TextRenderer,
									StyleMgrClass::Get_Tab_Text_Color (),
									StyleMgrClass::Get_Text_Shadow_Color (),
									text_rect, true, true);

				/*TextRenderer.Set_Clipping_Rect (text_rect);

				//
				//	Get the extents of the text we will be drawing
				//
				Vector2 text_extent = TextRenderer.Get_Text_Extents (title);

				//
				//	Assume left justification
				//
				int x_pos = text_rect.Left + 1;
				int y_pos = int(text_rect.Top + (text_rect.Height () / 2) - (text_extent.Y / 2));

				//
				//	Construct the textures needed to render the text
				//
				TextRenderer.Build_Sentence (title);

				TextRenderer.Set_Location (Vector2 (x_pos - 1, y_pos - 1));
				TextRenderer.Draw_Sentence (RGB_TO_INT32 (255, 255, 255));

				TextRenderer.Set_Location (Vector2 (x_pos + 1, y_pos + 1));
				TextRenderer.Draw_Sentence (RGB_TO_INT32 (0, 0, 0));

				//
				//	Render the text
				//
				TextRenderer.Set_Location (Vector2 (x_pos, y_pos));
				TextRenderer.Draw_Sentence (RGB_TO_INT32 (147, 155, 153));*/

			
			StyleMgrClass::Render_Glow (title, &GlowRenderer, text_rect, 4, 4,
									StyleMgrClass::Get_Tab_Glow_Color ());
		}

		//
		//	Move down to the next tab
		//
		y_pos += tab_height;
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Create_Control_Renderer
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::Create_Control_Renderer (void)
{
	Render2DClass &renderer = ControlRenderer;
	renderer.Reset ();	

	//
	//	Determine which UVs to use for the bubble
	//
	RectClass bubble_uvs = UnfocusUVs;
	if (IsBubbleDisplayed) {
		bubble_uvs = FocusUVs;
	}

	//
	//	Scale the dimensions of the components
	//
	float bar_tile_height	= BarTileUVs.Height () * ScaleY;
	float bar_tip_height		= BarTopUVs.Height () * ScaleY;
	float bar_width			= BarTileUVs.Width () * ScaleX;
	float sel_width			= SelUVs.Width () * ScaleX;
	float sel_height			= SelUVs.Height () * ScaleY;
	float bubble_width		= bubble_uvs.Width () * ScaleX;
	float bubble_height		= bubble_uvs.Height () * ScaleX;

	//
	//	Setup some variables we can use to simulate a semi-circle for the text
	//
	float angle_min	= DEG_TO_RADF (ANGLE_MIN);
	float angle_max	= DEG_TO_RADF (ANGLE_MAX);
	float radius		= TEXT_RADIUS * ScaleX;
	float min_y			= Pos_From_Tab (0);
	float max_y			= Pos_From_Tab (TabList.Count () - 1);
	float percent		= (SelectorPos - min_y) / (max_y - min_y);
	float angle			= angle_min + percent * (angle_max - angle_min);
	//float left_pos		= -radius;
	float x_offset		= radius + (WWMath::Cos (angle) * radius);

	//
	//	Calculate the screen rectangle for the bar
	//
	RectClass bar_rect;	
	bar_rect.Left		= int(ClientRect.Left + x_offset + (BAR_OFFSET * ScaleX) - (bar_width / 2));
	bar_rect.Right		= int(bar_rect.Left + bar_width);
	bar_rect.Top		= int(ClientRect.Top - (x_offset * 1.5F));
	bar_rect.Bottom	= int(ClientRect.Bottom + (x_offset * 1.5F));

	//
	//	Calculate the screen rectangle for the selector
	//
	SelRect.Left	= int(ClientRect.Left + x_offset);
	SelRect.Right	= int(SelRect.Left + sel_width);
	SelRect.Top		= int(SelectorPos - (sel_height / 2));
	SelRect.Bottom	= int(SelRect.Top + sel_height);

	//
	//	Calculate the screen rectangle for the bubble
	//
	RectClass bubble_rect;
	bubble_rect.Left		= int(SelRect.Left + BUBBLE_OFFSET_X * ScaleX);
	bubble_rect.Right		= int(bubble_rect.Left + bubble_width);
	bubble_rect.Top		= int(SelRect.Top + BUBBLE_OFFSET_Y * ScaleY);
	bubble_rect.Bottom	= int(bubble_rect.Top + bubble_height);

	//
	//	Normalize the UVs
	//
	RectClass sel_uvs				= SelUVs;
	RectClass bar_top_uvs		= BarTopUVs;
	RectClass bar_bottom_uvs	= BarBottomUVs;
	sel_uvs.Inverse_Scale (Vector2 (256, 256));
	bar_top_uvs.Inverse_Scale (Vector2 (256, 256));
	bar_bottom_uvs.Inverse_Scale (Vector2 (256, 256));
	bubble_uvs.Inverse_Scale (Vector2 (256, 256));

	//
	//	Render the bar top and bottom
	//
	RectClass bar_top_rect;
	bar_top_rect.Left		= int(bar_rect.Left);
	bar_top_rect.Right	= int(bar_rect.Right);
	bar_top_rect.Top		= int(bar_rect.Top);
	bar_top_rect.Bottom	= int(bar_top_rect.Top + bar_tip_height);
	
	RectClass bar_bottom_rect;
	bar_bottom_rect.Left		= int(bar_rect.Left);
	bar_bottom_rect.Right	= int(bar_rect.Right);
	bar_bottom_rect.Top		= int(bar_rect.Bottom - bar_tip_height);
	bar_bottom_rect.Bottom	= int(bar_rect.Bottom);
	
	renderer.Add_Quad (bar_top_rect, bar_top_uvs);
	renderer.Add_Quad (bar_bottom_rect, bar_bottom_uvs);

	//
	//	Tile the remaining pieces
	//
	float y_pos				= bar_top_rect.Bottom;
	float total_height	= bar_bottom_rect.Top - y_pos;
	while (total_height > 0) {
		
		float height = min (bar_tile_height, total_height);

		//
		//	Setup the UV rectangle
		//
		RectClass uvs	= BarTileUVs;
		uvs.Bottom		= uvs.Top + height;
		uvs.Inverse_Scale (Vector2 (256, 256));

		//
		//	Setup the screen rectangle
		//
		RectClass bar_tile_rect = bar_rect;
		bar_tile_rect.Top			= y_pos;
		bar_tile_rect.Bottom		= y_pos + height;

		//
		//	Render the section
		//
		renderer.Add_Quad (bar_tile_rect, uvs);
		
		y_pos				+= height;
		total_height	-= height;		
	}
	
	//
	//	Render the bar and selector
	//
	renderer.Add_Quad (SelRect, sel_uvs);
	renderer.Add_Quad (bubble_rect, bubble_uvs);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	On_Set_Cursor
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::On_Set_Cursor (const Vector2 &mouse_pos)
{
	//
	//	Change the mouse cursor
	//
	if (mouse_pos.X < (ClientRect.Left + PAGE_AREA_OFFSET * ScaleX)) {
		MouseMgrClass::Set_Cursor (MouseMgrClass::CURSOR_ACTION);
	} else {
		MouseMgrClass::Set_Cursor (MouseMgrClass::CURSOR_ARROW);
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Update_Client_Rect
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::Update_Client_Rect (void)
{
	//
	//	Set the client area
	//
	ClientRect = Rect;
	Set_Dirty ();

	//
	//	Resize each child dialog so it fits in the new rectangle
	//
	for (int index = 0; index < TabList.Count (); index ++) {
		RectClass rect;
		rect.Left	= (int)(ClientRect.Left + PAGE_AREA_OFFSET * ScaleX);
		rect.Top		= (int)ClientRect.Top;
		rect.Right	= (int)ClientRect.Right;
		rect.Bottom	= (int)ClientRect.Bottom;
		TabList[index]->Set_Rect (rect);
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Render
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::Render (void)
{
	Update_Selector ();
	Update_Bubble ();	

	//
	//	Recreate the renderers (if necessary)
	//
	if (IsDirty) {		
		Create_Control_Renderer ();
		Create_Text_Renderer ();		
	}

	//
	//	Render the background and text
	//
	GlowRenderer.Render ();
	HilightGlowRenderer.Render ();
	TextRenderer.Render ();
	HilightRenderer.Render ();
	ControlRenderer.Render ();

	DialogControlClass::Render ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	On_LButton_Down
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::On_LButton_Down (const Vector2 &mouse_pos)
{
	//
	//	Change tabs
	//
	if (mouse_pos.X < (ClientRect.Left + PAGE_AREA_OFFSET * ScaleX)) {
		Set_Curr_Tab (Tab_From_Pos (mouse_pos));
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	On_LButton_Up
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::On_LButton_Up (const Vector2 &mouse_pos)
{
	return ;
}


////////////////////////////////////////////////////////////////
//
//	On_Mouse_Move
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::On_Mouse_Move (const Vector2 &mouse_pos)
{
	return ;
}


////////////////////////////////////////////////////////////////
//
//	On_Set_Focus
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::On_Set_Focus (void)
{
	Set_Dirty ();

	DialogControlClass::On_Set_Focus ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	On_Kill_Focus
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::On_Kill_Focus (DialogControlClass *focus)
{
	Set_Dirty ();	

	DialogControlClass::On_Kill_Focus (focus);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	On_Key_Down
//
////////////////////////////////////////////////////////////////
bool
TabCtrlClass::On_Key_Down (uint32 key_id, uint32 key_data)
{
	bool handled = true;

	switch (key_id)
	{
		case VK_UP:
		case VK_LEFT:
			Set_Curr_Tab (CurrTabIndex - 1);
			break;

		case VK_DOWN:
		case VK_RIGHT:
			Set_Curr_Tab (CurrTabIndex + 1);
			break;

		case VK_HOME:
			Set_Curr_Tab (0);
			break;

		case VK_END:
			Set_Curr_Tab (TabList.Count () - 1);
			break;

		default:
			handled = false;
			break;
	}

	return handled;
}


////////////////////////////////////////////////////////////////
//
//	On_Create
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::On_Create (void)
{
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Tab_From_Pos
//
////////////////////////////////////////////////////////////////
int
TabCtrlClass::Tab_From_Pos (const Vector2 &mouse_pos)
{
	int retval = -1;

	float height		= ClientRect.Height ();
	float tab_height	= height / max (TabList.Count (), 1);

	//
	//	Check each of the tabs
	//
	float y_pos = ClientRect.Top;
	for (int index = 0; index < TabList.Count (); index ++) {

		//
		//	Is the mouse over this tab?
		//
		if (mouse_pos.Y >= y_pos && mouse_pos.Y <= (y_pos + tab_height)) {
			retval = index;
			break;
		}

		//
		//	Move down to the next tab
		//
		y_pos += tab_height;
	}

	return retval;
}


////////////////////////////////////////////////////////////////
//
//	Pos_From_Tab
//
////////////////////////////////////////////////////////////////
float
TabCtrlClass::Pos_From_Tab (int index)
{	
	float height		= ClientRect.Height ();
	float tab_height	= height / max (TabList.Count (), 1);

	//
	//	Return the centered y-position
	//
	return ClientRect.Top + (tab_height * (index + 1)) - (tab_height / 2);
}


////////////////////////////////////////////////////////////////
//
//	Set_Curr_Tab
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::Set_Curr_Tab (int index)
{
	//
	//	Bound the index
	//
	index = min (TabList.Count () - 1, index);
	index = max (0, index);	

	//
	//	Did we change tabs?
	//
	if (CurrTabIndex != index) {
		
		//
		//	Switch tabs visibly
		//
		TabList[CurrTabIndex]->Show (false);
		TabList[index]->Show (true);

		//
		//	Change the tab and force a repaint
		//
		CurrTabIndex = index;		
		Set_Dirty ();
	}

	return ;	
}


////////////////////////////////////////////////////////////////
//
//	Update_Bubble
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::Update_Bubble (void)
{
	if (HasFocus) {
		
		//
		//	Is it time to blink the bubble light?
		//
		int curr_time = DialogMgrClass::Get_Time ();
		if (curr_time > NextBlinkTime) {
			
			//
			//	Toggle the bubble light
			//
			IsBubbleDisplayed = !IsBubbleDisplayed;
			NextBlinkTime		= curr_time + BLINK_DELAY;
			
			//
			//	Force a repaint
			//
			Set_Dirty ();
		}

	} else {
		IsBubbleDisplayed = false;
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Update_Selector
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::Update_Selector (void)
{
	//
	//	Exit early if there's nothing to do
	//
	float end_pos = Pos_From_Tab (CurrTabIndex);
	if (SelectorPos == end_pos) {
		return ;
	}

	//
	//	Calculate the rate the selector moves
	//
	float rate = PIXELS_PER_SEC * ScaleY;

	//
	//	Calculate how far we need to move
	//
	float time		= DialogMgrClass::Get_Frame_Time () / 1000.0F;
	float dist		= rate * time;

	//
	//	Move the selector
	//
	if (SelectorPos < end_pos) {
		SelectorPos += dist;
		SelectorPos = min (end_pos, SelectorPos);
		Set_Dirty ();
	} else if (SelectorPos > end_pos) {
		SelectorPos -= dist;
		SelectorPos = max (end_pos, SelectorPos);
		Set_Dirty ();
	}

	//
	//	Bound the selector position
	//
	SelectorPos = min (Pos_From_Tab (TabList.Count () - 1), SelectorPos);
	SelectorPos = max (Pos_From_Tab (0), SelectorPos);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Add_Tab
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::Add_Tab (ChildDialogClass *dialog)
{
	if (dialog == NULL) {
		return ;
	}

	//
	//	Start the dialog
	//
	dialog->Show (TabList.Count () == 0);
	dialog->Start_Dialog ();
	Parent->Add_Child_Dialog (dialog);

	//
	//	Size the child so it fits perfectly in the
	// page area.
	//
	RectClass rect;
	rect.Left	= (int)(ClientRect.Left + PAGE_AREA_OFFSET * ScaleX);
	rect.Top		= (int)ClientRect.Top;
	rect.Right	= (int)ClientRect.Right;
	rect.Bottom	= (int)ClientRect.Bottom;
	dialog->Set_Rect (rect);	

	//
	//	Add this dialog to our list
	//
	dialog->Add_Ref ();
	TabList.Add (dialog);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Remove_Tab
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::Remove_Tab (int index)
{
	if (index < 0 || index >= TabList.Count ()) {
		return ;
	}

	//
	//	Remove this dialog from our list
	//
	Parent->Remove_Child_Dialog (TabList[index]);
	TabList[index]->End_Dialog ();
	REF_PTR_RELEASE (TabList[index]);
	TabList.Delete (index);
	return ;
}


////////////////////////////////////////////////////////////////
//
//	Free_Tabs
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::Free_Tabs (void)
{
	//
	//	Release our hold on each tab
	//
	for (int index = 0; index < TabList.Count (); index ++) {
		REF_PTR_RELEASE (TabList[index]);
	}

	TabList.Delete_All ();
	return ;
}


////////////////////////////////////////////////////////////////
//
//	On_Mouse_Wheel
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::On_Mouse_Wheel (int direction)
{
	if (direction < 0) {
		Set_Curr_Tab (CurrTabIndex - 1);
	} else {
		Set_Curr_Tab (CurrTabIndex + 1);
	}

	return ;
}


////////////////////////////////////////////////////////////////
//
//	Apply_Changes_On_Tabs
//
////////////////////////////////////////////////////////////////
bool
TabCtrlClass::Apply_Changes_On_Tabs (void)
{
	bool retval = true;

	//
	//	Get each tab to apply their changes
	//
	for (int index = 0; retval && index < TabList.Count (); index ++) {
		retval &= TabList[index]->On_Apply ();
	}

	return retval;
}


////////////////////////////////////////////////////////////////
//
//	Discard_Changes_On_Tabs
//
////////////////////////////////////////////////////////////////
bool
TabCtrlClass::Discard_Changes_On_Tabs (void)
{
	bool retval = true;

	//
	//	Get each tab to discard their changes
	//
	for (int index = 0; retval && index < TabList.Count (); index ++) {
		retval &= TabList[index]->On_Discard ();
	}

	return retval;
}


////////////////////////////////////////////////////////////////
//
//	Reload_Tabs
//
////////////////////////////////////////////////////////////////
void
TabCtrlClass::Reload_Tabs (void)
{
	//
	//	Get each tab to discard their changes
	//
	for (int index = 0; index < TabList.Count (); index ++) {
		TabList[index]->On_Reload ();
	}

	return ;
}
