/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2010/X/X - 2017/02/03
/// 
/// @brief  スクロールボタンコンポーネント。
/// 
/// ****************************************************************************

#pragma once

#include "CPL_GUC_Button.h"
#include "CPL_GUC_InputBox.h"


namespace CPL {
namespace GUC {


// _____________________________________________________________________________
/// @brief スクロールボタン
///
// *****************************************************************************
class ScrollButton
  : public Container
{
  using td_base = Container;
  using td_self = ScrollButton;
  friend Factory<td_self>;
  friend CallPrivateConstructor<td_self>;
public:
  //CPL_GUC_DECL_BASIC_SMARTPOINTER(ScrollButton);

protected:
  CPL_SCOPED_ENUM
    ( eType, int
    , Normal
    , Up
    , Down
    , Invalid
    );

  static int zzf_GetClassLevel(){
    return td_base::zzf_GetClassLevel() + 1; }

//  CPL_SINGLETON( SmartPtr<IDirect3DTexture9>::Com, sm_image );

  eType        m_type_L;
  eType        m_type_R;
//  WIN::DIBitmap m_image;
  float        m_min;
  float        m_max;
  float        m_value;
  float        m_step;
  long2        m_mouse_pos; // クリック位置保存用
  int          m_type_scroll; // 0:横 1:縦

  eEventReturnID
    On_MouseEnter
      ( _in<sdptr<Component>> in_sp_comp_enter
      , _in<sdptr<Component>> in_sp_comp_leave
      ) override;
  eEventReturnID
    On_MouseLeave
      ( _in<sdptr<Component>> in_sp_comp_leave
      , _in<sdptr<Component>> in_sp_comp_enter
      ) override;
  eEventReturnID
    On_MouseMove
      ( _in<sdptr<Component>> in_sp_component
      , _in<float           > in_mouse_x
      , _in<float           > in_mouse_y
      ) override;
  eEventReturnID
    On_MouseDown
      ( _in<sdptr<Component>> in_sp_component
      , _in<float           > in_mouse_x
      , _in<float           > in_mouse_y
      , _in<eMouseButton    > in_type_mouse_btn
      ) override;
  eEventReturnID
    On_MouseUp
      ( _in<sdptr<Component>> in_sp_component
      , _in<float           > in_mouse_x
      , _in<float           > in_mouse_y
      , _in<eMouseButton    > in_type_mouse_btn
      ) override;
  void On_DrawFrame ( _in<float4> in_rect ) override;
  void On_DrawClient( _in<float4> in_rect ) override;

  void          zzf_setChangedFlag(){ m_mouse_pos = long2(Gi,Gi); }
  DX::ColorType zzf_GetButtonColor( _in<eType> in_btn_type );

public:
  struct CreateInfo
  {
    sdptr<Component> sp_comp_parent;               ///< 親コンポーネントのスマートポインタを指定します。
    float2           pos   = float2{ 0.0f, 0.0f }; ///< コンポーネントの座標を指定します。
    float            min   = -9999.0f;             ///< 最小値を指定します。
    float            max   = 9999.0f;              ///< 最大値を指定します。
    float            value = 0.0f;                 ///< 現在値を指定します。
    float            step  = 1.0f;                 ///< ステップ値を指定します。
    int              type  = 0;                    ///< スクロールのタイプを指定します。\n 0:横 1:縦

    CreateInfo
    ( sdptr<Component> in_sp_component_for_parent = nullptr
    , float2           in_position_for_component = float2{ 0.0f, 0.0f }
    , float            in_min   = -9999.0f
    , float            in_max   = 9999.0f
    , float            in_value = 0.0f
    , float            in_step  = 1.0f
    , int              in_type  = 0
    ) : sp_comp_parent( in_sp_component_for_parent )
      , pos  ( in_position_for_component )
      , min  ( in_min )
      , max  ( in_max )
      , value( in_value )
      , step ( in_step )
      , type ( in_type != 0 )
    {}
  };
protected:
  ScrollButton( _in<CreateInfo> in_create_info );
  ScrollButton
  ( _in<sdptr<Component>> in_sp_component_for_parent
  , _in<float2          > in_position_for_button
  , _in<float           > in_min
  , _in<float           > in_max
  , _in<float           > in_value
  , _in<float           > in_step = 1.0f
  , _in<int             > in_type_scroll = 0
  ) : ScrollButton
    ( CreateInfo
      { in_sp_component_for_parent
      , in_position_for_button
      , in_min
      , in_max
      , in_value
      , in_step
      , in_type_scroll
      }
    )
  {}
  ScrollButton( cref<ScrollButton> in_scroll_button );
public:
  ~ScrollButton(){}

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  sdptr<Component>
    CreateClone
      ( _in<sdptr<Component>> in_sp_component_for_parent       = nullptr
      , _in<float2          > in_offset_position_from_original = float2{0,0}
      ) const override;

  // _____________________________________________________________________________
  /// @brief ステップ値の設定
  /// 
  /// @param[in] in_step
  ///   : クリックまたはドラッグした場合の１度の変化量を指定します。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual void SetStep( _in<float> in_step  ){ m_step  = in_step; }

  // _____________________________________________________________________________
  /// @brief 最小値の設定
  /// 
  /// @param[in] in_min : 最小値を指定します。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual void SetMin( _in<float> in_min ){ m_min   = in_min; }

  // _____________________________________________________________________________
  /// @brief 最大値の設定
  /// 
  /// @param[in] in_max : 最大値を指定します。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual void SetMax( _in<float> in_max ){ m_max   = in_max; }

  // _____________________________________________________________________________
  /// @brief 現在の設定
  /// 
  /// @param[in] in_value : 現在を指定します。
  /// 
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual void SetValue( _in<float> in_value ){ m_value = in_value; }

  // _____________________________________________________________________________
  /// @brief ステップ値の取得
  /// 
  /// @return ステップ値を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual float GetStep() const { return m_step; }

  // _____________________________________________________________________________
  /// @brief 最小値の取得
  /// 
  /// @return 最小値を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual float GetMin() const { return m_min; }

  // _____________________________________________________________________________
  /// @brief 最大値の取得
  /// 
  /// @return 最大値を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual float GetMax() const { return m_max; }

  // _____________________________________________________________________________
  /// @brief 現在値の取得
  /// 
  /// @return 現在地を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual float GetValue() const { return m_value; }

  // _____________________________________________________________________________
  /// @brief スクロール方向のタイプの取得
  /// 
  /// @retval 0 : 横
  /// @retval 1 : 縦
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual int GetType_for_Scroll() const { return m_type_scroll; }

  // _____________________________________________________________________________
  /// @brief 変更中かどうかの取得
  /// 
  /// @retval 0 : 変更中ではない。
  /// @retval 1 : 変更中。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual int IsChanging() const { return !(m_mouse_pos.x == Gi  &&  m_mouse_pos.y == Gi); }
};

//CPL_GUC_DECL_BASIC_SMARTPOINTER( ScrollButton );




// _____________________________________________________________________________
/// @brief スクロールボックス付き値設定コンポーネント
///
// *****************************************************************************
class InputScrollBox
  : public InputBox
{
  using td_base = InputBox;
  using td_self = InputScrollBox;
  friend Factory<td_self>;
  friend CallPrivateConstructor<td_self>;
public:
  //CPL_GUC_DECL_BASIC_SMARTPOINTER( InputScrollBox );

protected:
  static int zzf_GetClassLevel(){ return InputBox::zzf_GetClassLevel() + 1; }

  sdptr<ScrollButton> m_sp_scroll_btn;

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_Size( _in<sdptr<Component>> in_sp_component ) override;

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_UserProc
      ( _in<sdptr<Component>> in_sp_component
      , _in<long            > in_message
      , _in<WPARAM          > in_wparam
      , _in<LPARAM          > in_lparam
      ) override;

public:
  struct CreateInfo
    : public InputBox::CreateInfo
  {
    using td_base = InputBox::CreateInfo;
    float step; ///< ステップ値を指定します。
    int   type; ///< ボタンのタイプを指定します。\n 0:横 1:縦

    CreateInfo
    ( _in<sdptr<Component>> in_sp_component_for_parent
    , _in<float2          > in_position_for_component
    , pin<td_DefChar      > in_string_for_label
    , _in<float           > in_width_for_label
    , _in<float           > in_width_for_numbox
    , _in<float           > in_value_of_minimum
    , _in<float           > in_value_of_maximum
    , _in<float           > in_value_of_initial
    , _in<float           > in_step
    , _in<int             > in_type
    ) : td_base
        { in_sp_component_for_parent
        , in_position_for_component
        , in_string_for_label
        , in_width_for_label
        , in_width_for_numbox
        , in_value_of_minimum
        , in_value_of_maximum
        , in_value_of_initial
        , WIN::NumBox::eNumMode::Int
        }
      , step( in_step )
      , type( in_type )
    {}
  };
protected:
  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  InputScrollBox( _in<CreateInfo> in_create_info );

  // _____________________________________________________________________________
  /// @brief コンストラクタ
  ///  
  /// @copydoc doxycomment::arg_in_sp_component_for_parent
  /// @copydoc doxycomment::arg_in_position_for_component
  /// @copydoc doxycomment::arg_in_string_for_label
  /// @copydoc doxycomment::arg_in_width_for_label
  /// @copydoc doxycomment::arg_in_width_for_numbox
  /// @copydoc doxycomment::arg_in_value_of_minimum
  /// @copydoc doxycomment::arg_in_value_of_maximum
  /// @copydoc doxycomment::arg_in_value_of_initial
  /// @param[in] in_step
  ///   : ボタンをクリックした際の値の増減値を指定します。
  /// @param[in] in_type_scroll
  ///   : スクロールボタンのタイプを指定します。\n
  ///   : 0 - 横\n
  ///   : 1 - 縦
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  InputScrollBox
  ( _in<sdptr<Component>> in_sp_component_for_parent
  , _in<float2          > in_position_for_component
  , pin<td_DefChar      > in_string_for_label
  , _in<float           > in_width_for_label
  , _in<float           > in_width_for_numbox
  , _in<float           > in_value_of_minimum
  , _in<float           > in_value_of_maximum
  , _in<float           > in_value_of_initial
  , _in<float           > in_step
  , _in<int             > in_type_scroll
  ) : InputScrollBox
      { CreateInfo
        { in_sp_component_for_parent
        , in_position_for_component
        , in_string_for_label
        , in_width_for_label
        , in_width_for_numbox
        , in_value_of_minimum
        , in_value_of_maximum
        , in_value_of_initial
        , in_step
        , in_type_scroll
        }
      }
  {
  }

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  InputScrollBox( cref<InputScrollBox> in_input_scroll_box );

public:
  // _____________________________________________________________________________
  /// @brief デストラクタ。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ~InputScrollBox(){ /*今のところ特に何もしない。*/ }
  

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual void
    SetValue( _in<float> in_value ) override;

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  sdptr<Component>
    CreateClone
      ( _in<sdptr<Component>> in_sp_component_for_parent       = nullptr
      , _in<float2          > in_offset_position_from_original = float2{0,0}
      ) const override;
  
  // _____________________________________________________________________________
  /// @brief スクロールコンポーネントの取得。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual sdptr<ScrollButton>
    GetComponent_ScrollButton() const noexcept
  {
    return m_sp_scroll_btn;
  }
};

//CPL_GUC_DECL_BASIC_SMARTPOINTER( InputScrollBox );



} // namespace GUC
} // namespace CPL
