//
// Modifications History
//
//$LB (20/12/2002) : 16bits to 24bits
//



#include "Macro.h"
#include "CObjectList.h"
#include "../x/Objstr.h"
#include "utils.h"
#include "container.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 "CObjMessageSelect.h"			//pour la classe CObjMessageSelect et les actions prédéfinies
#include "CObjMessageStringSelect.h"
#include "CObjMessageHideAndShow.h"

extern int OBJNODE;
extern mmachine mm;

#define ELT		0
#define FONT	1
#define SLIDE_V 2



CObjectList::CObjectList(container * cont,Layer *layer,
						 int x,int y,int w,int h, int flags,int contflags, int transp,
						 int direction,
						 int text_color,int text_transp,int shadow_color, int shadow_decal,
						 int select_color, int select_transparency_coeff,
						 int visibleItemsCount, int reservedSpace, PtrObjFont font):CObjectBase(cont,layer,x,y,w,h,flags,contflags,transp)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::CObjectList");
#endif
//***********************************


	this->direction = direction;
	this->firstItem = 0;
	this->LSTtransp = transp;
	this->LSTtextColor = text_color;
	this->LSTtextTransp= text_transp;
	this->LSTshadowColor = shadow_color;
	this->LSTshadowDecal = shadow_decal;
	this->LSTselectColor = select_color;
	this->LSTselectTansparencyCoeff = select_transparency_coeff;
	
	if ( direction == LST_VERTICAL )
		this->itemSize = h / visibleItemsCount;
	else
		this->itemSize = w / visibleItemsCount;
	this->itemSize = max( 1, this->itemSize );
	this->visibleItemsCount = visibleItemsCount;
	
	this->itemClicked = NO_ITEM_CLICKED;
	this->itemSelected = NO_ITEM_SELECTED;
	this->itemsCount = 1;
	if ( reservedSpace == NIL )
		this->reservedSpace = 0;
	else
		this->reservedSpace = reservedSpace;

	
	this->LSTlayerSelect=NULL;
	if ( this->highlightSelected() )
	{
		if ( this->direction == LST_VERTICAL )
			this->LSTlayerSelect = new Layer( ObjW, itemSize, transp, 1 );
		else
			this->LSTlayerSelect = new Layer( itemSize, ObjH, transp, 1 );
		this->LSTlayerSelect->fillLayer( select_color  );
		this->LSTlayerSelect->fillAlphaLayer( select_transparency_coeff );
	}

	this->LSTlayerClicked=NULL;
	if ( this->highlightClicked() )
	{
		if ( this->direction == LST_VERTICAL )
			this->LSTlayerClicked = new Layer( ObjW, itemSize, transp, 1 );
		else
			this->LSTlayerClicked = new Layer( itemSize, ObjH, transp, 1 );
		this->LSTlayerClicked->fillLayer( select_color );
		this->LSTlayerClicked->fillAlphaLayer( select_transparency_coeff );
	}

	this->LSTlayersBitmaps = NULL;

	this->LSTfont = Lib2dFontService.getLayerFont(font);

	this->popup = 0;



//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::CObjectList end");
#endif
//***********************************
#ifdef DEBUG_COMPLIST
	MMechostr(MSKTRACE,"direction: %d\n", this->direction);
	MMechostr(MSKTRACE,"visibleItemsCount: %d\n", this->visibleItemsCount);
	MMechostr(MSKTRACE,"ObjTransparency: %d\n", transp);
#endif
}




CObjectList::~CObjectList()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::~CObjectList");
#endif
//***********************************

	if (ObjLayer!=NULL)
		ObjLayer->nulifyNext();

	if ( this->highlightSelected() )
		delete( this->LSTlayerSelect );
	if ( this->highlightClicked() )
		delete( this->LSTlayerClicked );

	// les layers pour les images des elements
	while ( this->LSTlayersBitmaps != NULL )
	{
		Layer *tmp = this->LSTlayersBitmaps->nextLayer();
		delete ( this->LSTlayersBitmaps );
		this->LSTlayersBitmaps = tmp;
	}
	Lib2dFontService.delLayerFont(this->LSTfont);
	

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::~CObjectList end");
#endif
//***********************************
}







int CObjectList::addItem( int position )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::addItem");
#endif
//***********************************
	this->itemsCount++;

#ifdef DEBUG_COMPLIST
	MMechostr(MSKTRACE,"addItem itemsCount: %d\n", this->itemsCount);
#endif

	if ( this->itemsCount > this->visibleItemsCount + 1 )
	{
		if ( this->direction == LST_VERTICAL )
			send_notification_max( LINK_RESIZE, DIR_VERTICAL, 1, 0 );
		else
			send_notification_max( LINK_RESIZE, DIR_HORIZONTAL, 1, 0 );
	}

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::addItem end");
#endif
//***********************************
	return this->itemsCount;
}






int CObjectList::removeItem( int position )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::removeItem");
#endif
//***********************************


	this->itemsCount--;

#ifdef DEBUG_COMPLIST
	MMechostr(MSKTRACE,"removeItem itemsCount: %d\n", this->itemsCount);
#endif

	if ( this->itemsCount > this->visibleItemsCount )
	{
		if ( this->direction == LST_VERTICAL )
			send_notification_max( LINK_RESIZE, -DIR_VERTICAL, 1, 0 );
		else
			send_notification_max( LINK_RESIZE, -DIR_HORIZONTAL, 1, 0 );
	}

	// deselection de l'element clique
	if ( getClickedItem() == position )
		setClickedItem( NO_ITEM_CLICKED, 1, 0 );


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::removeItem end");
#endif
//***********************************
	return this->itemsCount;
}







int CObjectList::removeAllItems()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::removeAllItems");
#endif
//***********************************
	
	if ( this->itemsCount > this->visibleItemsCount )
	{
		if ( this->direction == LST_VERTICAL )
			send_notification_max( LINK_RESIZE, DIR_VERTICAL, - this->itemsCount + this->visibleItemsCount + 1, 0 );
		else
			send_notification_max( LINK_RESIZE, DIR_HORIZONTAL, - this->itemsCount + this->visibleItemsCount + 1, 0 );
	}

	this->itemsCount = 1;
	this->firstItem = 0;
	this->itemClicked = NO_ITEM_CLICKED;
	this->itemSelected = NO_ITEM_SELECTED;


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





int CObjectList::getItemsCount()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::getItemsCount");
#endif
//***********************************

	return this->itemsCount - 1;
}




int CObjectList::getFirstItem()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::getFirstItem");
#endif
//***********************************

	return this->firstItem;
}





int CObjectList::setFirstItem( int newIndex, int notifylinks, int redrawobject )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::setFirstItem");
#endif
//***********************************


	// on plafonne pour ne pas sortir de la liste
	newIndex = max (min( newIndex, this->itemsCount - this->visibleItemsCount - 1 ), 0 );

	if ( this->firstItem != newIndex )
	{
		if ( notifylinks )
		{
			int direction;

			if ( this->direction == LST_VERTICAL )
				direction = DIR_VERTICAL;
			else
				direction = DIR_HORIZONTAL;

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

		this->firstItem = newIndex;

		if ( redrawobject )
			Redraw();

		return 1;
	}

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





int CObjectList::getSelectedItem()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::getSelectedItem");
#endif
//***********************************

	return this->itemSelected;
}




int CObjectList::getClickedItem()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::getClickedItem");
#endif
//***********************************

	return this->itemClicked;
}





int CObjectList::setSelectedItem( int newIndex, int notifylinks, int redrawobject )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::setSelectedItem");
#endif
//***********************************
    
	bool selectmodified=newIndex!=this->itemSelected;
    
    this->itemSelected = newIndex;

	if ( this->highlightSelected() )
	{
		if ( this->itemSelected != NO_ITEM_SELECTED )
		{
			if ( this->itemSelected < this->firstItem )
				setFirstItem( this->itemSelected, 0, 0 );
			else if ( this->itemSelected >= this->firstItem + this->visibleItemsCount )
				setFirstItem( this->itemSelected - this->visibleItemsCount + 1, 0, 0 );
		}
	}

	if ( notifylinks )
		this->send_notification_select(LINK_SELECT, this->itemSelected, ACT_MOUSEHOVER, redrawobject);

	if ( this->highlightSelected() && redrawobject )
		Redraw();

    if (selectmodified)
    {   // la selection courante a été modifiée
        int tmp_res;
        int k = OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_CHANGE);
	    if (k>0) return 1; 
	    if (k==0)
	    {
		    CHECK( MMpush( mm, ITOM( this->itemSelected ) ) );
		    return OBJcallreflex(mm,1);
	    }
    }

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






int CObjectList::setClickedItem( int newIndex, int notifylinks, int redrawobject )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::setClickedItem");
#endif
//***********************************
	
	this->itemClicked = max( -1, min( itemsCount - 1, newIndex) );
#ifdef DEBUG_COMPLIST
	MMechostr(MSKTRACE,"setClickedItem: %d %d %d\n", this->itemClicked, notifylinks, redrawobject);
#endif

	if ( this->highlightClicked() )
	{
		if ( this->itemClicked != NO_ITEM_CLICKED )
		{
			if ( this->itemClicked < this->firstItem )
				setFirstItem( this->itemClicked, 0, 0 );
			else if ( this->itemClicked >= this->firstItem + this->visibleItemsCount )
				setFirstItem( this->itemClicked - this->visibleItemsCount + 1, 0, 0 );
		}
	}

	if ( notifylinks )
	{
		int i, p_content;

		this->send_notification_select(LINK_SELECT, this->itemClicked, ACT_MOUSECLICK, redrawobject);

		if (this->itemClicked == NO_ITEM_CLICKED)
			p_content = NIL;
		else
		{
			p_content = MTOP( MMfetch( mm, GetTab( mm, FindObjNodeFromHdlSys( mm, (int)this ) ), 0 ) );
			i = 0;

			while ( i < this->itemClicked && p_content != NIL )
			{
				i++;
				p_content = MTOP( MMfetch( mm, p_content, 1 ) );
			}
		}

		if ( p_content != NIL ) // position specifiee valide
			this->send_notification_string_select(LINK_STRING_SELECT, MMstartstr( mm, MTOP( MMfetch( mm, MTOP( MMfetch( mm, p_content, 0 ) ), 0 ) ) ), redrawobject);
		else
			this->send_notification_string_select(LINK_STRING_SELECT, "", redrawobject);

		if ( this->popup )
		{
			//this->popup = 0; // est-ce necessaire ?
			this->send_notification_close_list();			
		}
		if ( redrawobject )
			this->repaint( 2 );
	}

	if ( this->highlightClicked() && redrawobject )
		Redraw();


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






int CObjectList::IsMouseOnObject(int x,int y, int p_tab)
{
	// on est toujours sur l'objet !
	return 1;
}








int CObjectList::CursorMove(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::CursorMove");
#endif
//***********************************
	
	if ( this->IsObjectEnabled() )
	{
		x = x - ObjX;
		y = y - ObjY;

		if ( (keyFlags&MK_LBUTTON) || (keyFlags&MK_RBUTTON) )
			return 0;

		if ( this->direction == LST_VERTICAL )
		{
			if (  y >= this->itemSize * this->itemsDisplayed )
				return CursorMoveOut( x, y, keyFlags, p_tab, redrawobject );

			setSelectedItem ( min( y / this->itemSize, this->visibleItemsCount ) + this->firstItem, 1, redrawobject );
		}
		else
		{
			if (  x >= this->itemSize * this->itemsDisplayed )
				return CursorMoveOut( x, y, keyFlags, p_tab, redrawobject );

			setSelectedItem ( min( x / this->itemSize, this->visibleItemsCount ) + this->firstItem, 1, redrawobject );
		}
	}


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







int CObjectList::CursorMoveIn(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::CursorMoveIn");
#endif
//***********************************


	return CursorMove( x, y, keyFlags, p_tab, redrawobject );
}





int CObjectList::CursorMoveInWithBtnPushed(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::CursorMoveInWithBtnPushed");
#endif
//***********************************


	return CursorMoveIn( x, y, keyFlags, p_tab, redrawobject);
}





int CObjectList::CursorMoveOut(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::CursorMoveOut");
#endif
//***********************************

	setSelectedItem( NO_ITEM_SELECTED, 1, redrawobject );
	return 0;
}




int CObjectList::CursorMoveOutWithBtnPushed(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::CursorMoveOutWithBtnPushed");
#endif
//***********************************


	return CursorMoveOut( x, y, keyFlags, p_tab, redrawobject);
}




int CObjectList::CursorMoveOutsideWithBtnPushed(int x,int y,int keyFlags, int p_tab,int redrawobject)
{
	return 0;
}





int CObjectList::ClickIn(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
	int k, tmp_res;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::ClickIn");
#endif
//***********************************	

	if ( ( this->direction == LST_VERTICAL && y - ObjY > this->itemSize * this->itemsDisplayed ) ||
		 ( this->direction == LST_HORIZONTAL && x - ObjX > this->itemSize * this->itemsDisplayed ) )
		return 0;

	setClickedItem(	this->itemSelected, 1, redrawobject );

	if ( this->itemClicked != NO_ITEM_CLICKED )
	{
        // evenement special click ajoute pour club-house
        // avec transmission du btn clique
        if ( this->popup ) // bidouille crade ??
		{
			int p_obj = FindObjNodeFromHdlSys( mm, (int)this );
			int p_father = GetFather( mm, GetFather( mm, p_obj ) );
			int desc = OBJfindTM(mm,OBJNODE,PTOM(p_father));
			int hdlsys_buf = MTOP( MMfetch( mm, desc, OFFOBJHAND ) );
			int father = MMfetch( mm, hdlsys_buf, 0 );
			k = OBJbeginreflex(mm,OBJNODE,father,RFLOBJNODE_SCLICK);
		}
		else
			k = OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_SCLICK);
		if (k>0) return 1; 
		if (k==0)
		{
			int mask=keyFlags&(MK_CONTROL|MK_LBUTTON|MK_MBUTTON|MK_RBUTTON|MK_SHIFT);

            CHECK( MMpush( mm, ITOM( this->itemSelected ) ) );
			CHECK( MMpush( mm, ITOM( btn)) );
            CHECK( MMpush( mm, ITOM( mask)) );
            CHECK( OBJcallreflex(mm,3) );
		}


		if ( this->popup ) // bidouille crade ??
		{
			int p_obj = FindObjNodeFromHdlSys( mm, (int)this );
			int p_father = GetFather( mm, GetFather( mm, p_obj ) );
			int desc = OBJfindTM(mm,OBJNODE,PTOM(p_father));
			int hdlsys_buf = MTOP( MMfetch( mm, desc, OFFOBJHAND ) );
			int father = MMfetch( mm, hdlsys_buf, 0 );
			k = OBJbeginreflex(mm,OBJNODE,father,RFLOBJNODE_CLICK);
		}
		else
			k = OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_CLICK);
		if (k>0) return 1; 
		if (k==0)
		{
			if ( redrawobject && IsObjectRepaintBeforeCallback() )
				Redraw();
			CHECK( MMpush( mm, ITOM( this->itemSelected ) ) );
			return OBJcallreflex(mm,1);
		}
		else if ( redrawobject )
			Redraw();
	}


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






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

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





int CObjectList::DblClickIn(int x,int y,int btn,int keyFlags, int p_tab,int redrawobject)
{
	int k, tmp_res;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::DblClickIn");
#endif
//***********************************	

	if ( ( this->direction == LST_VERTICAL && y - ObjY > this->itemSize * this->itemsDisplayed ) ||
		 ( this->direction == LST_HORIZONTAL && x - ObjX > this->itemSize * this->itemsDisplayed ) )
		return 0;

	k = OBJbeginreflex(mm,OBJNODE,(int)this,RFLOBJNODE_DBLCLICK);
	if (k>0) return 1; 
	if (k==0)
	{
		CHECK( MMpush( mm, ITOM( this->itemSelected ) ) );
		return OBJcallreflex(mm,1);
	}


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

	return 0;
}






int CObjectList::MouseWheel(int delta,int x,int y,int keyFlags,int p_tab,int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::MouseWheel");
#endif
//***********************************
	
	if ( setFirstItem( this->firstItem - delta, 1, 0 ) )
	{
		setSelectedItem( this->itemSelected - delta, 1, redrawobject );
		if ( redrawobject )
		{
			Redraw();
			this->repaint( 2 );
		}
	}


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







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

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

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

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


int CObjectList::Timer( int timerID )
{
	return 0;
}









// optimiser sans reparcourir toute la liste a chaque fois:
// le p_elt_content correspondant au firstItem est stocke dans le node
// pb car listes scol chainees que ds un sens !
Layer *CObjectList::DrawListElements( mmachine m, int p_content )
{
	int p_elt_content = p_content;
	int i;
	char *text;
	Layer *bitmapsLayers = NULL;


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::DrawListElements");
#endif
//***********************************
#ifdef DEBUG_COMPLIST
	MMechostr(MSKTRACE,"DrawListElements\n");
#endif
	// on se place sur le premier element visible
	// p_content pointe sur un TAB: S AlphaBitmap p_next
	i = 0;
	while ( i < this->firstItem && p_elt_content != NIL )
	{
		p_elt_content = MTOP( MMfetch( m, p_elt_content, 1 ) );
		i++;
	}
	// !!! si liste tres grande, ca va mouliner...
	// optimisation possible en memorisant le p_elt du premier objet ds le node ?

#ifdef DEBUG_COMPLIST
	MMechostr(MSKTRACE,"firstItem: %d (%d voulu)\n", i, this->firstItem);
#endif
	i = 0;
	if ( this->visibleItemsCount != NIL )
		while ( i < this->visibleItemsCount && p_elt_content != NIL )
		{
			// on recupere l'image associee
			if ( MMfetch( m, MTOP( MMfetch( m, p_elt_content, 0 ) ), 1 ) != NIL )
				bitmapsLayers = DrawBitmap( MTOP( MMfetch( m, MTOP( MMfetch( m, p_elt_content, 0 ) ), 1 ) ), i * this->itemSize )->addLayer( bitmapsLayers );
			// on recupere le texte
			if ( MMfetch( m, MTOP( MMfetch( m, p_elt_content, 0 ) ), 0 ) != NIL )
			{
				text = MMstartstr( m, MTOP( MMfetch( m, MTOP( MMfetch( m, p_elt_content, 0 ) ), 0 ) ) );
				DrawText( text, i * this->itemSize );
#ifdef DEBUG_COMPLIST
				MMechostr(MSKTRACE,"DrawText: %s / position: %d\n", text, i * this->itemSize);
#endif
			}

			p_elt_content = MTOP( MMfetch( m, p_elt_content, 1 ) );
			i++;
		}
	else
		while ( p_elt_content != NIL )
		{
			// on recupere le texte
			if ( MMfetch( m, MTOP( MMfetch( m, p_elt_content, 0 ) ), 1 ) != NIL )
				bitmapsLayers = DrawBitmap( MTOP( MMfetch( m, MTOP( MMfetch( m, p_elt_content, 0 ) ), 1 ) ), i * this->itemSize )->addLayer( bitmapsLayers );
			// on recupere l'image associee
			if ( MMfetch( m, MTOP( MMfetch( m, p_elt_content, 0 ) ), 0 ) != NIL )
			{
				text = MMstartstr( m, MTOP( MMfetch( m, MTOP( MMfetch( m, p_elt_content, 0 ) ), 0 ) ) );
				DrawText( text, i * this->itemSize );
#ifdef DEBUG_COMPLIST
				MMechostr(MSKTRACE,"DrawText: %s / position: %d\n", text, i * this->itemSize);
#endif
			}

			p_elt_content = MTOP( MMfetch( m, p_elt_content, 1 ) );
			i++;
		}
	this->itemsDisplayed = i;

#ifdef DEBUG_COMPLIST
	MMechostr(MSKTRACE,"itemsDisplayed: %d\n", this->itemsDisplayed);
#endif

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


	return bitmapsLayers;
}











Layer *CObjectList::DrawBitmap( int p_alphabmp, int position )
{
	PtrObjBitmap src_rgb, src_alpha;
	Layer *bitmapLayer;
	int transparency;
	int taillew, tailleh;

//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::DrawBitmap");
#endif
//***********************************


	src_rgb		 = GET_PTR_OBJ_BITMAP(GET_BMP(p_alphabmp));
	src_alpha	 = GET_PTR_OBJ_BITMAP(GET_ABMP(p_alphabmp));
	transparency = GET_TRANSP(p_alphabmp);

	taillew = src_rgb->TailleW;
	tailleh = src_rgb->TailleH;

	bitmapLayer = new Layer( src_rgb, src_alpha, transparency );
	bitmapLayer->sourceRect = Rect2D( 0, 0, taillew, tailleh );

	if ( this->direction == LST_VERTICAL )
	{
		if ( ObjFlags&LST_IMG_TOP || ObjFlags&LST_IMG_BOTTOM )
		{
			if ( ObjFlags&LST_IMG_TOP )
			{
				if ( ObjFlags&LST_TOP )
					bitmapLayer->Ydecal = position;
				else if ( ObjFlags&LST_BOTTOM )
					bitmapLayer->Ydecal = position + min( max( 0, this->reservedSpace - tailleh ), this->itemSize - tailleh );
				else // centré par défaut
					bitmapLayer->Ydecal = position + min( max( 0, ( this->reservedSpace - tailleh ) / 2 ), this->itemSize - tailleh );
			}
			else // LST_IMG_BOTTOM
			{
				if ( ObjFlags&LST_TOP )
					bitmapLayer->Ydecal = position + max( 0, this->itemSize - this->reservedSpace );
				else if ( ObjFlags&LST_BOTTOM )
					bitmapLayer->Ydecal = position + max( 0, this->itemSize - tailleh );
				else // centré par défaut
					bitmapLayer->Ydecal = position + max( 0, this->itemSize - ( this->reservedSpace + tailleh ) / 2 );
			}

			if ( ObjFlags&LST_RIGHT )
				bitmapLayer->Xdecal = max( 0, ObjW - taillew );
			else if ( ObjFlags&LST_LEFT )
				bitmapLayer->Xdecal = 0;
			else // centré par défaut
				bitmapLayer->Xdecal = max( 0, ( ObjW - taillew ) / 2 );
		}
		else
		{
			if ( ObjFlags&LST_IMG_RIGHT )
			{
				if ( ObjFlags&LST_RIGHT )
					bitmapLayer->Xdecal = max( 0, ObjW - taillew );
				else if ( ObjFlags&LST_LEFT )
					bitmapLayer->Xdecal = max( 0, ObjW - this->reservedSpace );
				else // centré par défaut
					bitmapLayer->Xdecal = max( 0, ObjW - ( this->reservedSpace + taillew ) / 2 );
			}
			else // images à gauche par défaut
			{
				if ( ObjFlags&LST_RIGHT )
					bitmapLayer->Xdecal = min( max( 0, this->reservedSpace - taillew ), ObjW - taillew );
				else if ( ObjFlags&LST_LEFT )
					bitmapLayer->Xdecal = 0;
				else // centré par défaut
					bitmapLayer->Xdecal = min( max( 0, ( this->reservedSpace - taillew ) / 2 ), ObjW - taillew );
			}

			if ( ObjFlags&LST_TOP )
				bitmapLayer->Ydecal = position;
			else if ( ObjFlags&LST_BOTTOM )
				bitmapLayer->Ydecal = position + max( 0, this->itemSize - tailleh );
			else // centré par défaut
				bitmapLayer->Ydecal = position + max( 0, ( this->itemSize - tailleh ) / 2 );
		}
	}
	else // LST_HORIZONTAL
	{
		if ( ObjFlags&LST_IMG_TOP || ObjFlags&LST_IMG_BOTTOM )
		{
			if ( ObjFlags&LST_IMG_BOTTOM )
			{
				if ( ObjFlags&LST_BOTTOM )
					bitmapLayer->Ydecal = max( 0, ObjH - tailleh );
				else if ( ObjFlags&LST_TOP )
					bitmapLayer->Ydecal = max( 0, ObjH - this->reservedSpace );
				else // centré par défaut
					bitmapLayer->Ydecal = max( 0, ObjH - ( this->reservedSpace + tailleh ) / 2 );
			}
			else // images à gauche par défaut
			{
				if ( ObjFlags&LST_BOTTOM )
					bitmapLayer->Ydecal = min( max( 0, this->reservedSpace - tailleh ), ObjH - tailleh );
				else if ( ObjFlags&LST_TOP )
					bitmapLayer->Ydecal = 0;
				else // centré par défaut
					bitmapLayer->Ydecal = min( max( 0, ( this->reservedSpace - tailleh ) / 2 ), ObjH - tailleh );
			}

			if ( ObjFlags&LST_LEFT )
				bitmapLayer->Xdecal = position;
			else if ( ObjFlags&LST_RIGHT )
				bitmapLayer->Xdecal = position + max( 0, this->itemSize - taillew );
			else // centré par défaut
				bitmapLayer->Xdecal = position + max( 0, ( this->itemSize - taillew ) / 2 );
		}
		else
		{
			if ( ObjFlags&LST_IMG_RIGHT )
			{
				if ( ObjFlags&LST_LEFT )
					bitmapLayer->Xdecal = position + max( 0, this->itemSize - this->reservedSpace );
				else if ( ObjFlags&LST_RIGHT )
					bitmapLayer->Xdecal = position + max( 0, this->itemSize - tailleh );
				else // centré par défaut
					bitmapLayer->Xdecal = position + max( 0, this->itemSize - ( this->reservedSpace + taillew ) / 2 );
			}
			else // LST_IMG_LEFT
			{
				if ( ObjFlags&LST_LEFT )
					bitmapLayer->Xdecal = position;
				else if ( ObjFlags&LST_RIGHT )
					bitmapLayer->Xdecal = position + min( max( 0, this->reservedSpace - taillew ), this->itemSize - taillew );
				else // centré par défaut
					bitmapLayer->Xdecal = position + min( max( 0, ( this->reservedSpace - taillew ) / 2 ), this->itemSize - taillew );
			}

			if ( ObjFlags&LST_BOTTOM )
				bitmapLayer->Ydecal = max( 0, ObjH - tailleh );
			else if ( ObjFlags&LST_TOP )
				bitmapLayer->Ydecal = 0;
			else // centré par défaut
				bitmapLayer->Ydecal = max( 0, ( ObjH - tailleh ) / 2 );
		}
	}


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

	return bitmapLayer;
}







void CObjectList::DrawText( char *text, int position )
{
	int x1, y1, x2, y2;


//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::DrawText");
#endif
//***********************************

	if ( text != NULL )
	{
		if ( this->direction == LST_VERTICAL )
		{
			x1 = 0;
			y1 = position;
			x2 = ObjW;
			y2 = position + this->itemSize;
		}
		else
		{
			x1 = position;
			y1 = 0;
			x2 = position + this->itemSize;
			y2 = ObjH;
		}

		if ( ObjFlags&LST_IMG_TOP )
			y1 += this->reservedSpace;
		else if ( ObjFlags&LST_IMG_BOTTOM )
			y2 -= this->reservedSpace;
		else if ( ObjFlags&LST_IMG_RIGHT )
			x2 -= this->reservedSpace;
		else
			x1 += this->reservedSpace;

		// gestion de l'ombre du texte
		if ( this->LSTshadowDecal != 0 )
			this->LSTfont->CopyStringOnRectLayer( ObjLayer,
												  Rect2D( x1 + this->LSTshadowDecal,
														  y1 + this->LSTshadowDecal,
														  x2 + this->LSTshadowDecal,
														  y2 + this->LSTshadowDecal ),
												  ObjFlags,
												  text,
												  strlen(text),
												  this->LSTshadowColor,
												  255,
												  0 );
		this->LSTfont->CopyStringOnRectLayer( ObjLayer,
											  Rect2D( x1, y1, x2, y2 ),
											  ObjFlags,
											  text,
											  strlen(text),
											  this->LSTtextColor,
											  255,
											  0 );
	}


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







Layer *CObjectList::GetLayer(mmachine m,int p_tab)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::GetLayer");
#endif
//***********************************
	
	if (ObjLayer==NULL) return NULL;

	int p_content = MTOP( MMfetch( m, p_tab, 0 ) );

#ifdef DEBUG_COMPLIST
	MMechostr(MSKTRACE,"GetLayer; p_tab: %d\n", p_tab);
#endif

	if ( p_content == NIL )
	{
#ifdef DEBUG_COMPLIST
		MMechostr(MSKTRACE,"p_content is NIL\n");
#endif
		this->itemsDisplayed = 0;
		return NULL;
	}

	ObjLayer->sourceRect = Rect2D( 0, 0, ObjW, ObjH );

	// on nettoie les layers
	ObjLayer->nulifyNext();
	ObjLayer->fillLayer( ObjTransparency );
	while ( this->LSTlayersBitmaps != NULL )
	{  
		Layer *tmp = this->LSTlayersBitmaps->nextLayer();
		delete ( this->LSTlayersBitmaps );
		this->LSTlayersBitmaps = tmp;
	}
	// les layers pour les images des elements
	this->LSTlayersBitmaps = DrawListElements( m, p_content );

	ObjLayer->addLayer( this->LSTlayersBitmaps );

	// les layers de selection et click
	if ( this->highlightSelected() && this->itemSelected != NO_ITEM_SELECTED )
	{
		if ( this->direction == LST_VERTICAL )
		{
			this->LSTlayerSelect->Ydecal = ( this->itemSelected - this->firstItem ) * this->itemSize;
			this->LSTlayerSelect->sourceRect = Rect2D( 0, 0, ObjW, this->itemSize );
		}
		else
		{
			this->LSTlayerSelect->Xdecal = ( this->itemSelected - this->firstItem ) * this->itemSize;
			this->LSTlayerSelect->sourceRect = Rect2D( 0, 0, this->itemSize, ObjH );
		}
		this->LSTlayerSelect->nulifyNext();
		ObjLayer->addLayer( this->LSTlayerSelect );
	}
	if ( this->highlightClicked() && this->itemClicked != NO_ITEM_CLICKED &&
		 this->firstItem <= this->itemClicked && this->itemClicked < this->firstItem + this->itemsDisplayed )
	{
		if ( this->direction == LST_VERTICAL )
		{
			this->LSTlayerClicked->Ydecal = ( this->itemClicked - this->firstItem ) * this->itemSize;
			this->LSTlayerClicked->sourceRect = Rect2D( 0, 0, ObjW, this->itemSize );
		}
		else
		{
			this->LSTlayerClicked->Xdecal = ( this->itemClicked - this->firstItem ) * this->itemSize;
			this->LSTlayerClicked->sourceRect = Rect2D( 0, 0, this->itemSize, ObjH );
		}
		this->LSTlayerClicked->nulifyNext();
		ObjLayer->addLayer( this->LSTlayerClicked );
	}

#ifdef DEBUG_COMPLIST
	if ( ObjLayer == NULL )
		MMechostr(MSKTRACE,"GetLayer is NULL\n");
#endif
	return ObjLayer;
}

Layer *CObjectList::GetLayerPart(mmachine m,Rect2D *paintrect,int p_tab)
{
	if (ObjLayer==NULL) return NULL;
	
	Layer *tmp;
	int p_content = MTOP( MMfetch( m, p_tab, 0 ) );

#ifdef DEBUG_COMPLIST
	MMechostr(MSKTRACE,"GetLayerPart\n");
#endif

	if ( p_content == NIL )
	{
		this->itemsDisplayed = 0;
		return NULL;
	}

	ObjLayer->sourceRect = IntersectionRectangle( Rect2D( 0, 0, ObjW, ObjH ), *paintrect );

	// on nettoie les layers
	ObjLayer->nulifyNext();
	ObjLayer->fillLayer( ObjTransparency );
	while ( this->LSTlayersBitmaps != NULL )
	{
		Layer *tmp = this->LSTlayersBitmaps->nextLayer();
		delete ( this->LSTlayersBitmaps );
		this->LSTlayersBitmaps = tmp;
	}
	// les layers pour les images des elements
	this->LSTlayersBitmaps = DrawListElements( m, p_content );

	ObjLayer->addLayer( this->LSTlayersBitmaps );

	// on clip au paintrect
	tmp = this->LSTlayersBitmaps;
	while ( tmp != NULL )
	{
		int w, h;
		w = tmp->RGBbitmap->TailleW;
		h = tmp->RGBbitmap->TailleH;
		tmp->sourceRect = IntersectionRectangle( Rect2D( 0, 0, w, h ), *paintrect );
		tmp = tmp->nextLayer();
	}

	// les layers de selection et click
	if ( this->highlightSelected() && this->itemSelected != NO_ITEM_SELECTED )
	{
		int selectionPosition = ( this->itemSelected - this->firstItem ) * this->itemSize;

		if ( this->direction == LST_VERTICAL )
		{
			this->LSTlayerSelect->Ydecal = max( 0, selectionPosition - paintrect->RctHG.iptY );
			this->LSTlayerSelect->sourceRect = MoveRectangleByVecteur( IntersectionRectangle( *paintrect,
																							   Rect2D( 0, selectionPosition,
																									   ObjW, selectionPosition + this->itemSize ) ),
																		Point2D( 0, - selectionPosition ) );
		}
		else
		{
			this->LSTlayerSelect->Xdecal = max( 0, selectionPosition - paintrect->RctHG.iptX );
			this->LSTlayerSelect->sourceRect = MoveRectangleByVecteur( IntersectionRectangle( *paintrect,
																							   Rect2D( selectionPosition, 0,
																									   selectionPosition + this->itemSize, ObjH ) ),
																		Point2D( - selectionPosition, 0 ) );
		}
		this->LSTlayerSelect->nulifyNext();
		ObjLayer->addLayer( this->LSTlayerSelect );
	}
	if ( this->highlightClicked() && this->itemClicked != NO_ITEM_CLICKED &&
		 this->firstItem <= this->itemClicked && this->itemClicked < this->firstItem + this->itemsDisplayed )
	{
		int selectionPosition = ( this->itemClicked - this->firstItem ) * this->itemSize;

		if ( this->direction == LST_VERTICAL )
		{
			this->LSTlayerClicked->Ydecal = max( 0, selectionPosition - paintrect->RctHG.iptY );
			this->LSTlayerClicked->sourceRect = MoveRectangleByVecteur( IntersectionRectangle( *paintrect,
																							   Rect2D( 0, selectionPosition,
																									   ObjW, selectionPosition + this->itemSize ) ),
																		Point2D( 0, - selectionPosition ) );
		}
		else
		{
			this->LSTlayerClicked->Xdecal = max( 0, selectionPosition - paintrect->RctHG.iptX );
			this->LSTlayerClicked->sourceRect = MoveRectangleByVecteur( IntersectionRectangle( *paintrect,
																							   Rect2D( selectionPosition, 0,
																									   selectionPosition + this->itemSize, ObjH ) ),
																		Point2D( - selectionPosition, 0 ) );
		}
		this->LSTlayerClicked->nulifyNext();
		ObjLayer->addLayer( this->LSTlayerClicked );
	}

#ifdef DEBUG_COMPLIST
	if ( ObjLayer == NULL )
		MMechostr(MSKTRACE,"GetLayerPart is NULL\n");
#endif


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





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

	// destrution des layers
	if (ObjLayer!=NULL)	
	{
		ObjLayer->removeAllNext();
		delete(ObjLayer);
		ObjLayer=NULL;
	}
	if (LSTlayersBitmaps != NULL)
	{
		delete(LSTlayersBitmaps);
		LSTlayersBitmaps = NULL;	
	}
	if (highlightClicked() && LSTlayerClicked!=NULL)
	{
		delete(LSTlayerClicked);
		LSTlayerClicked = NULL;	
	}
	if (highlightSelected() && LSTlayerSelect!=NULL)
	{
		delete(LSTlayerSelect);
		LSTlayerSelect = NULL;	
	}

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







int CObjectList::ResizeLayer(int w,int h,int p_tab)
{	
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::ResizeLayer");
#endif
//***********************************

	ObjLayer=new Layer( w, h, LSTtransp, LSTtextTransp!=255 );
	if (ObjLayer!=NULL && LSTtextTransp!=255 && ObjLayer->AlphaBitmap!=NULL)
		ObjLayer->fillAlphaLayer (LSTtextTransp);	
	
	if ( highlightSelected() )
	{
		if ( direction == LST_VERTICAL )
			LSTlayerSelect = new Layer( ObjW, itemSize, LSTtransp, 1 );
		else
			LSTlayerSelect = new Layer( itemSize, ObjH, LSTtransp, 1 );
		LSTlayerSelect->fillLayer( LSTselectColor );
		LSTlayerSelect->fillAlphaLayer( LSTselectTansparencyCoeff );
	}

	if ( highlightClicked() )
	{
		if ( direction == LST_VERTICAL )
			LSTlayerClicked = new Layer( ObjW, itemSize, LSTtransp, 1 );
		else
			LSTlayerClicked = new Layer( itemSize, ObjH, LSTtransp, 1 );
		LSTlayerClicked->fillLayer( LSTselectColor );
		LSTlayerClicked->fillAlphaLayer( LSTselectTansparencyCoeff );
	}

	
	// evaluation du nombre d'elts visibles
	int oldvisible=visibleItemsCount;
	visibleItemsCount=h/itemSize;
	int oldmax=max(0,itemsCount-oldvisible-1);
	int newmax=max(0,itemsCount-1-visibleItemsCount);
	
	// augmentation du nombre d'elts visible -> possibilité de
	// repositionnement de la premiere ligne visible
	if (oldvisible-visibleItemsCount<0 && itemsCount>visibleItemsCount)
	{	int diff=firstItem+visibleItemsCount-itemsCount;
		if (diff>0)
			firstItem-=diff;
		setFirstItem(firstItem,1,0);
	}
	
	// evaluation de la nouvelle taille du slidebar linké
	if ( direction == LST_VERTICAL )
		send_notification_max( LINK_RESIZE, DIR_VERTICAL,newmax-oldmax, 1 );
	else
		send_notification_max( LINK_RESIZE, DIR_HORIZONTAL,newmax-oldmax, 1 );
	


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






// gestion des liens entre objets

// supporte le LINK_RESIZE mais ne fait rien
int CObjectList::supports( int type )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::supports");
#endif
//***********************************

	return ( type == LINK_MOVE || type == LINK_SELECT || type == LINK_RESIZE || type == LINK_STRING_SELECT || type == LINK_HIDE_AND_SHOW );
}







int CObjectList::handle(CObjMessage* msg)
{
	int direction, value, sub_type, redrawobject;

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


	switch(msg->GetType())
	{
		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 == LST_VERTICAL)
			{
				if (direction == DIR_VERTICAL)
					setFirstItem( this->firstItem + value, 0, redrawobject );
				else if ( direction == -DIR_VERTICAL )
					setFirstItem( this->firstItem - value, 0, redrawobject );
			}
			else
			{
				if (direction == -DIR_HORIZONTAL)
					setFirstItem( this->firstItem + value, 0, redrawobject );
				else if ( direction == DIR_HORIZONTAL )
					setFirstItem( this->firstItem - value, 0, redrawobject );
			}
			break;

		case LINK_SELECT:
			//recherche les informations du message
			value =	   (int)(static_cast <CObjMessageSelect*> (msg))->GetIndex();
			sub_type = (int)(static_cast <CObjMessageSelect*> (msg))->GetAction();
			redrawobject = msg->GetRedrawObject();

			//traite les informations du message
			if ( sub_type == ACT_MOUSECLICK )
				setClickedItem( value, 0, redrawobject );
			else if ( sub_type == ACT_MOUSEHOVER )
				setSelectedItem( value, 0, redrawobject );
			break;

		case LINK_HIDE_AND_SHOW:
			if ( (int)(static_cast <CObjMessageHideAndShow*> (msg))->GetMode() == SHOW )
			{
				this->itemClicked = NO_ITEM_CLICKED;
				this->itemSelected = NO_ITEM_SELECTED;
				//this->firstItem = 0;
				setFirstItem( 0, 1, 1);
				this->popup = 1;
			}

			break;
		default:
			break;
	}

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

	return 0;
}







// pour les liens entre objets
int CObjectList::send_notification_close_list()
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::send_notification_close_list");
#endif
//***********************************
	
	CObjMessageHideAndShow *msg = new CObjMessageHideAndShow( HIDE, 1 );

	this->notify(msg);
	delete(msg);

	return 0;
}











int CObjectList::send_notification_value( int type, int direction, int value, int redrawobject )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::send_notification_value");
#endif
//***********************************
	
	//instancie la classe CObjMessageMove
	CObjMessageMove* msg = new CObjMessageMove(direction, value, redrawobject);

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

	return 0;
}









int CObjectList::send_notification_max( int type, int direction, int value, int redrawobject )
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::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 CObjectList::send_notification_select(int type, int index, int action, int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::send_notification_select");
#endif
//***********************************
	
	//instancie la classe CObjMessageSelect
	CObjMessageSelect* msg = new CObjMessageSelect(index, action, redrawobject);

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

	return 0;
}






int CObjectList::send_notification_string_select(int type, char *string, int redrawobject)
{
//***********************************
#if DEBUG_LIB2D
MMechostr (0, "\nCObjectList::send_notification_string_select");
#endif
//***********************************

	//instancie la classe CObjMessageSelect
	CObjMessageStringSelect* msg = new CObjMessageStringSelect( string, redrawobject );

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

	return 0;
	
}










// FONCTIONS SCOL ASSOCIEES

// gere les cas NULL en plus du strcmp classique
int MYstrcmp( char *str1, char *str2 )
{
	int found = 1;

	if ( str1 != NULL && str2 != NULL )
		found = strcmp( str1, str2 );
	else if ( str1 == NULL && str2 == NULL )
		found = 0;

	return found;
}




int _CRcompList( mmachine m )
{
	int tmp_res;
	int p_text_settings, p_select_settings, shadowflag, shadowcolor, textcolor, coeff_transp, select_color, text_transp;
	int p_font, p_coordinates, p_objpere, p_container, p_slidebar, flags_creation, flags_handler;
	int w, h, x, y, direction, itemsvisible, bitmaps_reserved_space;
	CObjectBase *obj_root,*obj_father,* new_object;
	container *co;

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

	// pile: Chn ObjContainer ObjNode [I I] I I I I I I ObjFont I [I I I] [I I] [[I I] I AlphaBitmap [I I I]] // 15 elts

	// les differents tests de non validité
	if ((MMget(m,14))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompList: channel is nil\n");
		m->pp += 14;
		MMset(m,0,NIL);
		return 0;	
	}
	if ((MMget(m,13))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompList: container is nil\n");
		m->pp += 14;
		MMset(m,0,NIL);
		return 0;
	}
	if ((MMget(m,6))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompList: number of visible items is nil\n");
		m->pp += 14;
		MMset(m,0,NIL);
		return 0;
	}
	else if (MTOI(MMget(m,6))<=0)
	{
		MMechostr(MSKTRACE,"_CRcompList: number of visible items is <= 0\n");
		m->pp += 14;
		MMset(m,0,NIL);
		return 0;
	}
	if ((MMget(m,4))==NIL)
	{
		MMechostr(MSKTRACE,"_CRcompList: font is nil\n");
		m->pp += 14;
		MMset(m,0,NIL);
		return 0;
	}

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

		// on inverse les infos de slidebar et les coordonnees
	INVERT( m, 0, 11 );

	// les coordonnées
	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));
	}

	p_select_settings = MTOP( MMpull( m ) );
	if ( p_select_settings == NIL )
	{
		coeff_transp = 50;
		select_color = 0 + (0 << 8) + (255 << 16); // dnMat: ????? 0 + 0 ?????
	}
	else
	{
		if ( (coeff_transp = MTOI( MMfetch( m, p_select_settings, 1 ) )) == NIL )
			coeff_transp = 50;
		if ( coeff_transp < 0 || coeff_transp > 100 )
		{
			MMechostr(MSKTRACE,"_CRcompList: selection transparency coefficient must be in [0;100] range\n");
			m->pp += 11;
			MMset(m,0,NIL);
			return 0;
		}
		else
			coeff_transp = 255 * ( 100 - coeff_transp ) / 100;
		if ( (select_color = MTOI( MMfetch( m, p_select_settings, 0 ) )) == NIL)
			select_color = 0 + (0 << 8) + (255 << 16); // dnMat: ????? 0 + 0 ?????
	}

	p_text_settings = MTOP( MMpull( m ) );
	if ( p_text_settings == NIL )
	{
		shadowcolor = 0;
		shadowflag = 0;
		textcolor = 255+(255<<8)+(255<<16);
		text_transp = 255;
	}
	else
	{
		if ( (shadowcolor = MTOI( MMfetch( m, p_text_settings, 3 ) )) == NIL )
			shadowcolor = 0;
		if ( (shadowflag = MTOI( MMfetch( m, p_text_settings, 2 ) )) == NIL )
			shadowflag = 0;
		if ( (text_transp = MTOI( MMfetch( m, p_text_settings, 1 ) )) == NIL )
			text_transp = 0;
		if ( text_transp < 0 || text_transp > 100 )
		{
			MMechostr(MSKTRACE,"_CRcompList: text transparency coefficient must be in [0;100] range\n");
			m->pp += 10;
			MMset(m,0,NIL);
			return 0;
		}
		else
			text_transp = 255 * ( 100 - text_transp ) / 100;
		if ( (textcolor = MTOI( MMfetch( m, p_text_settings, 0 ) )) == NIL )
			textcolor = 0;
	}

	bitmaps_reserved_space = MTOI( MMpull( m ) );

	// on inverse font et flags_creation
	INVERT( m, 0, 6 );

	if ( (flags_creation=MTOI( MMpull(m) )) == NIL ) flags_creation=OBJ_ENABLE|OBJ_VISIBLE;
	if ( !(flags_creation&LST_LEFT) && !(flags_creation&LST_RIGHT) )
		flags_creation|=LST_H_CENTER;
	if ( !(flags_creation&LST_TOP) && !(flags_creation&LST_BOTTOM) )
		flags_creation|=LST_V_CENTER;

	direction = (MTOI( MMpull( m ) ) ) % 2;
	itemsvisible = abs( MTOI(MMpull(m)) );

	if ( (h = MTOI( MMpull( m )) ) == NIL ) h = 0;
	if ( (w = MTOI( MMpull( m )) ) == NIL ) w = 0;

	if ( (flags_handler=MTOI( MMpull(m) )) == NIL ) flags_handler = 0;

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

	// le Chn
	CHECK( MMpush( m, MMget( m, 4 ) ) );
	// on inverse Chn et ObjFont
	INVERT( m, 0, 1 );
	// pile: Chn ObjContainer ObjNode infos_slidebar Chn ObjFont

	// le container et le pere
	p_objpere=MTOP(MMget(m,3));
	p_container=MTOP(MMget(m,4));
	obj_father=GetObjectBase(m,p_objpere);
	
	if ((p_objpere!=NIL)&&(obj_father==NULL))
	{
		MMechostr(MSKTRACE,"_CRcompList: object father already destroyed\n");
		m->pp += 5;
		MMset(m,0,NIL);
		return 0;
	}
	else if ((co=RetrievePtrContainer(m,p_container))==NULL)
	{
		MMechostr(MSKTRACE,"_CRcompList: container already destroyed\n");
		m->pp += 5;
		MMset(m,0,NIL);
		return 0;
	}
	else if (!co->OwnsObject(obj_father))
	{
		MMechostr(MSKTRACE,"_CRcompList: father object was not created in this container!\n");
		m->pp += 5;
		MMset(m,0,NIL);
		return 0;
	}
	else
	{
		// evaluation de l'Image
		// on va construire un Layer unique aux dimensions de la portion visible
		int transparency = getDifferentColor( 3, select_color, textcolor, shadowcolor );
		Layer *layer = new Layer( w, h, transparency, text_transp != 255 );

		if ( text_transp != 255 )
			layer->fillAlphaLayer( text_transp );

		p_font = MTOP( MMget( m, 0 ) );
		// creation du nouvel objet
		new_object=new CObjectList(co,layer,x,y,w,h,flags_creation,flags_handler,transparency,
								   direction, textcolor,text_transp,shadowcolor, shadowflag,
								   select_color, coeff_transp,
								   itemsvisible, bitmaps_reserved_space,
								   GET_PTR_OBJ_FONT( p_font ) );
	
		obj_root=co->Root();

		// pour le futur pointeur sur la liste des elements contenus
		CHECK( MMpush( m, NIL ) );
		CHECK( MMpush( m, NIL ) );
		// on inverse le NIL et l'ObjFont
		INVERT( m, 1, 2 );

		// pile: Chn ObjContainer ObjNode infos_slidebar Chn NIL ObjFont NIL
		// ajout de l'objet et creation du nouvel OBJNODE
		CHECK( AddNode(m,obj_root,obj_father,new_object,3) ); // p_font non utilisé mais tjs stocké pour ne pas le perdre

		// pile: Chn ObjContainer ObjNode infos_slidebar new_object
		// on ecrase l'ancien ObjNode avec le nouveau
		MMset( m, 2, MMget( m, 0 ) );
		MMpull( m );
		// pile: Chn ObjContainer new_object infos_slidebar

#if DEBUG_OBJNODE
	PrintTree(m,0,FindObjNodeFromHdlSys(m,(int)obj_root));
#endif
		// pile voulue pour creer le slidebar: .... Chn ObjContainer new_object [I I] I I AlphaBitmap [I I I] I I I I
		// empilement de tous les parametres du slidebar
		// on laisse les coordonnees de cote pour l'instant: on ecrasera infos_slidebar ds la pile avec a la fin
		p_slidebar = MTOP( MMget( m, 0 ) );
		if ( p_slidebar != NIL)
		{
			int p_new_object, flags_creation;

			// les flags
			flags_creation = MTOI( MMfetch( m, p_slidebar, 1 ) );
			flags_creation |= OBJ_ENABLE|OBJ_VISIBLE;
			flags_creation -= flags_creation&OBJ_DISABLE;
			flags_creation -= flags_creation&OBJ_HIDE;
			
			CHECK( MMpush( m, ITOM( flags_creation) ) );
			CHECK( MMpush( m, ITOM( flags_handler ) ) );
			// pile: Chn ObjContainer new_object infos_slidebar I I
			p_slidebar = MTOP( MMget( m, 2 ) );
			// tuple des offsets
			CHECK( MMpush( m, MMfetch( m, p_slidebar, 3 ) ) );
			// pile: Chn ObjContainer new_object infos_slidebar I I [I I I]
			// coordonnees
			p_slidebar = MTOP( MMget( m, 3 ) );
			MMset( m, 3, MMfetch( m, p_slidebar, 0 ) );
			// pile: Chn ObjContainer new_object [I I] I I [I I I]
			// AlphaBitmap
			CHECK( MMpush( m, MMfetch( m, p_slidebar, 2 ) ) );
			// pile: Chn ObjContainer new_object [I I] I I [I I I] AlphaBitmap
			// on inverse offsets et AlphaBitmap
			INVERT( m, 0, 1 );
			// pile: Chn ObjContainer new_object [I I] I I AlphaBitmap [I I I]
			// direction, min, max et step
			CHECK( MMpush( m, ITOM( direction == LST_VERTICAL ? SLB_VERTICAL : SLB_HORIZONTAL ) ) );
			CHECK( MMpush( m, ITOM( 0 ) ) );
			CHECK( MMpush( m, ITOM( 0 ) ) );
			CHECK( MMpush( m, ITOM( 1 ) ) );
			// pile: Chn ObjContainer new_object [I I] I I AlphaBitmap [I I I] I I I I


			// la creation !
			CHECK( _CRcompSlideBar( m ) );
			// pile: Slidebar 

			// mise à jour du p_tab de l'objet list en memorisant la
			// pointeur scol du slidebar
			p_new_object = FindObjNodeFromHdlSys(m,(int)new_object);
			MMstore(m,GetTab(m,p_new_object),SLIDE_V,MMget(m,0));

			// creation des liens
			CHECK( MMpush( m, PTOM( p_new_object ) ) );
			CHECK( MMpush( m, ITOM( LINK_MOVE|LINK_RESIZE ) ) );
			CHECK( _CRnodeLink( m ) );

			MMset( m, 0, PTOM( FindObjNodeFromHdlSys(m,(int)new_object) ) );
		}
		else
		{
			MMpull( m );
			INVERT( m, 0, 2 );
			MMpull( m );
			MMpull( m );
		}
	}


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

	return 0;
}








int _DScompList( mmachine m )
{
	int p;

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

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







int _CONVERTcompListToObjNode( mmachine m )
{
	return 0;
}

int _CBcompListClick(mmachine m)
{
	return OBJaddreflex( m, OBJNODE, RFLOBJNODE_CLICK );
}

int _CBcompListSClick(mmachine m)
{
	return OBJaddreflex( m, OBJNODE, RFLOBJNODE_SCLICK );
}


int _CBcompListDblClick(mmachine m)
{
	return OBJaddreflex( m, OBJNODE, RFLOBJNODE_DBLCLICK );
}







int _SETcompListFirst(mmachine m)
{

	CObjectBase *obj;
	int new_value;
	int p_obj;


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

	new_value = MTOI( MMpull( m ) );
	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL || new_value == NIL )
		return 0;

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


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

	return 0;
}










int _SSETcompListFirst( mmachine m )
{
	CObjectBase *obj;
	char *text, *text_tgt;
	int p_text, p_text_tgt, p_obj, p_tab;

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


	p_text = MTOP( MMpull( m ) );
	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
		return 0;

	// on recupere l'objet
	if ( p_text != NIL )
		text = MMstartstr( m, p_text );
	else
		text = NULL;

	if ((obj=GetObjectBase(m,p_obj))==NULL)
	{
		MMechostr(MSKTRACE,"_SSETcompListFirst: Object already destroyed.\n");
		MMset( m, 0, NIL);
	}
	else
	{
		if ((p_tab=GetTab(m,p_obj))!=NIL)
		{
			int i, p_content;

			p_content = MTOP( MMfetch( m, p_tab, 0 ) );
			
			if (p_content == NIL) // liste vide
				return 0;

			p_text_tgt = MTOP( MMfetch( m, MTOP( MMfetch( m, p_content, 0 ) ), 0 ) );
			if ( p_text_tgt != NIL )
				text_tgt = MMstartstr( m, p_text_tgt );
			else
				text_tgt = NULL;

			i = 0;
			while ( p_content != NIL && MYstrcmp( text, text_tgt ) )
			{
				p_content = MTOP( MMfetch( m, p_content, 1 ) );
				i++;

				p_text_tgt = MTOP( MMfetch( m, MTOP( MMfetch( m, p_content, 0 ) ), 0 ) );
				if ( p_text_tgt != NIL )
					text_tgt = MMstartstr( m, p_text_tgt );
				else
					text_tgt = NULL;
			}

			if ( p_content != NIL ) // l'objet a la position specifiee existe
				// on change la valeur mais on ne repeint pas
				(static_cast <CObjectList *> (obj))->setFirstItem( i, 1, 0 );	
		}
	}


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

	return 0;
}








// note: les 2 cas 'debut de liste' et 'milieu ou fin de liste' sont tres separes et ne fonctionnent
// meme pas sur le meme principe... il y a surement moyen d'homogeneiser mais est-ce bien utile ?
// re-note: le contenu du CompList est une liste de couple [S AlphaBitmap] d'ou le double MMmalloc...
int _ADDcompList( mmachine m )
{
	CObjectBase *obj;
	int new_item, position;
	int p_obj, p_tab_alloc, p_tablist_alloc, p_tab;
	int tmp_res;

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


	new_item = MTOP( MMpull( m ) );
	position = MTOI( MMpull( m ) );
	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
	{
		MMechostr(MSKTRACE,"_ADDcompList: Object is nil.\n");
		return 0;
	}

	// pile: CompList

	if ( new_item != NIL && position >= 0 ) // inclu position != NIL
	{
		// on recupere l'objet
		if ((obj=GetObjectBase(m,p_obj))==NULL)
		{
			MMechostr(MSKTRACE,"_ADDcompList: Object already destroyed.\n");
			MMset( m, 0, NIL);
		}
		else
		{
			CHECK( MMpush( m, PTOM( new_item ) ) );
			if ((p_tab=GetTab(m,p_obj))!=NIL)
			{
				// on ajoute l'element mais on ne repeint pas
				int i, p_content, prev_p_content = NIL;

				p_content = MTOP( MMfetch( m, p_tab, 0 ) );
				i = 0;

				while ( i < position && p_content != NIL )
				{
					i++;
					prev_p_content = p_content;
					p_content = MTOP( MMfetch( m, p_content, 1 ) );
				}

				if ( i == 0 ) // au debut de la liste
				{
					CHECK( MMpush( m, PTOM( p_tab ) ) );
					// pile: CompList new_item p_tab
					INVERT( m ,0, 1 );

					if (( p_tab_alloc = MMmalloc( m, 2, TYPETAB ) ) < 0 ) return p_tab_alloc;

					new_item = MTOP( MMpull( m ) );

					MMstore( m, p_tab_alloc, 0, MMfetch( m, new_item, 0 ) );
					MMstore( m, p_tab_alloc, 1, MMfetch( m, new_item, 1 ) );

					CHECK( MMpush( m, PTOM( p_tab_alloc ) ) );

					// pile: CompList p_tab p_tab_alloc
					if (( p_tablist_alloc = MMmalloc( m, 2, TYPETAB ) ) < 0 ) return p_tablist_alloc;

					p_tab_alloc = MMpull( m );
					p_tab = MTOP( MMpull( m ) );
					MMstore( m, p_tablist_alloc, 0, p_tab_alloc );
					MMstore( m, p_tablist_alloc, 1, MMfetch( m, p_tab, 0 ) ); // NIL la premiere fois

					MMstore( m, p_tab, 0, PTOM( p_tablist_alloc ) );
#ifdef DEBUG_COMPLIST
					MMechostr(MSKTRACE,"_ADDcompList: p_tab %d\n", p_tab);
#endif
				}
				else // au milieu ou a la fin de la liste
				{
					p_content = prev_p_content;

					CHECK( MMpush( m, PTOM( p_content ) ) );
					// pile: CompList new_item p_content

					if (( p_tab_alloc = MMmalloc( m, 2, TYPETAB ) ) < 0 ) return p_tab_alloc;

					p_content = MTOP( MMpull( m ) );
					MMstore( m, p_tab_alloc, 1, MMfetch( m, p_content, 1 ) );
					MMstore( m, p_tab_alloc, 0, NIL );
					MMstore( m, p_content, 1, PTOM( p_tab_alloc ) );

					CHECK( MMpush( m, PTOM( p_tab_alloc ) ) );
					// pile: CompList new_item p_tab_alloc

					if (( p_tablist_alloc = MMmalloc( m, 2, TYPETAB ) ) < 0 ) return p_tablist_alloc;
					p_tab_alloc = MTOP( MMpull( m ) );
					new_item = MTOP( MMpull( m ) );

					MMstore( m, p_tablist_alloc, 0, MMfetch( m, new_item, 0 ) );
					MMstore( m, p_tablist_alloc, 1, MMfetch( m, new_item, 1 ) );

					MMstore( m, p_tab_alloc, 0, PTOM( p_tablist_alloc ) );
				}
				// et voila! (en francais dans le texte)

				(int)(static_cast <CObjectList *> (obj))->addItem( i );
			}
		}
	}


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

	return 0;
}








int _DELcompList( mmachine m )
{
	CObjectBase *obj;
	int position;
	int p_obj, p_tab;


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

	position = MTOI( MMpull( m ) );
	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
		return 0;

	// on recupere l'objet
	if ( position >= 0 ) // ceci inclu != NIL
	{
		if ((obj=GetObjectBase(m,p_obj))==NULL)
		{
			MMechostr(MSKTRACE,"_DELcompList: Object already destroyed.\n");
			MMset( m, 0, NIL);
		}
		else
		{
			if ((p_tab=GetTab(m,p_obj))!=NIL)
			{
				int i, p_content, prev_p_content = NIL;

				p_content = MTOP( MMfetch( m, p_tab, 0 ) );
				i = 0;

				while ( i < position && p_content != NIL )
				{
					i++;
					prev_p_content = p_content;
					p_content = MTOP( MMfetch( m, p_content, 1 ) );
				}

				if ( p_content != NIL ) // l'objet a la position specifiee existe
				{
					if ( i == 0 ) // au debut de la liste
						MMstore( m, p_tab, 0, MMfetch( m, p_content, 1 ) );
					else
						MMstore( m, prev_p_content, 1, MMfetch( m, p_content, 1 ) );

					(int)(static_cast <CObjectList *> (obj))->removeItem( i );
				}
			}
		}
	}

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

	return 0;
}









int _SETcompListValue( mmachine m )
{
	CObjectBase *obj;
	int new_item, position;
	int p_obj, p_tab;


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

	new_item = MTOP( MMpull( m ) );
	position = MTOI( MMpull( m ) );
	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
		return 0;

	// on recupere l'objet
	if ( new_item != NIL && position >= 0 ) // ceci inclu position != NIL
	{
		if ((obj=GetObjectBase(m,p_obj))==NULL)
		{
			MMechostr(MSKTRACE,"_SETcompListValue: Object already destroyed.\n");
			MMset( m, 0, NIL);
		}
		else
		{
			if ((p_tab=GetTab(m,p_obj))!=NIL)
			{
				int i, p_content;

				p_content = MTOP( MMfetch( m, p_tab, 0 ) );
				i = 0;

				while ( i < position && p_content != NIL )
				{
					i++;
					p_content = MTOP( MMfetch( m, p_content, 1 ) );
				}

				if ( p_content != NIL ) // l'objet a la position specifiee existe
				{
					// on le recopie en ecrasant l'ancien
					MMstore( m, MTOP( MMfetch( m, p_content, 0 ) ), 0, MMfetch( m, new_item, 0 ) );
					MMstore( m, MTOP( MMfetch( m, p_content, 0 ) ), 1, MMfetch( m, new_item, 1 ) );
				}
			}
		}
	}


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

	return 0;
}








int _SSETcompListValue( mmachine m )
{
	CObjectBase *obj;
	char *text, *text_tgt;
	int p_text, p_text_tgt, p_obj, p_tab, new_item;


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

	new_item = MTOP( MMpull( m ) );
	p_text = MTOP( MMpull( m ) );
	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
		return 0;

	// on recupere l'objet
	if ( p_text != NIL )
		text = MMstartstr( m, p_text );
	else
		text = NULL;

	if ((obj=GetObjectBase(m,p_obj))==NULL)
	{
		MMechostr(MSKTRACE,"_SSETcompListValue: Object already destroyed.\n");
		MMset( m, 0, NIL);
	}
	else
	{
		if ((p_tab=GetTab(m,p_obj))!=NIL)
		{
			int p_content;

			p_content = MTOP( MMfetch( m, p_tab, 0 ) );
			
			if (p_content == NIL) // liste vide
				return 0;

			p_text_tgt = MTOP( MMfetch( m, MTOP( MMfetch( m, p_content, 0 ) ), 0 ) );
			if ( p_text_tgt != NIL )
				text_tgt = MMstartstr( m, p_text_tgt );
			else
				text_tgt = NULL;

			while ( p_content != NIL && MYstrcmp( text, text_tgt ) )
			{
				p_content = MTOP( MMfetch( m, p_content, 1 ) );

				p_text_tgt = MTOP( MMfetch( m, MTOP( MMfetch( m, p_content, 0 ) ), 0 ) );
				if ( p_text_tgt != NIL )
					text_tgt = MMstartstr( m, p_text_tgt );
				else
					text_tgt = NULL;
			}

			if ( p_content != NIL ) // l'objet a la position specifiee existe
			{
				// on le recopie en ecrasant l'ancien
				MMstore( m, MTOP( MMfetch( m, p_content, 0 ) ), 0, MMfetch( m, new_item, 0 ) );
				MMstore( m, MTOP( MMfetch( m, p_content, 0 ) ), 1, MMfetch( m, new_item, 1 ) );
			}
		}
	}

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

	return 0;
}








int _SDELcompList( mmachine m )
{
	CObjectBase *obj;
	char *text, *text_tgt;
	int p_text, p_text_tgt, p_obj, p_tab;

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

	p_text = MTOP( MMpull( m ) );
	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
		return 0;

	// on recupere l'objet
	if ( p_text != NIL )
		text = MMstartstr( m, p_text );
	else
		text = NULL;

	if ((obj=GetObjectBase(m,p_obj))==NULL)
	{
		MMechostr(MSKTRACE,"_SDELcompList: Object already destroyed.\n");
		MMset( m, 0, NIL);
	}
	else
	{
		if ((p_tab=GetTab(m,p_obj))!=NIL)
		{
			int i, p_content, prev_p_content = NIL;;

			p_content = MTOP( MMfetch( m, p_tab, 0 ) );
			i = 0;
			
			if (p_content == NIL) // liste vide
				return 0;

			p_text_tgt = MTOP( MMfetch( m, MTOP( MMfetch( m, p_content, 0 ) ), 0 ) );
			if ( p_text_tgt != NIL )
				text_tgt = MMstartstr( m, p_text_tgt );
			else
				text_tgt = NULL;

			while ( p_content != NIL && MYstrcmp( text, text_tgt ) )
			{
				i++;
				prev_p_content = p_content;
				p_content = MTOP( MMfetch( m, p_content, 1 ) );

				p_text_tgt = MTOP( MMfetch( m, MTOP( MMfetch( m, p_content, 0 ) ), 0 ) );
				if ( p_text_tgt != NIL )
					text_tgt = MMstartstr( m, p_text_tgt );
				else
					text_tgt = NULL;
			}

			if ( p_content != NIL ) // l'objet a la position specifiee existe
			{
				if ( i == 0 ) // au debut de la liste
					MMstore( m, p_tab, 0, MMfetch( m, p_content, 1 ) );
				else
					MMstore( m, prev_p_content, 1, MMfetch( m, p_content, 1 ) );

				(int)(static_cast <CObjectList *> (obj))->removeItem( i );
			}
		}
	}


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

	return 0;
}







int _POScompList( mmachine m )
{
	CObjectBase *obj;
	char *text, *text_tgt;
	int p_text, p_text_tgt, p_obj, p_tab;


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

	p_text = MTOP( MMpull( m ) );
	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
		return 0;

	// on recupere l'objet
	if ( p_text != NIL )
		text = MMstartstr( m, p_text );
	else
		text = NULL;

	if ((obj=GetObjectBase(m,p_obj))==NULL)
	{
		MMechostr(MSKTRACE,"_POScompList: Object already destroyed.\n");
		MMset( m, 0, NIL);
	}
	else
	{
		if ((p_tab=GetTab(m,p_obj))!=NIL)
		{
			int i, p_content;

			p_content = MTOP( MMfetch( m, p_tab, 0 ) );
			i = 0;
			
			if (p_content == NIL) // liste vide
			{
				MMset( m, 0, NIL );
				return 0;
			}

			p_text_tgt = MTOP( MMfetch( m, MTOP( MMfetch( m, p_content, 0 ) ), 0 ) );
			if ( p_text_tgt != NIL )
				text_tgt = MMstartstr( m, p_text_tgt );
			else
				text_tgt = NULL;

			while ( p_content != NIL && MYstrcmp( text, text_tgt ) )
			{
				i++;
				p_content = MTOP( MMfetch( m, p_content, 1 ) );

				p_text_tgt = MTOP( MMfetch( m, MTOP( MMfetch( m, p_content, 0 ) ), 0 ) );
				if ( p_text_tgt != NIL )
					text_tgt = MMstartstr( m, p_text_tgt );
				else
					text_tgt = NULL;
			}

			if ( p_content != NIL ) // l'objet a la position specifiee existe
				MMset( m, 0, ITOM( i ) );
			else
				MMset( m, 0, NIL );
		}
	}


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

	return 0;
}










int _GETcompListCount( mmachine m )
{
	CObjectBase *obj;
	int p_obj, p_tab;

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


	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
		return 0;

	// on recupere l'objet
	if ((obj=GetObjectBase(m,p_obj))==NULL)
	{
		MMechostr(MSKTRACE,"_GETcompListCount: Object already destroyed.\n");
		MMset( m, 0, NIL );
	}
	else
		if ((p_tab=GetTab(m,p_obj))!=NIL)
			MMset( m, 0, ITOM( (int)(static_cast <CObjectList *> (obj))->getItemsCount() ) );


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

	return 0;
}








int _RSTcompList( mmachine m )
{
	CObjectBase *obj;
	int p_obj, p_tab;

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

	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
		return 0;

	// on recupere l'objet
	if ((obj=GetObjectBase(m,p_obj))==NULL)
	{
		MMechostr(MSKTRACE,"_RSTcompList: Object already destroyed.\n");
		MMset( m, 0, NIL);
	}
	else
		if ((p_tab=GetTab(m,p_obj))!=NIL)
		{
			MMstore( m, p_tab, 0, NIL );
			(int)(static_cast <CObjectList *> (obj))->removeAllItems();
		}

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

	return 0;
}






int _GETcompListValue( mmachine m )
{
	CObjectBase *obj;
	int p_obj, p_tab;
	int position;

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

	position = MTOI( MMpull( m ) );
	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL || position < 0 ) // < 0 inclu NIL
	{
		MMset( m, 0, NIL );
		return 0;
	}

	// on recupere l'objet
	if ((obj=GetObjectBase(m,p_obj))==NULL)
	{
		MMechostr(MSKTRACE,"_GETcompListValue: Object already destroyed.\n");
		MMset( m, 0, NIL);
	}
	else
		if ((p_tab=GetTab(m,p_obj))!=NIL)
		{
			int i, p_content;

			p_content = MTOP( MMfetch( m, p_tab, 0 ) );
			i = 0;

			while ( i < position && p_content != NIL )
			{
				i++;
				p_content = MTOP( MMfetch( m, p_content, 1 ) );
			}

			if ( p_content != NIL ) // position specifiee valide
				MMset( m, 0, MMfetch( m, p_content, 0 ) );
			else
				MMset( m, 0, NIL );
		}

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

	return 0;
}









int _GETcompListClicked( mmachine m )
{
	CObjectBase *obj;
	int p_obj, p_tab;
	int tmp_res;

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


	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
		return 0;

	// on recupere l'objet
	if ((obj=GetObjectBase(m,p_obj))==NULL)
	{
		MMechostr(MSKTRACE,"_GETcompListClicked: Object already destroyed.\n");
		MMset( m, 0, NIL);
	}
	else
		if ((p_tab=GetTab(m,p_obj))!=NIL)
		{
			int i, p_content;
			int position = (static_cast <CObjectList *> (obj))->getClickedItem();

			if ( position != NO_ITEM_CLICKED )
			{
				p_content = MTOP( MMfetch( m, p_tab, 0 ) );
				i = 0;

				while ( i < position && p_content != NIL )
				{
					i++;
					p_content = MTOP( MMfetch( m, p_content, 1 ) );
				}

				if ( p_content != NIL ) // position specifiee valide
				{
					MMset( m, 0, MMfetch( m, p_content, 0 ) );
					CHECK( MMpush( m, ITOM( position ) ) );
					INVERT( m, 0, 1 );
					CHECK( MMpush( m, ITOM( 2 ) ) );
					CHECK( MBdeftab( m ) );
				}
				else
					MMset( m, 0, NIL );
			}
			else
				MMset( m, 0, NIL );
		}


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

	return 0;
}







int _SETcompListClicked( mmachine m )
{
	CObjectBase *obj;
	int p_obj;
	int position;

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

	position = MTOI( MMpull( m ) );
	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
		return 0;

	// on recupere l'objet
	if ((obj=GetObjectBase(m,p_obj))==NULL)
	{
		MMechostr(MSKTRACE,"_SETcompListClicked: Object already destroyed.\n");
		MMset( m, 0, NIL);
	}
	else
		(static_cast <CObjectList *> (obj))->setClickedItem( position, 1, 0 );

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

	return 0;
}






int _SSETcompListClicked( mmachine m )
{
	CObjectBase *obj;
	char *text, *text_tgt;
	int p_text, p_text_tgt, p_obj, p_tab;

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

	p_text = MTOP( MMpull( m ) );
	p_obj = MTOP( MMget( m, 0 ) );

	if ( p_obj == NIL )
		return 0;

	// on recupere l'objet
	if ( p_text != NIL )
		text = MMstartstr( m, p_text );
	else
		text = NULL;

	if ((obj=GetObjectBase(m,p_obj))==NULL)
	{
		MMechostr(MSKTRACE,"_SSETcompListClicked: Object already destroyed.\n");
		MMset( m, 0, NIL);
	}
	else
	{
		if ((p_tab=GetTab(m,p_obj))!=NIL)
		{
			int i, p_content;

			p_content = MTOP( MMfetch( m, p_tab, 0 ) );
			
			if (p_content == NIL) // liste vide
				return 0;

			p_text_tgt = MTOP( MMfetch( m, MTOP( MMfetch( m, p_content, 0 ) ), 0 ) );
			if ( p_text_tgt != NIL )
				text_tgt = MMstartstr( m, p_text_tgt );
			else
				text_tgt = NULL;
			i = 0;

			while ( p_content != NIL && MYstrcmp( text, text_tgt ) )
			{
				p_content = MTOP( MMfetch( m, p_content, 1 ) );
				i++;

				p_text_tgt = MTOP( MMfetch( m, MTOP( MMfetch( m, p_content, 0 ) ), 0 ) );
				if ( p_text_tgt != NIL )
					text_tgt = MMstartstr( m, p_text_tgt );
				else
					text_tgt = NULL;
			}

			if ( p_content != NIL ) // l'objet a la position specifiee existe
				// on change la valeur mais on ne repeint pas
				(static_cast <CObjectList *> (obj))->setClickedItem( i, 1, 0 );	
		}
	}

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

	return 0;
}









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






int _CBcompListResizeResource(mmachine m)
{
	int p_obj,tmp_res;

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

	if ((p_obj=MTOP(MMget(m,2)))==NIL)
	{
		MMechostr(1,"_CBcompListResizeResource: CompList is nil\n");
		m->pp += 2;
		MMset(m,0,NIL);
	}
	else if (GetObjectBase(m,p_obj)==NULL)
	{
		MMechostr(1,"_CBcompTextResizeResource: CompList already destroyed\n");
		m->pp += 2;
		MMset(m,0,NIL);
	}
	else
	{
		// pile  CompList fun1 p1
		int p_tab=GetTab(m,p_obj);
		CHECK(MMpush(m,MMfetch(m,p_tab,SLIDE_V)));
		INVERT(m,0,1);
		INVERT(m,1,2);
		
		// pile CompList slb1 fun1 p1
		CHECK(_CBcompSlideBarResizeResource(m));
		MMpull(m);
		
		//pile CompList
	}

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

	return 0;
}









int _CBcompListResize(mmachine m)
{
	int p_obj,tmp_res;

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

	if ((p_obj=MTOP(MMget(m,4)))==NIL)
	{
		MMechostr(1,"_CBcompListResize: CompList is nil\n");
		m->pp += 4;
		MMset(m,0,NIL);
	}
	else if (GetObjectBase(m,p_obj)==NULL)
	{
		MMechostr(1,"_CBcompListResize: CompList already destroyed\n");
		m->pp += 4;
		MMset(m,0,NIL);
	}
	else
	{
		// pile  CompList fun1 p1 fun2 p2
		int p_tab=GetTab(m,p_obj);
		CHECK(MMpush(m,MMfetch(m,p_tab,SLIDE_V)));
		INVERT(m,0,1);
		INVERT(m,1,2);
		
		// pile CompList fun1 p1 slb fun2 p2
		CHECK(_CBcompSlideBarResize(m));
		MMpull(m);
		
		//pile CompList fun1 p1
		return OBJaddreflex(m,OBJNODE,RFLOBJNODE_RESIZE);
	}

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

	return 0;
}