/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2017/02/01
/// 
/// @brief  セレクタークラス関連
/// 
/// ****************************************************************************

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


#include "CPL_GUC_ActiveSelector.h"
#include "CPL_GUC_ScrollBar.h"


namespace CPL {
namespace GUC {

int   const as_max_list_num    = 20;
float const as_max_list_height = as_max_list_num * Component::GetLineHeight() + ActiveSelector::GetSpaceSize() * 2;
float const as_min_list_width  = 80;
float const AS_TEXT_OFFS_X = 15;

// _____________________________________________________________________________
/// @brief セレクタのデフォルト背景カラー。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet>
  ActiveSelector::GetDefaultColor_SelectorBG()
{
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , ColorPattern::DynamicBG()
        );
  return sp_color;
}

// _____________________________________________________________________________
/// @brief セレクタのデフォルトフレームカラー。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet>
  ActiveSelector::GetDefaultColor_SelectorFrame()
{
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , ColorPattern::DynamicFrame()
        );
  return sp_color;
}

// _____________________________________________________________________________
/// @brief セレクタのデフォルトテキストカラー。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet>
  ActiveSelector::GetDefaultColor_SelectorText()
{
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , ColorPattern::DynamicText()
        );
  return sp_color;
}


// _____________________________________________________________________________
/// @brief リスト表示用コンテナクラス
///
// *****************************************************************************
class ActiveSelectorList
  : public ActiveForm
{
  using td_base = ActiveForm;
  using td_self = ActiveSelectorList;
  using StringArray = std::vector<DX::FontDrawManager::td_DefString>;
  friend Factory<td_self>;
  friend CallPrivateConstructor<td_self>;

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

  U32              m_select_idx;
  U32              m_active_idx;
  StringArray      m_str_list;
  wkptr<ScrollBar> m_wp_scroll;

  sdptr<DrawColorSet> GetDefaultColor_BG()   { return ActiveSelector::GetDefaultColor_SelectorBG(); }
  sdptr<DrawColorSet> GetDefaultColor_Frame(){ return ActiveSelector::GetDefaultColor_SelectorFrame(); }
  sdptr<DrawColorSet> GetDefaultColor_Text() { return ActiveSelector::GetDefaultColor_SelectorText(); }
  
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  virtual eEventReturnID
    On_Show( _in<sdptr<Component>> in_sp_component, _in<BOOL> in_show_flag )
  {
    if( in_show_flag )
    {
      SetTimer( eID::Tid_ActiveSelectorShow, 100 );
      m_hide_count = 0;
      
      // 自身を最前面（最後尾）へ
      this->ActivateTopOrder();
      if( auto sp_parent = GetBelongComponent( eParentType::Position ) )
      {
        sp_parent->ActivateTopOrder();
      }

      ///*** 画面外に出ないように座標補正 ***//*
      float move_y = 0;

      // 初期位置補正
      int  const item_num   = static_cast<int>(m_str_list.size());
      auto const LH         = GetLineHeight();
      auto const size_frame = GetFrameSize();
      auto const size_space = ActiveSelector::GetSpaceSize();
      auto const offs_y     = LH * m_select_idx + size_space;// + size_frame;
      this->SetPosition( float2( -1, -offs_y-2 ) );

      float4 rt_this = GetRectCoord(); // 現在の座標を取得
      float2 win_size = GetSubjectWindow()->GetClientSize(); // 大元のウィンドウのクライアントサイズを取得。（範囲外補正のため）
      float4 rt_top( 0, 0, win_size.x, win_size.y );
      // 
      MappingPosition
        ( nullptr
        , GetBelongComponent( eParentType::Position )
        , (float2_ptr)&rt_top
        , 2
        );
/*
      // 横方向補正
      if( rt_top_win.x > rt_this.x ) // 左方向
      {
        if( (m_pos_mode & BIT1) == 0 ) // 横配置の場合
        {
          move_x = rt_top_win.z - rt_this.x; // 右側に移動させる
        }
      }
      ef( rt_top_win.z < rt_this.z ) // 右方向
      {
        if( m_pos_mode & BIT1 ) // 縦配置の場合
        {
          move_x = rt_top_win.z - rt_this.z; // 右揃え
        }
        else // 横配置の場合
        {
          move_x = rt_top_win.x - rt_this.z; // 左側に移動させる
        }
      }
*/

      // 縦方向補正
      if( rt_top.y > rt_this.y ) // 上方向
      {
        move_y = rt_top.y - rt_this.y;
      }
      else
      if( rt_top.w < rt_this.w ) // 下方向
      {
        move_y = rt_top.w - rt_this.w;
      }

      //
      if( move_y != 0 )
      {
        rt_this.y += move_y;
        rt_this.w += move_y;
        this->SetRectCoord( rt_this );
      }
      // 表示メッセージを通知
      SendParentMessage
        ( this->GetLinkMyself()
        , eID::ActiveViewItemShow
        , 0
        , (LPARAM)this
        , eParentType::Position
        );
    }
    else
    {
      // タイマー削除
      KillTimer( eID::Tid_ActiveSelectorShow );

      // 自身を最背面（先頭）へ
      MoveLinkTop();

      // 非表示メッセージを通知
      SendParentMessage
        ( this->GetLinkMyself()
        , eID::ActiveViewItemHide
        , 0
        , (LPARAM)this
        , eParentType::Position
        );
    }

    return eEventReturnID::SendParent_Position;
  }
    
  // _____________________________________________________________________________
  /// @copydoc CPL::GUC::MouseEventInterface::On_MouseDown
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  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
  {
    if( in_sp_component == GetLinkMyself() )
    {
      ActivateTopOrder();
    }
    return eEventReturnID::LastCall;
  }

  // _____________________________________________________________________________
  /// @copydoc CPL::GUC::MouseEventInterface::On_MouseUp
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  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
  {
    if( in_sp_component == this->GetLinkMyself() )
    {
      if( in_type_mouse_btn == WIN::Component::eMouseButton::Left )
      {
        m_select_idx = m_active_idx;

        call_On_UserProc
          ( this->GetLinkMyself()
          , eID::ActiveSelectorChangeItem
          , m_select_idx
          , 0
          );

        SetStateVisible( false );
      }
      else
      if( in_type_mouse_btn == WIN::Component::eMouseButton::Right )
      {
        SetStateVisible( false );
      }
    }

    return eEventReturnID::SendParent_Position;
  }

  // _____________________________________________________________________________
  /// @copydoc CPL::GUC::MouseEventInterface::On_MouseMove
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID
    On_MouseMove
      ( _in<sdptr<Component>> in_sp_component
      , _in<float           > in_mouse_x
      , _in<float           > in_mouse_y
      ) override
  {
    if( in_sp_component == this->GetLinkMyself() )
    {
      auto const size_space = ActiveSelector::GetSpaceSize();
      auto const size_frame = GetFrameSize();

      m_active_idx =
        static_cast<int>((in_mouse_y - size_space - size_frame) / GetLineHeight());
      m_active_idx = Clamp( m_active_idx, 0, (U32)m_str_list.size()-1 );
      if( auto sp_scroll = m_wp_scroll.lock() )
      {
        m_active_idx += static_cast<int>(sp_scroll->GetPos());
      }
    }

    Update();

    return eEventReturnID::LastCall;
  }

  // _____________________________________________________________________________
  /// @copydoc CPL::GUC::Component::On_Size
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  eEventReturnID On_Size( _in<sdptr<Component>> in_sp_component )
  {
    if( in_sp_component == this->GetLinkMyself() )
    {
      if( auto sp_scroll = m_wp_scroll.lock() )
      {
        float4 rt = GetRectCoord();
        rt.x = rt.z - ScrollBar::GetBtnSize();
        sp_scroll->SetRectCoord( rt );
      }
    }

    return ActiveForm::On_Size( in_sp_component );
  }

  // _____________________________________________________________________________
  /// @copydoc CPL::GUC::Component::On_DrawBackground
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  void On_DrawBackground( _in<float4> in_rect )
  {
    td_base::On_DrawBackground( in_rect );

    float const height_line = GetLineHeight();
    float const size_space  = ActiveSelector::GetSpaceSize();

    // 選択矩形の描画。
    //zzf_DrawRect_DefaultComponentBG(
    zzf_DrawRectEx
      ( float4
          ( in_rect.x
          , in_rect.y + m_active_idx * height_line + size_space
          , in_rect.z
          , in_rect.y + m_active_idx * height_line + height_line + size_space
          )
      , GetColorParameterBG()->color_active.color
      );
  }

  // _____________________________________________________________________________
  /// @copydoc CPL::GUC::Component::On_DrawClient
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  void On_DrawClient( _in<float4> in_rect )
  {
    auto sp_scroll = m_wp_scroll.lock();
    float const height_line = GetLineHeight();
    float const size_space  = ActiveSelector::GetSpaceSize();
    float2 size_comp = GetSize();
    int flag_sc_bar = (sp_scroll != nullptr);
    int base_idx = flag_sc_bar ? static_cast<int>(sp_scroll->GetPos()) : 0;
    int num = flag_sc_bar ? as_max_list_num
                          : static_cast<int>(m_str_list.size());
    if( flag_sc_bar )
    {
      size_comp.x -= sp_scroll->GetSize().x;
    }

    for( int i = 0; i < num; ++i )
    {
      auto ptr_color_text = &GetColorParameterText()->color_default;
      //if( m_active_idx == i + base_idx )
      //{
      //  // 選択矩形の描画。
      //  //zzf_DrawRect_DefaultComponentBG(
      //  zzf_DrawRectEx
      //    ( float4
      //        ( in_rect.x
      //        , in_rect.y + i*height_line + size_space
      //        , in_rect.z
      //        , in_rect.y + i*height_line+height_line + size_space
      //        )
      //    , GetColorParameterBG()->color_active.color
      //    );
      //  //
      //  ptr_color_text = &GetColorParameterText()->color_active;
      //}

      float4
        rt( in_rect.x + AS_TEXT_OFFS_X
          , in_rect.y + i * height_line + size_space
          , in_rect.x + size_comp.x - AS_TEXT_OFFS_X
          , in_rect.y + i * height_line + height_line + size_space
          );
      if( (i + base_idx) == this->m_select_idx )
      {
        // 両三角の描画
        zzf_DrawParts
          ( float2(in_rect.x-2, rt.y+2)
          , eImagePartsID::TriangleRight
          , kCOLOR_BLACK
          );
        //zzf_DrawParts
        //  ( float2(in_rect.z-16, rt.y+2)
        //  , eImagePartsID::TriangleLeft
        //  , COLOr_WHITE
        //  );
      }

      // 項目描画
      zzf_DrawText
        ( rt
        , m_str_list[ base_idx + i ]
        , *ptr_color_text
        , 0.0f
        , float2( 0, 0 )
        , DX::kFDM_X_LEFT | DX::kFDM_Y_MIDDLE
        );
    }
  }


protected:
  ActiveSelectorList( _in<sdptr<Component>> in_sp_component_for_parent )
    : td_base( in_sp_component_for_parent )
    , m_select_idx( 0 )
    , m_active_idx( 0 )
  {
//    m_sp_scroll = new ScrollBar( getThisSmPtr(), NULL, NULL, 1 );

    zzf_setupDrawState( true, true, true ); // 描画ステートのデフォルト設定。

    zzf_SetInitializedLevel( zzf_GetClassLevel() );
  }
  ActiveSelectorList( cref<ActiveSelectorList> in_ASL )
    : td_base{ in_ASL }
    , m_select_idx{ in_ASL.m_select_idx }
    , m_active_idx{ in_ASL.m_active_idx }
    //, m_str_list  { in_ASL.m_str_list   }
    , m_wp_scroll
      { FindComponentT_by_UserID<ScrollBar>( in_ASL.m_wp_scroll.lock() )
      }
  {
    CPL_SAFE_PTR(m_wp_scroll.lock())->SetAutoUserID();
    // item list
    for( auto& str : in_ASL.m_str_list )
    {
      AddItem( str );
    }
  }
public:
  ~ActiveSelectorList(){}

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

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  void AddItem( _in<td_DefString> in_str )
  {
    m_str_list.push_back( in_str );

    auto const size_frame  = GetFrameSize();
    auto const size_space  = ActiveSelector::GetSpaceSize();
    auto const height_line = GetLineHeight();
    auto const SC_BTN_SIZE = ScrollBar::GetBtnSize();
    int  num               = static_cast<int>(m_str_list.size());
    auto sp_comp_belong    = GetBelongComponent( eParentType::Position );

    // 幅調整
    float width =
      Max<float>(as_min_list_width, sp_comp_belong->GetSize().x);
    float height = 0;
    //CPL_LOOP2( num, idx )
    for( size_t idx = 0; idx < num; ++idx )
    {
      short2 lang_size =
        sm_def_font_mng()->GetStringLineSize
          ( m_str_list[ idx ]
          , 0
          , nullptr
          ); // サイズ取得
      width =
        Max<float>
          ( width
          , lang_size.x + 5 + size_space * 2 * size_frame * 2
          );
    }

    // スクロールバーの設定
    if( num * height_line > as_max_list_height )
    {
      auto sp_scroll = m_wp_scroll.lock();
      if( sp_scroll == nullptr )
      {
        m_wp_scroll =
        sp_scroll   =
          Factory<ScrollBar>::Create
            ( this->GetLinkMyself()
            , float2(width, 0) // スクロールバーが必要される場合、後にサイズが
                               // 拡張されるので、ｘ位置はwidthのままでよい。
            , float2(SC_BTN_SIZE, as_max_list_height)
            , 1
            );
      }
      sp_scroll->SetParameter
        ( sp_scroll->GetPos()
        , 0.0f
        , static_cast<float>(num)
        , 1.0f
        , static_cast<float>(as_max_list_num)
        );
      sp_scroll->SetStateVisible( true );
      height = as_max_list_height * size_frame * 2;
    }
    else
    {
      height = height_line * static_cast<int>(num) + size_frame * 2;
    }

    if( m_wp_scroll.lock() )
    {
      width += SC_BTN_SIZE;
      m_wp_scroll.lock()->SetPos( static_cast<float>(m_select_idx) );
    }

    if( FAILED_INDEX(m_select_idx) )
    {
      m_select_idx = 0;
    }

    //
    SetSize( float2(width, height + ActiveSelector::GetSpaceSize()*2) );
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  void DelItem( _in<U32> in_del_idx )
  {
    m_str_list.erase( m_str_list.begin() + in_del_idx );

    if( m_select_idx >= static_cast<U32>(m_str_list.size()) )
    {
      m_select_idx = INVALID_INDEX32;
    }
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  void Release()
  {
    m_str_list.clear();
    m_select_idx = INVALID_INDEX32;

    CPL_SAFE_PTR(m_wp_scroll.lock())->DetachAll();
  }

  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  void SetSelectIndex( _in<U32> in_select_idx )
  {
    if( FAILED_INDEX(in_select_idx) )
    {
      m_select_idx = INVALID_INDEX32;
    }
    else
    if( in_select_idx >= (U32)m_str_list.size() )
    {
      m_select_idx = static_cast<U32>(m_str_list.size()) - 1;
    }
    else
    {
      m_select_idx = in_select_idx;
    }
  }

  U32          GetSelectIndex() const { return m_select_idx; }
  U32          GetNum() const { return static_cast<U32>(m_str_list.size()); }
  td_DefString GetSelectString() const
  {
    return GetItemString( m_select_idx );
  }
  td_DefString GetItemString( U32 in_item_idx ) const
  {
    if( FAILED_INDEX(in_item_idx) )
    {
      return CPL_GUC_DEF_STR("");
    }
    else
    {
      return m_str_list[ in_item_idx ];
    }
  }
};





// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydoc doxycomment::arg_in_sp_component_for_parent
/// @copydoc doxycomment::arg_in_position_for_component
/// @copydoc doxycomment::arg_in_size_for_component
///   : ※ ｘ要素のみ使用されます。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ActiveSelector::ActiveSelector
( _in<sdptr<Component>> in_sp_component_for_parent
, _in<float2          > in_position_for_component
, _in<float2          > in_size_for_component
) : ActiveManageComponent
    ( in_sp_component_for_parent
    , in_position_for_component
    , float2(in_size_for_component.x, GetLineHeight())
    )
{
  SetFrameWidth( 1 );

//  m_text = in_text;
  m_wp_active_form =
    Factory<ActiveSelectorList>::Create( this->GetLinkMyself() );

  zzf_setupDrawState( true, true, true ); // 描画ステートのデフォルト設定。

  zzf_SetInitializedLevel( zzf_GetClassLevel() );
}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ActiveSelector::ActiveSelector( cref<td_self> in_active_selector )
  : td_base( in_active_selector )
  , m_vertical_width{ in_active_selector.m_vertical_width }
{
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseMove
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  ActiveSelector::On_MouseMove
  ( _in<sdptr<Component>> in_sp_component
  , _in<float           > in_mouse_x
  , _in<float           > in_mouse_y
  )
{
  return eEventReturnID::SendParent_Position;
}


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

  return eEventReturnID::SendParent_Position;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseLeave
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  ActiveSelector::On_MouseLeave
    ( _in<sdptr<Component>> in_sp_comp_leave
    , _in<sdptr<Component>> in_sp_comp_enter
    )
{
  // 自身もしくは子供ならば
  if( in_sp_comp_leave == this->GetLinkMyself()
   || CheckBelongComponent( in_sp_comp_leave, eParentType::Position ) )
  {
    KillTimer( eID::Tid_MouseEnterDelay );
    Update();
  }

  return eEventReturnID::SendParent_Position;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseUp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  ActiveSelector::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() )
  {
    auto sp_acform = m_wp_active_form.lock();
    sp_acform->SetStateVisible( true );
    sp_acform->ActivateTopOrder();
    SetFocus( sp_acform );
    Update();
  }
  return eEventReturnID::SendParent_Position;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::WindowEventInterface::On_Timer
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID ActiveSelector::On_Timer( _in<int> in_timer_ID )
{
  if( in_timer_ID == eID::Tid_MouseEnterDelay )
  {
    m_wp_active_form.lock()->SetStateVisible( true );

    KillTimer( eID::Tid_MouseEnterDelay );
  }

  return eEventReturnID::SendParent_Position;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_DrawBackground
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ActiveSelector::On_DrawBackground( _in<float4> in_rect )
{
  CPl_GUC_ACTIVE_SELECTOR_BASE::On_DrawBackground( in_rect );
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_DrawFrame
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ActiveSelector::On_DrawFrame( _in<float4> in_rect )
{
  CPl_GUC_ACTIVE_SELECTOR_BASE::On_DrawFrame( in_rect );
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_DrawClient
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ActiveSelector::On_DrawClient( _in<float4> in_rect )
{
  // color
  auto sp_colorset_text = GetColorParameterText();
  auto ptr_color = &sp_colorset_text->color_default;
  if( !IsEnable() )
  {
    ptr_color = &sp_colorset_text->color_invalid;
  }
  else
  if( sm_sp_ac_comp() == this->GetLinkMyself() )
  {
    if( WIN::Mouse::GetDownL() )
    {
      ptr_color = &sp_colorset_text->color_active;
    }
    else
    {
      ptr_color = &sp_colorset_text->color_highlight;
    }
  }

  float4 rt = in_rect;
  rt.x += AS_TEXT_OFFS_X;
  rt.z -= AS_TEXT_OFFS_X;
  zzf_DrawText
    ( rt
    , this->GetSelectString()
    , *ptr_color
    , 0.0f
    , float2( 0, 0 )
    , DX::kFDM_X_LEFT | DX::kFDM_Y_MIDDLE
    );

  // 三角形の描画
  //zzf_DrawParts
  //  ( float2(in_rect.x+2,  in_rect.y+2)
  //  , eImagePartsID::TriangleDown
  //  , kCOLOR_BLACK
  //  );
  zzf_DrawParts
    ( float2(in_rect.z-16, in_rect.y+2)
    , eImagePartsID::TriangleDown
    , kCOLOR_BLACK
    );
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_UserProc
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  ActiveSelector::On_UserProc
    ( _in<sdptr<Component>> in_sp_component
    , _in<long            > in_message
    , _in<WPARAM          > in_wparam
    , _in<LPARAM          > in_lparam
    )
{
  if( in_message == eID::ActiveSelectorChangeItem )
  {
    this->SetSelectIndex( static_cast<U32>(in_wparam) );

    Update();
  }

  return
    CPl_GUC_ACTIVE_SELECTOR_BASE::On_UserProc
      ( in_sp_component
      , in_message
      , in_wparam
      , in_lparam
      );
}

// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::CreateClone
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<Component>
  ActiveSelector::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
      );
}

// _____________________________________________________________________________
/// @brief 項目の追加
/// 
/// @param[in] in_str : 追加する項目の文字列を指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ActiveSelector::AddItem( _in<td_DefString> in_str )
{
  auto sp_active_list =
    std::dynamic_pointer_cast<ActiveSelectorList>(m_wp_active_form.lock());

  if( sp_active_list )
  {
    sp_active_list->AddItem( in_str );
  }
}


// _____________________________________________________________________________
/// @brief 項目の削除。
/// 
/// @param[in] in_del_idx : 削除する項目のインデックスを指定。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ActiveSelector::DelItem( _in<U32> in_del_idx )
{
  auto sp_active_list =
    std::dynamic_pointer_cast<ActiveSelectorList>(m_wp_active_form.lock());

  if( sp_active_list )
  {
    sp_active_list->DelItem( in_del_idx );
  }
}


// _____________________________________________________________________________
/// @brief 全ての項目を削除。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ActiveSelector::Release()
{
  auto sp_active_list =
    std::dynamic_pointer_cast<ActiveSelectorList>(m_wp_active_form.lock());

  if( sp_active_list )
  {
    sp_active_list->Release();
  }
}


// _____________________________________________________________________________
/// @brief 選択項目の設定。
/// 
/// @param[in] in_select_idx : 選択するインデックスを指定。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ActiveSelector::SetSelectIndex( _in<U32> in_select_idx )
{
  auto sp_active_list =
    std::dynamic_pointer_cast<ActiveSelectorList>(m_wp_active_form.lock());

  if( sp_active_list )
  {
    sp_active_list->SetSelectIndex( in_select_idx );
  }
}


// _____________________________________________________________________________
/// @brief アイテム数を取得。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
U32 ActiveSelector::GetNum() const 
{
  auto sp_active_list =
    std::dynamic_pointer_cast<ActiveSelectorList>(m_wp_active_form.lock());

  if( sp_active_list )
  {
    return sp_active_list->GetNum();
  }

  return 0;
}


// _____________________________________________________________________________
/// @brief 選択インデックスを取得。
/// 
/// @return
/// 選択インデックスを返す。\n
/// 非選択状態で-1(全ビットON)を返す。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
U32 ActiveSelector::GetSelectIndex() const
{
  auto sp_active_list =
    std::dynamic_pointer_cast<ActiveSelectorList>(m_wp_active_form.lock());

  if( sp_active_list )
  {
    return sp_active_list->GetSelectIndex();
  }

  return 0;
}


// _____________________________________________________________________________
/// @brief 選択中の項目の文字列を取得。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
td_DefString ActiveSelector::GetSelectString() const
{
  auto sp_active_list =
    std::dynamic_pointer_cast<ActiveSelectorList>(m_wp_active_form.lock());

  if( sp_active_list )
  {
    return sp_active_list->GetSelectString();
  }

  return CPL_GUC_DEF_STR("");
}


// _____________________________________________________________________________
/// @brief 指定した項目の文字列を取得。
/// 
/// @param[in] in_item_idx : 取得する項目のインデックスを指定。
/// 
/// @return 文字列を格納したCore::Stringクラスを返す。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
td_DefString ActiveSelector::GetItemString( _in<U32> in_item_idx ) const
{
  auto sp_active_list =
    std::dynamic_pointer_cast<ActiveSelectorList>(m_wp_active_form.lock());

  if( sp_active_list )
  {
    return sp_active_list->GetItemString( in_item_idx );
  }

  return CPL_GUC_DEF_STR("");
}








// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydoc doxycomment::arg_in_sp_component_for_parent
/// @copydoc doxycomment::arg_in_position_for_component
/// @param[in] in_string_for_caption
///   : キャプションの文字列を指定します。
/// @param[in] in_width_for_caption
///   : キャプションの幅を指定します。
/// @param[in] in_width_for_item
///   : セレクタの幅を指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CaptionSelector::CaptionSelector
( _in<sdptr<Component>> in_sp_component_for_parent
, _in<float2          > in_position_for_component
, pin<td_DefChar      > in_string_for_caption
, _in<float           > in_width_for_caption
, _in<float           > in_width_for_item
) : td_base
    ( in_sp_component_for_parent
    , in_position_for_component
    , in_string_for_caption
    , in_width_for_caption
    )
{
  auto const space = 3;
  auto size_caption = m_sp_caption->GetSize();
  // セレクタコンテナの作成。
  m_sp_item =
    Factory<ActiveSelector>::Create
      ( this->GetLinkMyself()
      , float2
          { in_width_for_caption > 0.0f
              ? in_width_for_caption
              : size_caption.x + space
          , 1
          }
      , float2{ in_width_for_item, GetLineHeight() }
      );

  // クラスレベルの設定。
  zzf_SetInitializedLevel( zzf_GetClassLevel() );
}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CaptionSelector::CaptionSelector( cref<td_self> in_caption_selector )
  : td_base( in_caption_selector )
{
}


// _____________________________________________________________________________
/// @copydoc ActiveSelector::CreateClone
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<Component>
  CaptionSelector::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 ActiveSelector::AddItem
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void CaptionSelector::AddItem( _in<td_DefString> in_str )
{
  if( m_sp_item )
  {
    m_sp_item->AddItem( in_str );
  }
}


// _____________________________________________________________________________
/// @copydoc ActiveSelector::DelItem
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void CaptionSelector::DelItem( _in<U32> in_del_idx )
{
  if( m_sp_item )
  {
    m_sp_item->DelItem( in_del_idx );
  }
}


// _____________________________________________________________________________
/// @copydoc ActiveSelector::Release
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void CaptionSelector::Release()
{
  if( m_sp_item )
  {
    m_sp_item->Release();
  }
}


// _____________________________________________________________________________
/// @copydoc ActiveSelector::SetSelectIndex
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void CaptionSelector::SetSelectIndex( _in<U32> in_select_idx )
{
  if( m_sp_item )
  {
    m_sp_item->SetSelectIndex( in_select_idx );
  }
}


// _____________________________________________________________________________
/// @copydoc ActiveSelector::GetNum
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
U32 CaptionSelector::GetNum() const
{
  if( m_sp_item )
  {
    return m_sp_item->GetNum();
  }
  return 0;
}


// _____________________________________________________________________________
/// @copydoc ActiveSelector::GetSelectIndex
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
U32 CaptionSelector::GetSelectIndex() const
{

  if( m_sp_item )
  {
    return m_sp_item->GetSelectIndex();
  }
  return -1;
}


// _____________________________________________________________________________
/// @copydoc ActiveSelector::GetSelectString
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
td_DefString CaptionSelector::GetSelectString() const
{
  if( m_sp_item )
  {
    return m_sp_item->GetSelectString();
  }
  return CPL_GUC_DEF_STR("");
}


// _____________________________________________________________________________
/// @copydoc ActiveSelector::GetItemString
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
td_DefString CaptionSelector::GetItemString( _in<U32> in_item_idx ) const
{
  if( m_sp_item )
  {
    return m_sp_item->GetItemString( in_item_idx );
  }
  return CPL_GUC_DEF_STR("");
}


} // namespace GUC
} // namespace CPL

