/*
 * Webcam.prg
 * Clase TWebcam
 *
 * Copyright 2024 Ignacio Ortiz de Zúñiga
 * Copyright 2024 https://Xailer.com
 * All rights reserved
 *
 */
#include "Xailer.ch"

CLASS XWebcam FROM TControl
PUBLISHED:
   PROPERTY nWidth         INIT 100
   PROPERTY nHeight        INIT 100
   PROPERTY cCapture       INIT "Capture"
   PROPERTY nDriverIndex   INIT 0      WRITE SetDrvIdx
   PROPERTY nPreviewRate   INIT 15
   PROPERTY lStretch       INIT .T.    WRITE SetStretch

   METHOD New( oParent, nIndex )       CONSTRUCTOR
   METHOD Create( oParent, nIndex )    CONSTRUCTOR

   METHOD Connect( lMode ) INLINE ::SetConnect( lMode )
   METHOD Preview( lMode ) INLINE ::SetPreview( lMode )

   METHOD DlgVideoSource()
   METHOD DlgVideoFormat()
   METHOD DlgVideoDisplay()
   METHOD DlgVideoCompression()

   METHOD Photo( cFile )         // --> NIL. Use Sleep(??) and then check for the existence of the file
   METHOD StartCapture( cFile )
   METHOD EndCapture()

PUBLIC:
   PROPERTY lConnected  INIT .F.    WRITE SetConnect
   PROPERTY lPreview    INIT .F.    WRITE SetPreview

   DATA lOnCapture      INIT .F. READONLY
   DATA cCaptureFile    INIT ""  READONLY

PROTECTED:
   PROPERTY nAlign
   PROPERTY nAlignMarginBottom
   PROPERTY nAlignMarginLeft
   PROPERTY nAlignMarginTop
   PROPERTY nAlignMarginRight
   PROPERTY nAlignWeight
   PROPERTY nAlignWeightSibling
   PROPERTY lAlignKeepSpace
   PROPERTY lAlignShiftOnRotate
   PROPERTY nAnchors
   PROPERTY HelpId
   PROPERTY cBalloon
   PROPERTY cText
   PROPERTY cTooltip
   PROPERTY cTooltipTitle
   PROPERTY lEnabled
   PROPERTY lParentFont
   PROPERTY nClrText
   PROPERTY nTooltipIcon
   PROPERTY oBrush
   PROPERTY oFont

   EVENT OnContextMenu
   EVENT OnDispTooltip

RESERVED:
   PROPERTY lBorder      INIT .F.
   PROPERTY nBorderStyle INIT bvNONE

   METHOD CreateHandle()
   METHOD CreateHandleC()
   METHOD Free()         INLINE ::Disconnect(), ::Super:Free()

   METHOD SetDrvIdx( Value )
   METHOD SetStretch( Value )
   METHOD SetPreview( Value )
   METHOD SetConnect( Value )

ENDCLASS

//------------------------------------------------------------------------------

METHOD New( oParent, nIndex ) CLASS XWebcam

   UPDATE ::FnDriverIndex TO nIndex

RETURN ::Super:New( oParent )

//------------------------------------------------------------------------------

METHOD Create( oParent, nIndex ) CLASS XWebcam

   UPDATE ::FnDriverIndex TO nIndex

RETURN ::Super:Create( oParent )

//------------------------------------------------------------------------------

METHOD CreateHandle() CLASS XWebcam

   ::nAlign := IIF( ::lStretch, alCLIENT, alNONE )

   ::GetForm()
   ::Register()

   ::hTheme := Nil
   ::nId := ::oForm:GetNewID()
   ::OnBeforeCreate()
   ::Link()
   ::Scale( Application:nScale )

   IF ::CreateHandleC()
      ::SetBorderStyle()
      ::UpdateBounds()
      ::SetAnchors()
      IF ::FoParent != Nil .AND. lAnd( ::nCtlStyle, WS_CHILD )
         ::FoParent:InsertControl( Self )
      ENDIF
   ENDIF

RETURN ::Handle

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------

#pragma BEGINDUMP

#include <windows.h>
#include <vfw.h>
#include "Xailer.h"

#define DRIVES_SIZE  250

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_CREATEHANDLEC )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HANDLE hParent = GetHandleOf( XA_ObjGetItem( Self, "oParent" ) );
   LPSTR cName = XA_ObjGetC( Self, "cCapture" );
   BOOL lStretch = XA_ObjGetL( Self, "lStretch" );
   int nIndex = XA_ObjGetNL( Self, "nDriverIndex" );
   HWND hWndC;

   if ( lStretch )
      {
      RECT rect;
      GetClientRect( hParent, &rect );
      hWndC = capCreateCaptureWindowA( cName, WS_CHILD | WS_VISIBLE,
                                       0, 0, rect.right, rect.bottom,
                                       hParent, nIndex );
      if ( hWndC )
         capPreviewScale( hWndC, TRUE );
      }
   else
      {
      int nTop    = XA_ObjGetNL( Self, "nTop" );
      int nLeft   = XA_ObjGetNL( Self, "nLeft" );
      int nWidth  = XA_ObjGetNL( Self, "nWidth" );
      int nHeight = XA_ObjGetNL( Self, "nHeight" );
      hWndC = capCreateCaptureWindowA( cName, WS_CHILD | WS_VISIBLE,
                                       nLeft, nTop, nWidth, nHeight,
                                       hParent, nIndex );
      }

   XA_ObjSendNL( Self, "_Handle", (LONG) hWndC );

   hb_retl( (LONG) hWndC );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_SETCONNECT )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   BOOL lState = XA_ObjGetL( Self, "lConnected" );
   BOOL lSuccess = FALSE;
   int nIndex = XA_ObjGetNL( Self, "nDriverIndex" );

   if ( !HB_ISLOG( 1 ) || ( hb_parl( 1 ) == lState ) )
      {
      hb_retl( lState );
      return;
      }

   if ( hWnd )
      {
      BOOL lConnect = hb_parl( 1 );
      if ( lConnect )
         lSuccess = capDriverConnect( hWnd, nIndex );
      else
         lSuccess = capDriverDisconnect( hWnd );

      if ( lSuccess )
         XA_ObjSendL( Self, "_FlConnected", lConnect );
      }

   hb_retl( lSuccess );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_SETDRVIDX )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   HANDLE hParent = GetHandleOf( XA_ObjGetItem( Self, "oParent" ) );
   int nState = XA_ObjGetNL( Self, "nDriverIndex" );
   BOOL lConnected = FALSE;

   if ( !HB_ISNUM( 1 ) || ( hb_parnl( 1 ) == nState ) )
      {
      hb_retnl( nState );
      return;
      }

   if ( hWnd && hParent )
      {
      lConnected = XA_ObjGetL( Self, "lConnected" );
      if ( lConnected )
         capDriverDisconnect( hWnd );
      }

   if ( hParent )
      {
      RECT rect;
      GetClientRect( hParent, &rect );
      hWnd = capCreateCaptureWindowA( XA_ObjGetC( Self, "cCapture" ),
                                      WS_CHILD | WS_VISIBLE,
                                      0, 0, rect.right, rect.bottom,
                                      hParent, hb_parnl( 1 ) );

      XA_ObjSendNL( Self, "_Handle", (LONG) hWnd );
      XA_ObjSendNL( Self, "_FnDriverIndex", hb_parnl( 1 ) );
      XA_ObjSendL( Self, "_FlPreview", FALSE );
      XA_ObjSendL( Self, "_FlStretch", FALSE );
      XA_ObjSendL( Self, "_lOnCapture", FALSE );

      if ( hWnd && lConnected )
         capDriverConnect( hWnd, hb_parnl( 1 ) );
      }

   hb_retnl( XA_ObjGetNL( Self, "nDriverIndex" ) );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_SETPREVIEW )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HANDLE hParent = GetHandleOf( XA_ObjGetItem( Self, "oParent" ) );
   HWND hWnd = GetHandleOf( Self );
   BOOL lState = XA_ObjGetL( Self, "lPreview" );
   BOOL lPreview = lState;
   BOOL lSuccess;

   if ( !HB_ISLOG( 1 ) || ( hb_parl( 1 ) == lState ) )
      {
      hb_retl( lState );
      return;
      }

   if ( hWnd )
      {
      BOOL lStretch = XA_ObjGetL( Self, "lStretch" );
      int nRate = XA_ObjGetNL( Self, "nPreviewRate" );
      capPreviewScale( hWnd, lStretch );
      capPreviewRate( hWnd, nRate );
      lSuccess = capPreview( hWnd, hb_parl( 1 ) );

      if ( lSuccess )
         {
         lPreview = hb_parl( 1 );
         XA_ObjSendL( Self, "_FlPreview", lPreview );
         if ( lPreview )
            {
            if ( !lStretch )
               {
               CAPSTATUS CapStatus;
               capGetStatus( hWnd, &CapStatus, sizeof( CAPSTATUS ) );
               SetWindowPos( hWnd, NULL, 0, 0, CapStatus.uiImageWidth,
                             CapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE );
               }
            else
               {
               RECT rect;
               GetClientRect( hParent, &rect );
               SetWindowPos( hWnd, NULL, 0, 0, rect.right,
                             rect.bottom, SWP_NOZORDER | SWP_NOMOVE );
               }
            }
         }
      }

   hb_retl( lPreview );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_SETSTRETCH )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HANDLE hParent = GetHandleOf( XA_ObjGetItem( Self, "oParent" ) );
   HWND hWnd = GetHandleOf( Self );
   BOOL lState = XA_ObjGetL( Self, "lStretch" );
   BOOL lStretch;

   if ( !HB_ISLOG( 1 ) || ( hb_parl( 1 ) == lState ) )
      {
      hb_retl( lState );
      return;
      }

   lStretch = hb_parl( 1 );

   XA_ObjSendL( Self, "_FlStretch", lStretch );

   if ( hWnd )
      {
      hb_retl( capPreviewScale( hWnd, lStretch ) );

      if ( !lStretch )
         {
         CAPSTATUS CapStatus;

         capGetStatus( hWnd, &CapStatus, sizeof( CAPSTATUS ) );
         SetWindowPos( hWnd, NULL, 0, 0, CapStatus.uiImageWidth,
                       CapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE );
         }
      else
         {
         RECT rect;
         GetClientRect( hParent, &rect );
         SetWindowPos( hWnd, NULL, 0, 0, rect.right,
                       rect.bottom, SWP_NOZORDER | SWP_NOMOVE );
         }
      }
   else
      hb_retl( FALSE );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_DLGVIDEOSOURCE )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   CAPDRIVERCAPS CapDrvCaps;
   BOOL lSuccess = FALSE;

   if ( hWnd )
      {
      capDriverGetCaps( hWnd, &CapDrvCaps, sizeof( CAPDRIVERCAPS ) );

      if ( CapDrvCaps.fHasDlgVideoSource )
         {
         capDlgVideoSource( hWnd );
         lSuccess = TRUE;
         }
      }
   hb_retl( lSuccess );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_DLGVIDEOFORMAT )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   CAPDRIVERCAPS CapDrvCaps;
   BOOL lSuccess = FALSE;

   if ( hWnd )
      {
      capDriverGetCaps( hWnd, &CapDrvCaps, sizeof( CAPDRIVERCAPS ) );

      if (CapDrvCaps.fHasDlgVideoFormat)
         {
         capDlgVideoFormat(hWnd);
         if ( !XA_ObjGetL( Self, "lStretch" ) )
            {
            CAPSTATUS CapStatus;
            capGetStatus( hWnd, &CapStatus, sizeof (CAPSTATUS));
            SetWindowPos( hWnd, NULL, 0, 0, CapStatus.uiImageWidth,
                          CapStatus.uiImageHeight, SWP_NOZORDER | SWP_NOMOVE);
            }
         lSuccess = TRUE;
         }
      }
   hb_retl( lSuccess );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_DLGVIDEODISPLAY )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   CAPDRIVERCAPS CapDrvCaps;
   BOOL lSuccess = FALSE;

   if ( hWnd )
      {
      capDriverGetCaps( hWnd, &CapDrvCaps, sizeof( CAPDRIVERCAPS ) );

      if ( CapDrvCaps.fHasDlgVideoDisplay )
         {
         capDlgVideoDisplay( hWnd );
         lSuccess = TRUE;
         }
      }
   hb_retl( lSuccess );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_DLGVIDEOCOMPRESSION )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   CAPDRIVERCAPS CapDrvCaps;
   BOOL lSuccess = FALSE;

   if ( hWnd )
      {
      capDriverGetCaps( hWnd, &CapDrvCaps, sizeof( CAPDRIVERCAPS ) );

      if ( CapDrvCaps.fHasDlgVideoFormat )
         {
         capDlgVideoCompression( hWnd );
         lSuccess = TRUE;
         }
      }
   hb_retl( lSuccess );
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_PHOTO )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );

   if ( hWnd )
      {
      if HB_ISCHAR( 1 )
         capFileSaveDIB( hWnd, hb_parc( 1 ) );
      else
         capEditCopy( hWnd );
      }

   hb_ret();
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_STARTCAPTURE )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );

   if ( hWnd )
      {
      XA_ObjSendC( Self, "_cCaptureFile", hb_parc( 1 ) );
      XA_ObjSendL( Self, "_lOnCapture", TRUE );
      capFileSetCaptureFile( hWnd, hb_parc( 1 ) );
      capCaptureSequence( hWnd );
      }

   hb_ret();
}

//------------------------------------------------------------------------------

HB_FUNC_STATIC( XWEBCAM_ENDCAPTURE )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );

   if ( hWnd )
      {
      XA_ObjSendL( Self, "_lOnCapture", FALSE );
      capCaptureStop( hWnd );
   }

   hb_ret();
}

//------------------------------------------------------------------------------

HB_FUNC( WEBCAMGETDRIVES )
{
   PHB_ITEM pItem, pIndex, pName;
   char cName[ DRIVES_SIZE ], cVersion[ DRIVES_SIZE ];
   int nIndex;

   pItem    = hb_hashNew( NULL );
   pIndex   = hb_itemNew( NULL );
   pName    = hb_itemNew( NULL );

   for (nIndex = 0; nIndex < 10; nIndex ++ )
      {
      if ( capGetDriverDescription( nIndex, cName, DRIVES_SIZE, cVersion, DRIVES_SIZE ) )
         {
         hb_itemPutNL( pIndex, nIndex );
         hb_itemPutC( pName, cName );
         hb_hashAdd( pItem, pIndex, pName );
         }
      }

   hb_itemRelease( pIndex );
   hb_itemRelease( pName );
   hb_itemReturnRelease( pItem );
}

//------------------------------------------------------------------------------


#pragma ENDDUMP

