/*
 * Xailer source code:
 *
 * DropControl.prg
 * Clase TDropControl()
 *
 * Copyright 2020 Jose F. Gimenez
 * Copyright 2020 Ignacio Ortiz de Zúñiga
 * Copyright 2020 Xailer.com
 * All rights reserved
 *
 */

#include "Xailer.ch"

CLASS XDropControl FROM TForm

PUBLIC:
   PROPERTY lAnimation INIT .T.
   PROPERTY lAside     INIT .F.
   COMPONENT oLinked
   COMPONENT oControl

   METHOD Show()

   EVENT OnCalcBound( oSender, BYREF nLeft, BYREF nTop, BYREF nWidth, BYREF nHeight )
   EVENT OnReturn( oSender )
   EVENT OnSelect( oSender, oControl )

RESERVED:
   METHOD New( oParent )
   METHOD WMActivate()
   METHOD WMNCDestroy()
   METHOD ControlKeyDown()
   METHOD Initialize()
   METHOD Uninitialize()
   METHOD WMHelp( nWParam, nLParam )   INLINE ::oLinked:SendMsg( WM_HELP, nWParam, nLParam )
   METHOD WMNCHitTest( nWParam, nLParam )

ENDCLASS

//--------------------------------------------------------------------------

METHOD New( oParent ) CLASS XDropControl

   LOCAL oForm, nTop, nLeft

   oForm := oParent:oForm

   ::lDirectShortCuts := .T.

   ::oLinked := oParent

   IF oForm:nFormType == ftMDICHILD
      oForm := oForm:oParent
   ENDIF

   ::Super:New( oForm )
   ::Initialize()
   oParent:oForm:Update()

   ::lAutoScroll := .F.
   ::nBorderStyle := bsNONE

   IF Application:nWinVer > 5  // WinXP & >
      #define CS_DROPSHADOW       0x00020000
      ::nClassStyle := CS_DROPSHADOW
   ENDIF

   ::nClrPane := clWhite
   ::oLinked:oForm:lActive := .F.

RETURN Self

//--------------------------------------------------------------------------

METHOD Show() CLASS XDropControl

   LOCAL nWidth, nHeight, nLeft, nTop
   LOCAL lReverse

   IF ::oControl == NIL
      RETURN nil
   ENDIF

   lReverse := .F.

   WITH OBJECT ::oControl
      :nAlign    := alCLIENT
      IF __objHasMsg( ::oControl, "OnSelect" )
         :OnSelect  := {| oSender | ::OnSelect( ::oControl ), ::End() }
      ELSE
         :OnChange  := {| oSender | ::OnSelect( ::oControl ) }
      ENDIF
      :OnKeyDown := "ControlKeyDown"
      IF !:lCreated
         :Create()
      ENDIF
   END

   WITH OBJECT ::oLinked
      IF !::lAside
         nTop  := :nTop + :nHeight + :oParent:nClientTop
         nLeft := :nLeft + :oParent:nClientLeft
      ELSE
         nTop  := :nTop + :oParent:nClientTop
         nLeft := :nLeft + :nWidth + :oParent:nClientLeft
      ENDIF
   END WITH

   ClientToScreen( ::oLinked:oParent:Handle, @nLeft, @nTop )

   nWidth  := ::oControl:nWidth
   nHeight := ::oControl:nHeight

   WITH OBJECT ::oParent:GetMonitor()
      IF nLeft < :nClientLeft
         nLeft := :nClientLeft
      ELSEIF nLeft + nWidth >= :nClientLeft + :nClientWidth
         nLeft := :nClientLeft + :nClientWidth - nWidth - 1
      ENDIF
      IF nTop < :nClientTop
         nTop := :nClientTop
      ELSEIF nTop + nHeight >= :nClientTop + :nClientHeight
         nTop -= ( nHeight + ::oLinked:nHeight )
         lReverse := .T.
      ENDIF
   END

   ::OnCalcBound( @nLeft, @nTop, @nWidth, @nHeight )

   ::SetBounds( nLeft, nTop, nWidth, nHeight )

   IF ::lAnimation
      IF !lReverse
         AnimateWindow( ::Handle, 140, AW_VER_POSITIVE + AW_ACTIVATE + AW_SLIDE )
      ELSE
         AnimateWindow( ::Handle, 140, AW_VER_NEGATIVE + AW_ACTIVATE + AW_SLIDE )
      ENDIF
   ENDIF

   ::Super:Show()
   ::oControl:SetFocus()

RETURN NIL

//--------------------------------------------------------------------------

METHOD WMActivate( nWParam, hNext ) CLASS XDropControl

   IF LoWord( nWParam ) == 0
      // Deactivate
      ::Uninitialize()
      IF hNext == 0 .OR. hNext != ::oParent:Handle
         ::PostMsg( WM_CLOSE, 0, 1 )
         ::oParent:PostMsg( WM_NCACTIVATE, .F. )
      ELSE
         ::PostMsg( WM_CLOSE )
      ENDIF
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

METHOD WMNCDestroy() CLASS XDropControl

   ::Uninitialize()
   ::oControl:oForm:Refresh()
   ::OnReturn()

RETURN ::Super:WMNCDestroy()

//--------------------------------------------------------------------------

METHOD ControlKeyDown( oSender, nKey, nFlags ) CLASS XDropControl

   IF nKey == VK_RETURN .OR. nKey == VK_F4 .OR. nKey == VK_ESCAPE
      ::End()
   ENDIF

RETURN Nil

//--------------------------------------------------------------------------

#pragma BEGINDUMP

#include <windows.h>
#include <commctrl.h>
#include <xailer.h>
#include <constants.ch>

#define MARGIN    4

/* NOTA: oldWndProc esta como estatica sin problemas porque solo puede haber una
         instancia de TDropList() activa en todo el proceso - [JFG] */
static WNDPROC oldWndProc = NULL;

static LRESULT CALLBACK XDropControl_WndProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
   if ( uMsg == WM_ACTIVATE )
      return( 0 );
   else if ( uMsg == WM_NCACTIVATE )
      return( TRUE );

   return( CallWindowProc( oldWndProc, hwnd, uMsg, wParam, lParam ) );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XDROPCONTROL_INITIALIZE )
{
   PHB_ITEM Self  = hb_stackSelfItem();
   HANDLE hParent = GetHandleOf( XA_ObjGetItem( Self, "oParent" ) );

   oldWndProc = (WNDPROC) GetWindowLong( hParent, GWL_WNDPROC );
   SetWindowLong( hParent, GWL_WNDPROC, (long) XDropControl_WndProc );
}

//--------------------------------------------------------------------------

HB_FUNC_STATIC( XDROPCONTROL_UNINITIALIZE )
{
   PHB_ITEM Self  = hb_stackSelfItem();
   HANDLE hParent = GetHandleOf( XA_ObjGetItem( Self, "oParent" ) );

   if ( oldWndProc )
      {
      SetWindowLong( hParent, GWL_WNDPROC, (long) oldWndProc );
      oldWndProc = NULL;
      }
}

HB_FUNC_STATIC( XDROPCONTROL_WMNCHITTEST )
{
   PHB_ITEM Self = hb_stackSelfItem();
   HWND hWnd = GetHandleOf( Self );
   int lParam = hb_parnl( 2 );
   POINT pt;
   RECT rect;
   int nCode = PrevWindowProc( hWnd, WM_NCHITTEST, 0, lParam );

   if( nCode != HTCLOSE )
      {
      if( XA_ObjGetNL( Self, "nBorderStyle" ) == bsSPLASH )
         {
         nCode = HTCLIENT;
         pt.x = LOWORD( lParam );
         pt.y = HIWORD( lParam );
         GetWindowRect( hWnd, &rect );

         if( pt.x <= rect.left + MARGIN )
            {
            if( pt.y <= rect.top + MARGIN )
               nCode = HTTOPLEFT;
            else if( pt.y >= rect.bottom - MARGIN )
               nCode = HTBOTTOMLEFT;
            else
               nCode = HTLEFT;
            }
         else if( pt.x >= rect.right - MARGIN )
            {
            if( pt.y <= rect.top + MARGIN )
               nCode = HTTOPRIGHT;
            else if( pt.y >= rect.bottom - MARGIN )
               nCode = HTBOTTOMRIGHT;
            else
               nCode = HTRIGHT;
            }
         else if( pt.y <= rect.top + MARGIN )
            nCode = HTTOP;
         else if( pt.y <= rect.top + MARGIN  )
            {
            if( pt.x >= rect.right - MARGIN  )
               nCode = HTCLIENT; //HTSYSMENU;
            else
               nCode = HTCAPTION;
            }
         else if( pt.y >= rect.bottom - MARGIN )
            nCode = HTBOTTOM;
         }
      }

   hb_retnl( nCode );
}

#pragma ENDDUMP


