/*********************************************************************
*	Scroll
*	SOURCE FILE
*	Autor:	Michal Jirouš
*	Datum: 3.7.2008
*	Soubor: scroll.cpp
*	Popis: Rolovaci panel, ktery je vyuzivan ostatnimi komponentamy
*			pro moznost rolovani pohledy a tak moznosti zobrazeni
*			vice mnozstvi dat, nez by se veslo do zakladni vykreslovaci
*			oblasti
**********************************************************************/

#include "gfg.h"
#include "mathematic.h"
Scroll::Scroll(float w, float h  )
{
	top = bottom = center = NULL;
	baseInit( w, h );

	//vytvoreni ovladacich tlacitek
	top = new Button( m_ScissorBox.w, m_ScissorBox.w );

	//prostredni je jezdec
	center = new Button( m_ScissorBox.w, m_ScissorBox.h - 2 * m_ScissorBox.w );
	bottom = new Button( m_ScissorBox.w, m_ScissorBox.w );
	
	m_bArrowButtonPushed = false;
		
	m_fValue = 0;
	m_fCenterButtonPosition = m_fSlidingAreaSize = 0;

	m_fCenterButtonMaxSize = m_ScissorBox.h - 2 * m_ScissorBox.w;
	
	//nastaveni ovladacich tlacitek
	top->setPosition( m_ScissorBox.x, m_ScissorBox.y + m_ScissorBox.h - m_ScissorBox.w );
	top->setParent( this );
	
	center->setPosition( m_ScissorBox.x, m_ScissorBox.y + m_ScissorBox.w );
	center->setParent( this );
	
	bottom->setPosition( m_ScissorBox.x, m_ScissorBox.y );
	bottom->setParent( this );

	center->setTextureIdle( "GFG_SCROLL_PANEL" );
	center->setTexturePushed( "GFG_SCROLL_PANEL" );
	
	
	/* Colors settings */
	top->setColorMouseOver( GFG_COLOR_SCROLLBAR_MOUSEOVER );
	top->setColorIdle( GFG_COLOR_SCROLLBAR_IDLE );
	bottom->setColorMouseOver( GFG_COLOR_SCROLLBAR_MOUSEOVER );
	bottom->setColorIdle( GFG_COLOR_SCROLLBAR_IDLE );

	center->setColorMouseOver( GFG_COLOR_SCROLLBAR_MOUSEOVER );
	center->setColorIdle( GFG_COLOR_SCROLLBAR_IDLE );
	
	center->setColorPushed( GFG_COLOR_SCROLLBAR_MOUSEOVER );
	center->setColorPushedMouseOver( GFG_COLOR_SCROLLBAR_MOUSEOVER );

	top->setColorPushed( GFG_COLOR_SCROLLBAR_IDLE );
	top->setColorPushedMouseOver( GFG_COLOR_SCROLLBAR_MOUSEOVER );

	bottom->setColorPushed( GFG_COLOR_SCROLLBAR_IDLE );
	bottom->setColorPushedMouseOver( GFG_COLOR_SCROLLBAR_MOUSEOVER );


	/* Textures settings */
	top->setTextureIdle( "GFG_ARROW" );
	bottom->setTextureIdle( "GFG_ARROW" );
	top->setTexturePushed( "GFG_ARROW_PUSHED" );
	bottom->setTexturePushed( "GFG_ARROW_PUSHED" );

	setScrollParameters( 1,1 );
	m_bChangingPosition = false;
	m_iObjectType = GFG_SCROLL;
}

//nastaveni povoleni a predani zpravy tlacitkum
void Scroll::setEnabled(bool value)
{
	m_bEnabled = value;
	top->setEnabled( m_bEnabled );
	center->setEnabled( m_bEnabled );
	bottom->setEnabled( m_bEnabled );
}

//nastaveni docasneho zakazani a predani zpravy tlacitkum
void Scroll::setTemporaryDisabled( bool disabled )
{
	m_bTemporaryDisabled = disabled;
	top->setTemporaryDisabled( disabled );
	center->setTemporaryDisabled( disabled );
	bottom->setTemporaryDisabled( disabled );
}
	
//aktualizac velikosti jezdce
void Scroll::updateButtonSize()
{
	if( m_fDocumentDataSize < 0 || m_fDocumentDataSize > 0 )
	{
		m_fCenterButtonSize = m_fCenterButtonMaxSize * m_fDocumentAreaSize / m_fDocumentDataSize;
		m_fCenterButtonSize = min ( m_fCenterButtonSize, m_fCenterButtonMaxSize );
	}
	else
		m_fCenterButtonSize = m_fCenterButtonMaxSize;

	center->setHeight( m_fCenterButtonSize );

	//zmenou velikosti jezdce se meni i velikost mozne drahy jezdce
	m_fSlidingAreaSize = m_fCenterButtonMaxSize - m_fCenterButtonSize;
}

//nastaveni parametru rolovaciho panelu
void Scroll::setScrollParameters( float fDataSize, float fAreaSize )
{
	m_fDocumentAreaSize = fAreaSize;	//viditelne okno
	m_fDocumentDataSize = fDataSize;		//velikost zobrazovanych dat

	updateButtonSize();
	recalculatePosition();
}

//zobrazovaci hodnota
void Scroll::setValue( float v )
{
	m_fValue = getFromRange( v, 0.0f, 1.0f );
	recalculatePosition();
}

//spocitani pozice jezdce
void Scroll::recalculatePosition()
{
	if( center )
	{
		m_fCenterButtonPosition = m_fSlidingAreaSize * ( 1.0f - m_fValue ) + getButtonHeight( m_ScissorBox.w );
		center->setPosition( m_ScissorBox.x, m_ScissorBox.y + m_fCenterButtonPosition );
	}
}

void Scroll::draw( ScissorBox &scissorBox )
{
	if( !m_bVisible )
		return;

	glPushMatrix();
	glPushAttrib( GL_CURRENT_BIT | GL_ENABLE_BIT | GL_SCISSOR_BIT );
	glEnable(GL_BLEND);
	glEnable(GL_SCISSOR_TEST);
	ScissorBox intersected = m_ScissorBox.intersection( scissorBox );
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );


	glScissor( (GLint)intersected.x, (GLint)intersected.y, (GLint)intersected.w, (GLint)intersected.h );

	top->draw( intersected );
	glPushMatrix();
	float x_move = bottom->getXPosition() + bottom->getWidth() / 2;
	float y_move = bottom->getYPosition() + bottom->getHeight() / 2;
	glTranslatef( x_move, y_move, 0 );
	glRotatef( 180, 0, 0, 1 );	//aby sipka na texture tlacika mela spravny smer,
								//tak ho otocime
	
	glTranslatef( -x_move, -y_move, 0 );
	bottom->draw( intersected );
	glPopMatrix();	
	
	center->draw( intersected );

	glPopAttrib();
	glPopMatrix();
}

void Scroll::run()
{
	if( top )
	{
		if( top->getPushed() )	//posouvani jezdce nahoru pri drzeni tlacitka
		{
			m_bArrowButtonPushed = true;
			valueDown( m_fCenterButtonSize * GFG_SCROLL_INCREMENT_MULTIPLICATOR );
		}
		else if( bottom->getPushed() )//posouvani jezdce dolu pri drzeni tlacitka
		{
			m_bArrowButtonPushed = true;
			valueUp( m_fCenterButtonSize * GFG_SCROLL_INCREMENT_MULTIPLICATOR );
		}
		else
			m_bArrowButtonPushed = false;
	}
}


void Scroll::valueUp( float value )
{
	m_fValue = getFromRange( m_fValue + value, GFG_SCROLL_MIN_VALUE, GFG_SCROLL_MAX_VALUE );
	recalculatePosition();
}

void Scroll::valueDown( float value )
{
	m_fValue = getFromRange( m_fValue - value, GFG_SCROLL_MIN_VALUE, GFG_SCROLL_MAX_VALUE );
	recalculatePosition();
}

//pri zmene pozice se musi zmenit pozice i vsech tri tlacitek
void Scroll::onScissorBoxTranslate( float offsetX, float offsetY )
{
	if( top )
	{
		top->setPositionOffset( offsetX, offsetY );
		bottom->setPositionOffset( offsetX, offsetY );
		center->setPositionOffset( offsetX, offsetY );
	}
}

//pri zmene velikosti se meni velikost tlacitek
//funkce vrati novu hodnotu velikosti
//existuje ale hranice, terou velikost nesmi prekrocit
float Scroll::getButtonHeight( float requested )
{
	return getFromRange( requested, 0.0f, m_ScissorBox.h / GFG_SCROLL_MAX_BUTTON_SIZE_RATIO );
}

//pri zmene velikosti se musi prepocitat pozice a velikost tlacitek
void Scroll::onScissorBoxResize( float w_offset, float h_offset )
{
	if( top )
	{
		float fButtonHeight = getButtonHeight( m_ScissorBox.w );
		top->setSize( m_ScissorBox.w, fButtonHeight );
		top->setPosition( m_ScissorBox.x, m_ScissorBox.y + m_ScissorBox.h - fButtonHeight );
		center->setWidth( m_ScissorBox.w );
		bottom->setSize( m_ScissorBox.w, fButtonHeight );
		m_fCenterButtonMaxSize = m_ScissorBox.h - 2.0f * fButtonHeight;
		updateButtonSize();	//aktualizace velikosti jezdce
		recalculatePosition();
	}
}

bool Scroll::inputController(int type, float x, float y, int param1, int param2)
{
	if( !m_bVisible || !m_bEnabled )
		return false;

	float translated_x = x// - m_fGlobalXpos
		;
	float translated_y = y //- m_fGlobalYpos
		;

	if( type == GFG_GOT_FOCUS )
		m_bFocused = true;
	else if( type == GFG_LOST_FOCUS )
		m_bFocused = false;
	else if( type & GFG_MOUSE )
	{
		if( type == GFG_MOUSE_BUTTON)
		{
			//posun nahoru po stisku
			if( top->inputController( GFG_MOUSE_BUTTON, translated_x, translated_y,param1, param2 ) && param2 == GFG_DOWN)
			{
				valueDown( m_fCenterButtonSize*GFG_SCROLL_INCREMENT_MULTIPLICATOR );
				return true;
			}
			//posun dolu po stisku
			else if( bottom->inputController( GFG_MOUSE_BUTTON, translated_x, translated_y, param1, param2 ) && param2 == GFG_DOWN )
			{
				valueUp( m_fCenterButtonSize*GFG_SCROLL_INCREMENT_MULTIPLICATOR );
				return true;
			}
			else if( center->inputController(GFG_MOUSE_BUTTON, translated_x, translated_y, param1, param2 ) )
			{//toto tlacitko }jezdec] je mozne pouze tahnout nahoru nebo dolu
				if( param2 == GFG_DOWN )//zatacek tazeni
				{
					m_bChangingPosition = true;
					m_iMoveXpos = x;
					m_iMoveYpos = y;
				}
				else if( param2 == GFG_UP )	//konec tazeni
					m_bChangingPosition = false;
				
				return true;
			}
			else if( param2 == GFG_UP )
					m_bChangingPosition = false;
		
		}
		else if( type == GFG_MOUSE_OVER )
		{
			bool bValue = top->inputController( GFG_MOUSE_OVER, translated_x, translated_y, param1, param2 );
			bValue |= bottom->inputController( GFG_MOUSE_OVER, translated_x, translated_y, param1, param2 );
			bValue |= center->inputController( GFG_MOUSE_OVER, translated_x, translated_y, param1, param2 );
			return bValue && param1;
		}
		else if( type == GFG_MOUSE_MOTION && m_bChangingPosition )
		{
			//probihajici posun jezdce
			float fNewY = 0, fNewX = 0;

			fNewY = (float)y - m_iMoveYpos + m_fCenterButtonPosition;

			float iTmpWidth = getButtonHeight( m_ScissorBox.w );

			if( fNewY < iTmpWidth )
			{
				float div = m_fCenterButtonPosition - iTmpWidth;
				m_fCenterButtonPosition -= div;
				m_iMoveYpos -= div;
			}
			else if( fNewY >m_fSlidingAreaSize + iTmpWidth )
			{
				float div = m_fSlidingAreaSize - m_fCenterButtonPosition + iTmpWidth;
				m_fCenterButtonPosition += div;
				m_iMoveYpos += div;
			}
			else
			{
				m_iMoveXpos = x;
				m_iMoveYpos = y;
			}
			
			//reakce na zmenu pozice jezdce
			m_fCenterButtonPosition = getFromRange( fNewY, iTmpWidth, m_fSlidingAreaSize + iTmpWidth );
			center->setPosition( m_ScissorBox.x, m_ScissorBox.y + m_fCenterButtonPosition  );
			//vypocet nove hodnoty
			float d = (center->getYPosition() - (float)iTmpWidth - m_ScissorBox.y) / m_fSlidingAreaSize;
			m_fValue = getFromRange( 1.0f - d, GFG_SCROLL_MIN_VALUE, GFG_SCROLL_MAX_VALUE);
			return true;
		}
	}
	return false;
}

void Scroll::setAlphaMultiplier( float multiplier )
{
	m_fAlphaMultiplier = multiplier;
	if( top != NULL )
		top->setAlphaMultiplier( m_fAlphaMultiplier );
	if( center != NULL )
		center->setAlphaMultiplier( m_fAlphaMultiplier );
	if( bottom != NULL )
		bottom->setAlphaMultiplier( m_fAlphaMultiplier );
}

