/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   200X/X/X - 2016/11/15
/// 
/// @brief  基本コンポーネントクラス。
/// 
/// ****************************************************************************



//#include "CPL_WIN_Window.h"
#include "CPL_WIN_ScrollBar.h"
//#include "CPL_WIN_Graphics.h"
#include "CPL_WIN_ToolTip.h"
#include "../../Base/CPL_WIN_Mouse.h"
#include "../../Base/CPL_WIN_Keyboard.h"


namespace CPL {
namespace WIN {
  
unsigned char expandImage[] = {
  0x42,0x4d,0xee,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x00,0x00,0x00,0x28,0x00,0x00,0x00,0x14,0x00,
  0x00,0x00,0x0a,0x00,0x00,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x78,0x00,0x00,0x00,0x00,0x00,
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  0x80,0x00,0x00,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x80,0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x80,
  0x00,0x00,0x80,0x80,0x80,0x00,0xc0,0xc0,0xc0,0x00,0x00,0x00,0xff,0x00,0x00,0xff,0x00,0x00,0x00,0xff,
  0xff,0x00,0xff,0x00,0x00,0x00,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0xff,0xff,0xff,0x00,0xff,0xff,
  0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x0f,
  0x00,0x00,0x0f,0xff,0xff,0xff,0x0f,0x0f,0xff,0xff,0xff,0x0f,0x00,0x00,0x0f,0xff,0x0f,0xff,0x0f,0x0f,
  0xff,0xff,0xff,0x0f,0x00,0x00,0x0f,0xff,0x0f,0xff,0x0f,0x0f,0xff,0xff,0xff,0x0f,0x00,0x00,0x0f,0x00,
  0x00,0x0f,0x0f,0x0f,0x00,0x00,0x0f,0x0f,0x00,0x00,0x0f,0xff,0x0f,0xff,0x0f,0x0f,0xff,0xff,0xff,0x0f,
  0x00,0x00,0x0f,0xff,0x0f,0xff,0x0f,0x0f,0xff,0xff,0xff,0x0f,0x00,0x00,0x0f,0xff,0xff,0xff,0x0f,0x0f,
  0xff,0xff,0xff,0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,0x00,0x00,0x0f,0x00,0x00,
};





// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 新規コンポーネントID取得
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF BaseComponent::zzf_NewComponentID_()
{
  // IDの使用フラグをセット
  SDEF new_idx = sm_id_table().GetMinFalseIdx();
  if( !FAILED_INDEX(new_idx) )
  {
    sm_id_table().SetCheck( new_idx, true );
  }
  return new_idx;
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// コンポーネントIDの削除
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void BaseComponent::zzf_DelComponentID_( SDEF id )
{
  sm_id_table().SetCheck( id, false );
}


// _____________________________________________________________________________
/// @brief Componentコンストラクタ
/// 
/// @param[in] in_event_mask
///   : イベントマスク。\n
///   : 現仕様ではtrueを指定することでマウスキャプチャーを無効にする。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component::Component( U8 in_event_mask )
  : m_hdl_window( nullptr )
  , m_hdl_win_parent( nullptr )
{
  CPL_BLOCK_ONCE
  {
    // ウィンドウクラス登録
    WNDCLASSEX wcex;
    memset( &wcex, 0, sizeof(wcex) );
    wcex.cbSize        = sizeof(WNDCLASSEX);
    wcex.hInstance     = GetInstance_();
    wcex.style         = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc   = (WNDPROC)zzf_staticProc_;
    wcex.lpszClassName = zzf_GetClassName();
    wcex.hCursor       = nullptr;
    wcex.hbrBackground = nullptr;
    wcex.hIcon         = nullptr;

    ::RegisterClassEx( &wcex );

    // コモンコントロール用に初期化
    ::InitCommonControls();
  }

  m_def_cursor        = ::LoadCursor( nullptr, (LPCTSTR)IDC_ARROW );
  m_back_brush        = (HBRUSH)(COLOR_BTNFACE+1);
  m_back_color        = -1;
  m_flag_win_instance = false;
  m_event_mode        = eEventMode::Throw;
  m_event_mask        = in_event_mask;
  m_flag_child_size   = false;

  SetFont( *sm_sp_DefFont_MS_Gothic() );
}


// _____________________________________________________________________________
/// @brief デストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component::~Component()
{
  Destroy();
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ハンドル設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool Component::zzf_SetHandle( HWND in_hanele )
{
  if( m_flag_win_instance )
  {
    return true;
  }

  m_hdl_window = in_hanele;

  if( !in_hanele )
  {
    return false;
  }

  if( !::SetProp( m_hdl_window, GetPropertyName_(), this ) )
  {
    return false;
  }
  else
  {
    m_flag_win_instance = true;
    return true;
  }
}


// _____________________________________________________________________________
/// @brief コンポーネントサイズの取得
/// 
/// @return コンポーネントのサイズを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
td_Coord2 Component::GetWindowSize() const
{
  Rect rt;
  ::GetWindowRect( m_hdl_window, &rt );
  return { int(rt.right - rt.left), int(rt.bottom - rt.top) };
}


// _____________________________________________________________________________
/// @brief コンポーネント左上座標の取得
/// 
/// @return コンポーネントの左上の座標を返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
td_Coord2 Component::GetWindowPos() const
{
  Rect rt;
  GetWindowRect( rt, true );
  return { (int)rt.left, (int)rt.top };
}


// _____________________________________________________________________________
/// @brief コンポーネントの４点座標の取得
/// 
/// @copydetails doxycomment::arg_out_rect
/// @param[in] in_flag_parent_mapping
///   : true  - 親からの相対位置を取得します。\n
///   : false - スクリーン空間上の座標を取得します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  Component::GetWindowRect
    ( rout<Rect> out_rect
    , _in <bool> in_flag_parent_mapping
    ) const
{
  ::GetWindowRect( m_hdl_window, &out_rect );
  STYLE Style( GetWindowLongPtr( m_hdl_window, GWL_STYLE ) );

  if( in_flag_parent_mapping  &&  Style.Win.child ) // トップレベルウィンドウ対応？
  {
    // 親からの相対位置に変換する
    HWND hParent = GetParentWindowHandle();
    ::MapWindowPoints( nullptr, hParent, (POINT*)&out_rect, 2 );
  }
}


// _____________________________________________________________________________
/// @brief クライアントサイズの取得
/// 
/// @return クライアントサイズを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
td_Coord2 Component::GetClientSize() const
{
  td_Coord2 size;
  Rect rt;
  ::GetClientRect( m_hdl_window, &rt );
  size.x = int(rt.right - rt.left);
  size.y = int(rt.bottom - rt.top);
  return size;
}


// _____________________________________________________________________________
/// @brief サイズ変更
/// 
/// @copydetails doxycomment::arg_in_size
/// @copydetails doxycomment::arg_in_flag_redraw
/// @copydetails doxycomment::arg_in_flag_client_size
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  Component::SetWindowSize
    ( _in<td_Coord2> in_size
    , _in<bool     > in_flag_redraw
    , _in<bool     > in_flag_client_size
    )
{
  WIN::Rect rt;
  GetWindowRect( rt );

  auto size = in_size;
  UINT flags = SWP_NOMOVE | SWP_NOZORDER;
  if( !in_flag_redraw )
  {
    flags |= SWP_NOREDRAW;
  }
  if( in_flag_client_size )
  {
    auto size_client = GetClientSize();
    td_Coord2 size_win( (int)rt.GetWidth(), (int)rt.GetHeight() );
    size += size_win - size_client;
    ::SetWindowPos( m_hdl_window, HWND_TOP, 0, 0, size.x, size.y, flags );
  }
  else
  {
    ::SetWindowPos( m_hdl_window, HWND_TOP, 0, 0, size.x, size.y, flags );
  }
}


// _____________________________________________________________________________
/// @brief ウィンドウ位置の指定
/// 
/// @copydetails doxycomment::arg_in_pos
/// @copydetails doxycomment::arg_in_flag_redraw
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::SetWindowPos( _in<td_Coord2> in_pos, _in<bool> in_flag_redraw )
{
  UINT flags = SWP_NOSIZE | SWP_NOZORDER;
  if( !in_flag_redraw )
  {
    flags |= SWP_NOREDRAW;
  }
  ::SetWindowPos
    ( m_hdl_window
    , HWND_TOP
    , in_pos.x
    , in_pos.y
    , 0, 0
    , flags
    );
}


// _____________________________________________________________________________
/// @brief ウィンドウの４点座標の設定
/// 
/// @copydoc doxycomment::arg_in_rect
/// @copydoc doxycomment::arg_in_flag_client_size
/// @param[in] in_rect_factor
///   : 指定した４点座標のどの要素を使うか指定します。\n
///   : eRectFlagの組み合わせで指定します。\n
///   : Left   - leftメンバ使用\n
///   : Top    - topメンバ使用\n
///   : Right  - rightメンバ使用\n
///   : Bottom - bottomメンバ使用\n
///   : All    - 全てのメンバを使用\n
///   : 詳細はCPL::WIN::Component::eRectFlagを参照してください。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  Component::SetWindowRect
    ( _in<Rect> in_rect
    , _in<bool> in_flag_client_size
    , _in<int > in_rect_factor
    )
{
  WIN::Rect set_rect;
  if( in_rect_factor == eRectFlag::All )
  {
    set_rect = in_rect;
  }
  else
  {
    this->GetWindowRect( set_rect );
    if( in_rect_factor & eRectFlag::Left )
    {
      set_rect.left = in_rect.left;
    }
    if( in_rect_factor & eRectFlag::Top )
    {
      set_rect.top = in_rect.top;
    }
    if( in_rect_factor & eRectFlag::Right )
    {
      set_rect.right = in_rect.right;
    }
    if( in_rect_factor & eRectFlag::Bottom )
    {
      set_rect.bottom = in_rect.bottom;
    }
  }

  SetWindowRect
    ( td_Coord2(int(set_rect.left),       int(set_rect.top))
    , td_Coord2(int(set_rect.GetWidth()), int(set_rect.GetHeight()))
    , in_flag_client_size
    );
}


// _____________________________________________________________________________
/// @brief ウィンドウ座標の設定
/// 
/// @copydetails doxycomment::arg_in_pos
/// @copydetails doxycomment::arg_in_size
/// @copydetails doxycomment::arg_in_flag_client_size
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  Component::SetWindowRect
    ( _in<td_Coord2> in_pos
    , _in<td_Coord2> in_size
    , _in<bool     > in_flag_client_size
    )
{
  auto size = in_size;
  if( in_flag_client_size )
  {
    WIN::Rect rt;
    GetWindowRect( rt );

    auto size_client = GetClientSize();
    size +=
      td_Coord2
        ( (int)rt.GetWidth()  - size_client.x
        , (int)rt.GetHeight() - size_client.y
        );
  }
  ::SetWindowPos
    ( m_hdl_window
    , HWND_TOP
    , in_pos.x
    , in_pos.y
    , size.x
    , size.y
    , SWP_NOZORDER
    );

}


// _____________________________________________________________________________
/// @brief カーソル変更
/// 
/// @param[in] in_hdl_cursor : カーソルオブジェクトを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::SetDefaultCursor( _in<HCURSOR> in_hdl_cursor )
{
  m_def_cursor = in_hdl_cursor;
}


// _____________________________________________________________________________
/// @brief 背景色設定
/// 
/// @param[in] in_RGB
///   : 背景カラーをRGB(r,g,b)形式で指定します。\n
///   : -1を指定すると、in_hdl_brush_backgroundが使用されます。
/// @param[in] in_hdl_brush_background
///   : 背景の塗りつぶしに使うブラシを指定します。\n
///   : ブラシを使用するには、in_RGBに-1を指定する必要があります。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  Component::SetBgColor
    ( _in<COLORREF> in_RGB
    , _in<HBRUSH  > in_hdl_brush_background
    )
{
  // 既にブラシが作成されている場合、破棄する。
  if( m_back_color != (COLORREF)-1  &&  m_back_brush )
  {
    ::DeleteObject( m_back_brush );
  }
  // 
  if( in_RGB == (COLORREF)-1 )
  {
    m_back_color = -1;
    m_back_brush = in_hdl_brush_background;
  }
  else
  {
    m_back_color = in_RGB;
    m_back_brush = ::CreateSolidBrush( m_back_color );
  }
}


// _____________________________________________________________________________
/// @brief 背景色取得
/// 
/// @return 背景色をCOLORREF形式で返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
COLORREF Component::GetBgColor() const
{
  if( m_back_color == (COLORREF)-1 )
  {
    PaintDC pdc(m_hdl_window);
    return ::GetBkColor( pdc.GetDC() );
  }
  else
  {
    return m_back_color;
  }
}


// _____________________________________________________________________________
/// @brief 指定した子供のハンドルの保持判定
/// 
/// @param[in] in_hdl_child : 子供のウィンドウハンドルを指定します。
/// 
/// @retval true  : 指定した子供を保持しています。
/// @retval false : 指定した子供は保持していません。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BOOL Component::IsChild( _in<HWND> in_hdl_child ) const
{
  Component* ptr_comp_child = GetHandleToPointer( in_hdl_child );
  if( ptr_comp_child )
  {
    return ptr_comp_child->IsParent( this );
  }
  else
  {
    return ::IsChild( GetWindowHandle(), in_hdl_child );
  }
}


// _____________________________________________________________________________
/// @brief 指定した子供のコンポーネントの保持判定
/// 
/// @param[in] in_ptr_comp_child : 子供コンポーネントのポインタを指定します。
/// 
/// @retval true  : 指定した子供を保持しています。
/// @retval false : 指定した子供は保持していません。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BOOL Component::IsChild( pin<Component> in_ptr_comp_child ) const
{
  if( in_ptr_comp_child )
  {
    return in_ptr_comp_child->IsParent( this );
  }
  return false;
}


// _____________________________________________________________________________
/// @brief 指定した親に属するか判定
/// 
/// @param[in] in_hdl_parent : 親ハンドルを指定します。
/// 
/// @retval true  : 指定した親に属しています。
/// @retval false : 指定した親に属していません。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BOOL Component::IsParent( _in<HWND> in_hdl_parent ) const
{
  Component* ptr_comp_parent = GetHandleToPointer( in_hdl_parent );
  if( ptr_comp_parent )
  {
    return IsParent( ptr_comp_parent );
  }
  else
  {
    return ::IsChild( in_hdl_parent, GetWindowHandle() );
  }
}


// _____________________________________________________________________________
/// @brief 指定した親に属するか判定
/// 
/// @param[in] in_ptr_comp_parent : 親コンポーネントのポインタを指定します。
/// 
/// @retval true  : 指定した親に属しています。
/// @retval false : 指定した親に属していません。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BOOL Component::IsParent( pin<Component> in_ptr_comp_parent ) const
{
  if( in_ptr_comp_parent )
  {
    HWND hdl_win_parent = in_ptr_comp_parent->GetWindowHandle();
    Component const* ptr_comp = GetLinkParent();
    while( ptr_comp )
    {
      if( ptr_comp->GetWindowHandle() == hdl_win_parent )
      {
        return true;
      }
      ptr_comp = ptr_comp->GetLinkParent();
    };
  }
  return false;
}


// _____________________________________________________________________________
/// @brief 削除処理
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::Destroy()
{
  if( m_hdl_window )
  {
    if( m_flag_win_instance )
    {
//      String name = GetPropertyName_();
      ::DestroyWindow( m_hdl_window );
//      ::RemoveProp( m_hdl_window, name );
    }
    m_hdl_window  = nullptr;
  }
}


// _____________________________________________________________________________
/// @brief 表示／非表示設定
/// 
/// @param[in] in_flag_view
///   : true  - コンポーネントを表示します。\n
///   : false - コンポーネントを非表示にします。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::Show( _in<bool> in_flag_view ) const
{
  if( in_flag_view )
  {
    ::ShowWindow( m_hdl_window, SW_SHOW );
    Update( true );
  }
  else
  {
    ::ShowWindow( m_hdl_window, SW_HIDE );
  }
}


// _____________________________________________________________________________
/// @brief コンポーネントの更新
/// 
/// 更新リージョンに自身の矩形を追加します。
/// 
/// @param[in] in_flag_redraw
///   : 背景を消去するかどうかを指定します。\n
///   : true  - 背景を消去します。\n
///   : false - 背景を消去しません。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::Update( _in<bool> in_flag_redraw ) const
{
  ::InvalidateRect( m_hdl_window, nullptr, in_flag_redraw );
}


// _____________________________________________________________________________
/// @brief ウィンドウの関連付け
/// 
/// 外部で作成したウィンドウとの関連付けを行います。
/// 
/// @param[in] in_hdl_window
///   : 関連付けを行うウィンドウのハンドルを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::SetReferenceWndHandle( _in<HWND> in_hdl_window )
{
  Destroy(); // すでに作成されていたら破棄する
  zzf_SetHandle( in_hdl_window );
}


// _____________________________________________________________________________
/// @brief フォントの変更
/// 
/// @param[in] in_hdl_font : 論理フォントのハンドルを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::SetFont( _in<HFONT> in_hdl_font )
{
  ::SendMessage( m_hdl_window, WM_SETFONT, (WPARAM)in_hdl_font, MAKELPARAM(TRUE,0) );
}


// _____________________________________________________________________________
/// @brief フォントの変更
/// 
/// @param[in] in_drawfont : フォントオブジェクト(DrawFont)を指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::SetFont( _in<DrawFont> in_drawfont )
{
  SetFont( in_drawfont.GetHandle() );
}


// _____________________________________________________________________________
/// @brief ツールチップ設定
/// 
/// @param[in] in_ptr_str : ツールチップとして表示する文字列を指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::SetToolTip( _in<str_ptr> in_ptr_str )
{
  m_sp_tool_tip =
    CPL_MAKE_SHARED( ToolTip, GetInstance_(), m_hdl_window, in_ptr_str );
}


// _____________________________________________________________________________
/// @brief 親コンポーネントの設定
/// 
/// @param[in] in_hdl_win_parent : 親コンポ―ネントのハンドルを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::SetParent( _in<HWND> in_hdl_win_parent )
{
  ::SetParent( GetWindowHandle(), in_hdl_win_parent );

  m_hdl_win_parent = in_hdl_win_parent;
}


// _____________________________________________________________________________
/// @brief 親ウィンドウの設定
/// 
/// @param[in] in_ptr_win_parent : 親コンポーネントオブジェクトのポインタを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::SetParent( pin<Component> in_ptr_win_parent )
{
  ::SetParent( GetWindowHandle(), in_ptr_win_parent->GetWindowHandle() );

  m_hdl_win_parent = in_ptr_win_parent->GetWindowHandle();
}


// _____________________________________________________________________________
/// @brief ツールチップ解除
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::ReleaseTooltip()
{
  m_sp_tool_tip->Detach();
}


// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 関連付けられているフォントでテキストサイズを取得する
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
td_Coord2
  Component::zzf_GetTextSize( char_cptr in_ptr_text, HFONT in_hdl_font ) const
{
  HDC   hdc   = ::GetDC( m_hdl_window );
  HFONT hdl_font_old = nullptr;
  if( in_hdl_font == nullptr )
  {
    in_hdl_font = (HFONT)GetWindowFont( GetWindowHandle() );
  }
  hdl_font_old = SelectFont( hdc, in_hdl_font );
//  int old_mm = ::SetMapMode( hdc, MM_TEXT );

//  SIZE  size;
//  ::GetTextExtentPoint32( hdc, in_ptr_text, _tcslen(in_ptr_text), &size ); // サイズ取得
  WIN::Rect rt_size(0,0,0,0);
  //int size =
    DrawTextA(
      hdc,
      in_ptr_text,
      static_cast<int>(Core::StringA::str_len_( in_ptr_text )),
      &rt_size,
      DT_NOCLIP | DT_CALCRECT | DT_LEFT | DT_TOP );

  if( in_hdl_font )
  {
    SelectFont( hdc, hdl_font_old ); // フォントを戻す
  }
//  ::SetMapMode( hdc, old_mm );

  ::ReleaseDC( m_hdl_window, hdc );
  return
    { static_cast<int>(rt_size.right)
    , static_cast<int>(rt_size.bottom)
    };
}


td_Coord2
  Component::zzf_GetTextSize( wchar_t_cptr in_ptr_text, HFONT in_hdl_font ) const
{
  HDC   hdc   = ::GetDC( m_hdl_window );
  HFONT hdl_font_old = nullptr;
  if( in_hdl_font == nullptr )
  {
    in_hdl_font = (HFONT)GetWindowFont( GetWindowHandle() );
  }
  hdl_font_old = SelectFont( hdc, in_hdl_font );
//  int old_mm = ::SetMapMode( hdc, MM_TEXT );

//  SIZE  size;
//  ::GetTextExtentPoint32( hdc, in_ptr_text, _tcslen(in_ptr_text), &size ); // サイズ取得
  WIN::Rect rt_size(0,0,0,0);
  //int size =
    DrawTextW(
      hdc,
      in_ptr_text,
      static_cast<int>(Core::StringW::str_len_( in_ptr_text )),
      &rt_size,
      DT_NOCLIP | DT_CALCRECT | DT_LEFT | DT_TOP );

  if( in_hdl_font )
  {
    SelectFont( hdc, hdl_font_old ); // フォントを戻す
  }
//  ::SetMapMode( hdc, old_mm );

  ::ReleaseDC( m_hdl_window, hdc );
  return
    { static_cast<int>(rt_size.right)
    , static_cast<int>(rt_size.bottom)
    };
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ウィンドウ作成（ベース関数）
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  Component::zzf_Create
    ( _in<HWND     > in_hdl_win_parent
    , pin<char     > in_title
    , _in<td_Coord2> in_pos
    , _in<td_Coord2> in_size
    , _in<SDEF     > in_ID
    , _in<LONG_PTR > in_win_style
    , _in<LONG_PTR > in_win_ex_style
    , pio<void     > in_ptr_this
    )
{
  m_hdl_win_parent = in_hdl_win_parent;
  auto comp_ID = in_ID;
  if( comp_ID < 0 )
  {
    comp_ID = GetComponentID();
  }

  // 作成
  m_hdl_window =
    ::CreateWindowExA
      ( static_cast<DWORD>(in_win_ex_style)
      , zzf_GetClassNameA()
      , in_title
      , static_cast<DWORD>(in_win_style)
      , in_pos.x
      , in_pos.y
      , in_size.x < 0 ? CW_USEDEFAULT : in_size.x
      , in_size.y < 0 ? CW_USEDEFAULT : in_size.y
      , in_hdl_win_parent
      , (HMENU)comp_ID
      , GetInstance_()
      , (void*)in_ptr_this
      );

  if( !zzf_SetHandle( m_hdl_window ) )
  {
    return false; // ウィンドウ作成失敗
  }
  
  SetFont( *sm_sp_DefFont_MS_Gothic() );

  return true;
}


// -----------------------------------------------------------------------------
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  Component::zzf_Create
    ( _in<HWND     > in_hdl_win_parent
    , pin<wchar_t  > in_title
    , _in<td_Coord2> in_pos
    , _in<td_Coord2> in_size
    , _in<SDEF     > in_ID
    , _in<LONG_PTR > in_win_style
    , _in<LONG_PTR > in_win_ex_style
    , pio<void     > in_ptr_this
    )
{
  m_hdl_win_parent = in_hdl_win_parent;

  auto comp_ID = in_ID;
  if( comp_ID < 0 )
  {
    comp_ID = GetComponentID();
  }

  // 作成
  m_hdl_window =
    ::CreateWindowExW
      ( static_cast<DWORD>(in_win_ex_style)
      , zzf_GetClassNameW()
      , in_title
      , static_cast<DWORD>(in_win_style)
      , in_pos.x, in_pos.y
      , in_size.x, in_size.y
      , in_hdl_win_parent
      , (HMENU)comp_ID
      , GetInstance_()
      , (void*)in_ptr_this
      );

  if( !zzf_SetHandle( m_hdl_window ) )
  {
    OutputLastErrorMessage();
    return false; // ウィンドウ作成失敗
  }
  
  SetFont( *sm_sp_DefFont_MS_Gothic() );

  return true;
}


// _____________________________________________________________________________
/// @brief コンポーネント(ウィンドウ)作成
/// 
/// @copydetails CPL::WIN::doxycomment::arg_in_hdl_win_parent
/// @copydetails CPL::WIN::doxycomment::arg_in_pos
/// @copydetails CPL::WIN::doxycomment::arg_in_size
/// 
/// @retval true  : 作成成功。
/// @retval false : 作成失敗。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
bool
  Component::Create
    ( _in<HWND     > in_hdl_win_parent
    , _in<td_Coord2> in_pos
    , _in<td_Coord2> in_size
    )
{
  if( m_hdl_window )
  {
    return true;
  }
  return
    zzf_Create
      ( in_hdl_win_parent
      , SwS("")
      , in_pos
      , in_size
      , -1
      , WS_CHILD | WS_VISIBLE, 0, this
      );
}


// _____________________________________________________________________________
/// @brief クローンの生成
/// 
/// @param[in] in_hdl_win_parent : 親ウィンドウのハンドルを指定します。
/// @param[in] in_offs_x : 複製するオブジェクトの相対的なｘ座標を指定します。
/// @param[in] in_offs_y : 複製するオブジェクトの相対的なｙ座標を指定します。
/// 
/// @return 生成されたオブジェクトのポインタを返します。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Component*
  Component::CreateClone
    ( _in<HWND> in_hdl_win_parent
    , _in<int > in_offs_x
    , _in<int > in_offs_y
    ) const
{
  try{
    Core::String title;
    Rect rt;
    LONG_PTR style    = this->GetStyle();
    LONG_PTR ex_style = this->GetExStyle();
    this->GetTitle( title );
    this->GetWindowRect( rt );
    auto hdl_win_parent = in_hdl_win_parent;
    if( hdl_win_parent == nullptr )
    {
      hdl_win_parent =this->GetParentWindowHandle();
    }

    Component* ptr_comp = CPL_NEW(Component);

    bool f_create =
      ptr_comp->zzf_Create
        ( hdl_win_parent, title
        , td_Coord2( int(rt.left + in_offs_x), int(rt.top + in_offs_y) )
        , td_Coord2( (int)rt.GetWidth(), (int)rt.GetHeight() )
        , -1, style, ex_style, ptr_comp
        );

    if( f_create )
    {
      return ptr_comp;
    }
    else
    {
      return nullptr;
    }
  }
  catch(...)
  {
    return nullptr;
  }
}



// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// デフォルトプロシージャ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LRESULT CALLBACK
  Component::zzf_staticProc_
    ( HWND    in_hdl_window
    , UINT    in_message
    , WPARAM  in_wparam
    , LPARAM  in_lparam
    )
{
  SDEF flag = false;
  Component* ptr_comp = nullptr;

  if( in_message == WM_CREATE )
  {
    CREATESTRUCT* cs = (CREATESTRUCT*)in_lparam;
    ptr_comp = static_cast<Component*>(cs->lpCreateParams);
    if( ptr_comp )
    {
      CallStackMsg csm( ptr_comp, in_message, in_wparam, in_lparam );
      ptr_comp->zzf_SetHandle( in_hdl_window );
      flag = ptr_comp->On_Create();
    }
  }
  else
  if( in_message == WM_INITDIALOG )
  {
    CallStackMsg csm( ptr_comp, in_message, in_wparam, in_lparam );
    ptr_comp = reinterpret_cast<Component*>(in_lparam);
    ptr_comp->m_hdl_window = in_hdl_window;
    return ptr_comp->On_Create();
  }
  else
  {
    ptr_comp = GetHandleToPointer( in_hdl_window );
    if( ptr_comp )
    {
      if( ptr_comp->GetEventMode() != eEventMode::AllCut )
      {
        flag = ptr_comp->DefaultProc_( in_message, in_wparam, in_lparam );
      }
      else
      {
        return 0;
      }
    }
  }

  if( !flag )
  {
    return ::DefWindowProc( in_hdl_window, in_message, in_wparam, in_lparam );
  }
  return flag;
}



// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// デフォルトプロシージャ
// zzf_staticProc_より呼ばれます
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SDEF Component::DefaultProc_( _in<UINT> in_message, _in<WPARAM> in_wparam, _in<LPARAM> in_lparam )
{
  switch( in_message )
  {
  case WM_DESTROY: // ウィンドウ破棄
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      if( On_Destroy() )
      {
        ::PostQuitMessage( 0 );
      }
    }
    return 0;

  case WM_TIMER: // タイマー
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_Timer( (int)in_wparam );
    }

  case WM_ACTIVATE: // アクティブ
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_Active( LOWORD(in_wparam), (BOOL)HIWORD(in_wparam), (HWND)in_lparam );
    }

  case WM_SHOWWINDOW: // 表示
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_Show( (BOOL)in_wparam );
    }

  case WM_NCHITTEST:
    // モーダル検査
    {
      WIN::Component* pModalWin = sm_ptr_modal_window();
      if( pModalWin  &&  pModalWin->IsVisible() )
      {
        WIN::Component* pComp = this;
        while( pComp )
        {
          if( pComp == sm_ptr_modal_window() )
          {
            goto HIT_BREAK;
          }
          pComp = pComp->GetLinkParent();
        }
        return true; // モーダル設定があると、マウスイベントを処理させない
      }
    }
    HIT_BREAK:
    break;

  case WM_SETFOCUS: // フォーカス有効
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_Focus( 1 );
    }
  case WM_KILLFOCUS: // フォーカス失効
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_Focus( 0 );
    }

  case WM_PAINT: // 再描画
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_Paint();
    }

  case WM_ERASEBKGND: // 背景描画
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_EraseBkGnd( (HDC)in_wparam );
    }

  case WM_LBUTTONDOWN: // マウス左ボタンダウン
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      Mouse::downL_();
      if( !(m_event_mask & 1) )
      {
        SetCapture( m_hdl_window );
      }
      return On_MouseDown( eMouseButton::Left );
    }
  case WM_MBUTTONDOWN: // マウス中ボタンダウン
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      Mouse::downM_();
      if( !(m_event_mask & 1) )
      {
        SetCapture( m_hdl_window );
      }
      return On_MouseDown( eMouseButton::Middle );
    }
  case WM_RBUTTONDOWN: // マウス右ボタンダウン
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      Mouse::downR_();
      if( !(m_event_mask & 1) )
      {
        SetCapture( m_hdl_window );
      }
      return On_MouseDown( eMouseButton::Right );
    }

  case WM_LBUTTONUP: // マウス左ボタンアップ
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      SDEF flag = On_MouseUp( eMouseButton::Left );
      Mouse::upL_();
      if( !(m_event_mask & 1) )
      {
        ReleaseCapture();
      }
      return flag;
    }
  case WM_MBUTTONUP: // マウス中ボタンアップ
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      SDEF flag = On_MouseUp( eMouseButton::Middle );
      Mouse::upM_();
      if( !(m_event_mask & 1) )
      {
        ReleaseCapture();
      }
      return flag;
    }
  case WM_RBUTTONUP: // マウス右ボタンアップ
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      SDEF flag = On_MouseUp( eMouseButton::Right );
      Mouse::upR_();
      if( !(m_event_mask & 1) )
      {
        ReleaseCapture();
      }
      return flag;
    }

  //case WM_LBUTTONDBLCLK: // マウス左ボタンダブルクリック
  //  {
  //    CallStackMsg csm( this, in_message, in_wparam, in_lparam );
  //    Mouse::SetPos( m_hdl_window, in_lparam );
  //    return On_DblClick( eMouseButton::Left );
  //  }
  //case WM_MBUTTONDBLCLK: // マウス中ボタンダブルクリック
  //  {
  //    CallStackMsg csm( this, in_message, in_wparam, in_lparam );
  //    Mouse::SetPos( m_hdl_window, in_lparam );
  //    return On_DblClick( eMouseButton::Middle );
  //  }
  //case WM_RBUTTONDBLCLK: // マウス右ボタンダブルクリック
  //  {
  //    CallStackMsg csm( this, in_message, in_wparam, in_lparam );
  //    Mouse::SetPos( m_hdl_window, in_lparam );
  //    return On_DblClick( eMouseButton::Right );
  //  }

  case WM_MOUSEMOVE: // マウス移動
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Mouse::SetPos( m_hdl_window, in_lparam );
      if( m_def_cursor )
      {
        ::SetCursor( m_def_cursor ); // 強制デフォルトカーソル
      }
      if( Mouse::IsManualMove() )
      {
        Mouse::ResetManualFlag();
        break;
      }
      return On_MouseMove();
    }
  case WM_MOUSEWHEEL:
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_MouseWheel( GET_KEYSTATE_WPARAM(in_wparam), GET_WHEEL_DELTA_WPARAM(in_wparam) );
    }

  case WM_KEYDOWN: // キーダウン
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Keyboard::m_fVKey[ (int)in_wparam ] = true;
      return On_KeyDown( (int)in_wparam );
    }

  case WM_KEYUP: // キーアップ
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      Keyboard::m_fVKey[ (int)in_wparam ] = false;
      return On_KeyUp( (int)in_wparam );
    }

  case WM_CHAR: // キャラクタ
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_Char( (TCHAR)in_wparam, (int)in_lparam );
    }

  case WM_VKEYTOITEM: // リストボックスでのキーイベント？
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_KeyDown( LOWORD(in_wparam) );
    }

  case WM_MOVE:   // ウィンドウ移動
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_Move();
    }
  case WM_MOVING: // ウィンドウ移動中
//  case WM_WINDOWPOSCHANGED:
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_Moving( (Rect*)in_lparam );
    }

  case WM_SIZE: // ウィンドウサイズ変更
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      if( m_sp_tool_tip )
      {
        m_sp_tool_tip->SetWindowRect
          ( Rect{ 0, 0, LOWORD(in_lparam), HIWORD(in_lparam) }
          );
      }
      if( m_flag_child_size )
      {
        SDEF ret = On_Size( static_cast<eSizeMode>(in_wparam) );
        SendParentMessage( WIN::kWM_CPL_CHILD_SIZE, 0, (LPARAM)this );
        return ret;
      }
      else
      {
        return On_Size( (eSizeMode)in_wparam );
      }
    }
  case WM_SIZING: // ウィンドウサイズ変更中
    {
      CallStackMsg csm( this, in_message, in_wparam, in_lparam );
      return On_Sizing( (Rect*)in_lparam );
    }

  default: // その他
    if( in_message < WM_APP )
    {
      return On_OtherProc( m_hdl_window, in_message, in_wparam, in_lparam ); // その他システムメッセージ用
    }
    else
    {
      return On_UserProc( m_hdl_window, in_message, in_wparam, in_lparam ); // ユーザー定義用
    }
  }
  return 0;
}




// _____________________________________________________________________________
/// @brief タグ生成
/// 
/// @param[in] out_tag  : タグ取得用オブジェクトを指定します。
/// @param[in] in_types : 生成フラグの組み合わせを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::MakeTag( rout<TBTag> out_tag, _in<U64> in_types )
{
  using Tag = TBTag;

  if( in_types & WIN::eTagTypes::UserID )
  {
    out_tag.AddTag( Tag{ "UserID", this->GetUserID() } );
  }
  if( in_types & WIN::eTagTypes::Rect )
  {
    WINDOWPLACEMENT wp;
    GetWindowPlacement( GetWindowHandle(), &wp );
    auto& rt = wp.rcNormalPosition;
    out_tag.AddTag( Tag{ "Rect", rt.left, rt.top, rt.right, rt.bottom } );
  }
  if( in_types & WIN::eTagTypes::IsVisible )
  {
    out_tag.AddTag( Tag{ "IsVisible", this->IsVisible() != 0 } );
  }
  if( in_types & WIN::eTagTypes::IsEnable )
  {
    out_tag.AddTag( Tag{ "IsEnable", this->IsEnable() != 0 } );
  }
  if( in_types & WIN::eTagTypes::ColorBG )
  {
    auto c = this->GetBgColor();
    out_tag.AddTag( (ToTag( int3{GetRValue(c), GetGValue(c), GetBValue(c) } ), "ColorBG") );
  }
  if( in_types & WIN::eTagTypes::Title )
  {
    std::string title;
    this->GetTitle( title );
    out_tag.AddTag( (ToTag( title ), "Title") );
  }
  if( in_types & WIN::eTagTypes::SizeMode )
  {
    if( IsMaximized( GetWindowHandle() ) )
    {
      out_tag.AddTag( Tag{ "SizeMode", "Maximize" } );
    }
    else
    if( IsMinimized( GetWindowHandle() ) )
    {
      out_tag.AddTag( Tag{ "SizeMode", "Minimize" } );
    }
  }
}


// _____________________________________________________________________________
/// @brief タグ読み込み
/// 
/// @param[in] in_tag   : タグ取得用のルートタグを指定します。
/// @param[in] in_types : 生成フラグの組み合わせを指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Component::LoadTag( _in<TBTag> in_tag, _in<U64> in_types )
{
  for // 子供タグループ
    ( auto sp_tag_item = in_tag.GetTagChild()
    ; sp_tag_item
    ; sp_tag_item = sp_tag_item->GetTagNext()
    )
  {
    auto sp_tag_data = sp_tag_item->GetTagChild();
    auto& name = sp_tag_item->GetName();

    if( in_types & WIN::eTagTypes::UserID  &&  name == "UserID" )
    {
      m_user_ID << *sp_tag_item;
    }
    else
    if( in_types & WIN::eTagTypes::Rect  &&  name == "Rect" )
    {
      int4 rt;
      rt << *sp_tag_item;
      this->SetWindowRect( WIN::Rect{ rt.x, rt.y, rt.z, rt.w } );
    }
    else
    if( in_types & WIN::eTagTypes::IsVisible  &&  name == "IsVisible" )
    {
      this->Show( sp_tag_data->GetName() == "true" );
    }
    else
    if( in_types & WIN::eTagTypes::IsEnable  &&  name == "IsEnable" )
    {
      this->SetEnable( sp_tag_data->GetName() == "true" );
    }
    else
    if( in_types & WIN::eTagTypes::ColorBG  &&  name == "ColorBG" )
    {
      int3 c;
      c << *sp_tag_item;
      this->SetBgColor( RGB(c.r, c.g, c.b) );
    }
    else
    if( in_types & WIN::eTagTypes::Title  &&  name == "Title" )
    {
      std::string title;
      title << *sp_tag_item;
      this->SetTitle( title );
    }
    else
    if( in_types & WIN::eTagTypes::SizeMode  &&  name == "SizeMode" )
    {
      auto data = sp_tag_data->GetName();
      if( data == "Maximize" )
      {
        ShowWindow( GetWindowHandle(), SW_MAXIMIZE );
      }
      else
      if( data == "Minimize" )
      {
        ShowWindow( GetWindowHandle(), SW_MINIMIZE );
      }
    }
    else
    {
      On_LoadTagItem( *sp_tag_item );
    }
  }
}


} // namespace WIN
} // namespace CPL


