/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2016/11/18
/// 
/// @brief  タブコントロール
/// 
/// ****************************************************************************



#include "CPL_WIN_TabWindow.h"



namespace CPL {
namespace WIN {


// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydetails doxycomment::arg_in_hdl_win_parent
/// @copydetails doxycomment::arg_in_pos
/// @copydetails doxycomment::arg_in_size
/// @param[in] in_flag_bottom
///   : タブの位置を指定します。\n
///   : false - 上部に配置します。\n
///   : true  - 下部に配置します。
/// @param[in] in_tab_capacity
///   : タブの最大数を指定します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TabWindow::TabWindow
( _in<HWND     > in_hdl_win_parent
, _in<td_Coord2> in_pos
, _in<td_Coord2> in_size
, _in<bool     > in_flag_bottom
, _in<int      > in_tab_capacity
) : m_tab_comp_table( in_tab_capacity )
  , m_flag_auto_tab( true )
{
  LONG_PTR style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
  if( in_flag_bottom )
  {
    style = style | TCS_BOTTOM;  // 下にタブを作成
  }

  m_hdl_window =
    CreateWindowEx
      ( 0
      , WC_TABCONTROL
      , nullptr
      , static_cast<DWORD>(style)
      , in_pos.x, in_pos.y
      , in_size.x, in_size.y
      , in_hdl_win_parent
      , (HMENU)0
      , GetInstance_()
      , nullptr    // WM_CREATEのパラメーターなし
      );

  if( !zzf_SetHandle( m_hdl_window ) )
  {
    CPL_THROW( CPL_WIN_MSG_NOT_CREATE_TABCONTROL );
  }
  
  // サブクラス化
  if( !zzf_TAB_PROC() )
  {
    zzf_TAB_PROC() = zzf_GetProc( m_hdl_window );
  }
  zzf_SetProc( zzf_StaticProcTab );
}


// _____________________________________________________________________________
/// @brief タブの追加
/// 
/// @param[in] in_sp_win
///   : 追加するコンテナのポインタを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TabWindow::AddTabWindow( _in<sdptr<Container>> in_sp_win )
{
  if( in_sp_win == nullptr ) return;
//  if( tab_ac < 0 ) tab_ac = 0;

  str_type str[ 256 ] = { 0 };
  TC_ITEM  tc_item;
  tc_item.mask = TCIF_TEXT;
//  in_sp_win->GetTitle( tc_item.pszText, sizeof(tc_item.pszText));
  m_tab_comp_table.AddEnd( in_sp_win );
  in_sp_win->GetTitle( str, sizeof(str) );
  tc_item.pszText = str;
  ::SendMessage( m_hdl_window, TCM_INSERTITEM, (WPARAM)m_tab_comp_table.GetNum(), (LPARAM)&tc_item );

  // 親ウィンドウの変更
  in_sp_win->SetParent( m_hdl_window );

//  m_tab_comp_table[ tab_cnt ] = in_sp_win;
  // 表示設定
  if( m_tab_comp_table.GetNum()-1 != TabCtrl_GetCurSel( m_hdl_window ) )
  {
    m_tab_comp_table[ m_tab_comp_table.GetNum()-1 ]->Show( false );
  }
}


// _____________________________________________________________________________
/// @brief タブの追加
/// 
/// @param[in] in_title : 追加するタブの文字列を指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TabWindow::AddTabWindow( pio<str_type> in_title )
{
  sdptr<WIN::Container> win = CPL_MAKE_SHARED(Window);

  TC_ITEM tc_item;
  tc_item.mask = TCIF_TEXT;
  m_tab_comp_table.AddEnd( win );
  tc_item.pszText = in_title;
  ::SendMessage( m_hdl_window, TCM_INSERTITEM, (WPARAM)m_tab_comp_table.GetNum(), (LPARAM)&tc_item );
}


// _____________________________________________________________________________
/// @brief タブの描画
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TabWindow::DrawTab()
{
  int idx = TabCtrl_GetCurSel( m_hdl_window );
  if( idx < 0  ||  m_tab_comp_table[ idx ] == nullptr ) return;

  InvalidateRect( m_hdl_window, nullptr, false );
  ValidateRect( m_tab_comp_table[ idx ]->GetWindowHandle(), nullptr );
  InvalidateRect( m_tab_comp_table[ idx ]->GetWindowHandle(), nullptr, false );
//  m_tab_comp_table[ idx ]->On_Paint();
  ::UpdateWindow( m_tab_comp_table[ idx ]->GetWindowHandle() );
};


// _____________________________________________________________________________
/// @brief タブ切り替え処理
/// 
/// @param[in] in_tab_no
///   : 選択するタブのインデックスを指定します。\n
///   : 負数を指定すると、
/// 
/// @return 選択したインデックスを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int TabWindow::TabChange( _in<int> in_tab_no )
{
  for( int i = 0; i < (signed)m_tab_comp_table.GetNum(); ++i )
  {
    if( m_tab_comp_table[ i ] )
    {
      m_tab_comp_table[ i ]->Show( false );
    }
  }
  if( in_tab_no < 0 )
  {
    int idx = TabCtrl_GetCurSel( m_hdl_window );
    if( m_tab_comp_table[ idx ] )
    {
      m_tab_comp_table[ idx ]->Show( true );
//      m_tab_comp_table[ idx ]->On_Paint();
      ::UpdateWindow( m_tab_comp_table[ idx ]->GetWindowHandle() );
    }
    return TabCtrl_GetCurSel( m_hdl_window );
  }
  else
  {
    TabCtrl_SetCurSel( m_hdl_window, in_tab_no );
    return in_tab_no;
  }
}


// _____________________________________________________________________________
/// @brief 指定したコンテナがタブに含まれているかチェック
/// 
/// @param[in] in_ptr_check_window : 比較するコンテナののアドレスを指定します。
/// 
/// @return
/// 該当したインデックスを返します。\n
/// 該当しなかった場合、INVALID_INDEX32を返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
U32 TabWindow::GetTabWindowIndex( pin<Container> in_ptr_check_window ) const
{
  U32 tab_num = static_cast<U32>(m_tab_comp_table.GetNum());

  CPL_LOOP2( tab_num, idx )
  {
    if( m_tab_comp_table[ idx ].get() == in_ptr_check_window )
    {
      return idx;
    }
  }

  return INVALID_INDEX32;
}


// _____________________________________________________________________________
/// @brief 全ての子コンポーネントを含む最小のサイズを取得
/// 
/// @param[in] in_tab_check
///   : タブを含めるかどうかを指定します。\n
///   : true  - タブを含める。\n
///   : false - タブを含めない。
/// 
/// @return 全ての子コンポーネントを含む最小のサイズを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
td_Coord2 TabWindow::GetAdjustSize( _in<BOOL> in_tab_check ) const
{
  auto size = Container::GetAdjustSize( false );
  if( in_tab_check )
  {
    auto tab_size = GetAllTabSize();
    if( size.x < tab_size.x )
    {
      size.x = tab_size.x;
    }
    if( size.y < tab_size.y )
    {
      size.y = tab_size.y;
    }
  }
  return size;
}


// _____________________________________________________________________________
/// @brief 自動サイズ設定
/// 
/// @param[in] in_offs_size : 自動計算されたサイズ補正する値を指定します。
/// @param[in] in_tab_check
///   : タブを含めるかどうかを指定します。\n
///   : true  - タブを含める。\n
///   : false - タブを含めない。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TabWindow::AdjustSize( _in<td_Coord2> in_offs_size, _in<BOOL> in_tab_check )
{
  SetWindowSize( GetAdjustSize(in_tab_check) + in_offs_size, true, true );
}


// _____________________________________________________________________________
/// @brief 選択しているタブのインデックスの取得
/// 
/// @return 選択しているタブのインデックスを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int TabWindow::GetSelectIndex() const
{
  return TabCtrl_GetCurSel( m_hdl_window );
}


// _____________________________________________________________________________
/// @brief 全てのタブが収まる最小サイズの取得
/// 
/// @return 全てのタブが収まる最小サイズを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
td_Coord2 TabWindow::GetAllTabSize() const
{
  WIN::Rect rt;
  int tab_idx = static_cast<int>(m_tab_comp_table.GetNum()) - 1;
  TabCtrl_GetItemRect( m_hdl_window, tab_idx, &rt );
  return td_Coord2( int(rt.right), int(rt.bottom) );
}


// _____________________________________________________________________________
/// @brief 選択しているタブのコンテナの取得
/// 
/// @return 選択しているタブのコンテナのスマートポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<Container> TabWindow::GetSelectWindow() const
{
  return m_tab_comp_table[ TabCtrl_GetCurSel( m_hdl_window ) ];
}


// _____________________________________________________________________________
/// @brief 選択しているタブのコンテナのみ表示
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TabWindow::ShowSelectFormOnly() const
{
  const size_t num = m_tab_comp_table.GetNum();
  auto sp_win_select = GetSelectWindow();

  CPL_LOOP2( num, i )
  {
    m_tab_comp_table[ i ]->Show( sp_win_select == m_tab_comp_table[ i ] );
  }
}



// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// タブウィンドウ用拡張プロシージャ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LRESULT
  CALLBACK TabWindow::zzf_StaticProcTab
  ( HWND   in_hdl_window,
    UINT   in_message,
    WPARAM in_wparam,
    LPARAM in_lparam )
{
  TabWindow* in_ptr_tab_window =
    dynamic_cast<TabWindow*>(GetHandleToPointer(in_hdl_window));
  bool flag = false;
  if( in_ptr_tab_window )
  {
    flag =
      in_ptr_tab_window->DefaultProc_(
        in_message,
        in_wparam,
        in_lparam ) != 0;
  }
  if( !flag )
  {
    return
      CallWindowProc(
        zzf_TAB_PROC(),
        in_hdl_window,
        in_message,
        in_wparam,
        in_lparam );
  }
  else
  {
    return 0;
  }
}



// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 拡張プロシージャ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF
  TabWindow::DefaultProc_
    ( _in<UINT  > in_message
    , _in<WPARAM> in_wparam
    , _in<LPARAM> in_lparam
    )
{
  if( in_message == WM_COMMAND  ||
      in_message == WM_NOTIFY   ||
      in_message == WM_HSCROLL  ||
      in_message == WM_VSCROLL  || 
      in_message >= kID_CPL )
  {
    SendParentMessage( in_message, in_wparam, in_lparam );
    return 0;
  }
  else
  {
    return Window::DefaultProc_( in_message, in_wparam, in_lparam );
  }
}



} // namespace WIN
} // namespace CPL

