/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2010/X/X - 2016/12/18
/// 
/// @brief  ツリービューコンポーネント。
/// 
/// ****************************************************************************

#include "CPL_GUC_TreeView.h"


namespace CPL {
namespace GUC {


const float cpl_guc_treeview_offs_x = 20;

// _____________________________________________________________________________
/// @brief ツリービューの標準背景カラー
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet> TreeViewBox::GetDefaultColor_TreeViewBoxBG()
{
  static DX::RectColor4P
    gradiate
    ( DX::ColorType(1.0f, 1.0f, 1.0f, 1.0f),
      DX::ColorType(0.9f, 0.9f, 0.9f, 1.0f),
      DX::ColorType(0.8f, 0.8f, 0.8f, 1.0f),
      DX::ColorType(0.9f, 0.9f, 0.9f, 1.0f) );
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , DX::RectColor4P( kCOLOR_WHITE     ) * gradiate
        , DX::RectColor4P( kCOLOR_WHITE     ) * gradiate
        , DX::RectColor4P( kCOLOR_BLUE      ) * gradiate
        , DX::RectColor4P( kCOLOR_LIGHTGRAY ) * gradiate
        );
  return sp_color;
}

// _____________________________________________________________________________
/// @brief ツリービューの標準フレームカラー
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet> TreeViewBox::GetDefaultColor_TreeViewBoxFrame()
{
  static DX::RectColor4P
    gradiate
      ( DX::ColorType(1.0f, 1.0f, 1.0f, 1.0f)
      , DX::ColorType(0.9f, 0.9f, 0.9f, 1.0f)
      , DX::ColorType(0.8f, 0.8f, 0.8f, 1.0f)
      , DX::ColorType(0.9f, 0.9f, 0.9f, 1.0f)
      );
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , DX::RectColor4P( kCOLOR_BLACK     ) * gradiate
        , DX::RectColor4P( kCOLOR_BLACK     ) * gradiate
        , DX::RectColor4P( kCOLOR_WHITE     ) * gradiate
        , DX::RectColor4P( kCOLOR_LIGHTGRAY ) * gradiate
        );
  return sp_color;
}

// _____________________________________________________________________________
/// @brief ツリービューの標準テキストカラー
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet> TreeViewBox::GetDefaultColor_TreeViewBoxText()
{
  static DX::RectColor4P
    gradiate
      ( DX::ColorType(1.0f, 1.0f, 1.0f, 1.0f)
      , DX::ColorType(0.9f, 0.9f, 0.9f, 1.0f)
      , DX::ColorType(0.8f, 0.8f, 0.8f, 1.0f)
      , DX::ColorType(0.9f, 0.9f, 0.9f, 1.0f)
      );
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , DX::RectColor4P( kCOLOR_BLACK     ) * gradiate
        , DX::RectColor4P( kCOLOR_BLACK     ) * gradiate
        , DX::RectColor4P( kCOLOR_WHITE     ) * gradiate
        , DX::RectColor4P( kCOLOR_LIGHTGRAY ) * gradiate
        );
  return sp_color;
}


// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydoc doxycomment::arg_in_sp_component_for_parent
/// @copydoc doxycomment::arg_in_position_for_component
/// @copydoc doxycomment::arg_in_size_for_component
/// @param[in] in_sp_item_data
///   : 追加するアイテムコンポーネントのスマートポインタを指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TreeViewBox::TreeViewBox
( _in<sdptr<Component>> in_sp_component_for_parent
, _in<float2          > in_position_for_component
, _in<float2          > in_size_for_component
, _in<sdptr<Component>> in_sp_item_data
) : RenderOwner
    ( in_sp_component_for_parent
    , in_position_for_component
    , in_size_for_component
    , float2(0,0)
    , in_size_for_component - float2(2,2)
    )
{
  //// アイテムを配置するレイヤーを作成（スクロール移動がしやすいため）
  //// ツリービューノードはこのレイヤー下に作成すること。
  //m_sp_layer = Factory<Layer>::Create( GetClient() );

  // ルートアイテム設定
  if( in_sp_item_data )
  {
    m_sp_node_root =
      Factory<TreeViewNode>::Create
        ( GetComponent_RenderClient()
        , in_sp_item_data
        );

    AutoRepositionItems();
  }

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


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TreeViewBox::TreeViewBox( cref<TreeViewBox> in_tree_view_box )
  : td_base( in_tree_view_box )
  , m_sp_node_root
    { FindComponentT_by_UserID<TreeViewNode>( in_tree_view_box.m_sp_node_root )
    }
  , m_sp_node_select
    { FindComponentT_by_UserID<TreeViewNode>( in_tree_view_box.m_sp_node_select )
    }
{
  m_sp_node_root  ->SetAutoUserID();
  m_sp_node_select->SetAutoUserID();
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::CreateClone
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<Component>
  TreeViewBox::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::Component::On_DrawBackground(_in<float4>)
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TreeViewBox::On_DrawBackground( _in<float4> in_rect )
{
  Component::On_DrawBackground( in_rect );
}


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


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

  Component::On_DrawBackground( in_rect );
/*
  //
  const int cpl_guc_treeview_offs_x = static_cast<int>(m_sp_scroll_h->GetPos());
  const int offs_y = static_cast<int>(m_sp_scroll_v->GetPos());

  // ループ終端の検索
  SpComponent sp_node_end = GetRootNode().GetNodeEnd();
  while( sp_node_end.GetNodeChild() )
  {
    sp_node_end = sp_node_end.GetNodeChild();
  }
  sp_node_end = sp_node_end.GetNodeEnd();
  sp_node_end = sp_node_end.GetNodeNextAll();

  // 開閉ボタンの描画
  WpTreeViewNode sp_node = GetRootNode();
  while( sp_node != sp_node_end )
  {
    short4 rt = sp_node->GetRectCoord();
    MappingPosition( sp_node->GetBelongComponent(), GetClient(), (short2_ptr)&rt, 2 );
    rt.x = rt.x - 15;
    rt.y = rt.y + 2;
    rt.z = rt.x + 12;
    rt.w = rt.y + 12;

    zzf_DrawRect( rt, COLOr_WHITE );

    sp_node = sp_node.GetNodeNextAll();
  }
  */
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseDown
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  TreeViewBox::On_MouseDown
    ( _in<sdptr<Component>> in_sp_component
    , _in<float           > in_mouse_x
    , _in<float           > in_mouse_y
    , _in<eMouseButton    > in_type_mouse_btn
    )
{
  // デフォルト処理呼び出し
  td_base::On_MouseDown
    ( in_sp_component
    , in_mouse_x
    , in_mouse_y
    , in_type_mouse_btn
    );

  if( in_sp_component == this->GetLinkMyself() )
  {
  }
  else
  {
    auto sp_tv_node =
      FindNode_to_CompID( in_sp_component->GetComponentID() );

    if( sp_tv_node )
    {
      // クリックされたのが、ボタンの場合。
      if( in_sp_component == sp_tv_node->GetComponent_ExpandButton() )
      {
        AutoRepositionItems();
        
        On_ItemExpand( sp_tv_node );
      }

      SetSelectNode( sp_tv_node );
    }
  }

  return eEventReturnID::SendParent_All;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_Size
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  TreeViewBox::On_Size( _in<sdptr<Component>> in_sp_component )
{
  if( in_sp_component == this->GetLinkMyself()  &&
      GetInitialized() >= zzf_GetClassLevel() )
  {
    // ワーキングエリアの調整（スクロールバー調整）
    auto const size_frame = GetFrameSize() * IsDrawFrame();
    auto const rect_comp = GetRectCoord();
    SetupWorkingArea
      ( float4
          ( size_frame
          , size_frame
          , rect_comp.Width()  - size_frame
          , rect_comp.Height() - size_frame
          )
      , GetSize_WorkingArea()
      );

    ////
    //m_sp_layer->SetPosition
    //  ( short2( static_cast<short>(-GetComponent_ScrollH()->GetPos() - cpl_guc_treeview_offs_x)
    //          , static_cast<short>(-GetComponent_ScrollV()->GetPos()) )
    //  );
    Update();
  }

  return eEventReturnID::SendParent_Render;
}


//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//// 
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//eEventReturnID
//  TreeViewBox::On_UserProc
//    ( _in<sdptr<Component>> in_sp_component
//    , _in<long            > in_message
//    , _in<WPARAM          > in_wparam
//    , _in<LPARAM          > in_lparam
//    )
//{
//  switch( in_message )
//  {
//  case eID::ScrollBarChangeValue:
//    m_sp_layer->SetPosition
//      ( short2
//        ( static_cast<short>(-GetComponent_ScrollH()->GetPos() - cpl_guc_treeview_offs_x)
//        , static_cast<short>(-GetComponent_ScrollV()->GetPos())
//        )
//      );
//    break;
//
//  case eID::ValueChanged:
//    break;
//  }
//
//  return eEventReturnID::SendParent;
//}

/*
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// アイテムの追加　※ 子供に追加
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WpComponent TreeViewBox::AddItemChild(
      WpComponent           in_sp_item_parent,
      SMPTR_BASE_TREE_VIEW_ITEM in_sp_new_item )
{
  if( in_sp_item_parent == nullptr )
  {
    return nullptr;
  }

  ITEM_NODE* ptr_new_node = new ITEM_NODE( in_sp_new_item );

  if( m_ptr_node_root == nullptr )
  {
    m_ptr_node_root = ptr_new_node;

    return ptr_new_node;
  }
  else
  {
    return in_sp_item_parent->AddNodeChild( ptr_new_node );
  }
}
*/
/*
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// アイテムの追加　※ 次に追加
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WpComponent TreeViewBox::AddItemNext(
      WpComponent           in_ptr_item_prev,
      SMPTR_BASE_TREE_VIEW_ITEM in_sp_new_item )
{
  if( in_ptr_item_prev == nullptr )
  {
    return nullptr;
  }

  ITEM_NODE* ptr_new_node = new ITEM_NODE( in_sp_new_item );

  if( m_ptr_node_root == nullptr )
  {
    m_ptr_node_root = ptr_new_node;

    return m_ptr_node_root;
  }
  else
  {
    return in_ptr_item_prev->AddNodeNext( ptr_new_node );
  }
}
*/

// _____________________________________________________________________________
/// @brief ツリービューノードの追加
/// 
/// @param[in] in_sp_node_for_parent
///   : 親となるノードのスマートポインタを指定します。\n
///   : nullptrを指定すると、ルートクラスへの追加となります。
/// @param[in] in_sp_new_item
///   : 新しいノードに保持させるコンポーネントを指定します。
/// 
/// @return 追加したノードのポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<TreeViewNode>
  TreeViewBox::AddTreeViewNode
    ( _in<sdptr<TreeViewNode>> in_sp_node_for_parent
    , _in<sdptr<Component   >> in_sp_new_item
    )
{
  // 
  sdptr<TreeViewNode> sp_new_node;
  if( in_sp_node_for_parent )
  {
    sp_new_node = Factory<TreeViewNode>::Create( in_sp_node_for_parent, in_sp_new_item );
    in_sp_node_for_parent->GetComponent_ExpandButton()->SetStateVisible( true );
  }
  else
  {
    sp_new_node =
      Factory<TreeViewNode>::Create
        ( GetComponent_RenderClient()
        , in_sp_new_item
        );
  }

  if( m_sp_node_root == nullptr )
  {
    m_sp_node_root = sp_new_node;
  }

  //AutoRepositionItems();

  return sp_new_node;
}

// _____________________________________________________________________________
/// @brief ツリービューノードの削除
/// 
/// @param[in] in_sp_del_node
///   : 削除対象のツリービューノードを指すスマートポインタを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TreeViewBox::DeleteTreeViewNode( _in<sdptr<TreeViewNode>> in_sp_del_node )
{
  if( !in_sp_del_node )
  {
    return;
  }

  // 指定ノードがツリー内かチェック。
  if( GetRootNode()->CheckLinkDownClass( in_sp_del_node ) )
  {
    // 
    if( !in_sp_del_node->GetLinkPrev()  &&  !in_sp_del_node->GetLinkNext() )
    {
      sdptr<TreeViewNode> sp_node_parent =
        std::dynamic_pointer_cast<TreeViewNode>(in_sp_del_node->GetLinkParent());
      if( sp_node_parent )
      {
        sp_node_parent->GetComponent_ExpandButton()->SetStateVisible( false );
      }
    }

    // 削除ノードが選択対象ならば、選択対象を無効にする。
    if( in_sp_del_node == GetSelectNode() )
    {
      m_sp_node_select.reset();
    }

    // 自身および保持するノードを全て開放。
    in_sp_del_node->DetachAll();

    //AutoRepositionItems();
  }
}


// _____________________________________________________________________________
/// @brief 選択ノードを変更。
/// 
/// @param[in] in_sp_node : 選択するツリービューノードのポインタを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TreeViewBox::SetSelectNode( _in<sdptr<TreeViewNode>> in_sp_node ) noexcept
{
  // 選択ノード設定
  if( GetSelectNode() )
  {
    GetSelectNode()->SetStateDrawFrame( false );
  }
  m_sp_node_select = in_sp_node;
  m_sp_node_select->SetStateDrawFrame( true );

  // コールバック関数呼び出し
  On_ItemSelect( in_sp_node );
}


// _____________________________________________________________________________
/// @brief コンポーネントＩＤに対応するノードの検索
/// 
/// 指定したＩＤと一致するノード、もしくは一致するアイテムを保持するノードを取得します。
/// 
/// @param[in] in_item_comp_ID : 検索するコンポーネントＩＤ.
/// 
/// @return
/// ヒットしたツリービューノードのスマートポインタを返します。\n
/// ヒットしなければnullptrを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<TreeViewNode>
  TreeViewBox::FindNode_to_CompID( _in<U32> in_item_comp_ID )
{
  sdptr<Component> sp_node_search( GetRootNode() );

  while( sp_node_search )
  {
    // チェックするコンポーネントがツリービューノードでない場合、
    // その親がツリービューノードかを検査し、その親がツリービューノードならば
    // チェックするコンポーネントのIDを比較し、IDが一致したらツリービューノードを返す。
    if( SmartCast<TreeViewNode const*>(sp_node_search) == nullptr ) // 変換不可ならば
    {
      auto sp_tv_node =
        std::dynamic_pointer_cast<TreeViewNode>(sp_node_search->GetLinkParent());
      if( sp_tv_node )
      {
        if( sp_node_search->GetComponentID() == in_item_comp_ID )
        {
          return sp_tv_node;
        }
      }
    }

    sp_node_search = sp_node_search->GetLinkNextAll();
  }

  //SpComponent      sp_node_end = sp_node_item->GetNodeChild();
  //if( !sp_node_end )
  //{
  //  return nullptr;
  //}

  //while( sp_node_end->GetNodeChild() )
  //{
  //  sp_node_end = sp_node_end->GetNodeChild();
  //}
  //sp_node_end = sp_node_end.GetNodeEnd().GetNodeNextAll();

  //while( sp_node_item  &&  sp_node_item != sp_node_end )
  //{
  //  if( sp_node_item->GetComponentID() == in_item_comp_ID )
  //  {
  //    return sp_node_item;
  //  }

  //  sp_node_item = sp_node_item.GetNodeNextAll();
  //}

  return nullptr;
}


// _____________________________________________________________________________
/// @brief ユーザーＩＤに対応するノードの検索
/// 
/// 指定したユーザーＩＤと一致するコンポーネントを持つノードのポインタを取得。
/// 
/// @param[in] in_item_user_ID : 検索するユーザーＩＤを指定します。
/// 
/// @return
/// ヒットしたツリービューノードのポインタを返します。\n
/// ヒットしなければnullptrを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<TreeViewNode>
  TreeViewBox::FindNode_to_UserID( _in<std::string> in_item_user_ID )
{
  auto sp_node_search( GetRootNode() );

  while( sp_node_search )
  {
    if( sp_node_search->GetUserID() == in_item_user_ID )
    {
      return sp_node_search;
    }
    sp_node_search = sp_node_search->GetLinkNextAllTVN();
  }

  //WpTreeViewNode sp_node_item( GetRootNode() );
  //SpComponent      sp_node_end = sp_node_item->GetNodeChild();

  //while( sp_node_end->GetNodeChild() )
  //{
  //  sp_node_end = sp_node_end->GetNodeChild();
  //}
  //sp_node_end = sp_node_end.GetNodeEnd().GetNodeNextAll();

  //while( sp_node_item  &&  sp_node_item != sp_node_end )
  //{
  //  if( sp_node_item->GetUserID() == in_item_user_ID )
  //  {
  //    return sp_node_item;
  //  }

  //  sp_node_item = sp_node_item.GetNodeNextAll();
  //}

  return nullptr;
}

// _____________________________________________________________________________
/// @brief アイテムの解放
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TreeViewBox::ReleaseItem()
{
//  DEL<ITEM_NODE*>( m_ptr_node_root, nullptr );
//  DEL_CLEAR( m_ptr_node_root );

//  m_ptr_node_select = nullptr;

  GetRootNode()->DetachAll();
}

/*
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ノードを指定したノードの前に移動
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TreeViewBox::MoveItemPrev(
      ITEM_NODE* in_ptr_item_base,
      ITEM_NODE* in_ptr_item_target )
{
  // ツリー内のアイテムかどうか検査
  if( in_ptr_item_target )
  {
    if( !m_ptr_node_root->CheckNodeAllClass( in_ptr_item_target ) )
    {
      return;
    }
  }
  else
  {
    return;
  }

  // 移動処理
  if( in_ptr_item_base ) // 移動先アイテムが指定されている場合
  {
    if( !m_ptr_node_root->CheckNodeAllClass( in_ptr_item_base ) )
    {
      // 移動先の指すアイテムポインタが自身のツリー内に無い場合は無効
      return;
    }
    ef( in_ptr_item_target->CheckNodeDownClass( in_ptr_item_base ) )
    {
      // 移動先が子供の場合は無効
      return;
    }
    in_ptr_item_target->MoveNodePrev( in_ptr_item_base );
  }
  else // 移動先なしの場合は
  {
    in_ptr_item_target->MoveNodePrev();
  }
  m_ptr_node_root = in_ptr_item_target->GetNodeRoot();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ノードを指定したノードの次に移動
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TreeViewBox::MoveItemNext(
      ITEM_NODE* in_ptr_item_base,
      ITEM_NODE* in_ptr_item_target )
{
  // ツリー内のアイテムかどうか検査
  if( in_ptr_item_target )
  {
    if( !m_ptr_node_root->CheckNodeAllClass( in_ptr_item_target ) )
    {
      return;
    }
  }
  else
  {
    return;
  }
  
  // 移動処理
  if( in_ptr_item_base ) // 移動先アイテムが指定されている場合
  {
    if( !m_ptr_node_root->CheckNodeAllClass( in_ptr_item_base ) )
    {
      // 移動先の指すアイテムポインタが自身のツリー内に無い場合は無効
      return;
    }
    ef( in_ptr_item_target->CheckNodeDownClass( in_ptr_item_base ) )
    {
      // 移動先が子供の場合は無効
      return;
    }
    in_ptr_item_target->MoveNodeNext( in_ptr_item_base );
  }
  else // 移動先なしの場合は
  {
    in_ptr_item_target->MoveNodeNext();
  }
  m_ptr_node_root = in_ptr_item_target->GetNodeRoot();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 指定したノードを一つ上層に移動
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TreeViewBox::MoveItemUp( ITEM_NODE* in_ptr_item_target )
{
  if( in_ptr_item_target == nullptr )
  {
    return;
  }

  // ツリー内のアイテムかどうか検査
  if( !m_ptr_node_root->CheckNodeAllClass( in_ptr_item_target ) )
  {
    return;
  }
  
  // 移動処理
  in_ptr_item_target->MoveNodeParent();

  // ルートを再設定
  m_ptr_node_root = in_ptr_item_target->GetNodeRoot();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 指定したノードを一つ下層に移動
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TreeViewBox::MoveItemDown( ITEM_NODE* in_ptr_item_target )
{
  if( in_ptr_item_target == nullptr )
  {
    return;
  }

  // ツリー内のアイテムかどうか検査
  if( !m_ptr_node_root->CheckNodeAllClass( in_ptr_item_target ) )
  {
    return;
  }
  
  //
  if( in_ptr_item_target->GetLinkPrev() )
  {
    in_ptr_item_target->GetLinkPrev()->AddNodeChild( in_ptr_item_target );
  }
}
*/


// _____________________________________________________________________________
/// @brief アイテムの整列
/// 
/// ノードの保持するアイテムのサイズを変更した場合などに呼び出す必要があります。
/// 
/// @param[in] in_sp_tv_node      : 整列するルートとなるノードを指定します。
/// @param[in] in_sp_tv_node_prev : 整列するノードの前のノードを指定します。
/// 
/// @return 配置されたアイテムの表示に必要な最大領域サイズを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
float2
  TreeViewBox::AutoRepositionItems
    ( _in<sdptr<TreeViewNode>> in_sp_tv_node
    , _in<sdptr<TreeViewNode>> in_sp_tv_node_prev
    )
{
  auto sp_tv_node = in_sp_tv_node;
  float2 work_size_max( 1, 1 );
  //
  static float4 rt_prev(0,0,0,0);

  if( !sp_tv_node )
  {
    sp_tv_node = GetRootNode();
    rt_prev = float4(0,0,0,0);
  }
  else
  if( in_sp_tv_node_prev )
  {
    rt_prev = in_sp_tv_node_prev->GetRectCoord();
  }

  sp_tv_node->SetPosition
    ( float2( cpl_guc_treeview_offs_x
            , rt_prev.w + 2
            )
    );

  auto rt = sp_tv_node->GetRectCoord();
  // オーナーウィンドウ座標への変換
  MappingPosition
    ( sp_tv_node->GetBelongComponent( eParentType::Position )
    , this->GetOwnerWindow() //IsOwner() ? nullptr : in_sp_draw_owner,
    , (float2_ptr)&rt
    , 2
    );
  // 最大サイズ保存
  work_size_max.x = Max( work_size_max.x, rt.right );
  work_size_max.y = Max( work_size_max.y, rt.bottom );

  // child items
  sdptr<TreeViewNode>
    sp_tv_node_child = sp_tv_node->GetLinkChildTVN(); // 
  if( sp_tv_node_child )
  {
    if( sp_tv_node->GetFlag_Expand() )
    {
      auto size = AutoRepositionItems( sp_tv_node_child, sp_tv_node );

      auto sp_tvn = sp_tv_node_child;
      while( sp_tvn )
      {
        sp_tvn->SetStateVisible( true );
        sp_tvn = sp_tvn->GetLinkNextTVN();
      }

      //rt = sp_tv_node_child->GetRectCoord();
      work_size_max.x = Max( work_size_max.x, size.x );
      work_size_max.y = Max( work_size_max.y, size.y );
    }
    else
    {
      auto sp_tvn = sp_tv_node_child;
      while( sp_tvn )
      {
        sp_tvn->SetStateVisible( false );
        sp_tvn = sp_tvn->GetLinkNextTVN();
      }
    }
  }

  //
  sp_tv_node->AdjustSize();

  // next
  if( auto sp_tv_node_next = sp_tv_node->GetLinkNextTVN() )
  {
    auto size =
      AutoRepositionItems
        ( sp_tv_node_next
        , (sp_tv_node->GetFlag_Expand() && sp_tv_node_child)
            ? std::static_pointer_cast<TreeViewNode>(sp_tv_node_child->GetLinkEnd())
            : sp_tv_node
        );
    work_size_max.x = Max( work_size_max.x, size.x );
    work_size_max.y = Max( work_size_max.y, size.y );
  }

  SetupWorkingArea( work_size_max );

  Update();

  return work_size_max;
}


//// _____________________________________________________________________________
///// @brief スクロールバー調整。
///// 
///// @param[in] in_client_max_view_size
/////   : スクロールバーの最大値となるサイズを指定。\n
/////   : 原則的にはアイテムが配置される最大領域サイズにとなる。
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//void TreeViewBox::SetupScrollBar( _in<short2> in_client_max_area_size )
//{
//  // スクロールバーが必要かどうか設定。
//  short2 this_size = GetSize();
//  bool f_scb_h = (in_client_max_area_size.x > this_size.x);
//  bool f_scb_v = (in_client_max_area_size.y > this_size.y);
//  // 横スクロールバー
//  if( f_scb_h )
//  {
//    auto sp_scroll_h = GetComponent_ScrollH();
//    sp_scroll_h->SetMax( in_client_max_area_size.x );
//    sp_scroll_h->SetPage( this_size.x );
//    sp_scroll_h->SetRectCoord(
//      short4( 0, this_size.y-sp_scroll_h->GetSize().y,
//              this_size.x, this_size.y ) );
//    sp_scroll_h->SetStateVisible( true );
//    this_size.y -= sp_scroll_h->GetSize().y;
//  }
//  else
//  {
//    GetComponent_ScrollH()->SetStateVisible( false );
//  }
//  // 縦スクロールバー
//  if( f_scb_v )
//  {
//    auto sp_scroll_v = GetComponent_ScrollV();
//    auto sp_scroll_h = GetComponent_ScrollH();
//    sp_scroll_v->SetMax( in_client_max_area_size.y );
//    sp_scroll_v->SetPage( this_size.y );
//    sp_scroll_h->SetRectCoord(
//      short4( this_size.x-sp_scroll_v->GetSize().x, 0,
//              this_size.x, this_size.y ) );
//    sp_scroll_v->SetStateVisible( true );
//    this_size.x -= sp_scroll_v->GetSize().x;
//  }
//  else
//  {
//    GetComponent_ScrollV()->SetStateVisible( false );
//  }
//
//  // クライアントサイズを調整
//  GetClient()->SetSize( this_size );
//}


} // namespace GUC
} // namespace CPL

