/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2010/X/X - 2016/12/18
/// 
/// @brief  テキストボックスコンポーネント。
/// 
/// ****************************************************************************


#include "../DX/CPL_DX_AutoSaveRenderTargets.h"
#include "CPL_GUC_TextBox.h"
#include "CPL_GUC_ActiveMenu.h"
#include "CPL_GUC_MasterLayer.h"

namespace CPL {
namespace GUC {

// _____________________________________________________________________________
/// @brief GUCコンポーネント対応のキャレット設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
  EditBase::UpdateCaret
    ( _in<  ptr<WIN::Component>> in_ptr_win
    , _in<sdptr<GUC::Component>> in_sp_component
    , _in<int> in_X
    , _in<int> in_Y
    , _in<int> in_height
    )
{
//  sm_sp_caret() = new zzc_Caret( in_height );
  float2 pos( static_cast<float>(in_X), static_cast<float>(in_Y) );
  HWND hwnd_frame = in_ptr_win->GetWindowHandle();
  // コンポーネントからルートへ座標変換
  Component::MappingPosition( in_sp_component, nullptr, &pos, 1 );
//  SetCaretPos( pos.x, pos.y );
//  ShowCaret( hwnd_frame );

  // IME編集位置
  COMPOSITIONFORM CompForm;
  HIMC            hIMC = ::ImmGetContext( hwnd_frame );
  POINT           point;

  ::GetCaretPos( &point );
  CompForm.dwStyle = CFS_POINT;
  CompForm.ptCurrentPos.x = (long)pos.x;
  CompForm.ptCurrentPos.y = (long)pos.y;// + in_height;

  if ( hIMC )
  {
    ::ImmSetCompositionWindow( hIMC, &CompForm );
  }
  ::ImmReleaseContext( hwnd_frame, hIMC );
}

// _____________________________________________________________________________
/// @brief 基本メニュー表示
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int
  EditBase::PopupBasicMenu
    ( _in<SpGucComp> in_sp_comp_edit
    , _in<float    > in_mouse_X
    , _in<float    > in_mouse_Y
    )
{
  enum eMemuID
  { kIDM_FRAME
  , kIDM_CUT
  , kIDM_COPY
  , kIDM_PASTE
  , kIDM_DELETE
  };
  float2 win_size = WIN::GetWinFrame()->GetWindowSize();
  float4 rect{ 0, 0, win_size.x, win_size.y };
  float2 pos{ in_mouse_X, in_mouse_Y };
  // マスターレイヤーの取得。
  // ※ このポインタは必ず存在するのでチェックしない。
  //    もしnullならそれ自体違法であるので、null参照例外でOK.
  auto sp_comp_master =
    std::dynamic_pointer_cast<MasterLayer>(in_sp_comp_edit->GetMasterLayer());
  auto sp_overlayer = sp_comp_master->GetComponent_for_OverLayer();

  auto
    sp_menu =
      Factory<ActiveMenu>::Create
        ( sp_overlayer
        , rect
        , CPL_GUC_DEF_STR("")
        , 0
        , ActiveMenu::eListMode::AutoVertical
        , ActiveForm::ePosMode::Manual
        );
  sp_menu->InsertItem( CPL_GUC_DEF_STR("切り取り"), eID::EditCut );
  sp_menu->InsertItem( CPL_GUC_DEF_STR("コピー"),   eID::EditCopy );
  sp_menu->InsertItem( CPL_GUC_DEF_STR("貼り付け"), eID::EditPaste );
  sp_menu->InsertItem( CPL_GUC_DEF_STR("削除"),     eID::EditDelete );
  sp_menu->AutoRepositionItems();

  Component::MappingPosition( sp_overlayer, in_sp_comp_edit, (float2*)&rect, 2 );
  //Component::MappingPosition( in_sp_comp_edit, nullptr, &pos, 1 );
  sp_menu->SetBelongComponent
    ( in_sp_comp_edit
    , eParentType::Position
    );
  sp_menu->SetRectCoord( rect );
  sp_menu->SetStateVisible( true );
  auto sp_comp_active = sp_menu->GetComponent_ActiveForm();
  sp_comp_active->SetBelongComponent
    ( in_sp_comp_edit
    , eParentType::Position
    );
  sp_comp_active->SetPosition( float2{ in_mouse_X, in_mouse_Y } );
  sp_comp_active->SetStateVisible( true );

  return 0;
}


// _____________________________________________________________________________
/// @brief テキストボックスのデフォルト背景カラー。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet> TextBox::GetDefaultColor_TextBoxBG()
{
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , kCOLOR_WHITE
        , kCOLOR_LIGHTBLUE
        , kCOLOR_WHITE
        , kCOLOR_LIGHTGRAY
        );
  return sp_color;
}

// _____________________________________________________________________________
/// @brief テキストボックスのデフォルトフレームカラー。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet> TextBox::GetDefaultColor_TextBoxFrame()
{
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , kCOLOR_BLACK
        , kCOLOR_BLUE
        , kCOLOR_RED
        , kCOLOR_GRAY
        );
  return sp_color;
}

// _____________________________________________________________________________
/// @brief テキストボックスのデフォルトテキストカラー。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
sdptr<DrawColorSet> TextBox::GetDefaultColor_TextBoxText()
{
  static auto
    sp_color =
      CPL_MAKE_SHARED
        ( DrawColorSet
        , kCOLOR_BLACK
        , kCOLOR_BLACK
        , kCOLOR_BLACK
        , kCOLOR_GRAY
        );
  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_text
///   : 設定する文字列を指定します。文字コードはUTF-16です。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TextBox::TextBox
( _in<sdptr<Component>> in_sp_component_for_parent
, _in<float2          > in_position_for_component
, _in<float2          > in_size_for_component
, pin<td_DefChar      > in_text
) : Label
    ( in_sp_component_for_parent
    , in_position_for_component
    , in_size_for_component
    , in_text
    )
{
  //CallOnce( zzf_StaticInitializeTB );

  float2 size =
  { in_size_for_component.x <= 0 ? 1 : in_size_for_component.x
  , in_size_for_component.y <= 0 ? 1 : in_size_for_component.y
  };

  m_sp_render_tex =
    CPL_MAKE_SHARED
      ( DX::RenderTexture
      , static_cast<size_t>(size.x)
      , static_cast<size_t>(size.y)
      , DXGI_FORMAT_R8G8B8A8_UNORM
      , DXGI_FORMAT_D24_UNORM_S8_UINT
      );

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


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TextBox::TextBox( cref<TextBox> in_text_box )
  : td_base( in_text_box )
  , m_msg_info( in_text_box.m_msg_info )
  , m_offset_x( in_text_box.m_offset_x )
  , m_offset_idx( in_text_box.m_offset_idx )
{
  if( in_text_box.m_sp_render_tex ) // かならずあるはずだが、一応チェック。
  {
    m_sp_render_tex =
      Factory<DX::RenderTexture>::Create( *in_text_box.m_sp_render_tex );
  }
}


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


//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//// テキストボックス静的初期化
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//int TextBox::zzf_StaticInitializeTB()
//{
////  sm_text_box().SetFont( sm_def_font_mng()->GetFont()->GetHandle() );
////  sm_text_box().SetDefaultCursor( NULL );
//
//  return true;
//}


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

  ++rect.x;
  ++rect.y;
  --rect.z;
  --rect.w;

  zzf_DrawRectEx( rect, GetColorParameterBG()->color_default.color );
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_DrawFrame
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TextBox::On_DrawFrame( _in<float4> in_rect )
{
  auto sp_colorset_frame = GetColorParameterFrame();
  auto ptr_color = &sp_colorset_frame->color_default;
  if( !this->IsEnable() )
  {
    ptr_color = &sp_colorset_frame->color_invalid;
  }
  else
  if( sm_sp_focus() == this->GetLinkMyself() )
  {
    ptr_color = &sp_colorset_frame->color_active;
  }
  else
  if( sm_sp_ac_comp() == this->GetLinkMyself() )
  {
    ptr_color = &sp_colorset_frame->color_highlight;
  }
  zzf_DrawFrameEx( in_rect, ptr_color->color );
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_DrawClient
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TextBox::On_DrawClient( _in<float4> in_rect )
{
  auto& cp_d3d_IC = DX::Graphics_i_::GetImmediateContext();

  if( IsUpdate() )
  {
    // 既に描画オブジェクトにプールされていたら転送する。
    sm_def_font_mng()->Translate( sm_ptr_d3ddev() );

    // 現在のレンダリングターゲットを保存
    DX::AutoSaveRenderTargets target_holder( cp_d3d_IC, 1 );

    m_sp_render_tex->ChangeTarget();
    // クリア
    m_sp_render_tex->ClearColor( float4(0,0,0,0) );
    m_sp_render_tex->ClearDepthStencil( 1.0f, 0 );

    // テキストカラー
    auto sp_colorset_text = GetColorParameterText();
    auto ptr_color_text   = &sp_colorset_text->color_default;
    if( !IsEnable() )
    {
      ptr_color_text = &sp_colorset_text->color_invalid;
    }
    else
    if( sm_sp_ac_comp() == this->GetLinkMyself() )
    {
      if( WIN::Mouse::GetDownL() )
      {
        ptr_color_text = &sp_colorset_text->color_active;
      }
      else
      {
        ptr_color_text = &sp_colorset_text->color_highlight;
      }
    }
    U32x4 color_text;
    ptr_color_text->ConvertColor_to_U32x4( color_text );

    // 背景カラー
    //CDI::ColorType bg_color = GetColorParameterBG()->color_default.color[0];
    
    float4 rt_text
      ( static_cast<float>(DRAw_OFFS_X - m_offset_x)
      , static_cast<float>(DRAw_OFFS_Y)
      , in_rect.Width()  - static_cast<float>(DRAw_OFFS_X)
      , in_rect.Height() - static_cast<float>(DRAw_OFFS_Y)
      );

    DX::FontDrawManager::MsgInfo
      mi( m_text
        , WIN::Rect
            ( static_cast<long>(rt_text.x)
            , static_cast<long>(rt_text.y)
            , static_cast<long>(rt_text.z)
            , static_cast<long>(rt_text.w)
            )
        , 0.0f // z
        , color_text // default text color
        , 0 // rotate z
        , int2(0,0) // rotate center
        , -1 // line height
        , DX::kFDM_X_LEFT | DX::kFDM_Y_TOP
        );

    const int2 p0 = sm_caret().pos_x0;
    const int2 p1 = sm_caret().pos_x1;
    const int  i0 = sm_caret().idx_pos0;
    const int  i1 = sm_caret().idx_pos1;

    if( sm_sp_focus() == this->GetLinkMyself() )
    {
      if( p0.x >= 0 )
      {
        // キャレット描画。
        float4 rt
          ( rt_text.x + p1.x
          , rt_text.y + p0.y
          , rt_text.x + p1.x + 1
          , rt_text.y + p1.y
          );
        zzf_DrawRectEx( rt, ptr_color_text->color ); // このカラーはテキストと同色でよい。
      }

      // 選択範囲がある場合。
      if( i0 != i1 )
      {
        // 反対色作成。
        DX::RectColor4P
          rev_color_text
            ( kCOLOR_WHITE - ptr_color_text->color[0].rgb
            , kCOLOR_WHITE - ptr_color_text->color[1].rgb
            , kCOLOR_WHITE - ptr_color_text->color[2].rgb
            , kCOLOR_WHITE - ptr_color_text->color[3].rgb
            );
        U32x4 rev_color_text32;
        rev_color_text.ConvertColor_to_U32x4( rev_color_text32 );

        int x0 = (p0.x < 0) ? -p0.x-1 : p0.x;
        float4
          rt( Clamp( rt_text.x + x0, rt_text.left, rt_text.right )
            , rt_text.y + p0.y
            , Clamp( rt_text.x + p1.x, rt_text.left, rt_text.right )
            , rt_text.y + p1.y
            );
        zzf_DrawRectEx( rt, ptr_color_text->color );

        // カラー変更
        for( int idx = Min(i0,i1), max = Max(i0,i1);
             idx < max;
             ++idx )
        {
          mi.SetColor_Index( idx, rev_color_text32 );
        }
      }
    }

    //Label::On_DrawClient( in_rect );
    sm_def_font_mng()->DrawMessage( mi );
    sm_def_font_mng()->Translate( sm_ptr_d3ddev() );
  }

  // テクスチャ描画
  sm_def_sprite_mng().Draw
    ( this->m_sp_render_tex->GetShaderResourceView()
    , in_rect.x, in_rect.y
    , 0.0f, 0.0f
    , in_rect.Width()
    , in_rect.Height()
    , 0.0f
    , DX::RectColor4P( 1.0f )
    );
  sm_def_sprite_mng().Transrate();

  SetUpdated();
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 指定したインデックスのキャレットの情報を取得
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TextBox::zzf_GetCaretInfo( rio<DX::FontDrawManager::CaretData> io_caret_data )
{
  // テキストボックス（ラベルボックス）用補正
  float2 size = GetSize();
  float4 rt( 0,0, size.x, size.y );
  if( IsDrawFrame() )
  {
    io_caret_data.x--;
    io_caret_data.y--;
    size.x -= 2;
    size.y -= 2;
  }
  io_caret_data.x -= DRAw_OFFS_X;
  io_caret_data.x += m_offset_x;

  // 文字描画情報
  DX::FontDrawManager::MsgInfo
    mi( m_text
      , WIN::Rect
          ( static_cast<long>(rt.x)
          , static_cast<long>(rt.y)
          , static_cast<long>(rt.z + m_offset_x)
          , static_cast<long>(rt.w)
          )
      , 0.0f
      , kCOLOR_BLACK
      );

  //
  //io_caret_data.idx = sm_caret().idx_pos1;
  sm_def_font_mng()->GetCaretData( mi, io_caret_data );

  // 座標オフセット調整
  if( io_caret_data.x - m_offset_x < 0 )
  {
    m_offset_x = io_caret_data.x; // io_caret_data.x - m_offset_xが０になるように。
  }
  else
  if( size.x < io_caret_data.x - m_offset_x + DRAw_OFFS_X )
  {
    m_offset_x = io_caret_data.x - static_cast<int>(size.x) + DRAw_OFFS_X;
  }
  //io_caret_data.x -= m_offset_x;
  // インデックスオフセット設定
  DX::FontDrawManager::CaretData ci;
  ci.get_type = DX::FontDrawManager::CaretData::kXY_TO_INDEX;
  ci.x = m_offset_x;
  ci.y = 5;
  sm_def_font_mng()->GetCaretData( mi, ci );
  ci.y = DRAw_OFFS_Y;
  m_offset_idx = ci.idx;
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// メッセージ情報の更新
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TextBox::zzf_UpdateMessageInfo()
{
  // テキストカラー
  auto sp_colorset_text = GetColorParameterText();
  auto ptr_color_text = &sp_colorset_text->color_default;
  if( !IsEnable() )
  {
    ptr_color_text = &sp_colorset_text->color_invalid;
  }
  else
  if( sm_sp_ac_comp() == this->GetLinkMyself() )
  {
    if( WIN::Mouse::GetDownL() )
    {
      ptr_color_text = &sp_colorset_text->color_active;
    }
    else
    {
      ptr_color_text = &sp_colorset_text->color_highlight;
    }
  }
  U32x4 color_text;
  ptr_color_text->ConvertColor_to_U32x4( color_text );

  // 背景カラー
  //CDI::ColorType bg_color = GetColorParameterBG()->color_default.color[0];

  m_msg_info.SetMessage( &m_text[ m_offset_idx ] );
  m_msg_info.default_color = color_text;

  const int i0 = sm_caret().idx_pos0;
  const int i1 = sm_caret().idx_pos1;

  if( sm_sp_focus() == this->GetLinkMyself() )
  {
    // 選択範囲がある場合。
    if( i0 != i1 )
    {
      // 反対色作成。
      DX::RectColor4P
        rev_color_text
          ( kCOLOR_WHITE - ptr_color_text->color[0].rgb
          , kCOLOR_WHITE - ptr_color_text->color[1].rgb
          , kCOLOR_WHITE - ptr_color_text->color[2].rgb
          , kCOLOR_WHITE - ptr_color_text->color[3].rgb
          );
      U32x4 rev_color_text32;
      rev_color_text.ConvertColor_to_U32x4( rev_color_text32 );

      //int x0 = (p0.x < 0) ? -p0.x-1 : p0.x;
      //float4
      //  rt( Clamp( in_rect.x + x0 - 1, rt_text.left, rt_text.right )
      //    , in_rect.y + p0.y
      //    , Clamp( in_rect.x + p1.x, rt_text.left, rt_text.right )
      //    , in_rect.y + p1.y
      //    );
      //zzf_DrawRectEx( rt, ptr_color_text->color );

      //// カラー変更
      //for(
      //  int idx = Min(i0,i1), max = Max(i0,i1);
      //  idx < max;
      //  ++idx )
      //{
      //  mi.SetColor_Index( idx, rev_color_text32 );
      //}
    }
  }

}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::WindowEventInterface::On_Timer
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID TextBox::On_Timer( _in<int> in_timer_ID )
{
  if( in_timer_ID == eID::Tid_CaretSwitch )
  {
    sm_caret().pos_x0.x = -sm_caret().pos_x0.x - 1; // １の補数を設定
                                                    // マイナスのときは非表示とする
    Update();
  }

  return eEventReturnID::SendParent_All;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_Size
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  TextBox::On_Size( _in<sdptr<Component>> in_sp_component )
{
  if( m_sp_render_tex )
  {
    auto size = this->GetSize();
    //float4 rt = { 1, 1, size.x-1, size.y-1 };
    m_sp_render_tex->Resize
      ( static_cast<int>(size.x - 2)
      , static_cast<int>(size.y - 2)
      );
    //m_sp_render->SetupWorkingArea( size - float2(2,2) );
    Update();
  }
  return eEventReturnID::SendParent_Render;
}


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

    if( in_type_mouse_btn == eMouseButton::Left )
    {
      //
      DX::FontDrawManager::CaretData ci;
      if( WIN::Mouse::IsMultiClickL(2) )
      {
        ci.get_type = DX::FontDrawManager::CaretData::kXY_TO_INDEX;
        ci.x = 0;
        ci.y = 5;
        zzf_GetCaretInfo( ci );
        sm_caret().pos_x0 = int2( ci.x, ci.y );
        sm_caret().idx_pos0 = 0;

        ci.x = 10000;
        ci.y = 5;
        zzf_GetCaretInfo( ci );
        sm_caret().pos_x1 = int2( ci.x, ci.y + ci.height );
        sm_caret().idx_pos1 = ci.idx;
      }
      else
      {
        ci.get_type = DX::FontDrawManager::CaretData::kXY_TO_INDEX;
        ci.x = static_cast<int>(in_mouse_x);
        ci.y = static_cast<int>(in_mouse_y);
        zzf_GetCaretInfo( ci );

        sm_caret().pos_x0   = int2( ci.x, ci.y );
        sm_caret().pos_x1   = int2( ci.x, ci.y + ci.height );
        sm_caret().idx_pos0 = ci.idx;
        sm_caret().idx_pos1 = ci.idx;
      }
    }
  }

  return eEventReturnID::LastCall;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseUp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  TextBox::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() )
  {
    if( in_type_mouse_btn == eMouseButton::Left )
    {
      SetFocus( GetLinkMyself() );
      SetCapture( nullptr );

      DX::FontDrawManager::CaretData ci;
      if( WIN::Mouse::IsMultiClickL(2) )
      {
      }
      else
      {
        ci.get_type = DX::FontDrawManager::CaretData::kXY_TO_INDEX;
        ci.x = static_cast<int>(in_mouse_x);
        ci.y = static_cast<int>(in_mouse_y);
        zzf_GetCaretInfo( ci );

        sm_caret().pos_x1   = int2( ci.x, ci.y + ci.height );
        sm_caret().idx_pos1 = ci.idx;

        const int h = sm_caret().pos_x1.y - sm_caret().pos_x0.y;
        const int x = sm_caret().pos_x1.x;
        const int y = sm_caret().pos_x1.y;
        UpdateCaret( GetSubjectWindow(), GetLinkMyself(), x, y, h );
      }
    }
    else
    if( in_type_mouse_btn == eMouseButton::Right )
    {
      if( GetFocus() == GetLinkMyself() )
      {
        //SetFocus( nullptr );
        SetCapture( nullptr );
        PopupBasicMenu
          ( GetLinkMyself()
          , in_mouse_x
          , in_mouse_y
          );
      }
    }
  }

  return eEventReturnID::LastCall;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::MouseEventInterface::On_MouseMove
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  TextBox::On_MouseMove
    ( _in<sdptr<Component>> in_sp_component
    , _in<float           > in_mouse_x
    , _in<float           > in_mouse_y
    )
{
  if( in_sp_component == GetLinkMyself()
   && WIN::Mouse::GetDownL() )
  {
    //
    DX::FontDrawManager::CaretData ci;
    ci.get_type = DX::FontDrawManager::CaretData::kXY_TO_INDEX;
    ci.x = static_cast<int>(in_mouse_x);
    ci.y = static_cast<int>(in_mouse_y);
    zzf_GetCaretInfo( ci );

    sm_caret().pos_x1 = int2( ci.x, ci.y + ci.height );
    sm_caret().idx_pos1 = ci.idx;
/*
    if( sm_caret().pos_x1.x < 0 )
    {
      m_offset_x = sm_caret().pos_x0.x;
    }
    else
    if( GetSize().x < sm_caret().pos_x1.x )
    {
      m_offset_x = sm_caret().pos_x1.x - GetSize().x;
    }*/

    Update();
  }

  return eEventReturnID::LastCall;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_Char
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  TextBox::On_Char
    ( _in<sdptr<Component>> in_sp_component
    , _in<TCHAR           > in_char_code
    , _in<int             > in_key_data
    )
{
  if( in_sp_component == this->GetLinkMyself() )
  {
    TCHAR char_code = in_char_code;

    // キー判別
    switch( (int)char_code )
    {
    case VK_BACK:
    case VK_TAB:
    case VK_CLEAR:
    case VK_ESCAPE:
      break;

    case VK_RETURN:
      //char_code = '\n';
      break;
    default:
      {
        if( WIN::Keyboard::Control() )
        {
          break;
        }
        auto& caret = sm_caret();
        int idx0 = caret.idx_pos0;
        int idx1 = caret.idx_pos1;

        if( idx0 != idx1 )
        {
          int min_idx = Min(idx0, idx1);
          int max_idx = Max(idx0, idx1);
          m_text.Cut( min_idx, max_idx-1 );

          idx0 = caret.idx_pos0 = min_idx;
          idx1 = caret.idx_pos1 = min_idx;
        }

        if( idx1 >= 0 )
        {
          str_type chr[] = { char_code, 0 };
          m_text.Insert
            ( idx1
            , Core::ChangeCodeStrings<td_DefString>( chr )
            );

          ++caret.idx_pos0;
          ++caret.idx_pos1;
          //
          DX::FontDrawManager::CaretData ci;
          ci.get_type = DX::FontDrawManager::CaretData::kINDEX_TO_XY;
          ci.idx = caret.idx_pos1;
          zzf_GetCaretInfo( ci );
          //
          caret.pos_x0 = int2( ci.x, ci.y );
          caret.pos_x1 = int2( ci.x, ci.y + ci.height );

          // 変換位置更新
          const int h = caret.pos_x1.y - caret.pos_x0.y;
          const int x = caret.pos_x1.x;
          const int y = caret.pos_x1.y;
          UpdateCaret( GetSubjectWindow(), GetLinkMyself(), x, y, h );
        }

        Update();
      }
    }
  }

  return eEventReturnID::LastCall;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::KeyEventInterface::On_KeyDown
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  TextBox::On_KeyDown
    ( _in<sdptr<Component>> in_sp_component
    , _in<int             > in_virtual_key_code
    )
{
  const int idx0 = sm_caret().idx_pos0;
  const int idx1 = sm_caret().idx_pos1;
  const int min_idx = Min( idx0, idx1 );
  const int max_idx = Max( idx0, idx1 );
  bool flag_caret_update = false;

  // delete
  if( in_virtual_key_code == VK_DELETE )
  {
    if( min_idx >= 0  &&  max_idx >= 0 )
    {
      if( min_idx == max_idx )
      {
        m_text.Cut( min_idx, min_idx );
      }
      else
      {
        m_text.Cut( min_idx, max_idx-1 );
      }

      if( idx0 < idx1 )
      {
        sm_caret().idx_pos1 = sm_caret().idx_pos0;
        sm_caret().pos_x1.x = sm_caret().pos_x0.x;
      }
      else
      {
        sm_caret().idx_pos0 = sm_caret().idx_pos1;
        sm_caret().pos_x0.x = sm_caret().pos_x1.x;
      }
    }
    Update();
  }

  // back space
  else
  if( in_virtual_key_code == VK_BACK )
  {
    if( min_idx > 0  &&  idx1 == idx0 )
    {
      const int del_idx = min_idx - 1;
      m_text.Cut( del_idx, del_idx );
      --sm_caret().idx_pos0;
      --sm_caret().idx_pos1;
    }
    else
    if( min_idx >= 0 && max_idx > 0 )
    {
      m_text.Cut( min_idx, max_idx-1 );

      sm_caret().idx_pos0 =
      sm_caret().idx_pos1 =
        Min( sm_caret().idx_pos0, sm_caret().idx_pos1 );
    }
    
    //
    DX::FontDrawManager::CaretData ci;
    ci.get_type = DX::FontDrawManager::CaretData::kINDEX_TO_XY;
    ci.idx = sm_caret().idx_pos1;
    zzf_GetCaretInfo( ci );

    sm_caret().pos_x0 = int2( ci.x, ci.y );
    sm_caret().pos_x1 = int2( ci.x, ci.y + ci.height );

    Update();

    flag_caret_update = true;
  }

  // ←
  else
  if( in_virtual_key_code == VK_LEFT )
  {
    if( sm_caret().idx_pos1 > 0 )
    {
      if( WIN::Keyboard::Control() )
      {
        sm_caret().idx_pos1 = 0;
      }
      else
      {
        --sm_caret().idx_pos1;
      }

      //
      DX::FontDrawManager::CaretData ci;
      ci.get_type = DX::FontDrawManager::CaretData::kINDEX_TO_XY;
      ci.idx = sm_caret().idx_pos1;
      zzf_GetCaretInfo( ci );
      
      sm_caret().pos_x0.y = ci.y;
      sm_caret().pos_x1 = int2( ci.x, ci.y + ci.height );

      flag_caret_update = true;
    }
    if( !WIN::Keyboard::Shift() )
    {
      sm_caret().pos_x0.x = sm_caret().pos_x1.x;
      sm_caret().idx_pos0 = sm_caret().idx_pos1;
    }

    Update();
  }

  // →
  else
  if( in_virtual_key_code == VK_RIGHT )
  {
    if( sm_caret().idx_pos1 < static_cast<int>(m_text.GetLength()) )
    {
      if( WIN::Keyboard::Control() )
      {
        sm_caret().idx_pos1 = static_cast<int>(m_text.GetLength());
      }
      else
      {
        ++sm_caret().idx_pos1;
      }

      //
      DX::FontDrawManager::CaretData ci;
      ci.get_type = DX::FontDrawManager::CaretData::kINDEX_TO_XY;
      ci.idx = sm_caret().idx_pos1;
      zzf_GetCaretInfo( ci );
      
      sm_caret().pos_x0.y = ci.y;
      sm_caret().pos_x1 = int2( ci.x, ci.y + ci.height );

      flag_caret_update = true;
    }
    if( !WIN::Keyboard::Shift() )
    {
      sm_caret().pos_x0.x = sm_caret().pos_x1.x;
      sm_caret().idx_pos0 = sm_caret().idx_pos1;
    }
    Update();
  }
  
  if( flag_caret_update )
  {
    const int h = sm_caret().pos_x1.y - sm_caret().pos_x0.y;
    const int x = sm_caret().pos_x1.x;
    const int y = sm_caret().pos_x1.y;
    UpdateCaret( GetSubjectWindow(), GetLinkMyself(), x, y, h );
  }

  return eEventReturnID::LastCall;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_UserProc
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  TextBox::On_UserProc
    ( _in<sdptr<Component>> in_sp_component
    , _in<long            > in_message
    , _in<WPARAM          > in_wparam
    , _in<LPARAM          > in_lparam
    )
{
  if( auto sp_menu = std::dynamic_pointer_cast<ActiveMenu>(in_sp_component) )
  {
    if( in_message == WM_COMMAND )
    {
      switch( in_wparam )
      {
      case eID::EditCut:    Cut();    return eEventReturnID::LastCall;
      case eID::EditCopy:   Copy();   return eEventReturnID::LastCall;
      case eID::EditPaste:  Paste();  return eEventReturnID::LastCall;
      case eID::EditDelete: Delete(); return eEventReturnID::LastCall;
      }
    }
  }
  return td_base::On_UserProc( in_sp_component, in_message, in_wparam, in_lparam );
}



// _____________________________________________________________________________
/// @brief コンストラクタ
/// 
/// @copydoc doxycomment::arg_in_sp_component_for_parent
/// @copydoc doxycomment::arg_in_position_for_component
/// @copydoc doxycomment::arg_in_size_for_component
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NumBox::NumBox
( _in<sdptr<Component>> in_sp_component_for_parent
, _in<float2          > in_position_for_component
, _in<float2          > in_size_for_component
) : TextBox
    ( in_sp_component_for_parent
    , in_position_for_component
    , in_size_for_component
    , CPL_GUC_DEF_STR("0")
    )
  , m_value( 0 )
  , m_value_min( 0 )
  , m_value_max( 0 )
  , m_mode( WIN::NumBox::eNumMode::Int )
  , m_length_dec( -1 )
{
  //CallOnce( zzf_StaticInitializeNB );

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

  zzf_SetInitializedLevel( zzf_GetClassLevel() );
}


// _____________________________________________________________________________
/// @brief コピーコンストラクタ
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
NumBox::NumBox( cref<NumBox> in_num_box )
  : td_base( in_num_box )
  , m_value     { in_num_box.m_value      }
  , m_value_min { in_num_box.m_value_min  }
  , m_value_max { in_num_box.m_value_max  }
  , m_mode      { in_num_box.m_mode       }
  , m_length_dec{ in_num_box.m_length_dec }
{
}


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


//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//// 数値ボックス静的初期化
//// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//int NumBox::zzf_StaticInitializeNB()
//{
////  sm_num_box().SetFont( sm_def_font_mng()->GetFont()->GetHandle() );
////  sm_num_box().SetDefaultCursor( NULL );
//
//  return true;
//}


// _____________________________________________________________________________
/// @brief 数値設定
/// 
/// @param[in] in_value : 設定する値を指定します。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NumBox::SetValue( _in<double> in_value )
{
  m_value = in_value;
  Clamp( m_value, m_value_min, m_value_max );
  
  switch( m_mode )
  {
  case WIN::NumBox::eNumMode::Float:
    if( m_length_dec == -1 )
    {
      m_text = td_DefString( m_value );
    }
    else
    {
      m_text.reserve( 64 );
      td_DefString format( CPL_GUC_DEF_STR("%.*f") );
      format[2] = '0' + m_length_dec;
      swprintf_s( &m_text[0], 64, &format[0], m_value );
    }
    break;

  case WIN::NumBox::eNumMode::Int:
    m_text = td_DefString( (int)m_value );
    break;

  case WIN::NumBox::eNumMode::IntX:
    {
      td_DefChar tmp_str[256] = {};
      CPL_SPRINTF_W( tmp_str, CPL_GUC_DEF_STR("%x"), (int)m_value );
      m_text = tmp_str;
    }
    break;
  }

  // キャレット位置調整
  if( sm_sp_focus() == GetLinkMyself() )
  {
    if( sm_caret().idx_pos1 >= (int)m_text.GetLength() )
    {
      sm_caret().idx_pos0 =
      sm_caret().idx_pos1 = static_cast<int>(m_text.GetLength()) - 1;
    }
  }

  Update();
}


// _____________________________________________________________________________
/// @brief 最小値設定
/// 
/// @copydoc doxycomment::arg_in_value_of_minimum
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NumBox::SetMin( _in<double> in_value_of_minimum )
{
  m_value_min = in_value_of_minimum;
  if( m_value < m_value_min )
  {
//    m_value = m_value_min;
    SetValue( m_value_min );
  }

  Update();
}


// _____________________________________________________________________________
/// @brief 最大値設定
/// 
/// @copydoc doxycomment::arg_in_value_of_maximum
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NumBox::SetMax( _in<double> in_value_of_maximum )
{
  m_value_max = in_value_of_maximum;
  if( m_value > m_value_max )
  {
//    m_value = m_value_max;
    SetValue( m_value_max );
  }

  Update();
}


// _____________________________________________________________________________
/// @brief 数値モード設定
/// 
/// @param[in] in_mode
///   : 数値の表示様式を指定します。\n
///   : 詳しくはeNumModeを参照してください。
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NumBox::SetIntegerMode( _in<WIN::NumBox::eNumMode> in_mode )
{
  m_mode = in_mode;

  Update();
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::Component::On_Char
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  NumBox::On_Char
    ( _in<sdptr<Component>> in_sp_component
    , _in<TCHAR           > in_char_code
    , _in<int             > in_key_data
    )
{
  if( in_sp_component == this->GetLinkMyself() )
  {
    int code_char = (int)in_char_code;
    bool is_changed = false;
    // キー判別
    switch( code_char )
    {
    case '-':
      {
        int value;
        CPL_SSCANF_W( m_text, CPL_GUC_DEF_STR("%d"), &value );
        if( value > 0 )
        {
          SetValue( -value );
          is_changed = true;
        }
      }
      break;
    case '+':
      {
        int value;
        CPL_SSCANF_W( m_text, CPL_GUC_DEF_STR("%d"), &value );
        if( value < 0 )
        {
          SetValue( -value );
          is_changed = true;
        }
      }
      break;

    case '.':
      if( sm_caret().idx_pos1 != 1 )
      {
        break;
      }
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
      {
        td_base::On_Char( in_sp_component, in_char_code, in_key_data );
        int value;
        CPL_SSCANF_W( m_text, CPL_GUC_DEF_STR("%d"), &value );
        m_value = value;
        is_changed = true;
      }
      break;
    }
    if( is_changed )
    {
      double value = m_value;
      this->SendParentMessage
        ( GetLinkMyself()
        , eID::ValueChanged
        , (WPARAM)&value
        , (LPARAM)this
        , eParentType::Position
        );
      return eEventReturnID::SendParent_Render;
    }
  }

  return eEventReturnID::LastCall;
}


// _____________________________________________________________________________
/// @copydoc CPL::GUC::KeyEventInterface::On_KeyDown
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
eEventReturnID
  NumBox::On_KeyDown
    ( _in<sdptr<Component>> in_sp_component
    , _in<int             > in_virtual_key_code
    )
{
  if( in_sp_component == this->GetLinkMyself() )
  {
    td_base::On_KeyDown( in_sp_component, in_virtual_key_code );

    switch( in_virtual_key_code )
    {
    case VK_DELETE:
    case VK_BACK:
      {
        int value;
        if( m_text == CPL_GUC_DEF_STR("") )
        {
          value = 0;
        }
        else
        {
          CPL_SSCANF_W( m_text, CPL_GUC_DEF_STR("%d"), &value );
        }
        double value_d = m_value = value;
        this->SendParentMessage
          ( GetLinkMyself()
          , eID::ValueChanged
          , (WPARAM)&value_d
          , (LPARAM)this
          , eParentType::Position
          );
      }
      return eEventReturnID::SendParent_Position;
    }
  }
  return eEventReturnID::LastCall;
}


// _____________________________________________________________________________
/// @brief 選択範囲コピー
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TextBox::Copy()
{
  // コピー用文字列の生成。
  // ※ 内部的にはライン毎の文字列配列で管理しているため、
  //    クリップボードにコピーするため、１つのバッファにまとめる。
  td_DefString buf{L""};
  auto& caret = sm_caret();
  auto const idx_low  = Min( caret.idx_pos0, caret.idx_pos1 );
  auto const idx_high = Max( caret.idx_pos0, caret.idx_pos1 );
  auto const length = idx_high - idx_low;
  auto const size   = length * sizeof(buf[0]);
  buf.resize( length + 1 );
  memcpy( &buf[0], &m_text[ idx_low ], size );
  //buf += L"\n";

  // クリップボードへコピー
  WIN::Clipboard cb;
  cb.SetData
    ( WIN::Clipboard::eFormat::UnicodeText
    , &buf[0]
    , (buf.length()+1) * sizeof(buf[0])
    );
}

// _____________________________________________________________________________
/// @brief 選択範囲削除
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TextBox::Delete()
{
  auto& caret = sm_caret();
  auto idx_low  = Min( caret.idx_pos0, caret.idx_pos1 );
  auto idx_high = Max( caret.idx_pos0, caret.idx_pos1 );
  auto const length = idx_high - idx_low;

  if( idx_low == idx_high )
  {
    ++idx_high;
  }
  m_text.Cut( idx_low, idx_high );
  
  caret.idx_pos0 =
  caret.idx_pos1 = idx_low;

}

// _____________________________________________________________________________
/// @brief ペースト
/// 
/// @return なし。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TextBox::Paste()
{
  // クリップボードからコピー。
  WIN::Clipboard cb;
  td_DefString str;
  std::vector<char> buf;
  if( cb.GetData( WIN::Clipboard::eFormat::UnicodeText, buf ) )
  {
    Core::ChangeCodeStrings( str, (wchar_t_cptr)&buf[0] );
  }
  else
  if( cb.GetData( WIN::Clipboard::eFormat::Text, buf ) )
  {
    Core::ChangeCodeStrings( str, (char_cptr)&buf[0] );
  }
  else
  {
    return;
  }
  // 最初の改行を無効化する。
  auto idx = str.FindStrBegin( L"\n" );
  if( idx != -1 )
  {
    str.FindBeginFront( str, L"\n", false );
  }

  // ***** 現在位置に追加。 *****
  Delete(); // 現在位置の文字列をいったん削除。
  auto& caret = sm_caret();
  auto idx_low  = Min( caret.idx_pos0, caret.idx_pos1 );
  auto idx_high = Max( caret.idx_pos0, caret.idx_pos1 );
  m_text.Insert( idx_low, str );

  // 変換位置更新
  const int h = caret.pos_x1.y - sm_caret().pos_x0.y;
  const int x = caret.pos_x1.x;
  const int y = caret.pos_x1.y;
  UpdateCaret( GetSubjectWindow(), GetLinkMyself(), x, y, h );
}


// _____________________________________________________________________________
/// @brief カレットインデックスの設定
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void TextBox::SetCaretIndex( _in<int> in_idx0, _in<int> in_idx1 )
{
  auto i0 = in_idx0 >= 0 ? in_idx0 : (int)m_text.length();
  auto i1 = in_idx0 >= 1 ? in_idx1 : (int)m_text.length();
  auto idx_min = Min(i0, i1);
  auto idx_max = Max(i0, i1);
  sm_caret().idx_pos0 = idx_min;
  sm_caret().idx_pos1 = idx_max;

  DX::FontDrawManager::CaretData ci;
  ci.get_type = DX::FontDrawManager::CaretData::kINDEX_TO_XY;
  ci.idx = sm_caret().idx_pos0;
  zzf_GetCaretInfo( ci );
  sm_caret().pos_x0.x = ci.x;
  sm_caret().pos_x0.y = ci.y;
  
  ci.idx = sm_caret().idx_pos1;
  zzf_GetCaretInfo( ci );
  sm_caret().pos_x1.x = ci.x;
  sm_caret().pos_x1.y = ci.y + ci.height;
}



} // namespace GUC
} // namespace CPL

