//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================

#ifndef ATTRIBUTESLIDER_H
#define ATTRIBUTESLIDER_H
#ifdef _WIN32
#pragma once
#endif

#include "vgui_controls/EditablePanel.h"
#include "dme_controls/AnimSetAttributeValue.h"
#include "materialsystem/MaterialSystemUtil.h"
#include "datamodel/dmehandle.h"

using namespace vgui;


//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
class CBaseAnimSetAttributeSliderPanel;
class CDmElement;
class CAttributeSliderTextEntry;
class CSubRectImage;


//-----------------------------------------------------------------------------
// CAttributeSlider
//-----------------------------------------------------------------------------

// THIS CODE IS KIND OF A MESS WRT THE VARIOUS STATES WE CAN BE IN:
// we can be driven by the preset pane or by dragging on any individual control
// we can also be driven by ctrl hovering over the preset pane or an individual control
// if we move from control to control in the preset or here, we need to be able to decay into/out of the various individual sliders
class CAttributeSlider : public EditablePanel 
{
	DECLARE_CLASS_SIMPLE( CAttributeSlider, EditablePanel );

	// Overridden methods of EditablePanel
public:
	virtual void Paint();
	virtual void PaintBackground();
	virtual void ApplySchemeSettings( IScheme *scheme );
	virtual void PerformLayout();
	virtual void OnCursorMoved(int x, int y);
	virtual void OnMousePressed(MouseCode code);
	virtual void OnMouseDoublePressed(MouseCode code);
	virtual void OnMouseReleased(MouseCode code);
	virtual void OnCursorEntered();
	virtual void OnCursorExited();
	virtual void OnKeyCodeTyped( KeyCode code );

	// Other public methods
public:
	CAttributeSlider( CBaseAnimSetAttributeSliderPanel *parent, const char *panelName, CDmElement *control );
	virtual ~CAttributeSlider();

	// Returns the control we're modifying
	CDmElement *GetControl();

	// Activates/deactivates a slider control
	// NOTE: Slider control 'value' defaults to active, 'balance' and 'multilevel' defaults to inactive
	void ActivateControl( AnimationControlType_t type, bool bActive );
	bool IsControlActive( AnimationControlType_t type );

	// Gets/sets the slider value. 
	// NOTE: This may not match the value pushed into the control because of fading
	void SetValue( AnimationControlType_t type, float flValue );
	float GetValue( AnimationControlType_t type ) const;
	void SetValue( const AttributeValue_t& value );
	const AttributeValue_t& GetValue() const;

	// Is this slider manipulating a transform control? 
	// [NOTE: This is a utility method; the control contains these states]
	bool IsTransform() const;

	// Returns the default value for a control
	// [NOTE: These is a utility method; the control contains these states]
	float GetControlDefaultValue( AnimationControlType_t type ) const;

	// Are we dragging? If so, what control is being dragged?
	bool IsDragging() const;
	AnimationControlType_t GetDragControl() const;

	// Are we in text entry mode? If so, what control is having text entered?
	bool IsInTextEntry() const;
	AnimationControlType_t GetTextEntryControl() const;

	// Estimates the value of the control given a local coordinate
	float EstimateValueAtPos( int nLocalX, int nLocalY ) const;

	void		SetPreview( const AttributeValue_t &value, const AttributeValue_t &full, bool instantaneous, bool startfromcurrent );
	float		GetPreview( AnimationControlType_t type ) const;
	const AttributeValue_t &GetPreview() const;

	void		EnablePreview( bool state, bool simple, bool faderdrag );
	bool		IsPreviewEnabled() const;
	bool		IsSimplePreview() const; 

	void		UpdateTime( float dt );
	void		UpdateFaderAmount( float amount );

	bool		IsRampingTowardPreview() const;
	void		RampDown();

	bool		IsFaderBeingDragged();

	void		SetIsLogPreviewControl( bool state );

	void		SetSelected( bool state );
	bool		IsSelected() const;

private:
	// Various slider modes
	enum SliderMode_t
	{
		SLIDER_MODE_FIRST_DRAG_MODE = 0x0,
		SLIDER_MODE_FIRST_TEXT_MODE = 0x4,
		SLIDER_MODE_LAST_DRAG_MODE = SLIDER_MODE_FIRST_DRAG_MODE + ANIM_CONTROL_COUNT - 1,
		SLIDER_MODE_LAST_TEXT_MODE = SLIDER_MODE_FIRST_TEXT_MODE + ANIM_CONTROL_COUNT - 1,

		SLIDER_MODE_NONE = -1,

		SLIDER_MODE_DRAG_VALUE = SLIDER_MODE_FIRST_DRAG_MODE + ANIM_CONTROL_VALUE,
		SLIDER_MODE_DRAG_BALANCE = SLIDER_MODE_FIRST_DRAG_MODE + ANIM_CONTROL_BALANCE,
		SLIDER_MODE_DRAG_MULTILEVEL = SLIDER_MODE_FIRST_DRAG_MODE + ANIM_CONTROL_MULTILEVEL,

		SLIDER_MODE_TEXT_VALUE = SLIDER_MODE_FIRST_TEXT_MODE + ANIM_CONTROL_VALUE,
		SLIDER_MODE_TEXT_BALANCE = SLIDER_MODE_FIRST_TEXT_MODE + ANIM_CONTROL_BALANCE,
		SLIDER_MODE_TEXT_MULTILEVEL = SLIDER_MODE_FIRST_TEXT_MODE + ANIM_CONTROL_MULTILEVEL,
	};

	struct Preview_t
	{
		AttributeValue_t m_Current;
		AttributeValue_t m_Full;
	};

private:
	// Returns the location of a particular control
	void GetControlRect( Rect_t *pRect, AnimationControlType_t type ) const;

	// Given a mouse position in (x,y) in local coordinates, which animation control is it over?
	AnimationControlType_t DetermineControl( int x, int y );

	// Draws a tick on a circular control
	void DrawCircularTick( const Color& clr, float flValue, int nCenterX, int nCenterY, float flRadius );

	// Draws a preview of a circular control
	void DrawCircularPreview( AnimationControlType_t type, bool bMainTick, float flRadius );

	// Paints the a circular control
	void PaintCircularControl( float flValue, const Rect_t& rect );

	// Called by the text entry code to enter the value into the logs
	void StampValueIntoLogs( AnimationControlType_t type, float flValue );

	// Methods related to rendering
	void DrawMidpoint( int x, int ty, int ttall );
	void DrawPreviewTick( bool mainTick );
	void DrawTick( const Color& clr, float frac, int width, int inset );
	void DrawNameLabel();
	void DrawValueLabel( float flValue );
	float GetPreviewAlphaScale() const;

	// Methods related to text entry mode
	void EnterTextEntryMode( AnimationControlType_t type, bool bRelatchValues );
	void AcceptTextEntryValue();
	void DiscardTextEntryValue();

private:
	CBaseAnimSetAttributeSliderPanel *m_pParent;
	TextImage *m_pName;
	TextImage *m_pValues[ 3 ];
	CSubRectImage *m_pCircleImage;	// The background for the balance + multilevel controls

	// This is the control we're modifying
	CDmeHandle< CDmElement > m_hControl;

	// White material used for drawing non-textured things
	CMaterialReference m_pWhite;

	// The current mode of the slider
	SliderMode_t m_SliderMode;

	// The slider value; it may not match the control attribute value due to blending
	AttributeValue_t m_Control;

	// Is the slider control active?
	bool m_bIsControlActive[ANIM_CONTROL_COUNT];

	// Info used when in text entry mode
	AttributeValue_t m_InitialTextEntryValue;
	CAttributeSliderTextEntry *m_pTextField; // if this is a stereo control, then this will be the left text field
	CAttributeSliderTextEntry *m_pRightTextField;

	Preview_t		m_Next;
	Preview_t		m_Previous;
	Preview_t		m_Preview;
	float			m_flPreviewGoalTime;
	float			m_flFaderAmount;

	// Fields used to help with drag
	int				m_nDragStartPosition[2];	// Where was the mouse clicked?
	int				m_nAccum[2];				// What's the total mouse movement during the drag?
	float			m_flDragStartValue;			// What was the value of the slider before the drag started?
	float			m_flDragStartBalance;		// What was the balance of the slider before the drag started?

	bool			m_bCursorInsidePanel : 1;	// Used to 
	bool			m_bRampUp : 1;
	bool			m_bPreviewEnabled : 1;
	bool			m_bSimplePreviewOnly : 1;
	bool			m_bFaderBeingDragged : 1;
	bool			m_bIsLogPreviewControl : 1;
	bool			m_bTransform : 1;
	bool			m_bSelected : 1;

	friend class CAttributeSliderTextEntry;
};


//-----------------------------------------------------------------------------
// Inline methods
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
// Returns the control
//-----------------------------------------------------------------------------
inline CDmElement *CAttributeSlider::GetControl()
{
	return m_hControl;
}


//-----------------------------------------------------------------------------
// Returns information about the control
//-----------------------------------------------------------------------------
inline bool CAttributeSlider::IsTransform() const
{
	// NOTE: We may well not wish to cache this off in the constructor.
	// It's done purely for efficiency reasons.
	// Uncomment the line to make it read from the control.
	// return m_hControl->GetValue< bool >( "transform" )
	return m_bTransform;
}


//-----------------------------------------------------------------------------
// Are we dragging?
//-----------------------------------------------------------------------------
inline bool CAttributeSlider::IsDragging() const
{
	COMPILE_TIME_ASSERT( ANIM_CONTROL_COUNT < 4 );
	return ( m_SliderMode >= SLIDER_MODE_FIRST_DRAG_MODE && m_SliderMode <= SLIDER_MODE_LAST_DRAG_MODE ); 
}

inline AnimationControlType_t CAttributeSlider::GetDragControl() const
{
	if ( IsDragging() )
		return (AnimationControlType_t)( m_SliderMode - SLIDER_MODE_FIRST_DRAG_MODE );
	return ANIM_CONTROL_INVALID;
}


//-----------------------------------------------------------------------------
// Are we in text entry mode?
//-----------------------------------------------------------------------------
inline bool CAttributeSlider::IsInTextEntry() const
{
	COMPILE_TIME_ASSERT( ANIM_CONTROL_COUNT < 4 );
	return ( m_SliderMode >= SLIDER_MODE_FIRST_TEXT_MODE && m_SliderMode <= SLIDER_MODE_LAST_TEXT_MODE ); 
}

inline AnimationControlType_t CAttributeSlider::GetTextEntryControl() const
{
	if ( IsInTextEntry() )
		return (AnimationControlType_t)( m_SliderMode - SLIDER_MODE_FIRST_TEXT_MODE );
	return ANIM_CONTROL_INVALID;
}

#endif // ATTRIBUTESLIDER_H