/*
 * Xailer source code:
 *
 * TabCtrl.prg
 * Clase TabCtrl()
 *
 * Copyright 2003, 2007 Ignacio Ortiz de Zuņiga
 * Copyright 2003, 2007 Xailer.com
 * All rights reserved
 *
 */

#include "Xailer.ch"
#include "CommCtrl.api"


//--------------------------------------------------------------------------

CLASS XTabCtrl FROM TWinControl

PUBLISHED:
   PROPERTY nWidth      INIT 200
   PROPERTY nHeight     INIT 160

   PROPERTY oImageList  AS TImageList  WRITE METHOD SetImageList  EDITOR PE_ImageList

   PROPERTY aItems      INIT {} WRITE METHOD SetItems EDITOR PE_StringList AS TTabItem[]

   PROPERTY nIndex      INIT 0 READ METHOD GetIndex   WRITE METHOD SetIndex

   PROPERTY nOrientation      INIT orTOP VALUES orTOP, orBOTTOM, orLEFT, orRIGHT

   PROPERTY lButtonStyle      INIT .F.
   PROPERTY lMultiLine        INIT .F.
   PROPERTY lRightJustify     INIT .F.
   PROPERTY lFixedWidth       INIT .F.
   PROPERTY lForceIconLeft    INIT .F.
   PROPERTY lForceLabelLeft   INIT .F.

   PROPERTY lFlatButtons      INIT .F.
   PROPERTY lScrollOpposite   INIT .F.

   PROPERTY lHotTrack         INIT .F.
   PROPERTY lTabCloseButtons  INIT .F.

   PROPERTY nMinTabWidth      INIT 0   WRITE SetMinTabWidth

   PROPERTY lTabStop          INIT .F.
   PROPERTY lTransparent      INIT .F.
   PROPERTY nOpacity          INIT 0
   PROPERTY lTransparentBody  INIT .F.

   EVENT OnChanging( oSender, nIndex, nFromTab ) // --> Nil | lResult
   EVENT OnChange( oSender, nIndex, nFromTab ) // --> Nil
   EVENT OnRClick( oSender, nX, nY, nIndex ) // --> Nil
   EVENT OnCloseTab( oSender, nIndex ) // --> Nil

PROTECTED:
   DATA cWinClassName   INIT WC_TABCONTROL
   DATA nCtlStyle       INIT nOr( WS_CHILD, WS_CLIPCHILDREN, WS_CLIPSIBLINGS, TCS_TOOLTIPS )
   DATA aBitmaps        INIT {}
   DATA hUpDown
   DATA nCaptured       INIT 0

   PROPERTY cTheme      INIT "Tab"
   PROPERTY cText

   PROPERTY l3D
   PROPERTY lBorder
   PROPERTY oBkgnd
   PROPERTY nBkgndMode
   PROPERTY nBkgndMarginX
   PROPERTY nBkgndMarginY
   PROPERTY nGradient
   PROPERTY nClrPaneEnd
   PROPERTY nClrText
   PROPERTY nClrPane

PUBLIC:
   METHOD New( oParent )      CONSTRUCTOR
   METHOD Create( oParent )   CONSTRUCTOR
   METHOD Free()

   METHOD AddItem( cText, xImage, cTooltip, nClrText, lEnabled ) INLINE ::InsertItem( Nil, cText, xImage, cTooltip, nClrText, lEnabled ) // --> oTabItem
   METHOD InsertItem( nItem, cText, xImage, cTooltip, nClrText, lEnabled ) // --> oTabItem
   METHOD DeleteItem( nItem ) // --> Nil
   METHOD DeleteItems() // --> Nil
   METHOD AddImage( cImage ) // --> nImage
   METHOD SetIndex( nIndex, lTriggerOnChange ) // --> nPosition

RESERVED:
   PROPERTY cBalloon
   PROPERTY cTooltip
   PROPERTY cTooltipTitle
   PROPERTY nTooltipIcon

   METHOD SetImageList( oImageList )
   METHOD SetItems( aItems )
   METHOD SetItem( nItem, cText, xImage, cTooltip, nClrText )
   METHOD Notify( nWParam, nLParam )
   METHOD GetIndex()
   METHOD ChangeTab( nIndex, nFromTab ) VIRTUAL
   METHOD Changing( nIndex, nFromTab )
   METHOD Changed( nIndex, nFromTab )  INLINE ::OnChange( nIndex, nFromTab )
   METHOD SetTabStop( lTabStop )
   METHOD ShortCut( cKey )
   METHOD Click( cKey )
   METHOD GetDisplayRect()
   METHOD InsertControl( oControl )
   METHOD AlignControls() INLINE ::Super:AlignControls( ::GetDisplayRect() )
   METHOD UpdateClientRect()
   METHOD WMKeyDown( nKey, nFlags, hWnd )
   METHOD WMEraseBkgnd() INLINE 1
   METHOD WMPaint()
   METHOD WMPrintClient()

   METHOD SetItemSize( nX, nY )  INLINE ::SendMsg( TCM_SETITEMSIZE, 0, MakeLParam( nX, nY ) )
   METHOD SetPadding( nX, nY )   INLINE ::SendMsg( TCM_SETPADDING, 0, MakeLParam( nX, nY ) )

   METHOD GetItemRect()

   // Solo si Multiselect
   METHOD DeselectAll( lExcludeFocus ) INLINE ::SendMsg( TCM_DESELECTALL, lExcludeFocus, 0 )

   // Solo si Hot tracking activado
   METHOD HighlightItem( nIndex, lOn ) INLINE ::SendMsg( TCM_HIGHLIGHTITEM, nIndex, lOn )

   METHOD GetImageList()               INLINE ::SendMsg( TCM_GETIMAGELIST, 0, 0 )

   METHOD SetImageList( hImageList )   INLINE ::SendMsg( TCM_SETIMAGELIST, 0, hImageList )

   METHOD GetItemCount()   INLINE ::SendMsg( TCM_GETITEMCOUNT, 0, 0 )
   METHOD GetRowCount()    INLINE ::SendMsg( TCM_GETROWCOUNT, 0, 0 )

   // Solo si tiene Button style
   METHOD GetCurFocus()          INLINE ::SendMsg( TCM_GETCURFOCUS, 0, 0 )
   METHOD SetCurFocus( nIndex )  INLINE ::SendMsg( TCM_SETCURFOCUS, nIndex, 0 )

   METHOD SetMinTabWidth( nWidth )  INLINE ::FnMinTabWidth := nWidth, ::SendMsg( TCM_SETMINTABWIDTH, 0, nWidth )

   METHOD HitTest( x, y )

   METHOD WMLButtonDown( nWParam, nLParam )
   METHOD WMLButtonUp( nWParam, nLParam )
   METHOD WMMouseMove( nWParam, nLParam )
   METHOD WMHScroll( nWParam, nLParam )

   METHOD SetShortCuts()

ENDCLASS

//--------------------------------------------------------------------------

METHOD New( oParent ) CLASS XTabCtrl

   ::oImageList := TImageList():Create( Self )

RETURN ::Super:New( oParent )

//--------------------------------------------------------------------------

METHOD Create( oParent ) CLASS XTabCtrl

   LOCAL nFor, nImage

   ::ChangeCtlStyle( TCS_BUTTONS, ::lButtonStyle )
   ::ChangeCtlStyle( TCS_MULTILINE, ::lMultiLine )
   ::ChangeCtlStyle( TCS_RIGHTJUSTIFY, ::lRightJustify )
   ::ChangeCtlStyle( TCS_FIXEDWIDTH, ::lFixedWidth .AND. ! ::lRightJustify )
   ::ChangeCtlStyle( TCS_FORCELABELLEFT, ::lForceLabelLeft )
   ::ChangeCtlStyle( TCS_FORCEICONLEFT, ::lForceIconLeft .AND. ! ::lForceLabelLeft )
   ::ChangeCtlStyle( TCS_HOTTRACK, ::lHotTrack )
   ::nCtlStyle := nExclude( ::nCtlStyle, TCS_VERTICAL, TCS_BOTTOM )
   IF ::nOrientation == orBOTTOM
      ::nCtlStyle := nOr( ::nCtlStyle, TCS_BOTTOM )
   ELSEIF ::nOrientation > orBOTTOM
      ::nCtlStyle := nOr( ::nCtlStyle, TCS_VERTICAL )
      IF ::nOrientation == orRIGHT
         ::nCtlStyle := nOr( ::nCtlStyle, TCS_RIGHT )
      ENDIF
   ENDIF

   ::hUpDown := Nil

   InitCommonControls( ICC_TAB_CLASSES )

   IF lAnd( ::nCtlStyle, TCS_VERTICAL )
      ::cTheme := ""
   ENDIF

   ::Super:Create( oParent )

   IF lAnd( ::nCtlStyle, TCS_VERTICAL )
      // NOTA: No se soporta orientacion TCS_VERTICAL con temas de XP - [JFG]
      ::Unlink()
      SetWindowTheme( ::Handle,, "" )
      ::Link()
   ELSEIF GetWindowTheme( ::Handle ) == 0
      ::SendMsg( TCM_SETPADDING, 0, MakeLParam( IIF( ::lTabCloseButtons, 14, 6 ), 4 ) )
   ELSEIF ::lTabCloseButtons
      ::SendMsg( TCM_SETPADDING, 0, MakeLParam( 14, 3 ) )
   ENDIF
   ::SendMsg( TCM_SETMINTABWIDTH, 0, ::nMinTabWidth )

   IF ::oImageList == Nil
      ::oImageList := TImageList():Create( Self )
   ENDIF
   ::SendMsg( TCM_SETIMAGELIST, 0, ::oImageList:Handle )

   FOR nFor := 1 TO Len( ::aItems )
		IF !::aItems[ nFor ]:lCreated
			TabCtrl_InsertItem( ::Handle, nFor, ::aItems[ nFor ]:cText, ::aItems[ nFor ]:nImage )
		ENDIF
   NEXT
   IF ::FnIndex <= 0 .AND. !Empty( ::aItems )
      ::FnIndex := 1
   ENDIF
   IF ::FnIndex > 0
      ::SendMsg( TCM_SETCURSEL, ::FnIndex - 1 )
   ENDIF

   ::SetShortCuts()
   ::UpdateClientRect()

RETURN Self

//--------------------------------------------------------------------------

METHOD Free() CLASS XTabCtrl

   ::oImageList := Nil

RETURN ::Super:Free()

//-----------------------------------------------------------------------------

METHOD SetImageList( oImageList ) CLASS XTabCtrl

   IF ::FoImageList != Nil .AND. ::FoImageList:oParent == Self
      ::FoImageList:Destroy()
   ENDIF
   ::FoImageList := oImageList

RETURN ::FoImageList

//-----------------------------------------------------------------------------

METHOD InsertItem( nItem, cText, xImage, cTooltip, nClrText, lEnabled ) CLASS XTabCtrl
RETURN TTabItem():Create( Self, nItem, cText, xImage, cTooltip, nClrText, lEnabled )

//--------------------------------------------------------------------------

METHOD SetItem( nItem, cText, xImage, cTooltip, nClrText ) CLASS XTabCtrl

   IF nItem < 1 .OR. nItem > Len( ::aItems )
      RETURN .F.
   ENDIF

RETURN ::aItems[ nItem ]:SetItem( cText, xImage, cTooltip, nClrText )

//--------------------------------------------------------------------------

METHOD DeleteItem( nItem ) CLASS XTabCtrl

   LOCAL nNewItem

   DEFAULT nItem TO ::nIndex

   IF nItem > 0 .AND. nItem <= Len( ::aItems )
      ::aItems[ nItem ]:End()
      ADel( ::aItems, nItem )
      ASize( ::aItems, Len( ::aItems ) - 1 )
      IF ! Empty( ::Handle )
         TabCtrl_DeleteItem( ::Handle, nItem - 1 )
         ::UpdateClientRect()
         ::SetShortCuts()
      ENDIF
      nNewItem := nItem
      WHILE nItem <= Len( ::aItems )
         ::aItems[ nItem ]:nItem := nItem++
      ENDDO
      IF nNewItem > Len( ::aItems )
         nNewItem--
      ENDIF
      ::SetIndex( nNewItem, .T. )
      RETURN .T.
   ENDIF

RETURN .F.

//--------------------------------------------------------------------------

METHOD DeleteItems() CLASS XTabCtrl

   AEval( ::aItems, {| oItem | oItem:End() } )
   ::FaItems := {}
   ::SendMsg( TCM_DELETEALLITEMS, 0, 0 )

RETURN Nil

//--------------------------------------------------------------------------

METHOD SetItems( aItems ) CLASS XTabCtrl

   LOCAL n

   ::DeleteItems()

   IF aItems != Nil
      ::SendMsg( WM_SETREDRAW, .F. )
      FOR n := 1 TO Len( aItems )
         IF ValType( aItems[ n ] ) == "C"
            ::InsertItem( Nil, aItems[ n ] )
         ELSEIF ValType( aItems[ n ] ) == "A"
            IF Len( aItems ) == 1
               ::InsertItem( Nil, aItems[ n ] )
            ELSEIF Len( aItems ) == 2
               ::InsertItem( Nil, aItems[ n, 1 ], aItems[ n, 2 ] )
            ELSEIF Len( aItems ) == 3
               ::InsertItem( Nil, aItems[ n, 1 ], aItems[ n, 2 ], aItems[ n, 3 ] )
            ELSEIF Len( aItems ) == 4
               ::InsertItem( Nil, aItems[ n, 1 ], aItems[ n, 2 ], aItems[ n, 3 ], aItems[ n, 4 ] )
            ELSE
               ::InsertItem( Nil, aItems[ n, 1 ], aItems[ n, 2 ], aItems[ n, 3 ], aItems[ n, 4 ], aItems[ n, 5 ] )
            ENDIF
         ENDIF
      NEXT
      IF ::FlRedraw
         ::SendMsg( WM_SETREDRAW, .T. )
      ENDIF
   ENDIF
   ::SetShortCuts()

RETURN Nil

//--------------------------------------------------------------------------

METHOD AddImage( cImage ) CLASS XTabCtrl

   LOCAL nImage

   cImage := Upper( cImage )
   IF ( nImage := AScan( ::aBitmaps, {| cBitmap | cBitmap == cImage } ) ) == 0
      IF ::oImageList == Nil
         ::oImageList := TImageList():Create( Self )
      ENDIF
      ::SendMsg( TCM_SETIMAGELIST, 0, ::oImageList:Handle )
      IF ( nImage := ::oImageList:Add( cImage ) + 1 ) > 0
         AAdd( ::aBitmaps, cImage )
      ENDIF
   ENDIF

RETURN nImage

//--------------------------------------------------------------------------

METHOD GetIndex() CLASS XTabCtrl

   IF ! Empty( ::Handle )
      ::FnIndex := ::SendMsg( TCM_GETCURSEL ) + 1
   ENDIF

RETURN ::FnIndex

//--------------------------------------------------------------------------

METHOD SetIndex( nIndex, lTriggerOnChange ) CLASS XTabCtrl

   LOCAL nFromTab := ::nIndex

   DEFAULT lTriggerOnChange TO .F.

   IF Empty( ::Handle )
      ::FnIndex := nIndex
   ELSE
      ::FnIndex := ::SendMsg( TCM_SETCURSEL, nIndex - 1 )
      ::ChangeTab( nIndex, nFromTab )
      IF lTriggerOnChange
	      ::Changed( nIndex, nFromTab )
      ENDIF
   ENDIF

RETURN nIndex

//--------------------------------------------------------------------------

METHOD Changing( nIndex, nFromTab ) CLASS XTabCtrl

   LOCAL lOk, lValid

   IF ( lOk := ::OnChanging( nIndex, nFromTab ) ) == Nil .OR. lOk
      IF ::oForm:oActiveControl != Nil
         IF ( lValid := ::oForm:oActiveControl:Valid() ) == Nil .OR. lValid
            ::oForm:oActiveControl:lFocused := .F.
         ELSE
            RETURN .F.
         ENDIF
      ENDIF
   ENDIF

RETURN lOk

//--------------------------------------------------------------------------

METHOD SetTabStop( lTabStop ) CLASS XTabCtrl

   UPDATE ::FlTabStop TO lTabStop

   IF ::lTabStop
      ::nCtlStyle := nExclude( ::nCtlStyle, TCS_FOCUSNEVER )
      ::nCtlStyle := nOr( ::nCtlStyle, TCS_FOCUSONBUTTONDOWN )
   ELSE
      ::nCtlStyle := nExclude( ::nCtlStyle, TCS_FOCUSONBUTTONDOWN )
      ::nCtlStyle := nOr( ::nCtlStyle, TCS_FOCUSNEVER )
   ENDIF

RETURN ::FlTabStop

//--------------------------------------------------------------------------

METHOD SetShortCuts() CLASS XTabCtrl

   LOCAL aKeys := {}, nAt

   IF ::oForm != Nil
      ::oForm:DelShortCut( Self )
      AEval( ::aItems, {| oItem | IIf( ( nAt := At( "&", oItem:cText ) ) > 0, AAdd( aKeys, Substr( oItem:cText, nAt + 1, 1 ) ), ) } )
      IF ! Empty( aKeys )
         ::oForm:AddShortCut( Self, aKeys )
      ENDIF
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD ShortCut( cKey ) CLASS XTabCtrl

   ::Click( cKey )

RETURN 0

//--------------------------------------------------------------------------

METHOD Click( cKey ) CLASS XTabCtrl

   LOCAL n, nAt, lChange

   IF ! Empty( cKey )
      cKey := Upper( cKey )
      FOR n := 1 TO Len( ::aItems )
         IF ( nAt := At( "&", ::aItems[ n ]:cText ) ) > 0 .AND. Upper( Substr( ::aItems[ n ]:cText, nAt + 1, 1 ) ) == cKey
            IF n != ::nIndex .AND. ::aItems[ n ]:lEnabled
               IF ( lChange := ::Changing( n, ::nIndex ) ) == Nil .OR. lChange
                  ::SetIndex( n, .T. )
                  //::SetFocus()
               ENDIF
            ENDIF
            EXIT
         ENDIF
      NEXT
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD InsertControl( oControl ) CLASS XTabCtrl

   oControl:nTop += ::nClientTop
   oControl:nLeft += ::nClientLeft

RETURN ::Super:InsertControl( oControl )

//--------------------------------------------------------------------------

METHOD WMKeyDown( nKey, nFlags, hWnd ) CLASS XTabCtrl

   LOCAL uResult := ::Super:WMKeyDown( nKey, nFlags, hWnd ), nIndex
   LOCAL lChange := .F.

   IF uResult == Nil
      IF GetFocus() == ::Handle
         IF nKey == VK_UP .OR. nKey == VK_DOWN
            RETURN 0    // NOTA: No permitir cambiar de pestaņa con K_UP o K_DOWN - [JFG]
         ELSEIF nKey == VK_RIGHT
            nKey := VK_NEXT
            lChange := .T.
         ELSEIF nKey == VK_LEFT
            nKey := VK_PRIOR
            lChange := .T.
         ENDIF
      ENDIF

      IF lChange .OR. lGetKeyState( VK_CONTROL )

         IF nKey == VK_NEXT .OR. ( nKey == VK_TAB .AND. !lGetKeyState( VK_SHIFT ) )
            nIndex := IIf( ::nIndex == Len( ::aItems ), 1, ::nIndex + 1 )
            DO WHILE nIndex <= Len( ::aItems ) .AND. !::aItems[ nIndex ]:lEnabled .AND. nIndex != ::nIndex
               nIndex := IIf( nIndex == Len( ::aItems ), 1, nIndex + 1 )
            ENDDO
            IF nIndex != ::nIndex
               IF ( lChange := ::Changing( nIndex, ::nIndex ) ) == Nil .OR. lChange
                  ::SetIndex( nIndex, .T. )
               ENDIF
            ENDIF
            RETURN 0

         ELSEIF nKey == VK_PRIOR .OR. ( nKey == VK_TAB .AND. lGetKeyState( VK_SHIFT ) )
            nIndex := IIf( ::nIndex == 1, Len( ::aItems ), ::nIndex - 1 )
            DO WHILE nIndex <= Len( ::aItems ) .AND. !::aItems[ nIndex ]:lEnabled .AND. nIndex != ::nIndex
               nIndex := IIf( nIndex == 1, Len( ::aItems ), nIndex - 1 )
            ENDDO
            IF nIndex != ::nIndex
               IF ( lChange := ::Changing( nIndex, ::nIndex ) ) == Nil .OR. lChange
                  ::SetIndex( nIndex, .T. )
               ENDIF
            ENDIF
            RETURN 0
         ENDIF

      ENDIF

   ENDIF

RETURN uResult

//--------------------------------------------------------------------------

#pragma BEGINDUMP

#undef _WIN32_WINNT
#define _WIN32_WINNT   0x0400
#define _WIN32_IE 0x0400

#include <windows.h>
#include <commctrl.h>
#include <xailer.h>

//--------------------------------------------------------------------------

XA_FUNC( TABCTRL_INSERTITEM )
{
   HWND hwnd = (HWND) hb_parnl( 1 );
   TCITEM tie;

   memset( &tie, 0, sizeof( TCITEM ) );

   tie.pszText = (LPSTR) hb_parc( 3 );
   tie.iImage = hb_parnl( 4 ) - 1;
   tie.mask = TCIF_TEXT;

	if( tie.iImage != -1 )
      tie.mask = tie.mask | TCIF_IMAGE;

   hb_retnl( TabCtrl_InsertItem( hwnd, hb_parnl( 2 ) - 1, &tie ) );
}

//--------------------------------------------------------------------------

XA_FUNC( TABCTRL_SETITEM )
{
   HWND hwnd = (HWND) hb_parnl( 1 );
   TCITEM tie;

   memset( &tie, 0, sizeof( TCITEM ) );

   tie.iImage = hb_parnl( 4 ) - 1;
   tie.mask |= TCIF_IMAGE;

   if ( hb_parclen( 3 ) )
   {
      tie.pszText = (LPSTR) hb_parc( 3 );
      tie.mask |= TCIF_TEXT;
   }

   hb_retl( TabCtrl_SetItem( hwnd, hb_parnl( 2 ) - 1, &tie ) );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTABCTRL_NOTIFY )
{
   LPNMHDR nmhdr = (LPNMHDR) hb_parnl( 2 );
   PHB_ITEM Self = hb_stackSelfItem();

   hb_ret();
   switch ( nmhdr->code )
      {
      case NM_RCLICK:
         {
         TCHITTESTINFO tchti;
         LONG lIndex;
         GetCursorPos( &(tchti.pt) );
         ScreenToClient( nmhdr->hwndFrom, &(tchti.pt) );
         lIndex = SendMessage( nmhdr->hwndFrom, TCM_HITTEST, 0, (LPARAM) &tchti );
         XA_ObjSendNL3( Self, "OnRClick", tchti.pt.x, tchti.pt.y, lIndex + 1 );
         break;
         }

      case TTN_GETDISPINFO:
         {
         PHB_ITEM oItem = hb_itemArrayGet( XA_ObjGetItem( Self, "aItems" ), nmhdr->idFrom + 1 );

         if( !HB_IS_NIL( oItem ) )
            {
            SendMessage( nmhdr->hwndFrom, TTM_SETMAXTIPWIDTH, 0, 32768 );
            ((LPNMTTDISPINFO)nmhdr)->lpszText = XA_ObjGetC( oItem, "cTooltip" );
            }
         hb_itemRelease( oItem );
         break;
         }
      }
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTABCTRL_WMLBUTTONDOWN )
{
   PHB_ITEM Self = hb_stackSelfItem(), oItem;
   HWND hWnd = GetHandleOf( Self );
   TCHITTESTINFO hti;
   long lParam = hb_parnl( 2 ), nIndex;
   BOOL lEnabled = FALSE;

   hti.pt.x = LOWORD( lParam );
   hti.pt.y = HIWORD( lParam );
   nIndex = SendMessage( hWnd, TCM_HITTEST, 0, (LPARAM) &hti ) + 1;
   if( nIndex > 0 )
      {
      oItem = hb_itemArrayGet( XA_ObjGetItem( Self, "aItems" ), nIndex );
      if( oItem && !HB_IS_NIL( oItem ) )
         lEnabled = XA_ObjGetL( oItem, "lEnabled" );
      hb_itemRelease( oItem );
      }

   if( lEnabled )
      {
      int nFromTab = TabCtrl_GetCurSel( hWnd ) + 1;

      if( XA_ObjGetL( Self, "lTabStop" ) )
         SetFocus( hWnd );

      if( nFromTab != nIndex )
         {
         XA_ObjSendNL2( Self, "Changing", nIndex, nFromTab );
         if( HB_ISNIL( -1 ) || hb_parl( -1 ) )
            {
            TabCtrl_SetCurSel( hWnd, nIndex - 1 );
            XA_ObjSendNL( Self, "_FnIndex", nIndex );
            XA_ObjSendNL2( Self, "ChangeTab", nIndex, nFromTab );
            XA_ObjSendNL2( Self, "Changed", nIndex, nFromTab );
            }
         }

      if( XA_ObjGetL( Self, "lTabCloseButtons" ) )
         {
         RECT Rect;
         int y;

         SendMessage( hWnd, TCM_GETITEMRECT, nIndex - 1, (LPARAM) &Rect );
         y = Rect.top + min( ( Rect.bottom - Rect.top ) >> 1, 8 ) - 2;
         if( ( hti.pt.y >= y ) && ( hti.pt.y <= y + 8 ) && ( hti.pt.x >= Rect.right - 15 ) && ( hti.pt.x <= Rect.right - 5 ) )
            {
            SetCapture( hWnd );
            XA_ObjSendNL( Self, "_nCaptured", nIndex );
            InvalidateRect( hWnd, &Rect, FALSE );
            }
         }
      }

   hb_retnl( 0 );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTABCTRL_WMLBUTTONUP )
{
   PHB_ITEM Self = hb_stackSelfItem(), oItem;
   HWND hWnd = GetHandleOf( Self );
   TCHITTESTINFO hti;
   long lParam = hb_parnl( 2 ), nIndex;
   BOOL lEnabled = FALSE;

   if( XA_ObjGetL( Self, "lTabCloseButtons" ) && XA_ObjGetNL( Self, "nCaptured" ) )
      {
      ReleaseCapture();
      XA_ObjSendNL( Self, "_nCaptured", 0 );
      hti.pt.x = LOWORD( lParam );
      hti.pt.y = HIWORD( lParam );
      nIndex = SendMessage( hWnd, TCM_HITTEST, 0, (LPARAM) &hti ) + 1;
      if( nIndex > 0 )
         {
         oItem = hb_itemArrayGet( XA_ObjGetItem( Self, "aItems" ), nIndex );
         lEnabled = XA_ObjGetL( oItem, "lEnabled" );
         hb_itemRelease( oItem );
         }

      if( lEnabled )
         {
         RECT Rect;
         int y;

         SendMessage( hWnd, TCM_GETITEMRECT, nIndex - 1, (LPARAM) &Rect );
         y = Rect.top + min( ( Rect.bottom - Rect.top ) >> 1, 8 ) - 2;
         if( ( hti.pt.y >= y ) && ( hti.pt.y <= y + 8 ) && ( hti.pt.x >= Rect.right - 15 ) && ( hti.pt.x <= Rect.right - 5 ) )
            XA_ObjSendNL( Self, "OnCloseTab", nIndex );
         }
      }

   hb_retnl( 0 );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTABCTRL_WMMOUSEMOVE )
{
   PHB_ITEM Self = hb_stackSelfItem();

   XA_ObjSendNL2( XA_ObjGetItem( Self, "TWinControl" ), "WMMouseMove", hb_parnl( 1 ), hb_parnl( 2 ) );

   if( XA_ObjGetL( Self, "lTabCloseButtons" ) )
      {
      HWND hWnd = GetHandleOf( Self );
      long lParam = hb_parnl( 2 ), nTab;
      TCHITTESTINFO hti;
      RECT Rect;

      hti.pt.x = LOWORD( lParam );
      hti.pt.y = HIWORD( lParam );
      nTab = SendMessage( hWnd, TCM_HITTEST, 0, (LPARAM) &hti );
      if( nTab >= 0 )
         {
         SendMessage( hWnd, TCM_GETITEMRECT, nTab, (LPARAM) &Rect );
         InvalidateRect( hWnd, &Rect, FALSE );
         }
      }

   hb_ret();
}
//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTABCTRL_GETDISPLAYRECT )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   RECT rct;

   GetClientRect( hWnd, &rct );
   TabCtrl_AdjustRect( hWnd, FALSE, &rct );
   hb_reta( 4 );
   hb_storvnl( rct.left      , -1, 1 );
   hb_storvnl( rct.top       , -1, 2 );
   hb_storvnl( rct.right + 1 , -1, 3 );
   hb_storvnl( rct.bottom + 1, -1, 4 );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTABCTRL_GETITEMRECT )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   RECT rct;

   SendMessage( hWnd, TCM_GETITEMRECT, hb_parnl( 1 ) - 1, (LPARAM) &rct );

   hb_reta( 4 );
   hb_storvnl( rct.left  , -1, 1 );
   hb_storvnl( rct.top   , -1, 2 );
   hb_storvnl( rct.right , -1, 3 );
   hb_storvnl( rct.bottom, -1, 4 );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XTABCTRL_HITTEST )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hwnd = GetHandleOf( Self );
   TCHITTESTINFO tchti;
   LONG lIndex;

   tchti.pt.x = hb_parnl( 1 );
   tchti.pt.y = hb_parnl( 2 );

   lIndex = SendMessage( hwnd, TCM_HITTEST, 0, (LPARAM) &tchti );

   hb_reta( 2 );
   hb_storvnl( lIndex + 1 , -1, 1 );
   hb_storvnl( tchti.flags, -1, 2 );
}

#pragma ENDDUMP

//--------------------------------------------------------------------------
