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

#ifdef _MSC_VER
  #pragma comment(lib, "msimg32.lib")
#endif


#include "CPL_GUC_ScrollButton.h"


namespace CPL {
namespace GUC {


extern unsigned char Image_ScrollBtn[];
extern int           Image_ScrollBtn_Size;



// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @param[in] in_create_info
///   : CreateInfoオブジェクトを指定します。\n
///   : 詳しくはCreateInfoを参照してください。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ScrollButton::ScrollButton( _in<CreateInfo> in_create_info )
  : Container
    ( in_create_info.sp_comp_parent
    , in_create_info.pos
    , float2(24,GetLineHeight())
    )
  , m_type_L( eType::Normal )
  , m_type_R( eType::Normal )
  , m_min( in_create_info.min )
  , m_max( in_create_info.max )
  , m_value( Min( in_create_info.max, Max( in_create_info.min, in_create_info.value ) ) )
  , m_step( in_create_info.step )
  , m_type_scroll( in_create_info.type )
{
  zzf_setupDrawState( false, true, true ); // 描画ステートのデフォルト設定。
  zzf_SetInitializedLevel( zzf_GetClassLevel() );
}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ScrollButton::ScrollButton( cref<ScrollButton> in_scroll_button )
  : td_base      { in_scroll_button }
  , m_type_L     { in_scroll_button.m_type_L      }
  , m_type_R     { in_scroll_button.m_type_R      }
  , m_min        { in_scroll_button.m_min         }
  , m_max        { in_scroll_button.m_max         }
  , m_value      { in_scroll_button.m_value       }
  , m_step       { in_scroll_button.m_step        }
  , m_mouse_pos  { in_scroll_button.m_mouse_pos   }
  , m_type_scroll{ in_scroll_button.m_type_scroll }
{
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::CreateClone
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<Component>
  ScrollButton::CreateClone
    ( _in<sdptr<Component>> in_sp_component_for_parent
    , _in<float2          > in_offset_position_from_original
    ) const
{
  return
    zzz_CreateClone_Basic<td_self>
      ( in_sp_component_for_parent
      , in_offset_position_from_original
      );
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseMove
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  ScrollButton::On_MouseMove
    ( _in<sdptr<Component>> in_sp_component
    , _in<float           > in_mouse_x
    , _in<float           > in_mouse_y
    )
{
  if( in_sp_component != this->GetLinkMyself() )
  {
    return eEventReturnID::SendParent_Position;
  }

  if( WIN::Mouse::IsManualMove() )
  {
    return eEventReturnID::SendParent_Position;
  }

  auto clt_rect = GetRectCoord();
  clt_rect -= float4( clt_rect.x, clt_rect.y, clt_rect.x, clt_rect.y );
  float2 mpos( in_mouse_x, in_mouse_y );

//  SetCapture( in_sp_component );
//  ::SetCapture( GetSubjectWindow()->GetWindowHandle() );

  if( WIN::Mouse::GetDownL() )
  {
    int move = (m_type_scroll == 0)
      ? WIN::Mouse::GetMoveX()
      : -WIN::Mouse::GetMoveY();
    m_value += m_step * move;
    if( move < 0 )
    {
      m_value = Max( m_min, m_value );
      m_type_L = eType::Down;
      m_type_R = eType::Up;
      double value = m_value;
      SendParentMessage
        ( this->GetLinkMyself()
        , eID::ScrollButtonChangeValue
        , (WPARAM)&value
        , 0
        , eParentType::Position
        );
    }
    else
    if( move > 0 )
    {
      m_value = Min( m_max, m_value );
      m_type_L = eType::Up;
      m_type_R = eType::Down;
      double value = m_value;
      SendParentMessage
        ( this->GetLinkMyself()
        , eID::ScrollButtonChangeValue
        , (WPARAM)&value
        , 0
        , eParentType::Position
        );
    }

    WIN::Mouse::SetPos
      ( GetSubjectWindow()->GetWindowHandle()
      , m_mouse_pos.x
      , m_mouse_pos.y
      );
  }
  else
  if( clt_rect.IsHit( mpos.x, mpos.y ) )
  {
    m_type_L = eType::Up;
    m_type_R = eType::Up;
  }
  else
  {
    m_type_L = eType::Normal;
    m_type_R = eType::Normal;

//    SetCapture( nullptr );
//    ::ReleaseCapture();
  }
  
  if( m_value <= m_min )
  {
    m_type_L = eType::Invalid;
  }
  if( m_value >= m_max )
  {
    m_type_R = eType::Invalid;
  }

  Update();

  return eEventReturnID::SendParent_Position;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseEnter
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  ScrollButton::On_MouseEnter
    ( _in<sdptr<Component>> in_sp_comp_enter
    , _in<sdptr<Component>> in_sp_comp_leave
    )
{
  if( in_sp_comp_enter == this->GetLinkMyself() )
  {
    Update();
  }

  return eEventReturnID::SendParent_Position;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseLeave
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  ScrollButton::On_MouseLeave
    ( _in<sdptr<Component>> in_sp_comp_leave
    , _in<sdptr<Component>> in_sp_comp_enter
    )
{
  if( in_sp_comp_leave == this->GetLinkMyself() )
  {
    Update();
  }
  
  return eEventReturnID::SendParent_Position;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseDown
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  ScrollButton::On_MouseDown
    ( _in<sdptr<Component>> in_sp_component
    , _in<float           > in_mouse_x
    , _in<float           > in_mouse_y
    , _in<eMouseButton    > in_type_mouse_btn
    )
{
  if( in_sp_component == GetLinkMyself() )
  {
    ActivateTopOrder();
  }

  if( in_type_mouse_btn == WIN::Component::eMouseButton::Left )
  {
    double value = m_value;
    m_mouse_pos = WIN::Mouse::GetPos();
    SendParentMessage
      ( this->GetLinkMyself()
      , eID::ScrollButtonChangeValueBegin
      , (WPARAM)&value
      , reinterpret_cast<LPARAM>(this)
      , eParentType::Position
      );

    SetCapture( GetLinkMyself() );
    //
    ShowCursor( FALSE );

    //
    const auto size = GetSize();
    const float x0 = 0;
    const float x2 = size.x;
    const float x1 = (x0 + x2) / 2;
    const float y0 = 0;
    const float y2 = size.y;
    const float y1 = (y0 + y2) / 2;

    float4 rt0
      { x0
      , m_type_scroll ? y1 : y0
      , m_type_scroll ? x2 : x1
      , y2
      };
    float4 rt1
      { m_type_scroll ? x0 : x1
      , y0
      , x2
      , m_type_scroll ? y1 : y2
      };
    if( rt0.IsHit( in_mouse_x, in_mouse_y ) )
    {
      m_value -= m_step;
      value = m_value = Max( m_min, m_value );
      SendParentMessage
        ( this->GetLinkMyself()
        , eID::ScrollButtonChangeValue
        , (WPARAM)&value
        , 0
        , eParentType::Position
        );
    }
    else
    {
      m_value += m_step;
      value = m_value = Min( m_max, m_value );

      SendParentMessage
        ( this->GetLinkMyself()
        , eID::ScrollButtonChangeValue
        , (WPARAM)&value
        , 0
        , eParentType::Position
        );
    }

    // ボタンの状態設定
    if( m_value <= m_min )
    {
      m_type_L = eType::Invalid;
    }
    if( m_value >= m_max )
    {
      m_type_R = eType::Invalid;
    }
  }
  return eEventReturnID::SendParent_Position;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseUp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  ScrollButton::On_MouseUp
    ( _in<sdptr<Component>> in_sp_component
    , _in<float           > in_mouse_x
    , _in<float           > in_mouse_y
    , _in<eMouseButton    > in_type_mouse_btn
    )
{
  if( in_sp_component == GetLinkMyself() )
  {
    zzf_setChangedFlag();
  //  ::ReleaseCapture();
    SendParentMessage
      ( this->GetLinkMyself()
      , eID::ScrollButtonChangeValueEnd
      , *(WPARAM*)&m_value
      , 0
      , eParentType::Position
      );

    SetCapture( nullptr );
    //
    ShowCursor( TRUE );
  }

  return eEventReturnID::SendParent_Position;
}

//// _____________________________________________________________________________
//// 背景描画
//// _____________________________________________________________________________
//void ScrollButton::On_DrawBackground( float4 in_rect )
//{
///*
//  const int x0 = in_rect.x;
//  const int x2 = in_rect.z;
//  const int x1 = (x0 + x2) / 2;
//  const int y0 = in_rect.y;
//  const int y2 = in_rect.w;
//  const int y1 = (y0 + y2) / 2;
//
//  float4 rt0( x0, y0, x1, y2 );
//  float4 rt1( x1, y0, x2, y2 );
//
//  zzf_DrawRect_DefaultComponentBG( rt0, COLOr_WHITE );
//  zzf_DrawRect_DefaultComponentBG( rt1, COLOr_WHITE );
//*/
//  //zzf_DrawRect_DefaultComponentBG( in_rect, COLOr_WHITE );
//}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_DrawFrame
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ScrollButton::On_DrawFrame( _in<float4> in_rect )
{
  DX::ColorType color = kCOLOR_BLACK;
  if( sm_sp_ac_comp() == this->GetLinkMyself() )
  {
    color = kCOLOR_GREEN;
  }

  zzf_DrawFrame( in_rect, color );
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ボタンカラーの取得
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DX::ColorType ScrollButton::zzf_GetButtonColor( _in<eType> in_btn_type )
{
  bool flag_this = (sm_sp_ac_comp() == this->GetLinkMyself());

  switch( in_btn_type )
  {
//    case eType::Normal:
    case eType::Up:
      return flag_this ? kCOLOR_LIGHTGREEN : kCOLOR_WHITE;

    case eType::Down:
      return flag_this ? kCOLOR_RED : kCOLOR_WHITE;

    case eType::Invalid:
      return kCOLOR_GRAY;

    default:
      return kCOLOR_WHITE;
  }
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_DrawClient
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ScrollButton::On_DrawClient( _in<float4> in_rect )
{
  float2 const size_img{ 16.0f, 16.0f };
  auto width = in_rect.Width();
  auto height = in_rect.Height();
  if( m_type_scroll == 0 ) // 横スクロール
  {
    zzf_DrawParts
      ( float2( in_rect.x + width  * 0.25f - size_img.x * 0.5f
              , in_rect.y + height * 0.5f  - size_img.y * 0.5f )
      , eImagePartsID::TriangleLeft
      , zzf_GetButtonColor(m_type_L)
      );
    zzf_DrawParts
      ( float2( in_rect.z + width  * 0.75f - size_img.x * 0.5f
              , in_rect.y + height * 0.5f  - size_img.y * 0.5f )
      , eImagePartsID::TriangleRight
      , zzf_GetButtonColor(m_type_R)
      );
  }
  else // 縦スクロール
  {
    zzf_DrawParts
      ( float2( in_rect.x + width  * 0.5f  - size_img.x * 0.5f
              , in_rect.y + height * 0.25f - size_img.y * 0.5f)
      , eImagePartsID::TriangleUp
      , zzf_GetButtonColor(m_type_R)
      );
    zzf_DrawParts
      ( float2( in_rect.x + width  * 0.5f  - size_img.x * 0.5f
              , in_rect.y + height * 0.75f - size_img.y * 0.5f)
      , eImagePartsID::TriangleDown
      , zzf_GetButtonColor(m_type_L)
      );
  }

}




// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @param[in] in_create_info
///   : 作成情報 CreateInfo構造体を指定します。\n
///   : 詳しくはInputScrollBox::CreateInfo構造体を参照してください。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
InputScrollBox::InputScrollBox
( _in<CreateInfo> in_create_info
) : InputBox
    ( in_create_info.sp_component_for_parent
    , in_create_info.position_for_component
    , in_create_info.string_for_label
    , in_create_info.width_for_label
    , in_create_info.width_for_numbox
    , in_create_info.value_of_minimum
    , in_create_info.value_of_maximum
    , in_create_info.value_of_initial
    , WIN::NumBox::eNumMode::Int
    )
{
  float4 rt = GetComponent_NumBox()->GetRectCoord();
  m_sp_scroll_btn =
    Factory<ScrollButton>::Create
      ( this->GetLinkMyself()
      , float2(rt.z, rt.y)
      , in_create_info.value_of_minimum
      , in_create_info.value_of_maximum
      , in_create_info.value_of_initial
      , in_create_info.step
      , in_create_info.type
      );

  zzf_SetInitializedLevel( zzf_GetClassLevel() );

  AdjustSize();
}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
InputScrollBox::InputScrollBox( cref<InputScrollBox> in_input_scroll_box )
  : td_base( in_input_scroll_box )
  , m_sp_scroll_btn
    { FindComponentT_by_UserID<ScrollButton>( in_input_scroll_box.m_sp_scroll_btn )
    }
{
  m_sp_scroll_btn->SetAutoUserID();
}

/*
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// スクロール処理
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
long InputScrollBox::On_Scroll( WIN::ScrollBar* pScroll, int scroll_flag )
{
//  WIN::ScrollBar* pScroll = dynamic_cast<WIN::ScrollBar*>(GetHandleToPointer( hScrollWnd ));
  if( m_pScroll == pScroll  &&  m_sp_num_box )
  {
    float in_value = static_cast<float>(pScroll->GetPos());
    if( scroll_flag == SB_ENDSCROLL )
    {
      m_flag_scroll_active = false;
      GetComponent_NumBox()->SetValue( in_value );
//      this->SendParentMessage( C4D_VALUE_CHANGE, *((DWORD*)&in_value), (LPARAM)this );
    }
    else
    {
      m_flag_scroll_active = true;
      GetComponent_NumBox()->SetValue( in_value );
    }
    return true;
  }
  return false;
}*/

/*
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// テキスト処理
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
long InputScrollBox::On_TextChange( WIN::TextBox* pTextBox )
{
  if( m_sp_num_box == pTextBox  &&  m_sp_scroll_btn )
  {
    float in_value = static_cast<float>(GetComponent_NumBox()->GetValue());
    GetComponent_ScrollButton()->SetValue( in_value );
    this->SendParentMessage( C4D_VALUE_CHANGED, *((DWORD*)&in_value), (LPARAM)this );
    return true;
  }
  return false;
}
*/


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_Size
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  InputScrollBox::On_Size( _in<sdptr<Component>> in_sp_component )
{
  return eEventReturnID::SendParent_Render;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_UserProc
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  InputScrollBox::On_UserProc
    ( _in<sdptr<Component>> in_sp_component
    , _in<long            > in_message
    , _in<WPARAM          > in_wparam
    , _in<LPARAM          > in_lparam
    )
{
  double value = GetComponent_NumBox()->GetValue();

  switch( in_message )
  {
  case eID::ValueChangeBegin:
  case eID::ScrollButtonChangeValueBegin:
    SendParentMessage
      ( this->GetLinkMyself()
      , eID::ValueChangeBegin
      , (WPARAM)&value
      , (LPARAM)this
      , eParentType::Render
      );
    break;

  case eID::ValueChanging:
  case eID::ScrollButtonChangeValue:
    {
      SetValue( *(float*)&in_wparam );
    }
    SendParentMessage
      ( this->GetLinkMyself()
      , eID::ValueChanging
      , (WPARAM)&value
      , (LPARAM)this
      , eParentType::Render
      );
    break;

  case eID::ValueChanged:
    GetComponent_ScrollButton()->SetValue( (float)value );
    SendParentMessage
      ( this->GetLinkMyself()
      , eID::ValueChanged
      , (WPARAM)&value
      , (LPARAM)this
      , eParentType::Render
      );
    break;
  case eID::ScrollButtonChangeValueEnd:
//    SendParentMessage( C4D_VALUE_CHANGED, *((DWORD*)&in_value), (LPARAM)this ); // スクロールボタンは、コレ通知禁止。
    break;
  }

  return eEventReturnID::LastCall;
}


// _____________________________________________________________________________
/// @brief 値の設定
/// 
/// @param[in] in_value : 設定する値を指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void InputScrollBox::SetValue( _in<float> in_value )
{
  GetComponent_NumBox()->SetValue( in_value );
  GetComponent_ScrollButton()->SetValue( in_value );

  Update();
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::CreateClone
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<Component>
  InputScrollBox::CreateClone
    ( _in<sdptr<Component>> in_sp_component_for_parent
    , _in<float2          > in_offset_position_from_original
    ) const
{
  return
    zzz_CreateClone_Basic<td_self>
      ( in_sp_component_for_parent
      , in_offset_position_from_original
      );
}




} // namespace GUC
} // namespace CPL