//
// Modifications History
//
//$ LB (13/06/2002)  : changed ObjBitmap management, according to the new ObjBitmap structure
//
//$LB (20/12/2002) : 16bits to 24bits
//




#include "Macro.h"
#include "CObjectSlideBar.h"
#include "CObjMessageResize.h"			//pour la classe CObjMessageResize et les directions prédéfinies
#include "CObjMessageMove.h"			//pour la classe CObjMessageMove et les directions prédéfinies
#include "../x/Objstr.h"
#include "utils.h"
#include "container.h"
#include "bitmap.h"
#include "colors.h"

extern int OBJNODE;
extern mmachine mm;

#define STATE_OFF_UNDISPLAYED		0	/* undisplay */
#define STATE_OFF_BODY				1	/* highlight */
#define STATE_OFF_MAX				2
#define STATE_OFF_MIN				3
#define STATE_OFF_PUSHED_BODY		4	/* pushed    */
#define STATE_OFF_PUSHED_MAX		5
#define STATE_OFF_PUSHED_MIN		6

#define MAX_ARROW 0
#define BODY_MAX  1
#define CURSOR    2
#define MIN_ARROW 3
#define BODY_MIN  4

/*
#define BMP  0
#define ABMP 1
*/

#define ALPHA 0

int CObjectSlideBar::GetIndexBitmap( int part )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::GetIndexBitmap");
#endif
//***********************************

	int res = 0;

	if ( ObjFlags&OBJ_DISABLE && ObjFlags&SLB_DISABLE )
	{
		if ( ObjFlags&SLB_ROLLOVER )
		{
			if ( ObjFlags&SLB_GAUGE )
				switch( part )
				{
					case MAX_ARROW:
					case BODY_MAX:
					case CURSOR:
						res = 7;
						break;
					case MIN_ARROW:
					case BODY_MIN:
						res = 8;
						break;
				}
			else
				res = 3;
		}
		else
		{
			if ( ObjFlags&SLB_GAUGE )
				switch( part )
				{
					case MAX_ARROW:
					case BODY_MAX:
					case CURSOR:
						res = 2;
						break;
					case MIN_ARROW:
					case BODY_MIN:
						res = 3;
						break;
				}
			else
				res = 1;
		}
	}
	else if ( ObjFlags&SLB_ROLLOVER )
	{
		if ( ObjFlags&SLB_GAUGE )
			switch( part )
			{
				case MAX_ARROW:
					if ( SLBstate == STATE_OFF_MAX )
						res = 2;
					if ( SLBstate == STATE_OFF_PUSHED_MAX )
						res = 4;
					break;
				case MIN_ARROW:
					if ( SLBstate == STATE_OFF_UNDISPLAYED )
						res = 1;
					if ( SLBstate == STATE_OFF_MIN )
						res = 3;
					if ( SLBstate == STATE_OFF_PUSHED_MIN )
						res = 5;
					break;
				case BODY_MAX:
					if ( SLBstate == STATE_OFF_BODY )
						res = 2;
					if ( SLBstate == STATE_OFF_PUSHED_BODY )
						res = 4;
					break;
				case BODY_MIN:
					if ( SLBstate == STATE_OFF_UNDISPLAYED )
						res = 1;
					if ( SLBstate == STATE_OFF_BODY )
						res = 3;
					if ( SLBstate == STATE_OFF_PUSHED_BODY )
						res = 5;
					break;
				case CURSOR:
					if ( SLBstate == STATE_OFF_BODY )
						res = 2;
					if ( SLBstate == STATE_OFF_PUSHED_BODY )
						res = 4;
					break;
			}
		else
			switch( part )
			{
				case MAX_ARROW:
					if ( SLBstate == STATE_OFF_MAX )
						res = 1;
					if ( SLBstate == STATE_OFF_PUSHED_MAX )
						res = 2;
					break;
				case MIN_ARROW:
					if ( SLBstate == STATE_OFF_MIN )
						res = 1;
					if ( SLBstate == STATE_OFF_PUSHED_MIN )
						res = 2;
					break;
				case BODY_MAX:
				case BODY_MIN:
				case CURSOR:
					if ( SLBstate == STATE_OFF_BODY )
						res = 1;
					if ( SLBstate == STATE_OFF_PUSHED_BODY )
						res = 2;
					break;
			}
	}
	else 
	{
		if ( (ObjFlags&SLB_GAUGE) )
			switch( part )
			{
				case MIN_ARROW:
					res = 1;
					break;
				case BODY_MIN:
					res = 1;
					break;
			}
	}


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::GetIndexBitmap end");
#endif
//***********************************
	return res;
}





int CObjectSlideBar::GetIndexMask()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::GetIndexMask");
#endif
//***********************************
	
	int res = -1;

	if ( ObjFlags&SLB_MASK )
	{
		res = 1;
		if ( ObjFlags&SLB_ROLLOVER )
			res = 3;
		if ( ObjFlags&SLB_DISABLE )
			res += 1;
		if ( ObjFlags&SLB_GAUGE )
			res *= 2;
	}



//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::GetIndexMask end");
#endif
//***********************************
	return res;
}





CObjectSlideBar::CObjectSlideBar( container * cont,
								  Layer *layer,
								  int x, int y, int w, int h,
								  int flags, int contflags,
								  int transp,
								  int realwidth, int realheight,
								  int min, int max,
								  int direction,
								  int step,
								  int offset1, int offset2, int offset3
								 ):CObjectBase( cont, layer, x, y, w, h, flags, contflags, transp )
{

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::CObjectSlideBar");
#endif
//***********************************

	this->timerID = -1;
	this->direction = direction % 2;
	this->step = abs(step);
	if ( min <= max )
		this->reverse = 0;
	else
		this->reverse = 1;
	this->min = min( min, max);
	this->max = max( min, max);
	this->range_min = this->min;
	this->range_max = this->max;
	this->offset1 = offset1;
	this->offset2 = offset2;
	this->offset3 = offset3;
	if ( min != max )
		this->valueStep = ( offset2 - offset1 ) / ( max - min );
	else
		this->valueStep = 0;
	this->value = this->range_min; // initialisé par défaut au minimum
	this->SLBstate = STATE_OFF_UNDISPLAYED;
	this->mouseCursorDecal = 0;
	this->realObjW = realwidth;
	this->realObjH = realheight;
}

CObjectSlideBar::~CObjectSlideBar()
{
}





int CObjectSlideBar::SetValue( int newValue, int notifylinks, int redrawobject )
{
	int tmp_res, direction, diff_value;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::SetValue");
#endif
//***********************************

	if ( this->range_min <= newValue && this->range_max >= newValue && this->value != newValue )
	{
		int k;

		// gestion des liens
		if ( notifylinks )
		{
			diff_value = newValue - this->value;
			if ( this->direction == SLB_VERTICAL )
				direction = DIR_VERTICAL;
			else
				direction = DIR_HORIZONTAL;

			this->send_notification_value( LINK_MOVE, direction, diff_value, redrawobject );
		}

		// maj de la valeur
		this->value = newValue;

		k = OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_CHANGE);
		if (k>0) return 1; 
		if (k==0)
		{
			if ( redrawobject && IsObjectRepaintBeforeCallback())
				Redraw();

			CHECK(MMpush(mm,ITOM( this->value )));
			return OBJcallreflex(mm,1);
		}
		else if ( redrawobject )
			Redraw();

	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::SetValue end");
#endif
//***********************************

	return 0;
}






int CObjectSlideBar::SetMax( int newValue, int scalerange, int notifylinks, int redrawobject )
{
	int direction, diff_value;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::SetMax");
#endif
//***********************************

	if ( this->min <= newValue && this->max != newValue )
	{
		diff_value = newValue - this->max;
		// gestion des liens
		if ( notifylinks )
		{
			if ( this->direction == SLB_VERTICAL )
				direction = DIR_VERTICAL;
			else
				direction = DIR_HORIZONTAL;

			this->send_notification_max( LINK_RESIZE, direction, diff_value, redrawobject );
		}

		this->max = newValue;

		this->range_max = min( this->range_max, this->max );
		this->range_min = min( this->range_min, this->max );

		if ( scalerange )
			SetRangeMax( this->max );

		if ( this->min == this->max )
			this->valueStep = 0;
		else if ( !this->reverse )
			this->valueStep = ( offset2 - offset1 ) / ( this->max - this->min );
		else
			this->valueStep = ( offset2 - offset1 ) / ( this->min - this->max );

		SetValue( min( this->value, this->range_max ), 0, 0 );

		return 1;
	}


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::SetMax end");
#endif
//***********************************
	return 0;
}





int CObjectSlideBar::SetMin( int newValue, int scalerange, int notifylinks, int redrawobject )
{
	int direction, diff_value;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::SetMin");
#endif
//***********************************

	if ( this->max >= newValue && this->min != newValue )
	{
		diff_value = newValue - this->min;
		// gestion des liens
		if ( notifylinks )
		{
			if ( this->direction == SLB_VERTICAL )
				direction = DIR_VERTICAL;
			else
				direction = DIR_HORIZONTAL;

			this->send_notification_min( LINK_RESIZE, direction, diff_value, redrawobject );
		}

		this->min = newValue;

		this->range_min = max( this->range_min, this->min );
		this->range_max = max( this->range_max, this->min );

		if ( scalerange )
			SetRangeMin( this->min );

		if ( this->min == this->max )
			this->valueStep = 0;
		else if ( !this->reverse )
			this->valueStep = ( offset2 - offset1 ) / ( this->max - this->min );
		else
			this->valueStep = ( offset2 - offset1 ) / ( this->min - this->max );

		SetValue( max( this->value, this->range_min ), 0, 0 );

		return 1;
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::SetMin end");
#endif
//***********************************

	return 0;
}





void CObjectSlideBar::SetStep( int newValue )
{
	this->step = newValue;
}




int CObjectSlideBar::SetRangeMax( int newValue )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::SetRangeMax");
#endif
//***********************************
	
	if ( this->range_min <= newValue && this->max >= newValue && this->range_max != newValue )
	{
		this->range_max = newValue;
		SetValue( min( this->value, this->range_max ), 0, 0 );

		return 1;
	}

	return 0;
}




int CObjectSlideBar::SetRangeMin( int newValue )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::SetRangeMin");
#endif
//***********************************
	
	if ( this->range_max >= newValue && this->min <= newValue && this->range_min != newValue )
	{
		this->range_min = newValue;
		SetValue( max( this->value, this->range_min ), 0, 0 );

		return 1;
	}

	return 0;
}





int CObjectSlideBar::IsMouseOnCursor( int x, int y, int p_tab )
{
	int idx, colorpix, cursor_pos;
	unsigned char r, g, b;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::IsMouseOnCursor");
#endif
//***********************************

	PtrObjBitmap bmp=GET_PTR_OBJ_BITMAP(GET_BMP(MTOP(MMfetch(mm,p_tab,ALPHA))));
	
	x = x - ObjX;
	y = y - ObjY;

	if ( direction == SLB_VERTICAL )
	{
		cursor_pos = getCursorPosition();
		if ( y > cursor_pos + realObjH - offset3 || y < cursor_pos )
			return 0;
	}
	else
	{
		cursor_pos = getCursorPosition();
		if ( x > cursor_pos + realObjW - offset3 || x < cursor_pos )
			return 0;
	}

	if ( ObjFlags&SLB_MASK )
	{
		if ( direction == SLB_VERTICAL )
		{
			idx = (x+GetIndexMask()*ObjW) * bmp->BytesPP   +   (y-cursor_pos+offset3) * bmp->BPL;
			b = bmp->bits[ idx   ];
			g = bmp->bits[ idx+1 ];
			r = bmp->bits[ idx+2 ];
			colorpix = _COLOR_BGR_TO_I (b, g, r);
		}
		else
		{
			idx = (x-cursor_pos+offset3) * bmp->BytesPP   +   (y+GetIndexMask()*ObjH) * bmp->BPL;
			b = bmp->bits[ idx   ];
			g = bmp->bits[ idx+1 ];
			r = bmp->bits[ idx+2 ];
			colorpix = _COLOR_BGR_TO_I (b, g, r);
		}

		return (colorpix!=0);
	}
	else
	{
		if ( direction == SLB_VERTICAL )
		{
			idx = x * bmp->BytesPP   +   (y-cursor_pos+offset3) * bmp->BPL;
			b = bmp->bits[ idx   ];
			g = bmp->bits[ idx+1 ];
			r = bmp->bits[ idx+2 ];
			colorpix = _COLOR_BGR_TO_I (b, g, r);
		}
		else
		{
			idx = (x-cursor_pos+offset3) * bmp->BytesPP   +   y * bmp->BPL;
			b = bmp->bits[ idx   ];
			g = bmp->bits[ idx+1 ];
			r = bmp->bits[ idx+2 ];
			colorpix = _COLOR_BGR_TO_I (b, g, r);
		}
		return ((ObjTransparency==NO_TRANSPARENCY)||(colorpix!=ObjTransparency));
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::IsMouseOnCursor");
#endif
//***********************************
}





int CObjectSlideBar::IsMouseOnObject( int x,int y, int p_tab )
{
	int idx, colorpix;
	unsigned char r, g, b;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::IsMouseOnObject");
#endif
//***********************************

	PtrObjBitmap bmp=GET_PTR_OBJ_BITMAP(GET_BMP(MTOP(MMfetch(mm,p_tab,ALPHA))));

	if ( bmp == NULL )
		return false;

	if ( SLBstate == STATE_OFF_PUSHED_BODY )
		return 1;

	if ( direction == SLB_VERTICAL )
	{
		if ( y - ObjY >= offset3 )
			return 0;
	}
	else if ( x - ObjX >= offset3 )
		return 0;

	if ( IsMouseOnCursor( x, y, p_tab ) )
		return 1;

	if (ObjFlags&SLB_MASK)
	{
		if ( direction == SLB_VERTICAL )
		{
			idx = (x-ObjX+GetIndexMask()*ObjW) * bmp->BytesPP   +   (y-ObjY) * bmp->BPL;
			b = bmp->bits[ idx   ];
			g = bmp->bits[ idx+1 ];
			r = bmp->bits[ idx+2 ];
			colorpix = _COLOR_BGR_TO_I (b, g, r);
		}
		else
		{
			idx = (x-ObjX) * bmp->BytesPP   +   (y-ObjY+GetIndexMask()*ObjH) * bmp->BPL;
			b = bmp->bits[ idx   ];
			g = bmp->bits[ idx+1 ];
			r = bmp->bits[ idx+2 ];
			colorpix = _COLOR_BGR_TO_I (b, g, r);
		}

		return (colorpix!=0);
	}
	else
	{
		idx = (x-ObjX) * bmp->BytesPP   +   (y-ObjY) * bmp->BPL;
		b = bmp->bits[ idx   ];
		g = bmp->bits[ idx+1 ];
		r = bmp->bits[ idx+2 ];
		colorpix = _COLOR_BGR_TO_I (b, g, r);

		return ((ObjTransparency==NO_TRANSPARENCY)||(colorpix!=ObjTransparency));
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::IsMouseOnObject end");
#endif
//***********************************
}










// bouton enfoncé
int CObjectSlideBar::CursorMoveOnBody(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	int new_value;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::CursorMoveOnBody");
#endif
//***********************************

	x = x - ObjX;
	y = y - ObjY;

	if ( direction == SLB_VERTICAL )
	{
		y -= ( realObjH - offset3 ) / 2 + this->mouseCursorDecal; // la largeur du curseur / 2 + le decalage de la souris par rapport au milieu du curseur
		if ( this->reverse )
			new_value = this->max + (int)((double)( y - this->valueStep / 2 - offset1 ) * (double)( this->max - this->min ) / (double)( offset1 - offset2 - offset3 + realObjH ));
		else
			new_value = this->min + (int)((double)( y + this->valueStep / 2 - offset1 ) * (double)( this->min - this->max ) / (double)( offset1 - offset2 - offset3 + realObjH ));
	}
	else
	{
		x -= ( realObjW - offset3 ) / 2 + this->mouseCursorDecal; // la largeur du curseur / 2 + le decalage de la souris par rapport au milieu du curseur
		if ( this->reverse )
			new_value = this->max + (int)((double)( x - this->valueStep / 2 - offset1 ) * (double)( this->max - this->min ) / (double)( offset1 - offset2 - offset3 + realObjW ));
		else
			new_value = this->min + (int)((double)( x + this->valueStep / 2 - offset1 ) * (double)( this->min - this->max ) / (double)( offset1 - offset2 - offset3 + realObjW ));
	}
	new_value = min( max( new_value, this->range_min ), this->range_max );

	return( SetValue( new_value, 1, redrawobject ) );

	return 0;
}










int CObjectSlideBar::CursorMove(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::CursorMove");
#endif
//***********************************

	if ( this->IsObjectEnabled() )
	{
		if ( !(keyFlags&MK_LBUTTON) )
		{
			if ( !IsMouseOnObject( x, y, p_tab ) )
				return 0;

			CursorMoveIn( x, y, keyFlags, p_tab, redrawobject );
		}
		else // bouton enfoncé !
		{
			x = x - ObjX;
			y = y - ObjY;

			if ( this->direction == SLB_VERTICAL )
			{
				if ( (SLBstate == STATE_OFF_PUSHED_BODY || SLBstate == STATE_OFF_BODY) )
				{
					SLBstate = STATE_OFF_PUSHED_BODY;
					CursorMoveOnBody( x + ObjX, y + ObjY, keyFlags, p_tab, redrawobject );
				}
				else if ( SLBstate == STATE_OFF_MIN && y < offset1 )
				{
					SLBstate = STATE_OFF_PUSHED_MIN;
					if ( ((this->reverse && this->range_max != this->value) || (!this->reverse && this->range_min != this->value)) && this->step != 0 )
					{
						this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
						Timer( this->timerID );
					}
				}
				else if ( SLBstate == STATE_OFF_MAX && y < offset3 && y >= offset2 )
				{
					SLBstate = STATE_OFF_PUSHED_MAX;
					if ( ((!this->reverse && this->range_max != this->value) || (this->reverse && this->range_min != this->value)) && this->step != 0 )
					{
						this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
						Timer( this->timerID ); // un premier appel tout de suite
					}
				}
				else
					CursorMoveOutWithBtnPushed( x + ObjX, y + ObjY, keyFlags, p_tab, redrawobject );
			}
			else
			{
				if ( (SLBstate == STATE_OFF_PUSHED_BODY || SLBstate == STATE_OFF_BODY) )
				{
					SLBstate = STATE_OFF_PUSHED_BODY;
					CursorMoveOnBody( x + ObjX, y + ObjY, keyFlags, p_tab, redrawobject );
				}
				else if ( SLBstate == STATE_OFF_MIN && x < offset1 )
				{
					SLBstate = STATE_OFF_PUSHED_MIN;
					if ( ((!this->reverse && this->range_max != this->value) || (this->reverse && this->range_min != this->value)) && this->step != 0 )
					{
						this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
						Timer( this->timerID );
					}
				}
				else if ( SLBstate == STATE_OFF_MAX && x < offset3 && x >= offset2 )
				{
					SLBstate = STATE_OFF_PUSHED_MAX;
					if ( ((this->reverse && this->range_max != this->value) || (!this->reverse && this->range_min != this->value)) && this->step != 0 )
					{
						this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
						Timer( this->timerID ); // un premier appel tout de suite
					}
				}
				else
					CursorMoveOutWithBtnPushed( x + ObjX, y + ObjY, keyFlags, p_tab, redrawobject );
			}
		}
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::CursorMove end");
#endif
//***********************************

	return 0;
}






int CObjectSlideBar::CursorMoveIn(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::CursorMoveIn");
#endif
//***********************************
	
	int stateBackup = SLBstate;

	if ( this->IsObjectEnabled() )
	{
		x = x - ObjX;
		y = y - ObjY;

		if ( direction == SLB_VERTICAL )
		{
			if ( y < offset1 )
				SLBstate = STATE_OFF_MIN;
			else if ( y < offset2 )
				SLBstate = STATE_OFF_BODY;
			else if ( y < offset3 )
				SLBstate = STATE_OFF_MAX;
		}
		else
		{
			if ( x < offset1 )
				SLBstate = STATE_OFF_MIN;
			else if ( x < offset2 )
				SLBstate = STATE_OFF_BODY;
			else if ( x < offset3 )
				SLBstate = STATE_OFF_MAX;
		}

		if ( redrawobject && SLBstate != stateBackup ) Redraw();
	}

	return 0;
}





int CObjectSlideBar::CursorMoveInWithBtnPushed(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::CursorMoveInWithBtnPushed");
#endif
//***********************************
	
	int stateBackup = SLBstate;

	if ( this->IsObjectEnabled() )
	{
		x = x - ObjX;
		y = y - ObjY;

		if ( keyFlags&MK_LBUTTON )
		{
			if ( direction == SLB_VERTICAL )
			{
				if ( SLBstate == STATE_OFF_MIN && y < offset1 )
				{
					SLBstate = STATE_OFF_PUSHED_MIN;
					if ( this->range_min != this->value && this->step != 0 )
					{
						this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
						Timer( this->timerID );
					}
				}
				else if ( SLBstate == STATE_OFF_BODY && y < offset2 && y >= offset1 )
				{
					SLBstate = STATE_OFF_PUSHED_BODY;
					CursorMoveOnBody( x + ObjX, y + ObjY, keyFlags, p_tab, redrawobject );
				}
				else if ( SLBstate == STATE_OFF_MAX && y < offset3 && y >= offset2 )
				{
					SLBstate = STATE_OFF_PUSHED_MAX;
					if ( this->range_max != this->value && this->step != 0 )
					{
						this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
						Timer( this->timerID ); // un premier appel tout de suite
					}
				}
			}
			else
			{
				if ( SLBstate == STATE_OFF_MIN && x < offset1 )
				{
					SLBstate = STATE_OFF_PUSHED_MIN;
					if ( this->range_min != this->value && this->step != 0 )
					{
						this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
						Timer( this->timerID );
					}
				}
				else if ( SLBstate == STATE_OFF_BODY && x < offset2 && x >= offset1 )
				{
					SLBstate = STATE_OFF_PUSHED_BODY;
					CursorMoveOnBody( x + ObjX, y + ObjY, keyFlags, p_tab, redrawobject );
				}
				else if ( SLBstate == STATE_OFF_MAX && x < offset3 && x >= offset2 )
				{
					SLBstate = STATE_OFF_PUSHED_MAX;
					if ( this->range_max != this->value && this->step != 0 )
					{
						this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
						Timer( this->timerID );
					}
				}
			}
		}
	}

	if ( redrawobject && stateBackup != SLBstate ) Redraw();


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::CursorMoveInWithBtnPushed end");
#endif
//***********************************
	return 0;
}





int CObjectSlideBar::CursorMoveOut(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::CursorMoveOut");
#endif
//***********************************
	
	int stateBackup = SLBstate;

	SLBstate = STATE_OFF_UNDISPLAYED;

	if ( redrawobject && stateBackup != SLBstate ) Redraw();
	
	return 0;
}





int CObjectSlideBar::CursorMoveOutWithBtnPushed(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::CursorMoveOutWithBtnPushed");
#endif
//***********************************
	
	int stateBackup = SLBstate;

	if ( this->timerID != NO_TIMER )
	{
		this->Container()->Unregister( this->timerID );
		this->timerID = NO_TIMER;
	}

	if ( SLBstate == STATE_OFF_PUSHED_MAX )
		SLBstate = STATE_OFF_MAX;
	else if ( SLBstate == STATE_OFF_PUSHED_MIN )
		SLBstate = STATE_OFF_MIN;

	if ( redrawobject && stateBackup != SLBstate ) Redraw();

	return 0;









}

int CObjectSlideBar::CursorMoveOutsideWithBtnPushed(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::CursorMoveOutsideWithBtnPushed");
#endif
//***********************************
	
	int stateBackup = SLBstate;

	if ( SLBstate != STATE_OFF_PUSHED_BODY && SLBstate != STATE_OFF_BODY )
		return CursorMoveOutWithBtnPushed( x, y, keyFlags, p_tab, redrawobject );

	if ( this->IsObjectEnabled() )
	{
		if ( this->direction == SLB_VERTICAL )
		{
			if ( x > ObjX - ObjW && x < ObjX + 2 * ObjW && y > ObjY - ObjW && y < ObjY + ObjH + ObjW )
			{
				SLBstate = STATE_OFF_PUSHED_BODY;
				CursorMove( x, max( y, ObjY ), keyFlags, p_tab, redrawobject );
			}
			else
			{
				if ( this->timerID != NO_TIMER )
				{
					this->Container()->Unregister( this->timerID );
					this->timerID = NO_TIMER;
				}

				SLBstate = STATE_OFF_BODY;

				if ( redrawobject && stateBackup != SLBstate ) Redraw();
			}
		}
		else
		{
			if ( y > ObjY - ObjH && y < ObjY + 2 * ObjH && x > ObjX - ObjH && x < ObjX + ObjW + ObjH )
			{
				SLBstate = STATE_OFF_PUSHED_BODY;
				CursorMove( max( x, ObjX ), y, keyFlags, p_tab, redrawobject );
			}
			else
			{
				int stateBackup = SLBstate;

				if ( this->timerID != NO_TIMER )
				{
					this->Container()->Unregister( this->timerID );
					this->timerID = NO_TIMER;
				}

				SLBstate = STATE_OFF_BODY;

				if ( redrawobject && stateBackup != SLBstate ) Redraw();
			}
		}
	}


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::CursorMoveOutsideWithBtnPushed end");
#endif
//***********************************
	return 0;
}





int CObjectSlideBar::ClickIn(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::ClickIn");
#endif
//***********************************
	
	int stateBackup = SLBstate;

	x = x - ObjX;
	y = y - ObjY;

	if ( btn == 1 )
	{
		if ( direction == SLB_VERTICAL )
		{
			if ( y < offset1 )
			{
				SLBstate = STATE_OFF_PUSHED_MIN;
				if ( ((!this->reverse && this->range_min != this->value) || (this->reverse && this->range_max != this->value)) && this->step != 0 )
				{
					this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
					Timer( this->timerID );
				}
			}
			else if ( y < offset2 )
			{
				SLBstate = STATE_OFF_PUSHED_BODY;
				if ( !IsMouseOnCursor( x + ObjX, y + ObjY, p_tab ) )
					CursorMoveOnBody( x + ObjX, y + ObjY, keyFlags, p_tab, redrawobject );
				else
					this->mouseCursorDecal = y - getCursorMiddlePosition() - 1;
			}
			else if ( y < offset3 )
			{
				SLBstate = STATE_OFF_PUSHED_MAX;
				if ( ((this->reverse && this->range_min != this->value) || (!this->reverse && this->range_max != this->value)) && this->step != 0 )
				{
					this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
					Timer( this->timerID );
				}
			}
		}
		else
		{
			if ( x < offset1 )
			{
				SLBstate = STATE_OFF_PUSHED_MIN;
				if ( ((!this->reverse && this->range_min != this->value) || (this->reverse && this->range_max != this->value)) && this->step != 0 )
				{
					this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
					Timer( this->timerID );
				}
			}
			else if ( x < offset2 )
			{
				SLBstate = STATE_OFF_PUSHED_BODY;
				if ( !IsMouseOnCursor( x + ObjX, y + ObjY, p_tab ) )
					CursorMoveOnBody( x + ObjX, y + ObjY, keyFlags, p_tab, redrawobject );
				else
					this->mouseCursorDecal = x - getCursorMiddlePosition() - 1;
			}
			else if ( x < offset3 )
			{
				SLBstate = STATE_OFF_PUSHED_MAX;
				if ( ((this->reverse && this->range_min != this->value) || (!this->reverse && this->range_max != this->value)) && this->step != 0 )
				{
					this->timerID = this->Container()->Register( TIMER_FREQUENCY, this );
					Timer( this->timerID );
				}
			}
		}
	}

	if ( redrawobject && stateBackup != SLBstate ) Redraw();


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::ClickIn end");
#endif
//***********************************
	return 0;
}





int CObjectSlideBar::UnClickIn(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::UnClickIn");
#endif
//***********************************
	
	int stateBackup = SLBstate;

	x = x - ObjX;
	y = y - ObjY;

	if ( this->timerID != NO_TIMER )
	{
		this->Container()->Unregister( this->timerID );
		this->timerID = NO_TIMER;
	}
	this->mouseCursorDecal = 0;

	if ( direction == SLB_VERTICAL )
	{
		if ( y < offset1 )
			SLBstate = STATE_OFF_MIN;
		else if ( y < offset2 )
			SLBstate = STATE_OFF_BODY;
		else if ( y < offset3 )
			SLBstate = STATE_OFF_MAX;
	}
	else
	{
		if ( x < offset1 )
			SLBstate = STATE_OFF_MIN;
		else if ( x < offset2 )
			SLBstate = STATE_OFF_BODY;
		else if ( x < offset3 )
			SLBstate = STATE_OFF_MAX;
	}

	if ( redrawobject && stateBackup != SLBstate ) Redraw();

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::UnClickIn end");
#endif
//***********************************	
	return 0;
}
	



int CObjectSlideBar::ClickOut(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
	return 0;
}



int CObjectSlideBar::UnClickOut(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::UnClickOut");
#endif
//***********************************

	this->mouseCursorDecal = 0;

	if ( SLBstate != STATE_OFF_UNDISPLAYED )
	{
		SLBstate = STATE_OFF_UNDISPLAYED;
		if ( redrawobject ) Redraw();
	}

	return 0;
}




int CObjectSlideBar::DblClickIn(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::DblClickIn");
#endif
//***********************************

	ClickIn( x, y, btn, keyFlags, p_tab, redrawobject );
	return 0;
}




int CObjectSlideBar::MouseWheel(int delta,int x,int y,int keyFlags,int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::MouseWheel");
#endif
//***********************************

	if ( this->reverse )
		this->SetValue( max( this->GetValue() + delta * this->step, this->GetMin() ), 1, 1 );
	else
		this->SetValue( min( this->GetValue() - delta * this->step, this->GetMax() ), 1, 1 );

	return 0;
}




int CObjectSlideBar::KeyUp(UINT vk,int cRepeat, UINT flags, int p_tab)
{
	return 0;
}

int CObjectSlideBar::KeyDown(UINT vk,int keysys,int cRepeat, UINT flags, int p_tab)
{
	return 0;
}

int CObjectSlideBar::SetFocus(int reset,int p_tab,int redraw)
{
	return 0;
}

int CObjectSlideBar::KillFocus(int p_tab,int redraw)
{
	return 0;
}








int CObjectSlideBar::Timer( int timerID )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::Timer");
#endif
//***********************************

	if ( SLBstate == STATE_OFF_PUSHED_MAX )
	{
		if ( this->reverse )
			this->SetValue( max( this->GetValue() - this->step, this->range_min ), 1, 1 );
		else
			this->SetValue( min( this->GetValue() + this->step, this->range_max ), 1, 1 );
	}
	else if ( SLBstate == STATE_OFF_PUSHED_MIN )
	{
		if ( this->reverse )
			this->SetValue( min( this->GetValue() + this->step, this->range_max ), 1, 1 );
		else
			this->SetValue( max( this->GetValue() - this->step, this->range_min ), 1, 1 );
	}

	return 0;
}




void CObjectSlideBar::setCursorLayerDecal( Layer *layer, int startDecal )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::setCursorLayerDecal");
#endif
//***********************************

	if ( direction == SLB_VERTICAL )
		layer->Ydecal = getCursorPosition() - startDecal;
	else
		layer->Xdecal = getCursorPosition() - startDecal;
}






/* on utilise des (double) a cause des grandes valeurs possibles pour le max et/ou min */
int CObjectSlideBar::getCursorPosition()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::getCursorPosition");
#endif
//***********************************


	if ( this->max == this->min )
	{
		if ( this->reverse )
		{
			if ( direction == SLB_VERTICAL )
				return offset2 - realObjH + offset3;
			else
				return offset2 - realObjW + offset3;
		}
		else
			return offset1;
	}

	if ( direction == SLB_VERTICAL )
	{
		if ( this->reverse )
			return (int)(offset1 - ((double)(offset1 - offset2 - offset3 + realObjH ) * (double)(this->max - value)) / (double)(max - min));
		else
			return (int)(offset1 - ((double)(offset1 - offset2 - offset3 + realObjH ) * (double)(this->min - value)) / (double)(min - max));
	}
	else
	{
		if ( this->reverse )
			return (int)(offset1 - ((double)(offset1 - offset2 - offset3 + realObjW ) * (double)(this->max - value)) / (double)(max - min));
		else
			return (int)(offset1 - ((double)(offset1 - offset2 - offset3 + realObjW ) * (double)(this->min - value)) / (double)(min - max));
	}
}






int CObjectSlideBar::getCursorMiddlePosition()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::getCursorMiddlePosition");
#endif
//***********************************

	if ( direction == SLB_VERTICAL )
		return getCursorPosition() + (realObjH - offset3) / 2;
	else
		return getCursorPosition() + (realObjW - offset3) / 2;
}





void CObjectSlideBar::setLayerDecal( Layer *layer, int offset )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::setLayerDecal");
#endif
//***********************************

	if ( direction == SLB_VERTICAL )
		layer->Ydecal = offset;
	else
		layer->Xdecal = offset;
}




Rect2D CObjectSlideBar::getRect( int part, int first_offset, int last_offset )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::getRect");
#endif
//***********************************

	if ( direction == SLB_VERTICAL )
		return Rect2D( GetIndexBitmap( part ) * ObjW, first_offset, 
					   GetIndexBitmap( part ) * ObjW + ObjW, last_offset );
	else
		return Rect2D( first_offset, GetIndexBitmap( part ) * ObjH, 
					   last_offset, GetIndexBitmap( part ) * ObjH + ObjH );
}




Rect2D CObjectSlideBar::getIntersectedRect( int part, int first_offset, int last_offset, Rect2D paintrect )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::getIntersectedRect");
#endif
//***********************************

	if ( direction == SLB_VERTICAL )
	{
		if ( part != CURSOR )
			return IntersectionRectangle( getRect( part, first_offset, last_offset ),
										  MoveRectangleByVecteur( paintrect, Point2D(GetIndexBitmap( part ) * ObjW, 0) ) );
		else
			return MoveRectangleByVecteur( IntersectionRectangle( paintrect,
																  Rect2D( 0, getCursorPosition(), ObjW, getCursorPosition() + realObjH - offset3 ) ),
										   Point2D( 0, first_offset - getCursorPosition() ) );
	}
	else
	{
		if ( part != CURSOR )
			return IntersectionRectangle( getRect( part, first_offset, last_offset ),
										  MoveRectangleByVecteur( paintrect, Point2D(0, GetIndexBitmap( part ) * ObjH) ) );
		else
			return MoveRectangleByVecteur( IntersectionRectangle( paintrect,
																  Rect2D( getCursorPosition(), 0, getCursorPosition() + realObjW - offset3, ObjH ) ),
										   Point2D( first_offset - getCursorPosition(), 0 ) );
	}
}





Layer *CObjectSlideBar::GetLayer(mmachine m, int p_tab)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::GetLayer");
#endif
//***********************************


	if (ObjLayer==NULL) return NULL;
	
	Layer *max_arrow, *min_arrow, *body_max, *body_min, *cursor;
	PtrObjBitmap p_bmp, p_abmp;

	max_arrow = ObjLayer;
	min_arrow = max_arrow->nextLayer();
	body_max  = min_arrow->nextLayer();
	body_min  = body_max->nextLayer();
	cursor	  = body_min->nextLayer();

	// m a j des ptr Scol
	p_bmp   = GET_PTR_OBJ_BITMAP(GET_BMP(MTOP(MMfetch(mm,p_tab,ALPHA))));
	p_abmp  = GET_PTR_OBJ_BITMAP(GET_ABMP(MTOP(MMfetch(mm,p_tab,ALPHA))));
	
	max_arrow->RGBbitmap   = p_bmp;
	max_arrow->AlphaBitmap = p_abmp;
	min_arrow->RGBbitmap   = p_bmp;
	min_arrow->AlphaBitmap = p_abmp;
	body_max->RGBbitmap	   = p_bmp;
	body_max->AlphaBitmap  = p_abmp;
	body_min->RGBbitmap	   = p_bmp;
	body_min->AlphaBitmap  = p_abmp;
	cursor->RGBbitmap	   = p_bmp;
	cursor->AlphaBitmap	   = p_abmp;

	max_arrow->sourceRect  = getRect( MAX_ARROW, this->offset2, this->offset3 );
	min_arrow->sourceRect  = getRect( MIN_ARROW, 0, this->offset1 );
	if ( this->reverse )
	{
		body_max->sourceRect   = getRect( BODY_MAX, this->offset1, getCursorMiddlePosition() );
		body_min->sourceRect   = getRect( BODY_MIN, getCursorMiddlePosition(), this->offset2 );
		setLayerDecal( body_max, offset1 );
		setLayerDecal( body_min, getCursorMiddlePosition() );
	}
	else
	{
		body_max->sourceRect   = getRect( BODY_MAX, getCursorMiddlePosition(), this->offset2 );
		body_min->sourceRect   = getRect( BODY_MIN, this->offset1, getCursorMiddlePosition() );
		setLayerDecal( body_max, getCursorMiddlePosition() );
		setLayerDecal( body_min, offset1 );
	}
	if ( direction == SLB_VERTICAL )
		cursor->sourceRect	   = getRect( CURSOR, this->offset3, realObjH);
	else
		cursor->sourceRect	   = getRect( CURSOR, this->offset3, realObjW );

	setLayerDecal( max_arrow, offset2 );
	setCursorLayerDecal( cursor, 0 );


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::GetLayer end");
#endif
//***********************************
	return ObjLayer;
}





Layer *CObjectSlideBar::GetLayerPart(mmachine m,Rect2D *paintrect,int p_tab)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::GetLayerPart");
#endif
//***********************************

	if (ObjLayer==NULL) return NULL;

	Layer *max_arrow, *min_arrow, *body_max, *body_min, *cursor;
	PtrObjBitmap p_bmp, p_abmp;

	max_arrow = ObjLayer;
	min_arrow = max_arrow->nextLayer();
	body_max  = min_arrow->nextLayer();
	body_min  = body_max->nextLayer();
	cursor	  = body_min->nextLayer();

	// m a j des ptr Scol
	p_bmp   = GET_PTR_OBJ_BITMAP(GET_BMP(MTOP(MMfetch(mm,p_tab,ALPHA))));
	p_abmp  = GET_PTR_OBJ_BITMAP(GET_ABMP(MTOP(MMfetch(mm,p_tab,ALPHA))));
	
	max_arrow->RGBbitmap   = p_bmp;
	max_arrow->AlphaBitmap = p_abmp;
	min_arrow->RGBbitmap   = p_bmp;
	min_arrow->AlphaBitmap = p_abmp;
	body_max->RGBbitmap	   = p_bmp;
	body_max->AlphaBitmap  = p_abmp;
	body_min->RGBbitmap	   = p_bmp;
	body_min->AlphaBitmap  = p_abmp;
	cursor->RGBbitmap	   = p_bmp;
	cursor->AlphaBitmap	   = p_abmp;

	max_arrow->sourceRect = getIntersectedRect( MAX_ARROW, this->offset2, this->offset3, *paintrect );
	min_arrow->sourceRect = getIntersectedRect( MIN_ARROW, 0, this->offset1, *paintrect );
	if ( this->reverse )
	{
		body_max->sourceRect  = getIntersectedRect( BODY_MAX, this->offset1, getCursorMiddlePosition(), *paintrect );
		body_min->sourceRect  = getIntersectedRect( BODY_MIN, getCursorMiddlePosition(), this->offset2, *paintrect );
	}
	else
	{
		body_max->sourceRect  = getIntersectedRect( BODY_MAX, getCursorMiddlePosition(), this->offset2, *paintrect );
		body_min->sourceRect  = getIntersectedRect( BODY_MIN, this->offset1, getCursorMiddlePosition(), *paintrect );
	}
	// on cherche quelle est la sous-bitmap de l'objet
	if ( direction == SLB_VERTICAL )
	{
		cursor->sourceRect	  = getIntersectedRect( CURSOR, this->offset3, realObjH, *paintrect );

		if ( this->reverse )
		{
			setLayerDecal( body_max, max( 0, offset1 - paintrect->RctHG.iptY ) );
			setLayerDecal( body_min, max( 0, getCursorMiddlePosition() - paintrect->RctHG.iptY ) );
		}
		else
		{
			setLayerDecal( body_max, max( 0, getCursorMiddlePosition() - paintrect->RctHG.iptY ) );
			setLayerDecal( body_min, max( 0, offset1 - paintrect->RctHG.iptY ) );
		}
		setLayerDecal( max_arrow, max( 0, offset2 - paintrect->RctHG.iptY ) );
		setCursorLayerDecal( cursor, paintrect->RctHG.iptY );
	}
	else
	{
		cursor->sourceRect	  = getIntersectedRect( CURSOR, this->offset3, realObjW, *paintrect );

		if ( this->reverse )
		{
			setLayerDecal( body_max, max( 0, offset1 - paintrect->RctHG.iptX ) );
			setLayerDecal( body_min, max( 0, getCursorMiddlePosition() - paintrect->RctHG.iptX ) );
		}
		else
		{
			setLayerDecal( body_max, max( 0, getCursorMiddlePosition() - paintrect->RctHG.iptX ) );
			setLayerDecal( body_min, max( 0, offset1 - paintrect->RctHG.iptX ) );
		}
		setLayerDecal( max_arrow, max( 0, offset2 - paintrect->RctHG.iptX ) );
		setCursorLayerDecal( cursor, paintrect->RctHG.iptX );
	}


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::GetLayerPart end");
#endif
//***********************************
	return ObjLayer;
}





int CObjectSlideBar::DestroyAllLayers()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::DestroyAllLayers");
#endif
//***********************************

	if (ObjLayer!=NULL)
		deleteLayers(ObjLayer);
	ObjLayer=NULL;
	return 0;
}




int CObjectSlideBar::ResizeLayer(int w,int h,int p_tab)
{
	int k,tmp_res;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::ResizeLayer");
#endif
//***********************************

	k=OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_RESIZE_RESSOURCE);
	if (k==0)
	{
		
		// evaluation de la taille du slidebar
		int nbre_etat=1;
		if (ObjFlags&SLB_GAUGE) nbre_etat *= 2;
		if (ObjFlags&SLB_ROLLOVER) nbre_etat *= 3;
		if (ObjFlags&SLB_DISABLE) nbre_etat++;
		if (ObjFlags&SLB_MASK) nbre_etat++;
		if (direction % 2 == SLB_HORIZONTAL)
			h=h*nbre_etat;
		else
			w=w*nbre_etat;
		
		// execution du reflexe de redimensionnemnt du layer
		CHECK(MMpush(mm,ITOM(w)));
		CHECK(MMpush(mm,ITOM(h)));
		CHECK(MMpush(mm,ITOM(offset1)));
		CHECK(MMpush(mm,ITOM(offset2)));
		CHECK(MMpush(mm,ITOM(offset3)));
		CHECK(MMpush(mm,ITOM(3)));
		CHECK(MBdeftab(mm));
		CHECK(OBJcallreflex(mm,3));
		
		/* prevent from destruction of container or object in user callback */
		if (GetObjectBase(mm,FindObjNodeFromHdlSys(mm,(int)this))==NULL) 
			return 0;

		// pile : [AlphaBitmap [I I I]]
		int p_ret,p_param;
		int p_abmp=NIL;
		if ((p_ret=MTOP(MMget(mm,-2)))==NIL)
		{   // valeur de retour nil
			MMechostr(1,"_CBcompSlideBarResizeResource: return value is nil\n");
			ChangeResource(mm,ALPHA,NIL);
			return 0;
		}

		if ((p_abmp=MTOP(MMfetch(mm,p_ret,0)))==NIL)
		{
			MMechostr(1,"_CBcompSlideBarResizeResource: alphabitmap is nil\n");
			ChangeResource(mm,ALPHA,NIL);		
			return 0;
		}
				
		if ((p_param=MTOP(MMfetch(mm,p_ret,1)))==NIL)
		{
			MMechostr(1,"_CBcompSlideBarResizeResource: offsets is nil\n");
			ChangeResource(mm,ALPHA,NIL);		
			return 0;
		}
		
		// recuperation de l'alphabitmap utilisateur 
		// et creation du nouveau layer
		int transparency;
		PtrObjBitmap bmp =GET_PTR_OBJ_BITMAP(GET_BMP(p_abmp));
		PtrObjBitmap abmp=GET_PTR_OBJ_BITMAP(GET_ABMP(p_abmp));
		if ((transparency = GET_TRANSP(p_abmp))==NIL) transparency = NO_TRANSPARENCY;

		if (bmp==NULL)
		{
			MMechostr(1,"_CBcompSlideBarResizeResource: bitmap in alphabitmap is nil or already destroyed\n");
			ChangeResource(mm,ALPHA,NIL);		
			return 0;
		}

		
		if ((direction % 2 == SLB_HORIZONTAL && bmp->TailleH!=h) ||
			(direction % 2 == SLB_VERTICAL   && bmp->TailleW!=w)
			)
		{
			MMechostr(1,"_CBcompSlideBarResizeResource: not good format for alphabitmap (requested size :%d %d received size:%d %d)\n",w,h,bmp->TailleW,bmp->TailleH);
			ChangeResource(mm,ALPHA,NIL);		
			return 0;
		}


		// mise à jour des parametres du CompBitmap
		this->offset1 = MTOI( MMfetch( mm, p_param, 0 ) );
		this->offset2 = MTOI( MMfetch( mm, p_param, 1 ) );
		this->offset3 = MTOI( MMfetch( mm, p_param, 2 ) );
		
		if ( (direction % 2 == SLB_HORIZONTAL && offset3!=w) ||
			 (direction % 2 == SLB_VERTICAL   && offset3!=h)
			)
		{
			MMechostr(1,"_CBcompSlideBarResizeResource: not good format for alphabitmap (requested offset3:%d received offset3:%d)\n",w,offset3);
			ChangeResource(mm,ALPHA,NIL);		
			return 0;
		}
		
		if ( this->min != this->max )
			this->valueStep = ( this->offset2 - this->offset1 ) / ( this->max - this->min );
		else
			this->valueStep = 0;
	
		this->realObjW = bmp->TailleW;
		this->realObjH = bmp->TailleH;



		ObjLayer = new Layer( bmp, abmp, transparency );
		Layer *layerCursor = new Layer( bmp, abmp, transparency );
		ObjLayer->addLayer( layerCursor );
		layerCursor = new Layer( bmp, abmp, transparency );
		ObjLayer->addLayer( layerCursor );
		layerCursor = new Layer( bmp, abmp, transparency );
		ObjLayer->addLayer( layerCursor );
		layerCursor = new Layer( bmp, abmp, transparency );
		ObjLayer->addLayer( layerCursor );
		
		// remplacement de la valeur du pointeur de l'alphabitmap
		// dans le tab
		ChangeResource(mm,ALPHA,p_abmp);		
		return 0;
	}
	// callback non definie ou invalide et objet doit etre absolument resizé!!
	MMechostr(1,"_CBcompSlideBarResizeResource not defined and object need to be resized!!!\n");


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::ResizeLayer end");
#endif
//***********************************
	return 1;
}





int CObjectSlideBar::GetValue()
{
	return this->value;
}

int CObjectSlideBar::GetMax()
{
	return this->max;
}

int CObjectSlideBar::GetMin()
{
	return this->min;
}

int CObjectSlideBar::supports( int type )
{
	return ( type == LINK_MOVE || type == LINK_RESIZE );
}





int CObjectSlideBar::handle(CObjMessage *msg)
{
	int direction, min, max, value, redrawobject;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::handle");
#endif
//***********************************

	int repaint_needed = 0;

	switch (msg->GetType())
	{
	case LINK_RESIZE:
		//recherche les informations du message
		direction = (int)(static_cast <CObjMessageResize *> (msg))->GetDirection();
		min =		(int)(static_cast <CObjMessageResize *> (msg))->GetMinOffset();
		max =		(int)(static_cast <CObjMessageResize *> (msg))->GetMaxOffset();
		redrawobject = msg->GetRedrawObject();

		//traitement des informations du message
		if (this->direction == SLB_VERTICAL)
		{
			if (direction == DIR_VERTICAL)
			{
				if ( this->SetMax(max(this->max + max, this->min), 1, 0, redrawobject) )
					repaint_needed = 1;
				if ( this->SetMin(min(this->min + min, this->max), 1, 0, redrawobject) )
					repaint_needed = 1;
				if ( redrawobject && repaint_needed )
					Redraw();
			}
			else if (direction == -DIR_VERTICAL)
			{
				if ( this->SetMax(max(this->max - max, this->min), 1, 0, redrawobject) )
					repaint_needed = 1;
				if ( this->SetMin(min(this->min - min, this->max), 1, 0, redrawobject) )
					repaint_needed = 1;
				if ( redrawobject && repaint_needed )
					Redraw();
			}
		}
		else
		{
			if (direction == DIR_HORIZONTAL)
			{
				if ( this->SetMax(max(this->max + max, this->min), 1, 0, redrawobject) )
					repaint_needed = 1;
				if ( this->SetMin(min(this->min + min, this->max), 1, 0, redrawobject) )
					repaint_needed = 1;
				if ( redrawobject && repaint_needed )
					Redraw();
			}
			else if (direction == -DIR_HORIZONTAL)
			{
				if ( this->SetMax(max(this->max - max, this->min), 1, 0, redrawobject) )
					repaint_needed = 1;
				if ( this->SetMin(min(this->min - min, this->max), 1, 0, redrawobject) )
					repaint_needed = 1;
				if ( redrawobject && repaint_needed )
					Redraw();
			}
		}
		break;

	case LINK_MOVE:
		//recherche les informations du message
		direction = (int)(static_cast <CObjMessageMove*> (msg))->GetDirection();
		value =		(int)(static_cast <CObjMessageMove*> (msg))->GetOffset();
		redrawobject = msg->GetRedrawObject();

		//traite les informations du message
		if (this->direction == SLB_VERTICAL)
		{
			if (direction == DIR_VERTICAL)
				this->SetValue(max(min(this->value + value, this->range_max), this->range_min), 0, redrawobject);
			else
				if (direction == -DIR_VERTICAL)
					this->SetValue(max(min(this->value - value, this->range_max ), this->range_min), 0, redrawobject);
		}
		else
		{
			if (direction == DIR_HORIZONTAL)
				this->SetValue(max(min(this->value + value, this->range_max ), this->range_min), 0, redrawobject);
			else
				if (direction == -DIR_HORIZONTAL)
					this->SetValue(max(min(this->value - value, this->range_max ), this->range_min), 0, redrawobject);
		}
		break;

	default:
		break;
	}


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::handle end");
#endif
//***********************************

	return 0;
}





int CObjectSlideBar::send_notification_value( int type, int direction, int value, int redrawobject )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::send_notification_value");
#endif
//***********************************

	//instancie la classe CObjMessageMove
	CObjMessageMove* msg = new CObjMessageMove(direction, value, redrawobject);

	//propage le message aux objets liés
	this->notify(msg);
	delete msg;

	return 0;
}





int CObjectSlideBar::send_notification_max( int type, int direction, int value, int redrawobject )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::send_notification_max");
#endif
//***********************************

	//instancie la classe CObjMessageResize
	CObjMessageResize* msg = new CObjMessageResize(direction, 0, value, redrawobject);

	//propage le message aux objets liés
	this->notify(msg);
	delete msg;

	return 0;
}




int CObjectSlideBar::send_notification_min( int type, int direction, int value, int redrawobject )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectSlideBar::send_notification_min");
#endif
//***********************************

	//instancie la classe CObjMessageResize
	CObjMessageResize* msg = new CObjMessageResize(direction, value, 0, redrawobject);

	//propage le message aux objets liés
	this->notify(msg);
	delete msg;

	return 0;
}





// fonction de creation d'une scrollbar au niveau de scol.
// Le resultat est placé dans la pile!
int CreateLinkedScrollBar(mmachine m,int channelpos,int flag_hdl,int typescroll,int pas)
{
	int p_slidebar,tmp_res,i;
	// pile voulue pour creer le slidebar vertical : .... Chn ObjContainer new_object [I I] I I AlphaBitmap [I I I] I I I I
	// empilement de tous les parametres du slidebar


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCreateLinkedScrollBar");
#endif
//***********************************
			
	//Chn ObjContainer new_object
	CHECK( MMpush( m,MMget(m,channelpos)));
	CHECK( MMpush( m,MMget(m,channelpos)));
	CHECK( MMpush( m,MMget(m,channelpos)));
	
	// pile : Chn ObjCont new_object infos_slidebarh info_slidebarv Chn ObjCont new_object
	// on a besoin d'extraire 5 parametres a partir de info_slidebarv
	for (i=0;i<5;i++)
		CHECK(MMpush(m,NIL));
	
	// pile : Chn ObjCont new_object infos_slidebarh info_slidebarv Chn ObjCont new_object nil nil nil nil nil
	p_slidebar = MTOP( MMget( m, 8 ) );

	// les coordonees
	MMset( m, 4, MMfetch( m, p_slidebar, 0 ) );
	
	// les flags
	MMset( m, 3, ITOM(MTOI(MMfetch( m, p_slidebar, 1 ))|OBJ_ENABLE|OBJ_VISIBLE) );
	MMset( m, 2, ITOM( flag_hdl ) );

	// AlphaBitmap
	MMset( m, 1, MMfetch( m, p_slidebar, 2 ) );
	
	// offsets
	MMset( m, 0, MMfetch( m, p_slidebar, 3 ) );
	
	// pile: .... Chn ObjContainer new_object [I I] I I AlphaBitmap [I I I]
	// direction, min, max et step
	CHECK( MMpush( m, ITOM( typescroll ) ) );
	CHECK( MMpush( m, ITOM( 0 ) ) );
	CHECK( MMpush( m, ITOM( 0 ) ) );
	CHECK( MMpush( m, ITOM( pas ) ) );
	
	// pile: .... Chn ObjContainer new_object [I I] I I AlphaBitmap [I I I] I I I I

	// la creation !
	CHECK( _CRcompSlideBar( m ) );
	CHECK(MMpush(m,MMget(m,0)));

	// creation des liens
	CHECK( MMpush( m, MMget(m,channelpos)));
	CHECK( MMpush( m, ITOM( LINK_MOVE|LINK_RESIZE ) ) );
	CHECK( _CRnodeLink( m ) );
	MMpull(m);
	
	// pile: ... CompSlideBar
	return 0;
}







// FONCTIONS SCOL ASSOCIEES

int _CRcompSlideBar( mmachine m )
{
	int tmp_res;
	int p_alphabmp,flags_creation,flags_handler,p_objpere,p_container;
	PtrObjBitmap bmp,abmp;
	CObjectBase *obj_root,*obj_father,* new_object;
	container * co;
	int min, max, direction, step, offsets, offset1, offset2, offset3;
	int transparency;
	int p_coordinates,x,y,w,h,width,height;
	int nbre_etat = 1;


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_CRcompSlideBar");
#endif
//***********************************

	// pile: Chn ObjContainer ObjNode [I I] I I AlphaBitmap [I I I] I I I I

	if ((MMget( m, 11 )) == NIL )
	{
		MMechostr( MSKTRACE, "_CRcompSlideBar: channel is nil\n" );
		m->pp += 11;
		MMset( m, 0, NIL );
		return 0;
	}
	if ((MMget(m,10))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompSlideBar: container is nil\n");
		m->pp += 11;
		MMset(m,0,NIL);
		return 0;
	}
	if ((p_alphabmp=MTOP(MMget(m,5)))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompSlideBar: bitmap is nil\n");
		m->pp += 11;
		MMset(m,0,NIL);
		return 0;
	}
	if (GET_PTR_OBJ_BITMAP(GET_BMP(p_alphabmp))==NULL)
	{
		MMechostr(MSKTRACE,"_CRcompSlideBar: bitmap is already destroyed\n");
		m->pp += 11;
		MMset(m,0,NIL);
		return 0;
	}

#if DEBUG_OBJNODE
		MMechostr(MSKTRACE,"DEBUG_OBJNODE _CRcompSlideBar\n");
#endif

	if ( (step = MTOI( MMpull( m ) )) == NIL ) step = 0;
	max = MTOI( MMpull( m ) );
	min = MTOI( MMpull( m ) );
	direction = MTOI( MMpull( m ) );
	offsets = MTOP( MMpull( m ) );
	if ( max == NIL || min == NIL || direction == NIL || offsets == NIL ) //|| max == min )
	{
		m->pp += 6;
		MMset( m, 0, NIL );
		return 0;
	}
	offset1 = MTOI( MMfetch( m, offsets, 0 ) );
	offset2 = MTOI( MMfetch( m, offsets, 1 ) );
	offset3 = MTOI( MMfetch( m, offsets, 2 ) );

	// pile: Chn ObjContainer ObjNode [I I] I I AlphaBitmap
	// on inverse l'AlphaBitmap et les coordonnees
	INVERT( m, 0, 3 );

	if ((p_coordinates=MTOP(MMpull(m)))==NIL)
	{
		x=0;
		y=0;
	}
	else
	{
		x=MTOI(MMfetch(m,p_coordinates,0));
		y=MTOI(MMfetch(m,p_coordinates,1));
	}
	if ((flags_handler=MTOI(MMpull(m)))==NIL) flags_handler=0;
	if ((flags_creation=MTOI(MMpull(m)))==NIL) flags_creation=OBJ_ENABLE|OBJ_VISIBLE;

	// pile Chn ObjContainer ObjPere AlphaBitmap
	p_alphabmp = MTOP( MMget( m, 0 ) );
	bmp =GET_PTR_OBJ_BITMAP(GET_BMP(p_alphabmp));
	abmp=GET_PTR_OBJ_BITMAP(GET_ABMP(p_alphabmp));
	if ((transparency = GET_TRANSP(p_alphabmp))==NIL) transparency = NO_TRANSPARENCY;


	width  = bmp->TailleW;
	height = bmp->TailleH;

	// evaluation de la taille du slidebar
	if (flags_creation&SLB_GAUGE) nbre_etat *= 2;
	if (flags_creation&SLB_ROLLOVER) nbre_etat *= 3;
	if (flags_creation&SLB_DISABLE) nbre_etat++;
	if (flags_creation&SLB_MASK) nbre_etat++;
	if (direction % 2 == SLB_HORIZONTAL)
	{
		w=offset3;
		h=height/nbre_etat;
	}
	else
	{
		w=width/nbre_etat;
		h=offset3;
	}
	
	// pile Chn ObjContainer ObjPere AlphaBitmap
	p_objpere=MTOP(MMget(m,1));
	p_container=MTOP(MMget(m,2));
	obj_father=GetObjectBase(m,p_objpere);
	// on inverse p_objpere et channel
	INVERT( m, 1, 3 );
	
	if ((p_objpere!=NIL)&&(obj_father==NULL))
	{
		MMechostr(MSKTRACE,"_CRcompSlideBar: object father already destroyed\n");
		m->pp += 3;
		MMset(m,0,NIL);
		return 0;
	}
	else if ((co=RetrievePtrContainer(m,p_container))==NULL)
	{
		MMechostr(MSKTRACE,"_CRcompSlideBar: container already destroyed\n");
		m->pp += 3;
		MMset(m,0,NIL);
		return 0;
	}
	else if (!co->OwnsObject(obj_father))
	{
		MMechostr(MSKTRACE,"_CRcompSlideBar: father object was not created in this container!\n");
		m->pp += 3;
		MMset(m,0,NIL);
		return 0;
	}
	else
	{

		// evaluation de l'Image
		// un SlideBar est constitue de 5 Layer: 2 fleches, 2 corps et 1 curseur



		Layer *layer = new Layer( bmp, abmp, transparency );




		Layer *layerCursor = new Layer( bmp, abmp, transparency );
		layer->addLayer( layerCursor );

		layerCursor = new Layer( bmp, abmp, transparency );
		layer->addLayer( layerCursor );

		layerCursor = new Layer( bmp, abmp, transparency );
		layer->addLayer( layerCursor );

		layerCursor = new Layer( bmp, abmp, transparency );
		layer->addLayer( layerCursor );

		obj_root=co->Root();
		
	
		// creation du nouvel objet
		new_object=new CObjectSlideBar(co,layer,x,y,w,h,flags_creation,flags_handler,transparency,width,height,min,max,direction,step,offset1,offset2,offset3);
	
		// pile: ObjNode ObjContainer Chn ObjBitmap ObjBitmap
		// ajout de l'objet et creation du nouvel OBJNODE
		CHECK( AddNode(m,obj_root,obj_father,new_object,1) );
		// pile: ObjNode ObjContainer new_object

		// obj_pere et container
		tmp_res = MMpull( m );
		MMpull(m);
		MMpull(m);
		CHECK( MMpush( m, tmp_res ) );

#if DEBUG_OBJNODE
	PrintTree(m,0,FindObjNodeFromHdlSys(m,(int)obj_root));
#endif
	}


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_CRcompSlideBar");
#endif
//***********************************
	return 0;
}






int _DScompSlideBar( mmachine m )
{
	int p;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_DScompSlideBar");
#endif
//***********************************

	if ((p=MTOP(MMpull(m)))!=NIL)
	{
		DsNode(m,p);
		return MMpush(m,0);
	}
	else
		return MMpush(m,NIL);
}






int _SETcompSlideBarValue( mmachine m )
{
	int new_value;
	int p_obj;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_SETcompSlideBarValue");
#endif
//***********************************


	new_value = MTOI( MMpull( m ) );

	if ( new_value == NIL )
		return 0;

	if ((p_obj=MTOP(MMget(m,0)))!=NIL)
	{
		CObjectBase *obj;
		// on recupere l'objet
		if ((obj=GetObjectBase(m,p_obj))==NULL)
			MMechostr(MSKTRACE,"_SETcompSlideBarValue: Object already destroyed.\n");
		else
		{
			int p_tab;	
			if ((p_tab=GetTab(m,p_obj))!=NIL)
				// on change la valeur mais on ne repeind pas
				(static_cast <CObjectSlideBar *> (obj))->SetValue( new_value, 1, 0 );
		}
	}

	return 0;
}





int _SETcompSlideBarMax( mmachine m )
{
	int new_value;
	int p_obj;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_SETcompSlideBarMax");
#endif
//***********************************

	new_value = MTOI( MMpull( m ) );
	
	if ( new_value == NIL )
		return 0;

	if ((p_obj=MTOP(MMget(m,0)))!=NIL)
	{
		CObjectBase *obj;
		// on recupere l'objet
		if ((obj=GetObjectBase(m,p_obj))==NULL)
			MMechostr(MSKTRACE,"_SETcompSlideBarMax: Object already destroyed.\n");
		else
		{
			int p_tab;	
			if ((p_tab=GetTab(m,p_obj))!=NIL)
				// on change la valeur mais on ne repeint pas
				(static_cast <CObjectSlideBar *> (obj))->SetMax( new_value, 1, 1, 0 );	
		}
	}

	return 0;
}







int _SETcompSlideBarMin( mmachine m )
{
	int new_value;
	int p_obj;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_SETcompSlideBarMin");
#endif
//***********************************

	new_value = MTOI( MMpull( m ) );

	if ( new_value == NIL )
		return 0;

	if ((p_obj=MTOP(MMget(m,0)))!=NIL)
	{
		CObjectBase *obj;
		// on recupere l'objet
		if ((obj=GetObjectBase(m,p_obj))==NULL)
			MMechostr(MSKTRACE,"_SETcompSlideBarMin: Object already destroyed.\n");
		else
		{
			int p_tab;	
			if ((p_tab=GetTab(m,p_obj))!=NIL)
				// on change la valeur mais on ne repeint pas
				(static_cast <CObjectSlideBar *> (obj))->SetMin( new_value, 0, 1, 0 );
		}
	}

	return 0;
}






int _SETcompSlideBarStep( mmachine m )
{
	int new_value = MTOI( MMpull( m ) );
	int p_obj;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_SETcompSlideBarStep");
#endif
//***********************************

	if ( new_value == NIL )
		new_value = 0;

	if ((p_obj=MTOP(MMget(m,0)))!=NIL)
	{
		CObjectBase *obj;
		// on recupere l'objet
		if ((obj=GetObjectBase(m,p_obj))==NULL)
			MMechostr(MSKTRACE,"_SETcompSlideBarStep: Object already destroyed.\n");
		else
		{
			int p_tab;	
			if ((p_tab=GetTab(m,p_obj))!=NIL)
				(static_cast <CObjectSlideBar *> (obj))->SetStep( new_value );	
		}
	}

	return 0;
}





int _CONVERTcompSlideBarToObjNode(mmachine m)
{
	return 0;
}


int _CBcompSlideBarValue(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_CHANGE);
}




int _SETcompSlideBarRange( mmachine m )
{
	int new_value = MTOP( MMpull( m ) );
	int p_obj;
	int new_max, new_min;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\n_SETcompSlideBarRange");
#endif
//***********************************

	if ( new_value == NIL )
		return 0;

	new_min = MTOI( MMfetch( m, new_value, 0 ) );
	new_max = MTOI( MMfetch( m, new_value, 1 ) );

	if ((p_obj=MTOP(MMget(m,0)))!=NIL)
	{
		CObjectBase *obj;
		// on recupere l'objet
		if ((obj=GetObjectBase(m,p_obj))==NULL)
			MMechostr(MSKTRACE,"_SETcompSlideBarRange: Object already destroyed.\n");
		else
		{
			int p_tab;
			if ((p_tab=GetTab(m,p_obj))!=NIL)
			{
				if ( new_max != NIL )
					(static_cast <CObjectSlideBar *> (obj))->SetRangeMax( new_max );
				if ( new_min != NIL )
					(static_cast <CObjectSlideBar *> (obj))->SetRangeMin( new_min );
			}
		}
	}

	return 0;
}

int _CBcompSlideBarResizeResource(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_RESIZE_RESSOURCE);
}

int _CBcompSlideBarResize(mmachine m)
{
	return OBJaddreflex(m,OBJNODE,RFLOBJNODE_RESIZE);
}

