/*
**	Command & Conquer Red Alert(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/>.
*/

/* $Header: /CounterStrike/GAUGE.CPP 1     3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
 ***              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 : Command & Conquer                                            *
 *                                                                                             *
 *                    File Name : GAUGE.CPP                                                    *
 *                                                                                             *
 *                   Programmer : Joe L. Bostic, Maria del Mar McCready Legg                   *
 *                                                                                             *
 *                   Start Date : 01/15/95                                                     *
 *                                                                                             *
 *                  Last Update : January 16, 1995 [JLB]                                       *
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 *   GaugeClass::Action -- Handles input events for the gauge.                                 *
 *   GaugeClass::Draw_Me -- Draws the body of the gauge.                                       *
 *   GaugeClass::Pixel_To_Value -- Convert a pixel offset into a gauge value.                  *
 *   GaugeClass::Set_Maximum -- Sets the maximum value for the gauge.                          *
 *   GaugeClass::Set_Value -- Set the value of the gauge.                                      *
 *   GaugeClass::Value_To_Pixel -- Convert gauge value to pixel offset.                        *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include	"function.h"


/***************************************************************************
 * GaugeClass::GaugeClass -- class constructor                             *
 *                                                                         *
 * INPUT:    id                     -- button ID                           *
 *                                                                         *
 *             x,y                     -- upper-left corner, in pixels     *
 *                                                                         *
 *             w,h                     -- width, height, in pixels         *
 *                                                                         *
 * OUTPUT:   none.                                                         *
 *                                                                         *
 * WARNINGS: none.                                                         *
 *                                                                         *
 * HISTORY:  01/05/1995 MML : Created.                                     *
 *=========================================================================*/
GaugeClass::GaugeClass(unsigned id, int x, int y, int w, int h)
	: ControlClass(id, x, y, w, h, LEFTHELD|LEFTPRESS|LEFTRELEASE, true)
{
	Set_Maximum(255);
	Set_Value(0);

	HasThumb = true;
	IsHorizontal = (w > h);
	IsColorized = true;

	ClickDiff = 0;
}


/***********************************************************************************************
 * GaugeClass::Set_Maximum -- Sets the maximum value for the gauge.                            *
 *                                                                                             *
 *    This routine will set the maximum value for the gauge. This is the largest value that    *
 *    the current setting may reach. The ability to change this allows the gauge to use and    *
 *    return values that are convenient for the programmer's current needs.                    *
 *                                                                                             *
 * INPUT:   value -- The value to use as the gauge maximum.                                    *
 *                                                                                             *
 * OUTPUT:  bool; Was the gauge maximum changed? A false indicates that the specified value    *
 *                already matches the current maximum.                                         *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/16/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
int GaugeClass::Set_Maximum(int value)
{
	if (value != MaxValue) {
	   MaxValue = value;
		Flag_To_Redraw();
		return(true);
	}
	return(false);
}


/***********************************************************************************************
 * GaugeClass::Set_Value -- Set the value of the gauge.                                        *
 *                                                                                             *
 *    This routine will set the current value for the gauge. This value is clipped to the      *
 *    limits of the gauge maximum.                                                             *
 *                                                                                             *
 * INPUT:   value -- The value to set at the new current value.                                *
 *                                                                                             *
 * OUTPUT:  bool; Was the current setting changed? A false indicates that the setting          *
 *                specified is the same as what was already there.                             *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/16/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
int GaugeClass::Set_Value(int value)
{
	value = Bound(value, 0, MaxValue);
	if (value != CurValue) {
		CurValue = value;
		Flag_To_Redraw();
		return(true);
	}
	return(false);
}


/***********************************************************************************************
 * GaugeClass::Pixel_To_Value -- Convert a pixel offset into a gauge value.                    *
 *                                                                                             *
 *    Use this routine to convert the specified pixel offset into a gauge value. This is used   *
 *    in translating mouse clicks into a corresponding setting for the gauge.                  *
 *                                                                                             *
 * INPUT:   pixel -- The pixel offset form the start of the gauge.                             *
 *                                                                                             *
 * OUTPUT:  Returns with the setting value in gauge coordinates.                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/16/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
int GaugeClass::Pixel_To_Value(int pixel)
{
	int maximum;

	if (IsHorizontal) {
		pixel -= X+1;
		maximum = Width;
	} else {
		pixel -= Y+1;
		maximum = Height;
	}
	maximum -= 2;
	pixel = Bound(pixel, 0, maximum);
	return(MaxValue * fixed(pixel, maximum));
//	return(Fixed_To_Cardinal(MaxValue, Cardinal_To_Fixed(maximum, pixel)));
}


/***********************************************************************************************
 * GaugeClass::Value_To_Pixel -- Convert gauge value to pixel offset.                          *
 *                                                                                             *
 *    Use this routine to convert the specified gauge value into a pixel offset from the       *
 *    star of the gauge. This is used for thumb positioning.                                   *
 *                                                                                             *
 * INPUT:   value -- The value to convert to a pixel offset.                                   *
 *                                                                                             *
 * OUTPUT:  Returns with the pixel offset of the specified value from the start of the         *
 *          gauge.                                                                             *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/16/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
int GaugeClass::Value_To_Pixel(int value)
{
	int maximum;
	int start;
	if (IsHorizontal) {
		maximum = Width;
		start = X;
	} else {
		maximum = Height;
		start = Y;
	}
	maximum -= 2;
	return(start + maximum * fixed(value, MaxValue));
//	return(start + Fixed_To_Cardinal(maximum, Cardinal_To_Fixed(MaxValue, value)));
}


/***********************************************************************************************
 * GaugeClass::Draw_Me -- Draws the body of the gauge.                                         *
 *                                                                                             *
 *    This routine will draw the body of the gauge if necessary.                               *
 *                                                                                             *
 * INPUT:      forced   -- Should the gauge be redrawn regardless of the current redraw flag?  *
 *                                                                                             *
 * OUTPUT:     bool; Was the gauge redrawn?                                                    *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:    01/16/1995 JLB : Created.                                                       *
 *=============================================================================================*/
int GaugeClass::Draw_Me(int forced)
{
	if (ControlClass::Draw_Me(forced)) {

		/*
		**	Hide the mouse
		*/
		if (LogicPage == &SeenBuff) {
			Conditional_Hide_Mouse(X, Y, X+Width, Y+Height);
		}

		/*
		**	Draw the body & set text color
		*/
		Draw_Box (X, Y, Width, Height, BOXSTYLE_DOWN, true);

		/*
		**	Colourize the inside of the gauge if indicated.
		*/
		if (IsColorized) {
			int middle = Value_To_Pixel(CurValue);
			int color = GadgetClass::Get_Color_Scheme()->Bright;
			if (IsHorizontal) {
				if (middle >= (X + 1))
					LogicPage->Fill_Rect(X+1, Y+1, middle, Y+Height-2, color);
			} else {
				if (middle >= (Y + 1))
					LogicPage->Fill_Rect(X+1, Y+1, X+Width-2, middle, color);
			}
		}

		if (HasThumb) {
			Draw_Thumb();
		}

		/*
		**	Display the mouse
		*/
		if (LogicPage == &SeenBuff) {
			Conditional_Show_Mouse();
		}
		return(true);
	}
	return(false);
}


/***********************************************************************************************
 * GaugeClass::Action -- Handles input events for the gauge.                                   *
 *                                                                                             *
 *    This routine will handle input event processing for the gauge. It will adjust the        *
 *    current setting of the gauge according to the mouse position.                            *
 *                                                                                             *
 * INPUT:   flags -- The input event that is the reason for this function call.                *
 *          key   -- The key code that caused the event.                                       *
 *                                                                                             *
 * OUTPUT:  bool; Was the even recognized, processed, and no further gadget scanning is        *
 *                desired (for this pass).                                                      *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 * HISTORY:                                                                                    *
 *   01/16/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
int GaugeClass::Action(unsigned flags, KeyNumType &key)
{
	/*
	** If there's no thumb on this gauge, it's a display-only device.
	*/
	if (!HasThumb) {
		return(false);
	}

	/*
	**	We might end up clearing the event bits. Make sure that the sticky
	**	process is properly updated anyway.
	*/
	Sticky_Process(flags);

	/*
	**	If the thumb is currently being "dragged around", then update the slider
	**	position according to the mouse position. In all other cases, ignore the
	**	button being held down.
	*/
	if ((flags & LEFTPRESS) || ((flags & LEFTHELD) && StuckOn == this)) {

		/*
		** Compute the difference between where we clicked, and the edge of
		** the thumb (only if we clicked on the thumb.)
		*/
		if (flags & LEFTPRESS) {
			int curpix = Value_To_Pixel(CurValue);
			int clickpix = (IsHorizontal ? Get_Mouse_X() : Get_Mouse_Y());

			if ( (clickpix > curpix) && (clickpix - curpix) < Thumb_Pixels()) {
				ClickDiff = (clickpix - curpix);
			} else {
				ClickDiff = 0;
			}

			int testval = Pixel_To_Value(IsHorizontal ?
				Get_Mouse_X() - ClickDiff : Get_Mouse_Y() - ClickDiff);

			/*
			** Correct for round-down errors in Pixel_To_Value() and
			** Value_To_Pixel(); make ClickDiff exactly right so that
			** at this point, Get_Mouse_n() - ClickDiff converts to
			** CurValue.
			*/
			while (testval < CurValue && ClickDiff > 0) {
				ClickDiff--;
				testval = Pixel_To_Value(IsHorizontal ?
				Get_Mouse_X() - ClickDiff : Get_Mouse_Y() - ClickDiff);
			}
		}

		/*
		**	If no change occurred in the gauge, just call Control's Action routine,
		** but turn off the flags so it won't fill in 'key' with the button ID.
		** Thus, no button ID will be returned by Input.
		*/
		if (!Set_Value(Pixel_To_Value(IsHorizontal ?
			Get_Mouse_X() - ClickDiff : Get_Mouse_Y() - ClickDiff))) {

			flags &= ~(LEFTHELD|LEFTRELEASE|LEFTPRESS);
			ControlClass::Action(0, key);
			key = KN_NONE;
			return(true);
		}

	} else {

		/*
		**	Ignore the left mouse button being held down if this gauge is not
		**	currently in "sticky" mode. This allows processing of the LEFTPRESS
		**	by any derived classes such that this gauge can be more closely
		**	controlled.
		*/
		flags &= ~LEFTHELD;
	}
	return(ControlClass::Action(flags, key));
}


/***********************************************************************************************
 * GaugeClass::Draw_Thumb -- Draws the body of the gauge.                                      *
 *                                                                                             *
 *    This routine will draw the body of the gauge if necessary.                               *
 *                                                                                             *
 * INPUT:      none.                                                                           *
 *                                                                                             *
 * OUTPUT:     none.                                                                           *
 *                                                                                             *
 * WARNINGS:   none.                                                                           *
 *                                                                                             *
 * HISTORY:    01/16/1995 MML : Created.                                                       *
 *=============================================================================================*/
void GaugeClass::Draw_Thumb(void)
{
	int x = Value_To_Pixel(CurValue);

	if ((x + 4) > Value_To_Pixel(MaxValue)) {
		x = Value_To_Pixel(MaxValue) - 2;
	}

	if (x < X) {
		x = X;
	}

	if (IsHorizontal) {
		Draw_Box(x, Y, 4, Height, BOXSTYLE_RAISED, true);
	} else {
		Draw_Box(X, x, Width, 4,  BOXSTYLE_RAISED, true);
	}
}


/***********************************************************************************************
 * TriColorGaugeClass::TriColorGaugeClass -- Constructor for 3 color (red\yellow\green) gauge. *
 *                                                                                             *
 *    This routine will draw the body of the gauge if necessary.                               *
 *                                                                                             *
 * INPUT:      See below.                                                                      *
 *                                                                                             *
 * OUTPUT:     none.                                                                           *
 *                                                                                             *
 * WARNINGS:   none.                                                                           *
 *                                                                                             *
 * HISTORY:    01/16/1995 MML : Created.                                                       *
 *=============================================================================================*/
TriColorGaugeClass::TriColorGaugeClass(unsigned id, int x, int y, int w, int h)
	: GaugeClass(id, x, y, w, h)
{
	RedLimit = 0;				// maximum value for red
	YellowLimit = 0;			// maximum value for yellow
}


/***********************************************************************************************
 * TriColorGaugeClass::Set_Red_Limit -- Set the value for the red area of gauge.               *
 *                                                                                             *
 * INPUT:      int value.                                                                      *
 *                                                                                             *
 * OUTPUT:     bool true of false.                                                             *
 *                                                                                             *
 * WARNINGS:   none.                                                                           *
 *                                                                                             *
 * HISTORY:    01/16/1995 MML : Created.                                                       *
 *=============================================================================================*/
int TriColorGaugeClass::Set_Red_Limit(int value)
{
	if (value >= 0 && value < MaxValue) {

//		if (value > YellowLimit) {
//			RedLimit = YellowLimit;
//			YellowLimit = value;
//		} else {
			RedLimit = value;
//		}
		Flag_To_Redraw();
		return(true);
	}
	return(false);
}


/***********************************************************************************************
 * TriColorGaugeClass::Set_Yellow_Limit -- Set the value for the yellow area of gauge.         *
 *                                                                                             *
 * INPUT:      int value.                                                                      *
 *                                                                                             *
 * OUTPUT:     bool true of false.                                                             *
 *                                                                                             *
 * WARNINGS:   none.                                                                           *
 *                                                                                             *
 * HISTORY:    01/16/1995 MML : Created.                                                       *
 *=============================================================================================*/
int TriColorGaugeClass::Set_Yellow_Limit(int value)
{
	if (value >= 0 && value < MaxValue) {

//		if (value < RedLimit) {
//			YellowLimit = RedLimit;
//			RedLimit = value;
//		} else {
			YellowLimit = value;
//		}
		Flag_To_Redraw();
		return(true);
	}
	return(false);
}


/***********************************************************************************************
 * TriColorGaugeClass::Draw_Me -- Draw the tri color gauge.                                    *
 *                                                                                             *
 * INPUT:      int forced -- draw or not?                                                      *
 *                                                                                             *
 * OUTPUT:     bool true of false.                                                             *
 *                                                                                             *
 * WARNINGS:   none.                                                                           *
 *                                                                                             *
 * HISTORY:    01/16/1995 MML : Created.                                                       *
 *=============================================================================================*/
int TriColorGaugeClass::Draw_Me(int forced)
{
	if (ControlClass::Draw_Me(forced)) {

		/*
		**	Hide the mouse
		*/
		if (LogicPage == &SeenBuff) {
			Conditional_Hide_Mouse(X, Y, X+Width, Y+Height);
		}

		/*
		**	Draw the body & set text color
		*/
		Draw_Box (X, Y, Width, Height, (IsDisabled ? BOXSTYLE_RAISED : BOXSTYLE_DOWN), true);

		/*
		**	Colourize the inside of the gauge if indicated.
		*/
		int red    = Value_To_Pixel(RedLimit);
		int yellow = Value_To_Pixel(YellowLimit);
		int middle = Value_To_Pixel(CurValue);

		if (CurValue <= RedLimit) {
			if (IsHorizontal) {
				LogicPage->Fill_Rect(X+1, Y+1, middle, Y+Height-2, PINK);
			} else {
				LogicPage->Fill_Rect(X+1, Y+1, X+Width-2, middle, PINK);
			}
		} else if (CurValue > RedLimit && CurValue <= YellowLimit) {
			if (IsHorizontal) {
				LogicPage->Fill_Rect(X+1, Y+1, red,    Y+Height-2, PINK);
				LogicPage->Fill_Rect(red, Y+1, middle, Y+Height-2, YELLOW);
			} else {
				LogicPage->Fill_Rect(X+1, Y+1, X+Width-2, red,    PINK);
				LogicPage->Fill_Rect(X+1, red, X+Width-2, middle, YELLOW);
			}
		} else if (CurValue > YellowLimit && CurValue <= MaxValue) {

			if (IsHorizontal) {
				LogicPage->Fill_Rect(X+1,    Y+1, red,    Y+Height-2, PINK);
				LogicPage->Fill_Rect(red,    Y+1, yellow, Y+Height-2, YELLOW);
				LogicPage->Fill_Rect(yellow, Y+1, middle, Y+Height-2, GREEN);
			} else {
				LogicPage->Fill_Rect(X+1, Y+1,    X+Width-2, red,    PINK);
				LogicPage->Fill_Rect(X+1, red,    X+Width-2, yellow, YELLOW);
				LogicPage->Fill_Rect(X+1, yellow, X+Width-2, middle, GREEN);
			}
		}

		if (HasThumb) {
			Draw_Thumb();
		}

		/*
		**	Display the mouse
		*/
		if (LogicPage == &SeenBuff) {
			Conditional_Show_Mouse();
		}
		return(true);
	}
	return(false);
}