/*
 * TrackBarMod.prg
 * Control TrackBar moderno
 *
 * Copyright 2020 Ignacio Ortiz de Zúñiga
 * Copyright 2020 https://Xailer.com
 * All rights reserved
 *
 */

#include "Xailer.ch"

CLASS XTrackBarMod FROM TStdControl

PUBLISHED:
   PROPERTY nWidth         INIT 120
   PROPERTY nHeight        INIT 32
   PROPERTY nClrPane       INIT clBtnFace WRITE SetClrPane EDITOR PE_Color
   PROPERTY nClrBarFore    INIT clSystem;
                           WRITE INLINE ( ::FnClrBarFore := Value, ::Refresh() ) ;
                           EDITOR PE_Color

   PROPERTY nClrBarBack    INIT cl3DDkShadow ;
                           WRITE INLINE ( ::FnClrBarBack := Value, ::Refresh() ) ;
                           EDITOR PE_Color

   PROPERTY lTransparent   INIT .T.
   PROPERTY lShowBalloon   INIT .T.
   PROPERTY nBorderStyle   INIT  bvnone //bvWIN10


   PROPERTY nValue         INIT   0 WRITE SetPos
   PROPERTY nMin           INIT   0 WRITE INLINE ::SetRange( Value, ::nMax )
   PROPERTY nMax           INIT 100 WRITE INLINE ::SetRange( ::nMin, Value )
   PROPERTY nOrientation   INIT orHORIZONTAL VALUES orHORIZONTAL, orVERTICAL

   EVENT OnChange( oSender, nPos )  // --> Nil

PUBLIC:
   METHOD Create( oParent ) CONSTRUCTOR
   METHOD Destroy( lFree )

PROTECTED:
   PROPERTY cText
   PROPERTY lBorder     INIT .F.
   PROPERTY l3D
   PROPERTY lParentFont
   PROPERTY oBrush
   DATA nCtlStyle       INIT nOr( WS_CHILD, WS_CLIPCHILDREN, WS_CLIPSIBLINGS )
   DATA oPopup
   DATA oTimer
   DATA lIsHot          INIT .F.
   DATA lPushed         INIT .F.
   DATA aBtnRect        INIT {0,0,0,0}

RESERVED:
   METHOD SetPos( nPos, lEvents )
   METHOD SetClrPane( nColor )
   METHOD SetRange( nMin, nMax ) INLINE ::FnMin := nMin, ::FnMax := nMax, ;
                                        ::Refresh()
   METHOD HitTest( nX, nY )
   METHOD ShowBalloon()
   METHOD HideBalloon()
   METHOD IsShowBalloon() INLINE ::lShowBalloon

   METHOD WMPaint()
   METHOD WMEraseBkgnd() INLINE 1
   METHOD WMPrintClient() EXTERN XTrackBarMod_WMPaint()

   METHOD WMMouseMove( nWParam, nLParam, hWnd )
   METHOD WMKeyDown( nFlags, nLParam, hWnd )
   METHOD WMMouseLeave()

   METHOD WMLButtonDown( nWParam, nLParam )
   METHOD WMLButtonUp( nWParam, nLParam )

   METHOD WMKeyDown( nFlags, nLParam, hWnd )

   METHOD WMKillFocus( hCtl ) INLINE ( ::Super:WMKillFocus( hCtl ), ::Refresh( .F. ) )
   METHOD WMSetFocus( hCtl )  INLINE ( ::Super:WMSetFocus( hCtl ),  ::Refresh( .F. ) )

   METHOD XAClick() VIRTUAL

ENDCLASS

//--------------------------------------------------------------------------

METHOD Create( oParent ) CLASS XTrackBarMod

   ::Super:Create( oParent )

   ::oPopup := TPopupWindow():Create( Self, ::oParent )

   ::SetClrPane()

RETURN Self

//--------------------------------------------------------------------------

METHOD Destroy( lFree ) CLASS XTrackBarMod

   IF ::oTimer != NIL
      ::oTimer:End()
      ::oTimer := NIL
   ENDIF

   IF ::oPopup != NIL
      ::HideBalloon()
      ::oPopup:End()
      ::oPopup := NIL
   ENDIF

RETURN ::Super:Destroy( lFree )

//--------------------------------------------------------------------------

METHOD SetClrPane( nColor ) CLASS XTrackBarMod

   UPDATE ::FnClrPane TO nColor

   IF ::oPopup != NIL .AND. XA_Luminance( ::FnClrPane ) < 127 // lDark
      ::oPopup:nClrPane := clWhite
      ::oPopup:nClrText := clBlack
   ENDIF

   ::Refresh()

RETURN ::FnClrPane

//--------------------------------------------------------------------------

METHOD SetPos( nPos, lEvents ) CLASS XTrackBarMod

   DEFAULT lEvents TO .T.

   nPos := Max( Min( nPos, ::nMax ), ::nMin )

   IF ::FnValue != nPos
      ::FnValue := nPos
      IF lEvents
         ::OnChange( nPos )
      ENDIF
      ::Refresh()
   ENDIF

RETURN nPos

//--------------------------------------------------------------------------

METHOD HitTest( nX, nY )  CLASS XTrackBarMod

   LOCAL nValue, nRge

   nRge := ::nMax - ::nMin + 1

   IF ::nOrientation == orHORIZONTAL
      nValue := MulDiv( nX - 8, nRge, ::nClientWidth - 16 ) + ::nMin
   ELSE
      nValue := ::nMax - MulDiv( nY - 8, nRge, ::nClientHeight - 16 )
   ENDIF

RETURN nValue

//--------------------------------------------------------------------------

#define BOX_WIDTH   38
#define BOX_HEIGHT  32
#define BOX_HALFW   19
#define BOX_HALFH   16

#define BTN_WIDTH    8 // orHorizontal
#define BTN_HEIGHT  24
#define BTN_HALFW    4
#define BTN_HALFH   16

METHOD ShowBalloon() CLASS XTrackBarMod

   LOCAL aPos

   IF ::oTimer != NIL
      ::oTimer:End()
      ::oTimer := NIL
   ENDIF

   IF !::IsShowBalloon() .OR. ( !::lIsHot .AND. !::lPushed )
      RETURN nil
   ENDIF

   aPos  := { ::aBtnRect[ 1 ], ::aBtnRect[ 2 ] }

   ClientToScreen( ::Handle, @aPos )

   WITH OBJECT ::oPopup
      :cText := LTrim( Str( ::nValue ) )
      IF ::nOrientation == orHORIZONTAL
         :SetBounds( aPos[ 1 ] - BOX_HALFW + BTN_HALFW,;
                     aPos[ 2 ] - BOX_HEIGHT - 5,;
                     BOX_WIDTH, BOX_HEIGHT )
      ELSE
         :SetBounds( aPos[ 1 ] + BTN_HEIGHT + 5 ,;
                     aPos[ 2 ] + BTN_HALFW - BOX_HALFH ,;
                     BOX_WIDTH, BOX_HEIGHT )
      ENDIF

      IF :lVisible
         InvalidateRect( :Handle,,.t. )
      ELSE
         :Show()
      ENDIF

   END WITH

RETURN NIL

//--------------------------------------------------------------------------

METHOD HideBalloon() CLASS XTrackBarMod

   IF !::IsShowBalloon()
      RETURN nil
   ENDIF

   ::oPopup:Hide()

RETURN NIL

//--------------------------------------------------------------------------

METHOD WMMouseMove( nWParam, nLParam, hWnd ) CLASS XTrackBarMod

   LOCAL nX, nY

   nX   := LoWord( nLParam )
   nY   := HiWord( nLParam )

   IF !::lIsHot
      ::lIsHot  := .T.
      ::lPushed := lGetKeyState( VK_LBUTTON )
      TrackMouseEvent( ::Handle, TME_LEAVE )
      ::Refresh( .F. )
   ENDIF

   IF ::lPushed
      ::nValue := ::HitTest( nX, nY )
      ::ShowBalloon()
   ELSEIF ::IsShowBalloon() .AND. ::lIsHot
      IF PtInRect( ::aBtnRect, {nX, nY} )
         IF ::oTimer == NIL
            WITH OBJECT ::oTimer := TTimer():Create( ::oParent )
               :nInterval := 1500
               :OnTimer := {|| ::ShowBalloon() }
               :lEnabled := .t.
            END WITH
         ENDIF
      ELSEIF ::oTimer != NIL
         ::oTimer:End()
         ::oTimer := NIL
      ENDIF
   ENDIF

RETURN ::Super:WMMouseMove( nWParam, nLParam, hWnd )

//--------------------------------------------------------------------------

METHOD WMMouseLeave()  CLASS XTrackBarMod

   ::lIsHot  := .F.
   ::lPushed := .F.
   ::Refresh()
   ::HideBalloon()

RETURN nil

//--------------------------------------------------------------------------

METHOD WMLButtonDown( nWParam, nLParam )  CLASS XTrackBarMod

   LOCAL nX, nY

   nX := LoWord( nLParam )
   nY := HiWord( nLParam )

   ::nValue := ::HitTest( nX, nY )

   ::lPushed := .T.
   ::Refresh()
   ::ShowBalloon()

RETURN nil

//--------------------------------------------------------------------------

METHOD WMLButtonUp( nWParam, nLParam ) CLASS XTrackBarMod

   IF ::IsShowBalloon()
      ::HideBalloon()
   ENDIF

   ::lPushed := .F.
   ::Refresh()

RETURN nil

//--------------------------------------------------------------------------

METHOD WMKeyDown( nFlags, nLParam, hWnd ) CLASS XTrackBarMod

   SWITCH nFlags
   CASE VK_LEFT
   CASE VK_PRIOR
   CASE VK_DOWN
      ::nValue --
      RETURN 0
      EXIT
   CASE VK_RIGHT
   CASE VK_NEXT
   CASE VK_UP
      ::nValue ++
      RETURN 0
      EXIT
   CASE VK_HOME
      ::nValue := ::nMin
      RETURN 0
      EXIT
   CASE VK_END
      ::nValue := ::nMax
      RETURN 0
      EXIT
   END SWITCH

RETURN ::Super:WMKeyDown( nFlags, nLParam, hWnd )

//--------------------------------------------------------------------------
