/*
 * Xailer source code:
 *
 * Graphics.c
 * Funciones de manejo de imagenes y recursos
 *
 * Copyright 2003, 2007 Jose F. Gimenez
 * Copyright 2003, 2007 Xailer.com
 * All rights reserved
 *
 */

#define WINVER 0x0500

#include <windows.h>
#include <xailer.h>
#include <commctrl.h>
#include <Gdip.h>
#include <colors.ch>
#include <constants.ch>
#include <math.h>

//--------------------------------------------------------------------------

XA_FUNC( MAKEINTRESOURCE )    // MakeIntResource( <nId> ) --> nIntRes
{
   WORD w = hb_parni( 1 );

   hb_retnl( (LONG) MAKEINTRESOURCE( w ) );
}

//--------------------------------------------------------------------------

XA_FUNC( DELETEOBJECT ) // DeleteObject( <hGDIObject> ) --> lSuccess
{
   hb_retl( DeleteObject( (HANDLE) hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( SELECTOBJECT ) // SelectObject( <hDC>, <hGDIObject> ) --> nOldGDIObject
{
   hb_retnl( (LONG) SelectObject( (HDC) hb_parnl( 1 ), (HANDLE) hb_parnl( 2 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( CREATEDC )  // CreateDC( <cDriver>, <cDevice>, <cNotUsed> ) --> hDC
{
   hb_retnl( (LONG) CreateDC( hb_parc( 1 ), hb_parc( 2 ), hb_parc( 3 ), NULL ) );
}

//--------------------------------------------------------------------------

XA_FUNC( DELETEDC )  // DeleteDC( <hDC> ) --> lSuccess
{
   hb_retl( DeleteDC( (HDC) hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( CREATECOMPATIBLEDC ) // CreateCompatibleDC( <hDC> ) --> hDC
{
   hb_retnl( (LONG) CreateCompatibleDC( (HDC) hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( GETDC )  // GetDC( <hWnd> ) --> hDC
{
   hb_retnl( (LONG) GetDC( (HWND) hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( RELEASEDC ) // ReleaseDC( <hWnd>, <hDC> ) --> nResult
{
   hb_retnl( ReleaseDC( (HWND) hb_parnl( 1 ), (HDC) hb_parnl( 2 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( SETPIXEL )  // SetPixel( <hDC>, <nX>, <nY>, <nColor> ) --> nColor
{
   hb_retnl( SetPixel( (HDC) hb_parnl( 1 ), hb_parnl( 2 ), hb_parnl( 3 ), hb_parnl( 4 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( GETTEXTEXTENTPOINT32 )  // GetTextExtentPoint32( <hDC>, <cText> ) --> aPoint
{
   SIZE siz;

   GetTextExtentPoint32( (HDC) hb_parnl( 1 ), hb_parc( 2 ), hb_parclen( 2 ), &siz );
   hb_reta( 2 );
   hb_storvnl( siz.cx, -1, 1 );
   hb_storvnl( siz.cy, -1, 2 );
}

//--------------------------------------------------------------------------

XA_FUNC( LOADIMAGE ) // LoadImage( [<hInstance>], <cName>, <nType>, <nWidth>, <nHeight>, <nFlags> ) --> hImage
{
   hb_retnl( (LONG) LoadImage( HB_ISNIL( 1 ) ? NULL : (HINSTANCE) hb_parnl( 1 ),
                               hb_parc( 2 ), hb_parnl( 3 ),
                               hb_parnl( 4 ), hb_parnl( 5 ), hb_parnl( 6 ) ) );
}

//--------------------------------------------------------------------------

XA_EXPORT int ScreenColors( void ) // ScreenColors() --> nColors
{
   static long nColors = 0;

   if (!nColors)
      {
      HDC hDC;
      long nPlanes, nBitsPixel;

      hDC        = CreateDC( "DISPLAY", NULL, NULL, NULL );
      nPlanes    = GetDeviceCaps(hDC, PLANES);
      nBitsPixel = GetDeviceCaps(hDC, BITSPIXEL);

      DeleteDC(hDC);

      nColors = nPlanes * nBitsPixel;
      }

   return (nColors);
}

//--------------------------------------------------------------------------

XA_FUNC( DRAWTEXT )     // DrawText( <hDC>, <cText>, <aRect>, [<nFlags>] ) --> nResult
{
   RECT rc;
   UINT nFlags = hb_parnl( 4 );

   rc.left = hb_parvnl( 3, 1 );
   rc.top = hb_parvnl( 3, 2 );
   rc.right = hb_parvnl( 3, 3 );
   rc.bottom = hb_parvnl( 3, 4 );

   hb_retnl( DrawText( (HDC) hb_parnl( 1 ), hb_parc( 2 ),
                       hb_parclen( 2 ), &rc, nFlags ) );

   if( ( nFlags & DT_CALCRECT ) && ( hb_parinfo( 3 ) & HB_IT_BYREF ) )
      {
      hb_storvnl( rc.left, 3, 1 );
      hb_storvnl( rc.top, 3, 2 );
      hb_storvnl( rc.right, 3, 3 );
      hb_storvnl( rc.bottom, 3, 4 );
      }
}

//--------------------------------------------------------------------------

XA_FUNC( DRAWTEXTEX )     // DrawTextEx( <hDC>, <cText>, <aRect>, [<nFlags>], [nTabSize], [nLeftMargin], [nRightMargin], [@nCharsDrawn] ) --> nResult
{
   RECT rc;
   UINT nFlags = hb_parnl( 4 );
   DRAWTEXTPARAMS dtp;

   rc.left = hb_parvnl( 3, 1 );
   rc.top = hb_parvnl( 3, 2 );
   rc.right = hb_parvnl( 3, 3 );
   rc.bottom = hb_parvnl( 3, 4 );

   dtp.cbSize = sizeof( DRAWTEXTPARAMS );
   dtp.iTabLength = HB_ISNIL( 5 ) ? 3 :hb_parnl( 5 );
   dtp.iLeftMargin = hb_parnl( 6 );
   dtp.iRightMargin = hb_parnl( 7 );

   hb_retnl( DrawTextEx( (HDC) hb_parnl( 1 ), (LPSTR) hb_parc( 2 ),
                       hb_parclen( 2 ), &rc, nFlags, &dtp ) );

   if( hb_pcount() >= 8 )
      hb_stornl( dtp.uiLengthDrawn, 8 );

   if( ( nFlags & DT_CALCRECT ) && ( hb_parinfo( 3 ) & HB_IT_BYREF ) )
      {
      hb_storvnl( rc.left, 3, 1 );
      hb_storvnl( rc.top, 3, 2 );
      hb_storvnl( rc.right, 3, 3 );
      hb_storvnl( rc.bottom, 3, 4 );
      }
}

//--------------------------------------------------------------------------

XA_FUNC( FILLRECT )  // FillRect( <hDC>, <aRect>, <hBrush> ) --> lSuccess
{
   RECT rc;

   rc.left = hb_parvnl( 2, 1 );
   rc.top = hb_parvnl( 2, 2 );
   rc.right = hb_parvnl( 2, 3 );
   rc.bottom = hb_parvnl( 2, 4 );

   hb_retl( FillRect( (HDC) hb_parnl( 1 ), &rc, (HBRUSH) hb_parnl( 3 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( FRAMERECT )    // FrameRect( <hDC>, <aRect>, <hBrush> ) --> lSuccess
{
   RECT rc;

   rc.left   = hb_parvnl( 2, 1 );
   rc.top    = hb_parvnl( 2, 2 );
   rc.right  = hb_parvnl( 2, 3 );
   rc.bottom = hb_parvnl( 2, 4 );

   hb_retl( FrameRect( (HDC) hb_parnl( 1 ), &rc, (HBRUSH) hb_parnl( 3 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( RECTANGLE )    // Rectangle( <hDC>, <aRect> ) --> lSuccess
{
   int nLeft   = hb_parvnl( 2, 1 );
   int nTop    = hb_parvnl( 2, 2 );
   int nRight  = hb_parvnl( 2, 3 );
   int nBottom = hb_parvnl( 2, 4 );

   hb_retl( Rectangle( (HDC) hb_parnl( 1 ), nLeft, nTop, nRight, nBottom ) );
}

//--------------------------------------------------------------------------

XA_FUNC( ROUNDRECT )    // RoundRect( <hDC>, <aRect>, <nElliWidth>, <nElliHeight> ) --> lSuccess
{
   int nLeft   = hb_parvnl( 2, 1 );
   int nTop    = hb_parvnl( 2, 2 );
   int nRight  = hb_parvnl( 2, 3 );
   int nBottom = hb_parvnl( 2, 4 );

   hb_retl( RoundRect( (HDC) hb_parnl( 1 ), nLeft, nTop, nRight, nBottom,  hb_parnl( 3 ), hb_parnl( 4 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( MOVETO )    // MoveTo( <hDC>, <nX>, <nY> ) --> lSuccess
{
   POINT pt;

   hb_retl( MoveToEx( (HDC) hb_parnl( 1 ), hb_parni( 2 ), hb_parni( 3 ), &pt ) );
}

//--------------------------------------------------------------------------

XA_FUNC( LINETO )    // LineTo( <hDC>, <nX>, <nY>, [<hPen>] ) --> lSuccess
{
   HPEN hOldPen = NULL;

   if( HB_ISNUM( 4 ) )
      hOldPen = (HPEN) SelectObject( (HDC) hb_parnl( 1 ), (HGDIOBJ) hb_parnl( 4 ) );

   hb_retl( LineTo( (HDC) hb_parnl( 1 ), hb_parni( 2 ), hb_parni( 3 ) ) );

   if ( hOldPen )
      SelectObject( (HDC) hb_parnl( 1 ), (HGDIOBJ) hOldPen );
}

//--------------------------------------------------------------------------

XA_FUNC( DRAWFOCUSRECT )   // DrawFocusRect( <hDC>, <aRect> ) --> nResult
{
   RECT rc;

   rc.left = hb_parvnl( 2, 1 );
   rc.top = hb_parvnl( 2, 2 );
   rc.right = hb_parvnl( 2, 3 );
   rc.bottom = hb_parvnl( 2, 4 );

   hb_retl( DrawFocusRect( ( HDC ) hb_parnl( 1 ), &rc ) );
}

//--------------------------------------------------------------------------

XA_FUNC( DRAWBOX )   // DrawBox( <hDC>, <aRect>, [<hPen>] ) --> Nil
{
   HDC hDC      = (HDC) hb_parnl( 1 );
   HPEN hBlack  = NULL;
   HPEN hOldPen;
   POINT pt;
   RECT rc;

   rc.left = hb_parvnl( 2, 1 );
   rc.top = hb_parvnl( 2, 2 );
   rc.right = hb_parvnl( 2, 3 );
   rc.bottom = hb_parvnl( 2, 4 );

   if ( HB_ISNUM( 3 ) )
      hOldPen = ( HPEN ) SelectObject( hDC, (HGDIOBJ) hb_parnl( 3 ) );
   else
   {
      hBlack  = ( HPEN ) GetStockObject( BLACK_PEN );
      hOldPen = ( HPEN ) SelectObject( hDC, (HGDIOBJ) hBlack );
   }

   MoveToEx( hDC, rc.left, rc.top, &pt );
   LineTo( hDC, rc.left, rc.bottom );
   LineTo( hDC, rc.right, rc.bottom );
   LineTo( hDC, rc.right, rc.top );
   LineTo( hDC, rc.left, rc.top );
   SelectObject( hDC, hOldPen );

   if ( hBlack )
      DeleteObject( hBlack );

   hb_ret();
}

//--------------------------------------------------------------------------

XA_EXPORT void DrawRaisedBox( HDC hdc, LPRECT rect ) // DrawRaisedBox( <hDC>, <lpRect> ) --> void
{
   HPEN hGray   = CreatePen( PS_SOLID, 1, clBtnShadow );
   HPEN hWhite  = CreatePen( PS_SOLID, 1, clBtnHighlight );
   HPEN hOldPen = SelectObject( hdc, hWhite );

   MoveToEx( hdc, rect->right, rect->top, NULL );
   LineTo( hdc, rect->left, rect->top );
   LineTo( hdc, rect->left, rect->bottom );

   SelectObject( hdc, hGray );
   LineTo( hdc, rect->right, rect->bottom );
   LineTo( hdc, rect->right, rect->top );

   SelectObject( hdc, hOldPen );
   DeleteObject( hGray );
   DeleteObject( hWhite );
}

//--------------------------------------------------------------------------

XA_EXPORT void DrawSunkenBox( HDC hdc, LPRECT rect ) // DrawSunkenBox( <hDC>, <lpRect> ) --> void
{
   HPEN hGray   = CreatePen( PS_SOLID, 1, clBtnShadow );
   HPEN hWhite  = CreatePen( PS_SOLID, 1, clBtnHighlight );
   HPEN hOldPen = SelectObject( hdc, hGray );

   MoveToEx( hdc, rect->right, rect->top, NULL );
   LineTo( hdc, rect->left, rect->top );
   LineTo( hdc, rect->left, rect->bottom );

   SelectObject( hdc, hWhite );
   LineTo( hdc, rect->right, rect->bottom );
   LineTo( hdc, rect->right, rect->top );

   SelectObject( hdc, hOldPen );
   DeleteObject( hGray );
   DeleteObject( hWhite );
}

//--------------------------------------------------------------------------

XA_FUNC( DRAWRAISEDBOX )   // DrawRaisedBox( <hDC>, <aRect> ) --> Nil
{
   RECT rc;

   rc.left = hb_parvnl( 2, 1 );
   rc.top = hb_parvnl( 2, 2 );
   rc.right = hb_parvnl( 2, 3 );
   rc.bottom = hb_parvnl( 2, 4 );
   DrawRaisedBox( (HDC) hb_parnl( 1 ), &rc );
   hb_ret();
}

//--------------------------------------------------------------------------

XA_FUNC( DRAWSUNKENBOX )   // DrawSunkenBox( <hDC>, <aRect> ) --> Nil
{
   RECT rc;

   rc.left = hb_parvnl( 2, 1 );
   rc.top = hb_parvnl( 2, 2 );
   rc.right = hb_parvnl( 2, 3 );
   rc.bottom = hb_parvnl( 2, 4 );
   DrawSunkenBox( (HDC) hb_parnl( 1 ), &rc );
   hb_ret();
}

//--------------------------------------------------------------------------

XA_FUNC( DRAWFRAMECONTROL )   // DrawFrameControl( <hDC>, <aRect>, <nType>, <nState> ) --> lSuccess
{
   RECT rc;

   rc.left = hb_parvnl( 2, 1 );
   rc.top = hb_parvnl( 2, 2 );
   rc.right = hb_parvnl( 2, 3 );
   rc.bottom = hb_parvnl( 2, 4 );

   hb_retl( DrawFrameControl( ( HDC ) hb_parnl( 1 ), &rc, hb_parni( 3 ), hb_parni( 4 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( INVERTRECT )   // InvertRect( <hDC>, <aRect> ) --> nResult
{
   RECT rc;

   rc.left = hb_parvnl( 2, 1 );
   rc.top = hb_parvnl( 2, 2 );
   rc.right = hb_parvnl( 2, 3 );
   rc.bottom = hb_parvnl( 2, 4 );

   hb_retl( InvertRect( (HDC) hb_parnl( 1 ), &rc ) );
}

//--------------------------------------------------------------------------

XA_FUNC( TEXTOUT )   // TextOut( <hDc>, <nX>, <nY>, <cText> ) --> lSuccess
{
   hb_retl( TextOut( (HDC) hb_parnl( 1 ), hb_parnl( 2 ), hb_parnl( 3 ), hb_parc( 4 ), hb_parclen( 4 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( EXTTEXTOUT )   // ExtTextOut( <hDc>, <nX>, <nY>, <nFlags>, <aRect>, <cText> ) --> lSuccess
{
   RECT rc;

   rc.left   = hb_parvnl( 5, 1 );
   rc.top    = hb_parvnl( 5, 2 );
   rc.right  = hb_parvnl( 5, 3 );
   rc.bottom = hb_parvnl( 5, 4 );

   hb_retl( ExtTextOut( (HDC) hb_parnl( 1 ), hb_parnl( 2 ), hb_parnl( 3 ),
                         hb_parnl( 4 ), &rc, hb_parc( 6 ), hb_parclen( 6 ), NULL ) );
}


//--------------------------------------------------------------------------

XA_FUNC( SETTEXTALIGN ) // SetTextAlign( <hDC>, <nAlign> ) --> lSuccess
{
   hb_retl( SetTextAlign( (HDC) hb_parnl( 1 ), hb_parnl( 2 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_DRAWITEMSTRUCT )     // XA_DrawItemStruct( <pDrawItemStruct> ) --> aDrawItemStruct
{
   LPDRAWITEMSTRUCT lpdis = (LPVOID) hb_parnl( 1 );
   PHB_ITEM pArray = hb_itemArrayNew( 9 );
   PHB_ITEM pSub = hb_itemArrayNew( 4 );
   PHB_ITEM pItem = hb_itemNew( NULL );

   hb_itemArrayPut( pArray, 1, hb_itemPutNL( pItem, lpdis->CtlType ) );
   hb_itemArrayPut( pArray, 2, hb_itemPutNL( pItem, lpdis->CtlID ) );
   hb_itemArrayPut( pArray, 3, hb_itemPutNL( pItem, lpdis->itemID + 1 ) );
   hb_itemArrayPut( pArray, 4, hb_itemPutNL( pItem, lpdis->itemAction ) );
   hb_itemArrayPut( pArray, 5, hb_itemPutNL( pItem, lpdis->itemState ) );
   hb_itemArrayPut( pArray, 6, hb_itemPutNL( pItem, (LONG) lpdis->hwndItem ) );
   hb_itemArrayPut( pArray, 7, hb_itemPutNL( pItem, (LONG) lpdis->hDC ) );

   hb_itemArrayPut( pSub, 1, hb_itemPutNL( pItem, lpdis->rcItem.left ) );
   hb_itemArrayPut( pSub, 2, hb_itemPutNL( pItem, lpdis->rcItem.top ) );
   hb_itemArrayPut( pSub, 3, hb_itemPutNL( pItem, lpdis->rcItem.right ) );
   hb_itemArrayPut( pSub, 4, hb_itemPutNL( pItem, lpdis->rcItem.bottom ) );

   hb_itemArrayPut( pArray, 8, pSub );
   hb_itemRelease( pSub );

   hb_itemArrayPut( pArray, 9, hb_itemPutNL( pItem, lpdis->itemData ) );

   hb_itemReturnForward( pArray );
   hb_itemRelease( pItem );
   hb_itemRelease( pArray );
}

//--------------------------------------------------------------------------

XA_FUNC( GETSTOCKOBJECT )  // GetStockObject( <nGDIObject> ) --> hGDIObject
{
   hb_retnl( (LONG) GetStockObject( hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_EXPORT void XA_GradientFillV( HDC hdc, LPRECT rect, COLORREF nClrFrom, COLORREF nClrTo ) // XA_GradientFillV( <hDC>, <lpRect>, <nClrFrom>, <nClrTo> ) --> void
{
   TRIVERTEX vert[2];
   GRADIENT_RECT gRect;

   vert[0].x      = rect->left;
   vert[0].y      = rect->top;
   vert[0].Red    = ( nClrFrom & 0x0000FF ) << 8;
   vert[0].Green  = ( nClrFrom & 0x00FF00 );
   vert[0].Blue   = ( nClrFrom & 0xFF0000 ) >> 8;
   vert[0].Alpha  = 0;
   vert[1].x      = rect->right;
   vert[1].y      = rect->bottom;
   vert[1].Red    = ( nClrTo & 0x0000FF ) << 8;
   vert[1].Green  = ( nClrTo & 0x00FF00 );
   vert[1].Blue   = ( nClrTo & 0xFF0000 ) >> 8;
   vert[1].Alpha  = 0;
   gRect.UpperLeft  = 0;
   gRect.LowerRight = 1;
   GradientFill( hdc, vert, 2, &gRect, 1, GRADIENT_FILL_RECT_V );
}

//--------------------------------------------------------------------------

XA_EXPORT void XA_GradientFillH( HDC hdc, LPRECT rect, COLORREF nClrFrom, COLORREF nClrTo ) // XA_GradientFillH( <hDC>, <lpRect>, <nClrFrom>, <nClrTo> ) --> void
{
   TRIVERTEX vert[2];
   GRADIENT_RECT gRect;

   vert[0].x      = rect->left;
   vert[0].y      = rect->top;
   vert[0].Red    = ( nClrFrom & 0x0000FF ) << 8;
   vert[0].Green  = ( nClrFrom & 0x00FF00 );
   vert[0].Blue   = ( nClrFrom & 0xFF0000 ) >> 8;
   vert[0].Alpha  = 0;
   vert[1].x      = rect->right;
   vert[1].y      = rect->bottom;
   vert[1].Red    = ( nClrTo & 0x0000FF ) << 8;
   vert[1].Green  = ( nClrTo & 0x00FF00 );
   vert[1].Blue   = ( nClrTo & 0xFF0000 ) >> 8;
   vert[1].Alpha  = 0;
   gRect.UpperLeft  = 0;
   gRect.LowerRight = 1;
   GradientFill( hdc, vert, 2, &gRect, 1, GRADIENT_FILL_RECT_H );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_GRADIENTFILLV )      // XA_GradientFillV( <hDC>, <aRect>, <nStartColor>, <nEndColor> ) --> n/a
{
   RECT rect;

   rect.left = hb_parvnl( 2, 1 );
   rect.top = hb_parvnl( 2, 2 );
   rect.right = hb_parvnl( 2, 3 );
   rect.bottom = hb_parvnl( 2, 4 );

   XA_GradientFillV( (HDC) hb_parnl( 1 ), &rect, (COLORREF) hb_parnl( 3 ), (COLORREF) hb_parnl( 4 ) );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_GRADIENTFILLH )      // XA_GradientFillH( <hDC>, <aRect>, <nStartColor>, <nEndColor> ) --> n/a
{
   RECT rect;

   rect.left = hb_parvnl( 2, 1 );
   rect.top = hb_parvnl( 2, 2 );
   rect.right = hb_parvnl( 2, 3 );
   rect.bottom = hb_parvnl( 2, 4 );

   XA_GradientFillH( (HDC) hb_parnl( 1 ), &rect, (COLORREF) hb_parnl( 3 ), (COLORREF) hb_parnl( 4 ) );
}

//--------------------------------------------------------------------------

XA_FUNC( INFLATERECT )     // InflateRect( <aRect>, <nXInc>, <nYInc> ) --> lSuccess
{
   RECT rc;

   rc.left   = hb_parvnl( 1, 1 );
   rc.top    = hb_parvnl( 1, 2 );
   rc.right  = hb_parvnl( 1, 3 );
   rc.bottom = hb_parvnl( 1, 4 );

   hb_retl( InflateRect( &rc, hb_parnl( 2 ), hb_parnl( 3 ) ) );

   hb_storvnl( rc.left, 1, 1 );
   hb_storvnl( rc.top, 1, 2 );
   hb_storvnl( rc.right, 1, 3 );
   hb_storvnl( rc.bottom, 1, 4 );
}

//------------------------------------------------------------------------------

XA_FUNC( XA_LOADIMAGE ) // XA_LoadImage( <cName>, <nType>, <nxDesired>, <nyDesired>, <nFlags> ) --> hImage
{
   hb_retnl( (LONG) XA_LoadImage( HB_ISCHAR( 1 ) ? hb_parc( 1 ) : MAKEINTRESOURCE( hb_parnl( 1 ) ),
                                  hb_parnl( 2 ), hb_parnl( 3 ), hb_parnl( 4 ), hb_parnl( 5 ) ) );
}

//------------------------------------------------------------------------------

XA_EXPORT HANDLE XA_LoadImage( LPCTSTR lpszName, UINT uType, int cxDesired, int cyDesired, UINT fuLoad )
{
   HINSTANCE hInstance;
   HANDLE hImage = NULL;

   if( IS_INTRESOURCE( lpszName ) )
      hImage = LoadImage( NULL, lpszName, uType, cxDesired, cyDesired, fuLoad );
   if( hImage == NULL )
      {
      UINT n = XA_ResourceSearchOrder( 0 ) - 1;

      while( ( hInstance = GetInstance( n++ ) ) != NULL )
         if( ( hImage = LoadImage( hInstance, lpszName, uType, cxDesired, cyDesired, fuLoad ) ) != NULL )
            break;
      }

   return( hImage );
}

//------------------------------------------------------------------------------

XA_FUNC( XA_LOADCURSOR ) // XA_LoadCursor( <cName> ) --> hCursor
{
   hb_retnl( (LONG) XA_LoadCursor( HB_ISCHAR( 1 ) ? hb_parc( 1 ) : MAKEINTRESOURCE( hb_parnl( 1 ) ) ) );
}

//------------------------------------------------------------------------------

XA_EXPORT HCURSOR XA_LoadCursor( LPCTSTR lpszName )
{
   HINSTANCE hInstance;
   HCURSOR hCursor = NULL;

   if( IS_INTRESOURCE( lpszName ) )
      hCursor = LoadCursor( NULL, lpszName );
   if( hCursor == NULL )
      {
      UINT n = XA_ResourceSearchOrder( 0 ) - 1;

      while( ( hInstance = GetInstance( n++ ) ) != NULL )
         if( ( hCursor = LoadCursor( hInstance, lpszName ) ) != NULL )
            break;
      }

   return( hCursor );
}

//------------------------------------------------------------------------------

XA_FUNC( GETRVALUE )    // GetRValue( <nColor> ) --> nRed
{
  hb_retni( GetRValue( hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( GETGVALUE )    // GetGValue( <nColor> ) --> nGreen
{
  hb_retni( GetGValue( hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( GETBVALUE )    // GetBValue( <nColor> ) --> nBlue
{
  hb_retni( GetBValue( hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_EXPORT COLORREF XA_ColorBlend( COLORREF nClrFrom, COLORREF nClrTo, int nAlpha ) // XA_ColorBlend( <nColorFrom>, <nColorTo>, <nAlpha> ) --> nBlendColor
{
   BYTE nFromR = GetRValue( nClrFrom );
   BYTE nFromG = GetGValue( nClrFrom );
   BYTE nFromB = GetBValue( nClrFrom );
   BYTE nToR = GetRValue( nClrTo );
   BYTE nToG = GetGValue( nClrTo );
   BYTE nToB = GetBValue( nClrTo );

return RGB( ( ( nFromR * nAlpha ) / 255 ) + ( ( nToR * ( 255 - nAlpha ) ) / 255 ),
            ( ( nFromG * nAlpha ) / 255 ) + ( ( nToG * ( 255 - nAlpha ) ) / 255 ),
            ( ( nFromB * nAlpha ) / 255 ) + ( ( nToB * ( 255 - nAlpha ) ) / 255 ) );
}

//--------------------------------------------------------------------------

XA_FUNC( COLORBLEND )   // ColorBlend( <nClrFrom>, <nClrTo>, [<nAlpha>] ) --> nColor
{
   hb_retnl( XA_ColorBlend( (COLORREF) hb_parnl( 1 ), (COLORREF) hb_parnl( 2 ), HB_ISNUM( 3 ) ? hb_parnl( 3 ) : 128 ) );
}

//--------------------------------------------------------------------------

XA_FUNC( ELLIPSE )  // Ellipse( <hDC>, <nLeft>, <nTop>, <nRight>, <nBottom> ) --> lSuccess
{
   hb_retl( Ellipse( (HDC) hb_parnl( 1 ), hb_parnl( 2 ), hb_parnl( 3 ), hb_parnl( 4 ), hb_parnl( 5 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( EXTFLOODFILL ) // ExtFloodFill( <hDC>, <nX>, <nY>, <nClr>, <nMode> ) --> lSuccess
{
   hb_retl( ExtFloodFill( (HDC) hb_parnl( 1 ), hb_parni( 2 ), hb_parni( 3 ), (COLORREF) hb_parnl( 4 ), hb_parni( 5 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( GETBMPFROMCOLOR ) // GetBmpFromColor( <nColor>, [<nSize>], <lNoFrame> ) --> hBitmap
{
   HDC     hdc, hdcBmp;
   HBITMAP hBmp;
   HBRUSH  hBrush;
   HPEN    hPen;
   RECT    rect;
   BOOL    lNoFrame;

   rect.top    = 0;
   rect.left   = 0;
   rect.right  = HB_ISNUM( 2 ) ? hb_parnl( 2 ) : 16;
   rect.bottom = rect.right;

   lNoFrame = hb_parl( 3 );
   hBrush   = CreateSolidBrush( hb_parnl( 1 ) );
   hdc      = CreateDC( "DISPLAY", NULL, NULL, NULL );
   hdcBmp   = CreateCompatibleDC( hdc );
   hBmp     = CreateCompatibleBitmap( hdc, rect.right, rect.bottom );

   if( lNoFrame )
      hPen  = CreatePen( PS_SOLID, 2, hb_parnl( 1 ) );
   else
      hPen  = CreatePen( PS_SOLID, 2, 0xFABADA ); // ;-) color transparente

   SelectObject( hdcBmp, hBmp );
   SelectObject( hdcBmp, hBrush );
   SelectObject( hdcBmp, hPen );
   Rectangle( hdcBmp, rect.top, rect.left, rect.right, rect.bottom );
   DeleteObject( hBrush );
   DeleteObject( hPen );
   DeleteDC( hdcBmp );
   DeleteDC( hdc );

   hb_retnl( (LONG) hBmp );
}

//--------------------------------------------------------------------------

XA_FUNC( ANGLEARC )  // AngleArc( <hDC>, <nX>, <nY>, <nRadius>, <nStartAngle>, <nSweepAngle> ) --> lSuccess
{
   hb_retl( AngleArc( (HDC) hb_parnl( 1 ), hb_parnl( 2 ), hb_parnl( 3 ), hb_parnl( 4 ), hb_parnl( 5 ), hb_parnl( 6 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( ARC )  // Arc( <hDC>, <nLeft>, <nTop>, <nRight>, <nBottom>, <nXStart>, <nYStart>, <nXEnd>, <nYEnd> ) --> lSuccess
{
   hb_retl( Arc( (HDC) hb_parnl( 1 ), hb_parnl( 2 ), hb_parnl( 3 ), hb_parnl( 4 ), hb_parnl( 5 ), hb_parnl( 6 ), hb_parnl( 7 ), hb_parnl( 8 ), hb_parnl( 9 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( ARCTO )  // ArcTo( <hDC>, <nLeft>, <nTop>, <nRight>, <nBottom>, <nXRadial1>, <nYRadial1>, <nXRadial2>, <nYRadial2> ) --> lSuccess
{
   hb_retl( ArcTo( (HDC) hb_parnl( 1 ), hb_parnl( 2 ), hb_parnl( 3 ), hb_parnl( 4 ), hb_parnl( 5 ), hb_parnl( 6 ), hb_parnl( 7 ), hb_parnl( 8 ), hb_parnl( 9 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( CHORD )  // Chord( <hDC>, <nLeft>, <nTop>, <nRight>, <nBottom>, <nXRadial1>, <nYRadial1>, <nXRadial2>, <nYRadial2> ) --> lSuccess
{
   hb_retl( Chord( (HDC) hb_parnl( 1 ), hb_parnl( 2 ), hb_parnl( 3 ), hb_parnl( 4 ), hb_parnl( 5 ), hb_parnl( 6 ), hb_parnl( 7 ), hb_parnl( 8 ), hb_parnl( 9 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( PIE )  // Pie( <hDC>, <nLeft>, <nTop>, <nRight>, <nBottom>, <nXRadial1>, <nYRadial1>, <nXRadial2>, <nYRadial2> ) --> lSuccess
{
   hb_retl( Pie( (HDC) hb_parnl( 1 ), hb_parnl( 2 ), hb_parnl( 3 ), hb_parnl( 4 ), hb_parnl( 5 ), hb_parnl( 6 ), hb_parnl( 7 ), hb_parnl( 8 ), hb_parnl( 9 ) ) );
}


//--------------------------------------------------------------------------

XA_FUNC( POLYGON ) // Polygon( <hDC>, <aPoints> ) --> lSuccess
{
   HDC hDC = (HDC) hb_parnl( 1 );
   PHB_ITEM aPoints = hb_param( 2, HB_IT_ARRAY ), aPoint;
   int nPoints, n;
   LPPOINT pt;

   if( aPoints && ( ( nPoints = hb_arrayLen( aPoints ) ) != 0 ) )
   {
      pt = hb_xgrab( nPoints * sizeof( POINT ) );
      for( n = 0; n < nPoints; n++ )
      {
         aPoint = hb_arrayGetItemPtr( aPoints, n + 1 );
         pt[ n ].x = hb_arrayGetNL( aPoint, 1 );
         pt[ n ].y = hb_arrayGetNL( aPoint, 2 );
      }
      hb_retl( Polygon( hDC, pt, nPoints ) );
      hb_xfree( pt );
   }
   else
      hb_retl( 0 );
}

//--------------------------------------------------------------------------

XA_FUNC( GETWINDOWDC )  // GetWindowDC( <hWNd> ) --> hDC
{
   hb_retnl( (LONG) GetWindowDC( (HWND) hb_parnl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_EXPORT DWORD XA_ShadedColor( DWORD color, double shade_factor, BOOL lARGB ) // XA_ShadedColor( <nColor>, <nFactor>, <lARGB> )
{
   DWORD scolor;
   byte r,g,b;

   if( lARGB )
   {
      r = ((color >> 16) & 255 ) * ( 1 - shade_factor );
      g = ((color >> 8) & 255 ) * ( 1 - shade_factor );
      b = ((color & 255 )) * ( 1 - shade_factor );
      scolor = MAKEARGB( 255, r, g, b );
   }
   else
   {
      r = min( 255, GetRValue( color ) * ( 1 - shade_factor ) );
      g = min( 255, GetGValue( color ) * ( 1 - shade_factor ) );
      b = min( 255, GetBValue( color ) * ( 1 - shade_factor ) );
      scolor = RGB( r, g, b );
   }

   return scolor;
}

//------------------------------------------------------------------------------

XA_EXPORT DWORD XA_TintColor( DWORD color, double tint_factor, BOOL lARGB ) // XA_TintColor( <nColor>, <nFactor>, <lARGB> )
{
   DWORD tcolor;
   byte r,g,b;

   if( lARGB )
   {
      r = ((color >> 16) & 255 );
      g = ((color >> 8) & 255 );
      b = ((color & 255 ));

      r = r + ( 255 - r ) * tint_factor;
      g = g + ( 255 - g ) * tint_factor;
      b = b + ( 255 - b ) * tint_factor;

      tcolor = MAKEARGB( 255, r, g, b );
   }
   else
   {
      r = GetRValue( color );
      g = GetGValue( color );
      b = GetBValue( color );

      r = min( 255, r + ( 255 - r ) * tint_factor );
      g = min( 255, g + ( 255 - g ) * tint_factor );
      b = min( 255, b + ( 255 - b ) * tint_factor );

      tcolor = RGB( r, g, b );
   }

   return tcolor;
}

//------------------------------------------------------------------------------
// https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color

static double gamma2linear( double v )
{
   if ( v <= 0.04045 )
      v = (v / 12.92);
   else
      v = pow(((v + 0.055) / 1.055), 2.4);

   return v;
}

XA_EXPORT int XA_Lightness( DWORD color )
{
   double r,g,b,y;

   r = ((color >> 16) & 255 ) / 255;
   g = ((color >> 8) & 255 ) / 255;
   b = ((color & 255 )) / 255;

   r = gamma2linear(r);
   g = gamma2linear(g);
   b = gamma2linear(b);

   y = (0.2126 * r + 0.7152 * g + 0.0722 * b);

   if ( y <= (216/24389) )
      y = y * (24389/27);
   else
      y = pow(y,(1/3)) * 116 - 16;

   return (int) y;
}

//--------------------------------------------------------------------------

XA_FUNC( XA_LIGHTNESS ) // XA_Lightness( <nColor> ) --> % 0-100
{
   hb_retnl( XA_Lightness( hb_parnl( 1 ) ) );
}

//------------------------------------------------------------------------------

XA_EXPORT int XA_Luminance( DWORD color ) // XA_Luminance( <nColor> ) --> nValue (0-255)
{
   byte r,g,b;

   r = ((color >> 16) & 255 );
   g = ((color >> 8) & 255 );
   b = ((color & 255 ));

   return (int) (r+r+r+b+g+g+g+g)>>3;
}

//--------------------------------------------------------------------------

XA_FUNC( XA_LUMINANCE )  // XA_Luminance( <nColor> ) --> nValue (0-255)
{
   hb_retnl( XA_Luminance( hb_parnl( 1 ) ) );
}

//------------------------------------------------------------------------------

typedef HRESULT (WINAPI * COLORIZATION)( DWORD *pcrColorization, BOOL *pfOpaqueBlend );

DWORD XA_GetColorization( BOOL lARGB ) // XA_GetColorization( <lARGB> )
{
   static DWORD color = 0;

   if( !color )
      {
      HINSTANCE hLib = LoadLibrary( "dwmapi.dll" );
      COLORIZATION fnColor;
      BOOL opaque = FALSE;
      if( hLib )
         {
         fnColor = (COLORIZATION) GetProcAddress( hLib, "DwmGetColorizationColor" );
         if( fnColor )
            fnColor( &color, &opaque );
         FreeLibrary( hLib );
         }
      }
   if( lARGB )
      return MAKEARGB( 255, ( color >> 16 ) & 255, ( color >> 8 ) & 255, color & 255 );

return RGB( ( color >> 16 ) & 255, ( color >> 8 ) & 255, color & 255 );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_GETCOLORIZATION )  // XA_GetColorization( <lARGB> ) --> nColor
{
   hb_retnl( XA_GetColorization( hb_parl( 1 ) ) );
}

//--------------------------------------------------------------------------

XA_FUNC( XA_FILLRECTALPHA ) // XA_FillRectAlpha( <hDC>, <rect>, <nColor>, [<nOpacity>] ) --> NIL
{
   HDC hDC = (HDC )hb_parnl( 1 );
   PHB_ITEM pRect = hb_param( 2, HB_IT_ARRAY );
   int nColor = hb_parnl( 3 );
   int nOpacity = HB_ISNIL( 4 ) ? 50: hb_parnl( 4 );
   RECT rc;
   GpGraphics *g;
   GpBrush *gBrush;

   GdipCreateFromHDC( hDC, &g );
   GdipSetSmoothingMode( g, SmoothingModeAntiAlias );
   GdipSetCompositingQuality( g, CompositingQualityHighSpeed );

   rc.left = hb_arrayGetNL( pRect, 1 );
   rc.top = hb_arrayGetNL( pRect, 2 );
   rc.right = hb_arrayGetNL( pRect, 3 ) - rc.left - 1;
   rc.bottom = hb_arrayGetNL( pRect, 4 ) - rc.top - 1;

   GdipCreateSolidFill( XA_clr2argb( nOpacity, nColor ), &gBrush );
   GdipFillRectangleI( g, gBrush, rc.left, rc.top, rc.right, rc.bottom );
   GdipDeleteBrush( gBrush );

   GdipDeleteGraphics( g );

   hb_ret();
}

//--------------------------------------------------------------------------

XA_FUNC( XA_PAINTCHECKBOX ) // XA_PaintCheckBox( hDC, rect, nColor, lChecked ) --> NIL
{
   HDC hDC = (HDC )hb_parnl( 1 );
   PHB_ITEM pRect = hb_param( 2, HB_IT_ARRAY );
   int nColor = hb_parnl( 3 );
   BOOL lChecked = hb_parl( 4 );
   RECT rect;
   HPEN hPen, hOld;

   rect.left = hb_arrayGetNL( pRect, 1 );
   rect.top = hb_arrayGetNL( pRect, 2 );
   rect.right = hb_arrayGetNL( pRect, 3 ); // - rect.left - 1;
   rect.bottom = hb_arrayGetNL( pRect, 4 ); // - rect.top - 1;

   InflateRect( &rect, -2, -2 );  // Quitamos el ancho del pen

   hPen = CreatePen( PS_SOLID, 2, nColor );
   hOld = SelectObject( hDC, hPen );
   MoveToEx( hDC, rect.left, rect.top, NULL );
   LineTo( hDC, rect.right, rect.top );
   LineTo( hDC, rect.right, rect.bottom );
   LineTo( hDC, rect.left, rect.bottom );
   LineTo( hDC, rect.left, rect.top - 1);
   SelectObject( hDC, hOld );
   DeleteObject( hPen );


   if ( lChecked )
      {
      GpGraphics *g;
      GpPen *gPen;
      int nXPt1, nXPt2, nXPt3, nYPt1, nYPt2, nYPt3;

      GdipCreateFromHDC( hDC, &g );
      GdipSetSmoothingMode( g, SmoothingModeAntiAlias );
      GdipSetCompositingQuality( g, CompositingQualityHighSpeed );

      nXPt1 = rect.left;
      nYPt1 = rect.top + (int) ( (rect.bottom - rect.top) / 2 );
      nXPt2 = rect.left + (int) ( (rect.right - rect.left) / 3 );
      nYPt2 = rect.bottom - 4;
      nXPt3 = rect.right- 2;
      nYPt3 = rect.top + (int) ( (rect.bottom - rect.top) / 4 );

      GdipCreatePen1( XA_clr2argb( 255, nColor ) , 2, UnitPixel, &gPen );
      GdipDrawLineI( g, gPen, nXPt1, nYPt1, nXPt2, nYPt2 );
      GdipDrawLineI( g, gPen, nXPt2, nYPt2, nXPt3, nYPt3 );
      GdipDeletePen( gPen );

      GdipDeleteGraphics( g );
      }

   hb_ret();
}

//------------------------------------------------------------------------------

XA_FUNC( XA_DRAWBITMAPBYPOS ) // XA_DrawBitmapByPos( hDC, hImageList, nPos, aRect ) --> Nil
{
   HDC hdc = (HDC) hb_parnl( 1 );
   HIMAGELIST hIL = (HIMAGELIST) hb_parnl( 2 );
   int pos = hb_parnl( 3 ) - 1;
   RECT rc;
   int cx, cy;

   rc.left   = hb_parvnl( 4, 1 );
   rc.top    = hb_parvnl( 4, 2 );
   rc.right  = hb_parvnl( 4, 3 );
   rc.bottom = hb_parvnl( 4, 4 );

   ImageList_GetIconSize( hIL, &cx, &cy );
   ImageList_Draw( hIL, pos, hdc, ( rc.left + rc.right - cx ) >> 1, ( rc.top + rc.bottom - cy ) >> 1, ILD_TRANSPARENT );
   hb_ret();
}

//------------------------------------------------------------------------------

XA_FUNC( XA_DRAWTEXTEX2 ) // XA_DrawTextEx2( hDC, Value, aRect, nSpacing, nVAlign, nHAlign, nLinkColor, lClipped )
{
   HDC hDC            = (HDC) hb_parnl( 1 );
   LPTSTR cText       = (LPSTR) hb_parc( 2 );
   int nTextLen       = hb_parclen( 2 );
   int nSpacing       = HB_ISNUM( 4 ) ? hb_parnl( 4 ): 100;
   int nVAlign        = HB_ISNUM( 5 ) ? hb_parnl( 5 ): vaTOP;
   int nHAlign        = HB_ISNUM( 6 ) ? hb_parnl( 6 ): taLEFT;
   int nLinkColor     = HB_ISNUM( 7 ) ? hb_parnl( 7 ): clBlue;
   BOOL lClipped      = HB_ISLOG( 8 ) ? hb_parl( 8 ): FALSE;
   HRGN hRgn, hOldRgn;
   RECT rect;
   int nHeight, nWidth;

   rect.left   = hb_parvnl( 3, 1 );
   rect.top    = hb_parvnl( 3, 2 );
   rect.right  = hb_parvnl( 3, 3 );
   rect.bottom = hb_parvnl( 3, 4 );

   if ( nSpacing >= 0 )
      {
      if ( nVAlign != vaTOP )
         {
         nHeight = XA_DrawTextEx( hDC, cText, nTextLen, &rect, DT_CALCRECT | nSpacing, 0, NULL, NULL, NULL );
         if ( nVAlign == vaCENTER )
            rect.top += ( rect.bottom - rect.top - nHeight ) >>1;
         else
            rect.top = rect.bottom - nHeight;
         }
      }
   else
      {
      nHeight = XA_DrawTextEx( hDC, cText, nTextLen, &rect, DT_CALCRECT | -1, 0, NULL, NULL, &nWidth );
      switch ( nHAlign )
         {
         case taLEFT: break;
         case taCENTER: rect.left += ( rect.right - rect.left - nWidth ) >> 1; break;
         case taRIGHT: rect.left = rect.right - nWidth; break;
         }
      switch ( nVAlign )
         {
         case vaTOP: break;
         case vaCENTER: rect.top += ( rect.bottom - rect.top - nHeight ) >>1; break;
         case vaBOTTOM: rect.top = rect.bottom - nHeight; break;
         }
      }

   if( lClipped )
      {
      hRgn = CreateRectRgnIndirect( &rect );
      hOldRgn = hRgn;
      if( GetClipRgn( hDC, hOldRgn ) != 1 )
         {
         DeleteObject( hOldRgn );
         hOldRgn = NULL;
         }
      SelectClipRgn( hDC, hRgn );
      }

   XA_DrawTextEx( hDC, (LPSTR) cText, nTextLen, &rect, DT_NOPREFIX, nLinkColor, NULL, NULL, NULL );

   if( lClipped && hRgn )
      {
      SelectClipRgn( hDC, hOldRgn );
      DeleteObject( hRgn );
      if( hOldRgn )
         DeleteObject( hOldRgn );
      }
}

//------------------------------------------------------------------------------

XA_EXPORT void XA_PaintTriangle( HDC hDC, LPRECT rc, int nColor, int nDirection )
{
   int nMidH, nMidV;
   GpGraphics *g;
   GpPen *gPen;

   GdipCreateFromHDC( hDC, &g );
   GdipSetSmoothingMode( g, SmoothingModeAntiAlias );
   GdipSetCompositingQuality( g, CompositingQualityAssumeLinear );

   GdipCreatePen1( XA_clr2argb( 255, nColor ) , 2, UnitPixel, &gPen );

   nMidH = ( rc->right - rc->left ) >> 1;
   nMidV = ( rc->bottom - rc->top ) >> 1;

   switch ( nDirection )
      {
      case orTOP: // up
         GdipDrawLineI( g, gPen, rc->left,
                                 rc->bottom,
                                 rc->left + nMidH,
                                 rc->top );
         GdipDrawLineI( g, gPen, rc->left + nMidH,
                                 rc->top,
                                 rc->right,
                                 rc->bottom);
         break;
      case orBOTTOM: // down
         GdipDrawLineI( g, gPen, rc->left,
                                 rc->top,
                                 rc->left + nMidH,
                                 rc->bottom );
         GdipDrawLineI( g, gPen, rc->left + nMidH,
                                 rc->bottom,
                                 rc->right,
                                 rc->top );
         break;
      case orLEFT: // left
         GdipDrawLineI( g, gPen, rc->right,
                                 rc->top,
                                 rc->left,
                                 rc->top + nMidV );
         GdipDrawLineI( g, gPen, rc->left,
                                 rc->top + nMidV,
                                 rc->right,
                                 rc->bottom );
         break;
      case orRIGHT: // right
         GdipDrawLineI( g, gPen, rc->left,
                                 rc->top,
                                 rc->right,
                                 rc->top + nMidV );
         GdipDrawLineI( g, gPen, rc->right,
                                 rc->top + nMidV,
                                 rc->left,
                                 rc->bottom );
         break;
      }

   GdipDeletePen( gPen );
   GdipDeleteGraphics( g );
}

//------------------------------------------------------------------------------

XA_FUNC( XA_PAINTTRIANGLE ) // XA_PaintTriangle( hDC, rect, nColor, nDirection ) --> NIL
{
   HDC hDC = (HDC) hb_parnl( 1 );
   PHB_ITEM pRect = hb_param( 2, HB_IT_ARRAY );
   int nColor = hb_parnl( 3 );
   int nDirection = hb_parnl( 4 ); // 0 up, 1, down, 2, left, 3 right
   RECT rc;

   rc.left = hb_arrayGetNL( pRect, 1 );
   rc.top = hb_arrayGetNL( pRect, 2 );
   rc.right = hb_arrayGetNL( pRect, 3 );
   rc.bottom = hb_arrayGetNL( pRect, 4 );

   XA_PaintTriangle( hDC, &rc, nColor, nDirection );

   hb_ret();
}

//------------------------------------------------------------------------------

GpPath CreateRoundRect( RECT rect, int radius )
{
   GpPath * gpPath;
   int l = rect.left;
   int t = rect.top;
   int w = rect.right - rect.left;
   int h = rect.bottom - rect.top;
   int d;

   radius = min( min( radius, h >> 1 ), w >> 1 );
   d = radius << 1;

   GdipCreatePath( FillModeAlternate, &gpPath );
   GdipStartPathFigure( gpPath );
   GdipAddPathArc( gpPath, l, t, d, d, 180, 90 );
   GdipAddPathLine( gpPath, l + radius, t, l + w - radius, t );
   GdipAddPathArc( gpPath, l + w - d, t, d, d, 270, 90 );
   GdipAddPathLine( gpPath, l + w, t + radius, l + w, t + h - radius );
   GdipAddPathArc( gpPath, l + w - d, t + h - d, d, d, 0, 90 );
   GdipAddPathLine( gpPath, l + w - radius, t + h, l + radius, t + h );
   GdipAddPathArc( gpPath, l, t + h - d, d, d, 90, 90 );
   GdipAddPathLine( gpPath, l, t + h - radius, l, t + radius );
   GdipClosePathFigure( gpPath );

   return gpPath;
}

//------------------------------------------------------------------------------

XA_EXPORT void DrawRoundRect( HDC hDC, LPRECT rc, int nDia, int nColor, int nTrans, int nPen )
{
   GpGraphics *g;
   GpPath *gPath;
   GpPen *gPen;

   gPath = CreateRoundRect( *rc, nDia );

   GdipCreateFromHDC( hDC, &g );
   GdipSetSmoothingMode( g, SmoothingModeAntiAlias );
   GdipSetCompositingQuality( g, CompositingQualityHighQuality );

   GdipCreatePen1( XA_clr2argb( nTrans, nColor ), nPen, UnitPixel, &gPen );

   GdipDrawPath( g, gPen, gPath );
   GdipDeletePath( gPath );
   GdipDeletePen( gPen );

   GdipDeleteGraphics( g );
}

//------------------------------------------------------------------------------

XA_FUNC( XA_DRAWROUNDEDRECT ) // XA_DrawRoundedRect( hDC, rect, nDia, nColor, nTransparency, nPenSize ) --> NIL
{
   HDC hDC = (HDC) hb_parnl( 1 );
   PHB_ITEM pRect = hb_param( 2, HB_IT_ARRAY );
   int nDia = hb_parnl( 3 );
   int nColor = hb_parnl( 4 );
   int nTrans = HB_ISNUM( 5 ) ? hb_parnl( 5 ): 255;
   int nPen = HB_ISNUM( 6 ) ? hb_parnl( 6 ): 2;
   RECT rc;

   rc.left = hb_arrayGetNL( pRect, 1 );
   rc.top = hb_arrayGetNL( pRect, 2 );
   rc.right = hb_arrayGetNL( pRect, 3 );
   rc.bottom = hb_arrayGetNL( pRect, 4 );

   DrawRoundRect( hDC, &rc, nDia, nColor, nTrans, nPen );

   hb_ret();
}

//------------------------------------------------------------------------------

XA_EXPORT void FillRoundRect( HDC hDC, LPRECT rc, int nDia, int nColor, int nTrans )
{
   GpGraphics *g;
   GpPath *gPath;
   GpBrush *gBrush;
   ARGB aColor = XA_clr2argb( nTrans, nColor );

   gPath = CreateRoundRect( *rc, nDia );

   GdipCreateFromHDC( hDC, &g );
   GdipSetCompositingQuality( g, CompositingQualityHighQuality );
   GdipSetSmoothingMode( g, SmoothingModeAntiAlias );

   GdipCreateSolidFill( aColor, &gBrush );

   GdipFillPath( g, gBrush, gPath );

   GdipDeletePath( gPath );
   GdipDeleteBrush( gBrush );

   GdipDeleteGraphics( g );
}

//------------------------------------------------------------------------------

XA_FUNC( XA_FILLROUNDEDRECT ) // XA_FillRoundedRect( hDC, rect, nDia, nColor, nTransparency ) --> NIL
{
   HDC hDC = (HDC) hb_parnl( 1 );
   PHB_ITEM pRect = hb_param( 2, HB_IT_ARRAY );
   RECT rc;
   int nDia = hb_parnl( 3 );
   int nColor = hb_parnl( 4 );
   int nTrans = HB_ISNUM( 5 ) ? hb_parnl( 5 ): 255;

   rc.left = hb_arrayGetNL( pRect, 1 );
   rc.top = hb_arrayGetNL( pRect, 2 );
   rc.right = hb_arrayGetNL( pRect, 3 );
   rc.bottom = hb_arrayGetNL( pRect, 4 );

   FillRoundRect( hDC, &rc, nDia, nColor, nTrans );

   hb_ret();
}

//------------------------------------------------------------------------------

XA_EXPORT void XA_PaintCross( HDC hDC, LPRECT rc, int nColor, int nTrans )
{
   GpGraphics *g;
   GpPen *gPen;
   ARGB aColor = XA_clr2argb( nTrans, nColor );

   GdipCreateFromHDC( hDC, &g );
   GdipSetCompositingQuality( g, CompositingQualityHighQuality );
   GdipSetSmoothingMode( g, SmoothingModeAntiAlias );

   GdipCreatePen1( aColor , 2, UnitPixel, &gPen );

   GdipDrawLineI( g, gPen, rc->left, rc->bottom, rc->right,rc->top );
   GdipDrawLineI( g, gPen, rc->left, rc->top, rc->right,rc->bottom );

   GdipDeletePen( gPen );

   GdipDeleteGraphics( g );
}

//------------------------------------------------------------------------------

XA_FUNC( XA_PAINTCROSS ) // XA_PaintCross( hDC, rect, nColor, nOpacity ) --> NIL
{
   HDC hDC = (HDC) hb_parnl( 1 );
   PHB_ITEM pRect = hb_param( 2, HB_IT_ARRAY );
   RECT rc;
   int nColor = hb_parnl( 3 );
   int nTrans = HB_ISNUM( 4 ) ? hb_parnl( 4 ): 255;

   rc.left = hb_arrayGetNL( pRect, 1 );
   rc.top = hb_arrayGetNL( pRect, 2 );
   rc.right = hb_arrayGetNL( pRect, 3 );
   rc.bottom = hb_arrayGetNL( pRect, 4 );

   XA_PaintCross( hDC, &rc, nColor, nTrans );

   hb_ret();
}

//------------------------------------------------------------------------------

XA_FUNC( XA_GETPIXEL ) // XA_GETPIXEL( <hDC>, <nX>, <nY> ) --> nColor
{
   hb_retnl( GetPixel( (HDC) hb_parnl( 1 ), hb_parnl( 2 ), hb_parnl( 3 ) ) );
}
