/**********************************************/
/*                                            */
/* cursor.c                                   */
/*                                            */
/**********************************************/


#include "x/Version.h"
#include "x/scolplugin.h"

#include "objstr.h"
#include "objects/cursor.h"
#include "colors.h"



int TESTCURSORMOVE = 0 ;


/**************************************************************************************/
/*                                                                                    */
/*  int GRCreateCursor ( mmachine m ) ;                                               */
/*                                                                                    */
/*  cette fonction correspond a la fonction magma ObjCursor _create_cursor ( )        */
/*  ( ObjBitmap I Color1 I color2 I X I Y );                                          */
/*  laquelle cree un curseur de souris                                                */
/*                                                                                    */
/**************************************************************************************/

int GRCreateCursor ( mmachine m )
{
    int x , y , color1 , color2 , colorBitmap, s , s2 , sb , l, lb, res , i , j ;
    HCURSOR Hc ;
    PtrObjVoid O ;
    PtrObjBitmap B ;
    PtrObjCursor C ;
    int SourisW , SourisH , tand , tor , tailleW ;
    OBJBITMAP_BUFFER Bitmap ;
    OBJBITMAP_BUFFER tbitand;
	OBJBITMAP_BUFFER tbitor ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRCreateCursor");
#endif
//***********************************
    /* test le channel */
    if (MMget(m,5)==NIL)
    {
        MMechostr(MSKDEBUG,"CRchannel : channel NIL\n");
        m->pp+=5;
        return 0;
    }

   color2 = MMpull ( m ) >> 1 ;
    color1 = MMpull ( m ) >> 1 ;
    y = MMpull ( m ) >> 1 ;
    x = MMpull ( m ) >> 1 ;
    sb = MMpull( m ) ; 
    if ( sb == NIL )
    {
        MMechostr (1,"Bitmap is NIL in _CRcursor\n");
        MMpull(m); /* depile le channel */
        return MMpush(m,NIL);
    } else MMpush(m,sb);

    l = ( sizeof ( struct ObjVoid ) + 3 ) >> 2 ;
    s = MMmallocCLR (m,l,TYPETAB) ;
    if( s == NIL ) return MERRMEM ;
    if ( MMpush(m,(s<<1)+1)) return MERRMEM ;
  
    l = ( sizeof ( struct ObjCursor ) + 3 ) >> 2 ;
    s2 = MMmalloc ( m,l,TYPEBUF ) ;
    if ( s2 == NIL ) return MERRMEM ;
    s = MMpull(m) ;

    O = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;
    C = ( PtrObjCursor ) MMstart(m, s2 ) ;
    O->Type = OBJ_TYPE_CURSOR << 1 ; 
    O->Buffer = ( s2 << 1 ) + 1 ;       
    O->Father = NIL ;
    O->Tab= MMget(m,0) ;//SH
    sb = MMpull( m ) ; 
    O = ( PtrObjVoid ) MMstart(m,(sb>>1) ) ;
    B = ( PtrObjBitmap ) MMstart(m,(O->Buffer>>1) )  ;
    SourisW = GetSystemMetrics ( SM_CXCURSOR ) ;
    SourisH = GetSystemMetrics ( SM_CYCURSOR ) ;

    if ( B->TailleW != SourisW || B->TailleH != SourisH )
    {
        MMechostr ( 1 , "_create_cursor : The Bitmap haven't the good size. Cursor must be %dx%d and bitmap is %dx%d\n",
            SourisW , SourisH , B->TailleW , B->TailleH ) ;
		MMpull(m); //SH
        res = MMpush(m,NIL ) ;
    }
    else
    {

			//$LB : we have to hack this, 'cause some guys didn't understand what a 24bits color is.... 
			if (color1 == 0x7FFF) color1 = 0xFFFFFF;
			if (color2 == 0x7FFF) color2 = 0xFFFFFF;


            Bitmap = (OBJBITMAP_BUFFER)B->bits ;
			tailleW=B->TailleW;
            l = SourisW * SourisH  ;            
            if ( l & 7 ) l= l + 8 ;
            l >>= 3 ;

            if ( MMpush(m,s)) return MERRMEM ;
            tand = MMmallocCLR(m,( l + 3 ) >> 2,TYPEBUF ) ;
            if ( MMpush(m,(tand<<1)+1)) return MERRMEM ;
            tor = MMmallocCLR(m , ( l + 3 ) >> 2 , TYPEBUF ) ;
            tand = MMpull ( m ) >> 1 ;

            tbitand = (OBJBITMAP_BUFFER ) MMstart(m, tand ) ;
            tbitor = (OBJBITMAP_BUFFER ) MMstart(m, tor ) ;
          
            for ( i = 0 ; i < l ; i ++ )
            {        
                tbitor [ i ] = 0 ;
                tbitand [ i ] = 255 ;
            }
            

            for ( j = 0 ; j < SourisH ; j ++ )
            for ( i = 0 ; i < SourisW ; i ++ ) 
            {   
                //$LB
                l = i    + j * tailleW ;  
				lb = i*3 + j * B->BPL;

				colorBitmap = _COLOR_BGR_TO_I (Bitmap[lb+0], Bitmap[lb+1], Bitmap[lb+2]);

                if ( colorBitmap == color2 )
                {
                    tbitor [ l/8 ] ^= 01 << ( 7 -( i & 7 )) ;   
                    tbitand [l/8 ] ^= 01 << ( 7 - (i & 7 )) ;                   
                } else                
                if ( colorBitmap == color1 )
                {
                    
                    tbitand [ l /8 ] ^= 01 << ( 7 - (i & 7 )) ;                                      
                } 
            }

            s = MMpull( m ) ;
            O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;
            C = ( PtrObjCursor ) MMstart(m,(O->Buffer>>1)) ;
            C->X = x ;
            C->Y = y ;                    
            C->HCursor = CreateCursor ( (HINSTANCE)SCgetExtra("this_inst") , x , y , SourisW , SourisH , tbitand , tbitor ) ;
            Hc = C->HCursor ;
            if ( C->HCursor == NULL ) 
            {
                MMechostr ( 1 , "ERROR : _create_cursor failed x=%d y=%d w =%d h =%d\n",x,y,SourisW,SourisH);            
				MMpull(m);//SH
                res = MMpush ( m , NIL ) ;
            }
            else
            {
                res=MMpush(m,s) ;                
                res = OBJcreate (m,OBJTYPCURSOR,(int)Hc,-1,(int)NULL) ;
                
            }       
                                 
    }
    

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRCreateCursor end");
#endif
//***********************************
    return res ;
}


/**************************************************************************************************/
/*                                                                                                */
/*  int GRGetCursorSize ( mmachine m ) ;                                                          */
/*                                                                                                */
/*  correspond a la fonction [i i ] _get_cursor_size    () ;                                      */
/*                                                                                                */
/**************************************************************************************************/

int GRGetCursorSize ( mmachine m )
{
    int x , y ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetCursorSize");
#endif
//***********************************

    x = GetSystemMetrics ( SM_CXCURSOR ) ;
    y = GetSystemMetrics ( SM_CYCURSOR ) ;

    if ( MMpush ( m , x << 1 )) return MERRMEM ;
    if ( MMpush ( m , y << 1 )) return MERRMEM ;
    if ( MMpush ( m , 4 )) return MERRMEM ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetCursorSize end");
#endif
//***********************************

    return MBdeftab ( m ) ; 
}


/************************************************************************************************/
/*                                                                                              */
/*  int GRSetCursor ( mmachine m ) ;                                                            */
/*                                                                                              */
/*  correspond a la fonction magma _set_cursor ( ObjCursor ) -> ObjCursor                       */
/*                                                                                              */
/************************************************************************************************/


int GRSetCursor ( mmachine m )
{
    int s , res , sw ;
    PtrObjVoid O , OW ;
    PtrObjCursor C ;
    HWND H ;
    HCURSOR Hc ;
    POINT P ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRSetCursor");
#endif
//***********************************

    s = MMpull( m ) ;
    sw = MMpull ( m ) ;
    if ( sw != NIL )
    {
        if ( s == NIL ) Hc = arrowCursor; // SH : Hc = NULL
        else
        {
            O = ( PtrObjVoid ) MMstart(m,(s>>1) );
            C = ( PtrObjCursor ) MMstart(m,(O->Buffer >> 1 ) ) ;
            Hc = C->HCursor ; 
        }
        OW = ( PtrObjVoid ) MMstart(m,(sw>>1) ) ;
        switch ( OW->Type >> 1 )
        {
            case OBJ_TYPE_WINDOW :
                H =  (( PtrObjWindow ) MMstart(m,(OW->Buffer>>1) ) ) ->WHandler ;
                (( PtrObjWindow ) MMstart(m,(OW->Buffer>>1) ) ) ->Cursor =Hc;
                break ;
            case OBJ_TYPE_CHECK_BOX :
            case OBJ_TYPE_PUSHBUTTON :
                H = (( PtrObjButton ) MMstart(m,(OW->Buffer>>1) )) -> WHandler ;
                break ;
            case OBJ_TYPE_PUSH_BUTTON_BITMAP :
                H = (( PtrObjPushButtonBitmap ) MMstart(m,(OW->Buffer>>1) )) ->WHandler ;
                break ;
            default : H = NULL ;
                break ;
        }
        if ( Hc && H )
        {
            if ( Hc != ( HCURSOR ) GetClassLong ( H , GCL_HCURSOR ))
            {

                SetClassLong ( H , GCL_HCURSOR , (long) Hc ) ;
                if (GetCapture ( ) == H ) SetCursor ( Hc ) ;

                GetCursorPos (&P) ;
                TESTCURSORMOVE = 1 ;
                SetCursorPos(P.x , P.y);           
            }
        }
        
    }
    else MMechostr ( 1 , "ERROR : SETcursor : Cursor or Window object is NIL\n" ) ;
    res = MMpush ( m , sw ) ;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRSetCursor end");
#endif
//***********************************

    return res ;
}


/***********************************************************************************************/  
/*                                                                                             */
/*  int GRDestroyCursor ( mmachine m ) ;                                                       */
/*                                                                                             */
/*  correspond a la fonction magma I _destroy_cursor ( ObjCursor )                             */
/* laquelle detruit un curseur souris                                                          */
/*                                                                                             */
/***********************************************************************************************/

int GRDestroyCursor ( mmachine m )
{
    int s ;
    PtrObjVoid O ;
    HCURSOR h ;


 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDestroyCursor");
#endif
//***********************************



    s = MMget(m,0) ;
    if ( s != NIL )
    {
        O = ( PtrObjVoid ) MMstart(m,(s>>1) ) ;
        h = (( PtrObjCursor ) ( MMstart(m, (O->Buffer>>1 )) ))->HCursor ;
        OBJdelTH(m,OBJTYPCURSOR,(int)h) ;
    }
    
 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRDestroyCursor end");
#endif
//***********************************

    MMset(m,0,0) ;
    return 0 ;
}

/*************************************************************************************/
/*                                                                                   */
/*  int GRGetCursor ( mmachine m ) ;                                                 */
/*                                                                                   */
/*  correspond a la fonction ObjCursor _get_cursor ( ObjWin )                        */
/*  laquelle retourne le curseur d'une fenetre / bouton                              */
/*                                                                                   */
/*************************************************************************************/

int GRGetCursor ( mmachine m )
{
    int s , l , s2 ;
    PtrObjVoid O ;
    PtrObjCursor C ;
    HWND H ;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetCursor");
#endif
//***********************************

    s = MMpull( m ) ;
    if ( s == NIL ) return MMpush ( m , NIL ) ;
    O = ( PtrObjVoid ) MMstart(m,(s>>1) )  ;

    switch ( O->Type >> 1 )
    {
        case OBJ_TYPE_WINDOW :
            H = (( PtrObjWindow ) MMstart(m,(O->Buffer>>1) ))->WHandler ;
            break ;
        case OBJ_TYPE_PUSHBUTTON :
            H = (( PtrObjButton ) MMstart(m,(O->Buffer>>1) ))->WHandler ;
            break ;
    }

    l = ( sizeof ( struct ObjVoid ) + 3 ) >> 2 ;
    s = MMmallocCLR (m,l,TYPETAB) ;
    if( s == NIL ) return MERRMEM ;
    if ( MMpush(m,(s<<1)+1)) return MERRMEM ;
  
    l = ( sizeof ( struct ObjCursor ) + 3 ) >> 2 ;
    s2 = MMmalloc ( m,l,TYPEBUF ) ;
    if ( s2 == NIL ) return MERRMEM ;
    s = MMpull(m) ;

    O = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;
    C = ( PtrObjCursor ) MMstart(m, s2 ) ;
    O->Type = OBJ_TYPE_CURSOR << 1 ; 
    O->Buffer = ( s2 << 1 ) + 1 ;       
    O->Father = NIL ;
    O->Tab= NIL ;
    C->HCursor = ( HCURSOR ) GetClassLong ( H , GCL_HCURSOR ) ;    
    s2 = MMpush( m , s ) ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetCursor end");
#endif
//***********************************

    return s2 ;
}


/*************************************************************************************/
/*                                                                                   */
/*  int GRSetCursorPos ( mmachine m ) ;                                              */
/*                                                                                   */
/*  correspond a la fonction magma ObjWin _SETcursorPos ( ObjWin , I , I )           */
/*  laquelle positionne la souris dans une fenetre                                   */
/*                                                                                   */
/*************************************************************************************/

int GRSetCursorPos ( mmachine m )
{
    int s , x , y ;
    PtrObjVoid O;
    PtrObjWindow OW ;
    HWND W ;
    POINT P ;


 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRSetCursorPos");
#endif
//***********************************

    y = MMpull(m) >> 1 ;
    x = MMpull(m) >> 1 ;
    s = MMpull(m) ;

    if ( s != NIL )
    {
        O = ( PtrObjVoid ) MMstart(m,(s>>1));
        OW = ( PtrObjWindow) MMstart(m,(O->Buffer>>1)) ;
        W = OW->WHandler ;
        
        P.x = 0 ;
        P.y = 0 ;
        ClientToScreen ( W , &P ) ;        
       
        SetCursorPos (x + P.x , y + P.y ) ;
               
    }

    s = MMpush(m,s) ;


 //***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRSetCursorPos end");
#endif
//***********************************
    return s;
}


/**************************************************************************************/
/*                                                                                    */
/*  int GRGetCursorPos ( mmachine m ) ;                                               */
/*                                                                                    */
/*  Correspond a la fonction magma [ I I ] _GETcursorPos ( ObjWin )                   */
/*  laquelle retourne les coordonnees de la souris par rapport a une fenetre          */
/*                                                                                    */
/**************************************************************************************/

int GRGetCursorPos ( mmachine m )
{

    int s ;
    PtrObjWindow OW ;
    PtrObjVoid O ;
    HWND W ;
    POINT P , P2 ;

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetCursorPos");
#endif
//***********************************

    s = MMpull(m);
    if (s == NIL ) s = MMpush(m,NIL);
    else 
    {
        O = ( PtrObjVoid ) MMstart(m,(s>>1)) ;
        OW = ( PtrObjWindow ) MMstart(m,(O->Buffer>>1)) ;
        W = OW->WHandler ;
        GetCursorPos (&P ) ;
        P2.x = 0 ; P2.y = 0 ;
        ClientToScreen ( W , &P2 ) ;
        P.x -= P2.x ;
        P.y -= P2.y ;
        if (MMpush(m,(P.x)<<1)) return MERRMEM ;
        if (MMpush(m,(P.y)<<1)) return MERRMEM ;
        if (MMpush(m,4)) return MERRMEM;
        s = MBdeftab (m);
    }

//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRGetCursorPos end");
#endif
//***********************************

    return s;             
}

/****************************************************************************************/
/*                                                                                      */
/*  int GRShowCursor ( mmachine m ) ;                                                   */
/*                                                                                      */
/*  correspond a la fonction magma I _SHOWcursor ( I )                                  */
/*  laquelle active ou desactive la souris                                              */
/*                                                                                      */
/****************************************************************************************/

int GRShowCursor ( mmachine m )
{
    int s , sf ;
    PtrObjVoid O ;
    PtrObjWindow W ;


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRShowCursor");
#endif
//***********************************

    s = MMpull(m)>>1 ; 
    sf = MMpull(m);
    if ( sf != NIL )
    {
          O = ( PtrObjVoid ) MMstart(m,(sf>>1));
          W = ( PtrObjWindow ) MMstart(m,(O->Buffer>>1));
          SetFocus (W->WHandler);
          
          if ( s == 0 )
          {
              while ( ShowCursor ( FALSE ) >= 0 ) ;
              W->Flags |= WN_NOCURSOR;
          }
          else if ( s == 1 )
          {
              while ( ShowCursor ( TRUE ) < 0 ) ;
              W->Flags &= (0xFFFFFFFF - WN_NOCURSOR);
          }
    }


//***********************************
#if DEBUG_LIB2DOS
MMechostr (0, "\nGRShowCursor end");
#endif
//***********************************

    return MMpush(m,sf) ;
}

