/*
 * Xailer source code:
 *
 * StatusBar.prg
 * Clase TStatusBar()
 *
 * Copyright 2003 Jose F. Gimenez
 * Copyright 2003, 2007 Xailer.com
 * All rights reserved
 *
 */

#include "Xailer.ch"
#include "CommCtrl.api"


//--------------------------------------------------------------------------

CLASS XStatusBar FROM TWinControl

PUBLISHED:
   PROPERTY aItems      INIT {}  WRITE METHOD SetItems   EDITOR PE_StringList AS TStatusPanel[]

   /* NOTA: La clausula READ es porque la propiedad cText de TControl llama a
            ::GetText() y aqui tambien tenemos un metodo GetText para recuperar
            el texto y el estilo de los paneles [jlalin]
   */
   PROPERTY cText       INIT ""  READ INLINE ::FcText WRITE METHOD SetSimpleText

   PROPERTY nHeight     INIT 22  WRITE INLINE ::SetBounds( ,,, Value )

   PROPERTY nAlign      INIT alBOTTOM VALUES alNONE, alLEFT, alTOP, alRIGHT, alBOTTOM, alCLIENT

   PROPERTY lSimple     INIT .F. WRITE METHOD SetSimple
   PROPERTY oIcon       WRITE METHOD SetIcon EDITOR PE_Icon AS TIcon

   PROPERTY lSizeGrip   INIT sgAUTO VALUES sgAUTO, sgYES, sgNO ;
                        WRITE INLINE ( ::FlSizeGrip := Value, ::ChangeCtlStyle( SBARS_SIZEGRIP, Value ) )
   PROPERTY lFullSize   INIT .T. WRITE INLINE ( ::FlFullSize := Value, ::UpdatePanels() )

   PROPERTY nClrPane    INIT clBtnFace WRITE METHOD SetBkColor EDITOR PE_Color

   PROPERTY nBorderStyle   INIT sbDEFAULT WRITE METHOD SetBorderStyle ;
                           VALUES sbDEFAULT, sbNOBORDER, sbRAISED

   PROPERTY oImageList  AS TImageList  EDITOR PE_ImageList

   EVENT OnClick( oSender, nPosX, nPosY ) // --> Nil
   EVENT OnRClick( oSender, nPosX, nPosY ) // --> Nil

   EVENT OnDrawItem( oSender, hDC, nItem, aRect ) // --> Nil
   EVENT OnSimpleMode( oSender ) // --> Nil

PROTECTED:
   DATA cWinClassName   INIT STATUSCLASSNAME
   DATA nCtlStyle       INIT nOr( WS_CHILD, WS_CLIPCHILDREN, WS_CLIPSIBLINGS, CCS_NOPARENTALIGN )
   DATA lNotUpdate      INIT .F.
   PROPERTY oBkgnd
   PROPERTY nBkgndMode
   PROPERTY nBkgndMarginX
   PROPERTY nBkgndMarginY
   PROPERTY nGradient
   PROPERTY nClrPaneEnd

   DATA nLastWidth      INIT 0

   METHOD SetParts()

PUBLIC:
   PROPERTY nMinHeight  INIT 0   WRITE INLINE ::SetBounds( ,,, Value )     // NOTA: Se mantiene por compatibilidad hacia atras, pero se ha sustituido por ::nHeight [JFG]
   PROPERTY nClrText    INIT clWindowText
   PROPERTY l3D         INIT .T.
   PROPERTY lBorder     INIT .F.
   PROPERTY lTabStop    INIT .F.
   PROPERTY cMessage
   DATA oTimer          AS TTimer

   CONSTRUCTOR New( oParent )
   CONSTRUCTOR Create( oParent )

   METHOD Free()

   METHOD SetBounds( nLeft, nTop, nWidth, nHeight, lRedraw )

   METHOD AddItem( cText, nWidth, cTooltip, nImage, nAlignment, ; // --> oItem
                   nBorderStyle, nMinWidth, lOwnerDraw, nType,;
                   nResizeStyle, lRefresh )

   METHOD DeleteItem( nItem )  INLINE IIf( nItem > 0 .AND. nItem <= Len( ::aItems ), ::aItems[ nItem ]:End(), ) // --> Nil
   METHOD DeleteItems() // --> Nil
   METHOD AddIcon( cIcon )     INLINE ::oImageList:AddIcon( cIcon ) // --> nImage
   METHOD AddBitmap( cBitmap ) INLINE ::oImageList:Add( cBitmap ) // --> nImage

RESERVED:
   METHOD SetItems( aItems )
   METHOD GetItemRect( nItem, lFullRect )
   METHOD GetBorders()

   METHOD SetSimple( lSimple )
   METHOD SetSimpleText( cText )

   METHOD SetText( nPanel, cText ) INLINE ::aItems[ nPanel ]:cText := cText
   METHOD GetText( nPanel )

   METHOD SetIcon( oIcon )

   METHOD UpdatePanels( lOnlyText )
   METHOD SetTooltipZones()
   METHOD SetBkColor( nColor )

   METHOD WMPaint()        EXTERN XControl_EraseAndPaint()
   METHOD WMPrintClient()  EXTERN XControl_EraseAndPaint()
   METHOD WMEraseBkgnd()   INLINE 1
   METHOD Resize()
   METHOD WMNotify()       EXTERN XControl_WMNotify()
   METHOD WMSize( nWParam, nLParam ) INLINE ::Resize(), ::Super:WMSize( nWParam, nLParam ), ::Redraw(), 0

   METHOD Notify()
   METHOD DrawItem()

   METHOD SetBorderStyle( Value )
   METHOD XAClick() VIRTUAL

ENDCLASS

//--------------------------------------------------------------------------

METHOD New( oParent ) CLASS XStatusBar

   ::oImageList := TImageList():Create( Self )

RETURN ::Super:New( oParent )

//--------------------------------------------------------------------------

METHOD Create( oParent ) CLASS XStatusBar

   LOCAL nBS, nHeight := ::nHeight

   InitCommonControls( ICC_BAR_CLASSES )

   IF ::lSizeGrip == Nil
      nBS := ::GetForm():nBorderStyle
      ::ChangeCtlStyle( SBARS_SIZEGRIP, nBS == bsSIZEABLE .OR. nBS == bsSIZETOOLWIN )
   ELSE
      ::ChangeCtlStyle( SBARS_SIZEGRIP, ::lSizeGrip )
   ENDIF

   ::Super:Create( oParent )

   ::nHeight := MulDiv( nHeight, Application:nScale, 100 )
   ::SetBkColor()
   ::SetSimple()

   IF Empty( ::oForm:oMsgBar )
      ::oForm:oMsgBar := Self
   ENDIF

RETURN Self

//--------------------------------------------------------------------------

METHOD Free() CLASS XStatusBar

   IF ::oTimer != Nil
      ::oTimer:lEnabled := .F.
      ::oTimer:End()
      ::oTimer := NIL
   ENDIF

   ::DeleteItems()

   IF ::oImageList != Nil .AND. ::oImageList:oParent == Self
      ::oImageList:End()
   ENDIF

RETURN ::Super:Free()

//--------------------------------------------------------------------------

METHOD SetBounds( nLeft, nTop, nWidth, nHeight, lRedraw ) CLASS XStatusBar

   UPDATE ::FnHeight TO nHeight

   ::SendMsg( SB_SETMINHEIGHT, ::FnHeight - 2, 0 )

RETURN ::Super:SetBounds( nLeft, nTop, nWidth, nHeight, lRedraw )

//--------------------------------------------------------------------------

METHOD AddItem( cText, nWidth, cTooltip, nImage, nAlignment, ;
                nBorderStyle, nMinWidth, lOwnerDraw, nType,  ;
                nResizeStyle )  CLASS XStatusBar

   LOCAL oPanel

   oPanel :=  TStatusPanel():Create( Self, cText, nWidth, cTooltip, nImage, ;
                                     nAlignment, nBorderStyle, nMinWidth, ;
                                     lOwnerDraw, nType, nResizeStyle )

RETURN oPanel

//--------------------------------------------------------------------------

METHOD SetItems( aItems ) CLASS XStatusBar

   LOCAL n

   ::lNotUpdate := .T.

   ::DeleteItems()

   IF aItems != Nil
      FOR n := 1 TO Len( aItems )
         IF ValType( aItems[ n ] ) == "C"
            ::AddItem( aItems[ n ] )
         ELSEIF ValType( aItems[ n ] == "A" )
            IF Len( aItems ) == 1
               ::AddItem( aItems[ n ] )
            ELSEIF Len( aItems ) == 2
               ::AddItem( aItems[ n, 1 ], aItems[ n, 2 ] )
            ELSEIF Len( aItems ) == 3
               ::AddItem( aItems[ n, 1 ], aItems[ n, 2 ], aItems[ n, 3 ] )
            ELSEIF Len( aItems ) == 4
               ::AddItem( aItems[ n, 1 ], aItems[ n, 2 ], aItems[ n, 3 ], aItems[ n, 4 ] )
            ELSEIF Len( aItems ) == 5
               ::AddItem( aItems[ n, 1 ], aItems[ n, 2 ], aItems[ n, 3 ], aItems[ n, 4 ], aItems[ n, 5 ] )
            ELSEIF Len( aItems ) == 6
               ::AddItem( aItems[ n, 1 ], aItems[ n, 2 ], aItems[ n, 3 ], aItems[ n, 4 ], aItems[ n, 5 ], aItems[ n, 6 ] )
            ELSEIF Len( aItems ) == 7
               ::AddItem( aItems[ n, 1 ], aItems[ n, 2 ], aItems[ n, 3 ], aItems[ n, 4 ], aItems[ n, 5 ], aItems[ n, 6 ], aItems[ n, 7 ] )
            ELSEIF Len( aItems ) == 8
               ::AddItem( aItems[ n, 1 ], aItems[ n, 2 ], aItems[ n, 3 ], aItems[ n, 4 ], aItems[ n, 5 ], aItems[ n, 6 ], aItems[ n, 7 ], aItems[ n, 8 ] )
            ELSEIF Len( aItems ) == 9
               ::AddItem( aItems[ n, 1 ], aItems[ n, 2 ], aItems[ n, 3 ], aItems[ n, 4 ], aItems[ n, 5 ], aItems[ n, 6 ], aItems[ n, 7 ], aItems[ n, 8 ], aItems[ n, 9 ] )
            ENDIF
         ENDIF
      NEXT
   ENDIF

   ::lNotUpdate := .F.
   ::UpdatePanels()

RETURN Nil

//--------------------------------------------------------------------------

METHOD DeleteItems() CLASS XStatusBar

   DO WHILE Len( ::aItems ) > 0
      ::aItems[ 1 ]:End()
   ENDDO

RETURN Nil

//--------------------------------------------------------------------------

METHOD UpdatePanels( lOnlyText ) CLASS XStatusBar

   LOCAL oItem

   DEFAULT lOnlyText TO .F.

   IF ! ::lCreated .OR. ::lNotUpdate
      RETURN NIL
   ENDIF

   IF ! lOnlyText
      ::SetParts()
      ::SetTooltipZones()
   ENDIF

   AEval( ::aItems, {|v| v:Update( lOnlyText ) } )

   FOR EACH oItem IN ::aItems
      WITH OBJECT oItem
         IF :oControl != Nil
            :SetControl( :oControl )
         ENDIF
      END WITH
   NEXT

RETURN Nil

//--------------------------------------------------------------------------

METHOD SetTooltipZones() CLASS XStatusBar

   LOCAL aZone
   LOCAL cTooltip
   LOCAL nFor

   IF ! ::lCreated .OR. ::lNotUpdate
      RETURN Nil
   ENDIF

   IF ! Empty( ::Handle )
      IF Len( ::aItems ) > 0
         ::SetTooltip()
         FOR nFor := 1 TO Len( ::aItems )
            aZone    := ::GetItemRect( nFor )
            cTooltip := ::aItems[ nFor ]:cTooltip
            IF ! Empty( aZone ) .AND. ! Empty( cTooltip )
               ::SetTooltip( cTooltip, aZone, nFor )
            ENDIF
         NEXT
         ::FcTooltip := ""
      ELSE
         ::SetTooltip( ::FcTooltip )
      ENDIF
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD SetSimple( lSimple ) CLASS XStatusBar

   UPDATE ::FlSimple TO lSimple

   ::SendMsg( SB_SIMPLE, ::FlSimple, 0 )

RETURN ::FlSimple

//--------------------------------------------------------------------------

METHOD SetSimpleText( cText ) CLASS XStatusBar

   UPDATE ::FcText TO cText

   IF ::lSimple
      ::SendMsg( SB_SETTEXT, nOr( SB_SIMPLEID, ::FnBorderStyle ), ::FcText )
   ELSEIF Len( ::aItems ) > 0
      ::SetText( 1, ::FcText )
   ENDIF

RETURN ::FcText

//--------------------------------------------------------------------------

METHOD SetBorderStyle( nBorderStyle ) CLASS XStatusBar

   UPDATE ::FnBorderStyle  TO nBorderStyle

   ::SendMsg( SB_SETTEXT, nOr( SB_SIMPLEID, ::FnBorderStyle ), ::FcText )

RETURN ::FnBorderStyle

//--------------------------------------------------------------------------

METHOD SetBkColor( nColor ) CLASS XStatusBar

   LOCAL nOld := ::FnClrPane

   UPDATE ::FnClrPane TO nColor

   IF ::Handle != 0
      nOld := ::SendMsg( SB_SETBKCOLOR, 0, ::FnClrPane )
   ENDIF

RETURN nOld

//--------------------------------------------------------------------------

METHOD SetIcon( oIcon ) CLASS XStatusBar

   ::FoIcon := oIcon

   IF ValType( oIcon ) == "O"
      ::SendMsg( SB_SETICON, -1, oIcon:Handle )
   ELSE
      ::SendMsg( SB_SETICON, -1, 0 )
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD Resize() CLASS XStatusBar

   LOCAL nDelta := 0
   LOCAL nItems := 0
   LOCAL nSize  := 0
   LOCAL n

   AEval( ::aItems, {|oPanel| IIf( oPanel:nResizeStyle == sbAUTO, nItems++, nSize += oPanel:nWidth ) } )

   IF nItems > 0
      nDelta := ( ::oParent:nWidth - nSize ) / nItems
      nItems := Len( ::aItems )

      FOR n := 1 TO nItems
         WITH OBJECT ::aItems[ n ]
            IF :nResizeStyle == sbAUTO .AND. nDelta > :nMinWidth
               :nWidth := nDelta
            ENDIF
         END WITH
      NEXT
   ENDIF

   IF ::oTimer != Nil .AND. ! ::oTimer:lEnabled
      ::oTimer:lEnabled := .T.
   ENDIF

   ::UpdatePanels()

RETURN Nil

//--------------------------------------------------------------------------

#pragma BEGINDUMP

#define _WIN32_IE 0x0400

#include <windows.h>
#include <commctrl.h>
#include <xailer.h>

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XSTATUSBAR_SETPARTS )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hwnd = GetHandleOf( Self );
   PHB_ITEM pParts = XA_ObjGetItemCopy( Self, "aItems" );
   PHB_ITEM pItem;
   LPINT lpParts = NULL;
   int nParts;
   int nWidth = 0;
   int i;

   nParts = hb_arrayLen( pParts );

   if( nParts )
   {
      lpParts = (LPINT) hb_xgrab( sizeof( int ) * nParts );

      for( i = 1; i <= nParts; i++ )
      {
         pItem = hb_itemArrayGet( pParts, i );
         nWidth += XA_ObjGetNL( pItem, "nWidth" );
         hb_itemRelease( pItem );
         lpParts[ i - 1 ] = nWidth;
      }

      if( XA_ObjGetL( Self, "lFullSize" ) )
         lpParts[ nParts - 1 ] = -1;
   }

   hb_itemRelease( pParts );

   SendMessage( hwnd, SB_SETPARTS, (WPARAM) nParts, (LPARAM) lpParts );

   if( lpParts )
      hb_xfree( lpParts );

   hb_ret();
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XSTATUSBAR_GETTEXT )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hwnd = GetHandleOf( Self );
   int nPart = hb_parnl( 1 ) - 1;
   int nLen;
   char * cText;

   nLen = SendMessage( hwnd, SB_GETTEXTLENGTH, nPart, 0 );

   if( HIWORD( nLen ) & SBT_OWNERDRAW )  // Si es un bitmap
   {
      hb_retnl( SendMessage( hwnd, SB_GETTEXT, nPart, 0 ) );
   }
   else if( LOWORD( nLen ) )  // Si no esta vacio
   {
      cText = hb_xgrab( LOWORD( nLen ) );
      SendMessage( hwnd, SB_GETTEXT, nPart, (LPARAM) cText );
      hb_retc( cText );
      hb_xfree( cText );
   }
   else   // Si esta vacio, devolver Nil
   {
      hb_ret();
   }
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XSTATUSBAR_NOTIFY )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hwnd = GetHandleOf( Self );
   PHB_ITEM pParts = XA_ObjGetItemCopy( Self, "aItems" );
   LPNMHDR nmhdr = (LPNMHDR) hb_parnl( 2 );
   int iParts = hb_arrayLen( pParts );
   PHB_ITEM pItem;
   POINT pt;
   RECT rc;
   int iPanel = 0;
   int i;

   GetCursorPos( &pt );
   ScreenToClient( hwnd, &pt );

   for( i = 1; i <= iParts; i++ )
   {
      SendMessage( hwnd, SB_GETRECT, i - 1, (LPARAM) &rc );
      pItem = hb_itemArrayGet( pParts, i );

      hb_itemRelease( pItem );

      if( PtInRect( &rc, pt ) )
      {
         iPanel = i;
         break;
      }
   }

   pItem = hb_itemArrayGet( pParts, iPanel );

   switch( nmhdr->code )
   {
      case NM_CLICK:
         if( iPanel && XA_EventAssigned( pItem, "OnClick" ) )
            XA_ObjSendNL2( pItem, "OnClick", pt.x, pt.y );
         else
            XA_ObjSendNL2( Self, "OnClick", pt.x, pt.y );

         break;

      case NM_RCLICK:
         if( iPanel && XA_EventAssigned( pItem, "OnRClick" ) )
            XA_ObjSendNL2( pItem, "OnRClick", pt.x, pt.y );
         else
            XA_ObjSendNL2( Self, "OnRClick", pt.x, pt.y );
         break;

      case SBN_SIMPLEMODECHANGE:
         XA_ObjSend( Self, "OnSimpleMode" );
         break;
   }

   hb_itemRelease( pItem );
   hb_itemRelease( pParts );
   hb_ret();
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XSTATUSBAR_DRAWITEM )
{
   PHB_DYNS pMethod = hb_dynsymFindName( "OnDrawItem" );

   if( pMethod )
   {
      PHB_ITEM Self = hb_stackSelfItem();
      LPDRAWITEMSTRUCT di = ( LPDRAWITEMSTRUCT ) hb_parnl( 1 );
      PHB_ITEM pRect = hb_itemArrayNew( 4 );
      PHB_ITEM pItem = hb_itemNew( NULL );
      HRGN hRgn = NULL;

      // ABW: En XP con temas, el rectangulo que se recibe no esta ajustado - [JFG]
      if( GetWindowTheme( GetHandleOf( Self ) ) )
         {
         di->rcItem.left -= 3;
         hRgn = CreateRectRgnIndirect( &di->rcItem );
         SelectClipRgn( di->hDC, hRgn );
         }

      hb_itemArrayPut( pRect, 1, hb_itemPutNL( pItem, di->rcItem.left ) );
      hb_itemArrayPut( pRect, 2, hb_itemPutNL( pItem, di->rcItem.top ) );
      hb_itemArrayPut( pRect, 3, hb_itemPutNL( pItem, di->rcItem.right ) );
      hb_itemArrayPut( pRect, 4, hb_itemPutNL( pItem, di->rcItem.bottom ) );

      hb_vmPushDynSym( pMethod );
      hb_vmPush( Self );
      hb_vmPushLong( (LONG) di->hDC );
      hb_vmPushLong( di->itemID + 1 );
      hb_vmPush( pRect );
      hb_vmSend( 3 );

      if( hRgn )
         {
         SelectClipRgn( di->hDC, NULL );
         DeleteObject( hRgn );
         }

      hb_itemRelease( pRect );
      hb_itemRelease( pItem );
   }

   hb_ret();
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XSTATUSBAR_GETITEMRECT )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hwnd = GetHandleOf( Self );
   RECT rc;
   PHB_ITEM pParts = XA_ObjGetItem( Self, "aItems" );
   PHB_ITEM pItem = hb_itemArrayGet( pParts, hb_parni( 1 ) );

   SendMessage( hwnd, SB_GETRECT, hb_parni( 1 ) - 1, (LPARAM) &rc );

   if( hb_parl( 2 ) )   // lFullRect
   {
      LPINT aBorders = (LPINT) hb_xgrab( sizeof( int ) * 3 );

      SendMessage( hwnd, SB_GETBORDERS, 0, (LPARAM) aBorders );

      rc.left -= aBorders[ 1 ];     // -2
      rc.top -= aBorders[ 0 ];      // -2
      rc.right += aBorders[ 2 ];
      rc.bottom += aBorders[ 0 ];   // +2

      hb_xfree( aBorders );
   }

   hb_itemRelease( pItem );

   hb_reta( 4 );
   hb_storvnl( rc.left, -1, 1 );
   hb_storvnl( rc.top, -1, 2 );
   hb_storvnl( rc.right, -1, 3 );
   hb_storvnl( rc.bottom, -1, 4 );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XSTATUSBAR_GETBORDERS )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hwnd = GetHandleOf( Self );
   LPINT aBorders = (LPINT) hb_xgrab( sizeof( int ) * 3 );

   SendMessage( hwnd, SB_GETBORDERS, 0, (LPARAM) aBorders );

   hb_reta( 3 );
   hb_storvni( aBorders[ 0 ], -1, 1 );
   hb_storvni( aBorders[ 1 ], -1, 2 );
   hb_storvni( aBorders[ 2 ], -1, 3 );

   hb_xfree( aBorders );
}

//--------------------------------------------------------------------------

XA_FUNC( DRAWSTATUSTEXT )  // DrawStatusText( <hDC>, <aRect>, <cText>, <nFlags> ) --> n/a
{
   if( HB_ISARRAY( 2 ) )
   {
      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 );

      DrawStatusText( (HDC) hb_parnl( 1 ), (LPRECT) &rc,
                      hb_parc( 3 ), hb_parni( 4 ) );
   }
}

//--------------------------------------------------------------------------

XA_FUNC( GETKEYBOARDSTATE )   // GetKeyBoardState( <nKey> ) --> nState
{
   BYTE aKeys[256];
   int iKey = hb_parni( 1 );

   GetKeyboardState( (PBYTE) &aKeys );

   hb_retnl( aKeys[ iKey ] );
}

#pragma ENDDUMP

//--------------------------------------------------------------------------
